@hyper-fetch/react
Version:
React hooks and utils for the hyper-fetch
214 lines (188 loc) • 6.75 kB
text/typescript
import { act } from "@testing-library/react";
import { Socket } from "@hyper-fetch/sockets";
import { createWebsocketMockingServer } from "@hyper-fetch/testing";
import { renderUseSocketState } from "../../../utils/use-socket-state.utils";
describe("useSocketState [ Base ]", () => {
const spy = vi.fn();
const { url, startServer, stopServer } = createWebsocketMockingServer();
const socket = new Socket({ url });
let view = renderUseSocketState(socket);
beforeEach(async () => {
view = renderUseSocketState(socket);
vi.resetModules();
vi.resetAllMocks();
startServer();
});
afterEach(() => {
stopServer();
});
describe("when using actions", () => {
it("should set state with data", async () => {
const value = 1;
const [state, actions] = view.result.current;
act(() => {
actions.setData(value);
});
expect(state.data).toBe(value);
});
it("should set state with timestamp", async () => {
const value = 1;
const [state, actions] = view.result.current;
act(() => {
actions.setTimestamp(value);
});
expect(state.timestamp).toBe(value);
});
it("should set state with connected value", async () => {
const value = true;
const [state, actions] = view.result.current;
act(() => {
actions.setConnected(value);
});
expect(state.connected).toBe(value);
});
it("should set state with connecting value", async () => {
const value = true;
const [state, actions] = view.result.current;
act(() => {
actions.setConnecting(value);
});
expect(state.connecting).toBe(value);
});
});
describe("when using callbacks", () => {
it("should call onConnected callback", async () => {
const [, , callbacks] = view.result.current;
act(() => {
socket.events.emitConnected();
callbacks.onConnected(spy);
socket.events.emitConnected();
});
expect(spy).toHaveBeenCalledTimes(1);
});
it("should call onDisconnected callback", async () => {
const [, , callbacks] = view.result.current;
act(() => {
socket.events.emitDisconnected();
callbacks.onDisconnected(spy);
socket.events.emitDisconnected();
});
expect(spy).toHaveBeenCalledTimes(1);
});
it("should call onError callback", async () => {
const value = {
error: new Error("Test error"),
};
const [, , callbacks] = view.result.current;
act(() => {
socket.events.emitError(value);
callbacks.onError(spy);
socket.events.emitError(value);
});
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(value);
});
it("should call onConnecting callback", async () => {
const [, , callbacks] = view.result.current;
act(() => {
socket.events.emitConnecting({ connecting: true });
callbacks.onConnecting(spy);
socket.events.emitConnecting({ connecting: true });
});
expect(spy).toHaveBeenCalledTimes(1);
});
it("should call onReconnecting callback", async () => {
const value = 2;
const [, , callbacks] = view.result.current;
act(() => {
socket.events.emitReconnecting({ attempts: value });
callbacks.onReconnecting(spy);
socket.events.emitReconnecting({ attempts: value });
});
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith({ attempts: value });
});
it("should call onReconnectingFailed callback", async () => {
const value = 2;
const [, , callbacks] = view.result.current;
act(() => {
socket.events.emitReconnectingFailed({ attempts: value });
callbacks.onReconnectingFailed(spy);
socket.events.emitReconnectingFailed({ attempts: value });
});
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith({ attempts: value });
});
});
describe("when using dependency tracking", () => {
it("should not trigger re-render when key is not tracked", async () => {
const renderSpy = vi.fn();
view = renderUseSocketState(socket, { onRender: renderSpy });
const [, actions] = view.result.current;
renderSpy.mockClear(); // Clear initial render count
act(() => {
actions.setData(123);
});
expect(renderSpy).not.toHaveBeenCalled();
});
it("should trigger re-render when key is tracked", async () => {
const renderSpy = vi.fn();
view = renderUseSocketState(socket, { onRender: renderSpy });
const [, actions, , { setRenderKey }] = view.result.current;
act(() => {
setRenderKey("data");
});
renderSpy.mockClear(); // Clear initial render count
act(() => {
actions.setData(123);
});
expect(renderSpy).toHaveBeenCalledTimes(1);
});
it("should not add duplicate render keys", async () => {
const renderSpy = vi.fn();
view = renderUseSocketState(socket, { onRender: renderSpy });
const [, , , { setRenderKey }] = view.result.current;
act(() => {
setRenderKey("data");
setRenderKey("data"); // Adding same key twice
});
renderSpy.mockClear(); // Clear initial render count
act(() => {
view.result.current[1].setData(123);
});
expect(renderSpy).toHaveBeenCalledTimes(1);
});
});
describe("when using clearState", () => {
it("should reset all state to initial values", async () => {
view = renderUseSocketState(socket);
const [, actions, , { setRenderKey }] = view.result.current;
act(() => {
setRenderKey("data");
setRenderKey("extra");
setRenderKey("connected");
setRenderKey("connecting");
setRenderKey("timestamp");
});
act(() => {
actions.setData("some-data");
actions.setExtra({ test: true } as any);
actions.setConnected(true);
actions.setConnecting(true);
actions.setTimestamp(12345);
});
expect(view.result.current[0].data).toBe("some-data");
expect(view.result.current[0].connected).toBe(true);
expect(view.result.current[0].connecting).toBe(true);
expect(view.result.current[0].timestamp).toBe(12345);
act(() => {
view.result.current[1].clearState();
});
expect(view.result.current[0].data).toBe(null);
expect(view.result.current[0].extra).toBe(null);
expect(view.result.current[0].connected).toBe(false);
expect(view.result.current[0].connecting).toBe(false);
expect(view.result.current[0].timestamp).toBe(null);
});
});
});