jest-websocket-mock
jest-websocket-mock copied to clipboard
Running multiple jest tests after each other fails
Hi folks,
I've following tests:
Jest Test Code
import WS from "jest-websocket-mock";
import { act, cleanup, renderHook } from "@testing-library/react";
import { z } from "zod";
import useLiveDbHook from "./websockets";
const BASE_URL = "http://127.0.0.1:8080";
jest.mock("react-oidc-context", () => ({
useAuth: () => {
return {
isLoading: false,
isAuthenticated: true,
user: { access_token: "test-token" },
};
},
}));
describe("useLiveDbHook", () => {
let server: WS;
beforeEach(() => {
server = new WS(`${BASE_URL.replace(/^http/, "ws")}/endpoint`);
});
afterEach(() => {
server.close();
WS.clean();
});
test.only("elements will be updated if update was received", async () => {
const { result } = renderHook(() =>
useLiveDbHook(
"/endpoint",
z.object({ _id: z.string(), name: z.string(), age: z.number() }),
),
);
await server.connected;
server.send(
JSON.stringify({
operation_type: "insert",
object_id: "some-id",
data: { _id: "some-id", name: "Peter", age: 23 },
}),
);
expect(server).toReceiveMessage(JSON.stringify(["some-id"]));
server.send(
JSON.stringify({
operation_type: "insert",
object_id: "some-id2",
data: { _id: "some-id2", name: "Günther", age: 24 },
}),
);
expect(server).toReceiveMessage(JSON.stringify(["some-id", "some-id2"]));
server.send(
JSON.stringify({
operation_type: "update",
object_id: "some-id",
data: { _id: "some-id", name: "Hans", age: 30 },
}),
);
expect(result.current.elements.length).toBe(2);
expect(result.current.elements).toContainEqual({
_id: "some-id",
name: "Hans",
age: 30,
});
expect(result.current.elements).toContainEqual({
_id: "some-id2",
name: "Günther",
age: 24,
});
expect(server).toReceiveMessage(JSON.stringify(["some-id2", "some-id"])); // (elements.map(elem => elem._id)
await cleanup();
});
test.only("elements will not be effected if a update with not existing id was received", async () => {
const { result } = renderHook(() =>
useLiveDbHook(
"/endpoint",
z.object({ _id: z.string(), name: z.string(), age: z.number() }),
),
);
await server.connected;
act(() => {
server.send(
JSON.stringify({
operation_type: "insert",
object_id: "some-id",
data: { _id: "some-id", name: "Peter", age: 23 },
}),
);
});
expect(server).toReceiveMessage(JSON.stringify(["some-id"]));
act(() => {
server.send(
JSON.stringify({
operation_type: "insert",
object_id: "some-id2",
data: { _id: "some-id2", name: "Günther", age: 24 },
}),
);
});
expect(server).toReceiveMessage(JSON.stringify(["some-id", "some-id2"]));
act(() => {
server.send(
JSON.stringify({
operation_type: "insert",
object_id: "some-id3",
data: { _id: "some-id3", name: "Hans", age: 30 },
}),
);
});
expect(server).toReceiveMessage(
JSON.stringify(["some-id", "some-id2", "some-id3"]),
);
expect(result.current.elements.length).toBe(3);
act(() => {
server.send(
JSON.stringify({
operation_type: "update",
object_id: "NOT_EXISTING",
data: null,
}),
);
});
expect(result.current.elements.length).toBe(3);
expect(result.current.elements).toContainEqual({
_id: "some-id",
name: "Peter",
age: 23,
});
expect(result.current.elements).toContainEqual({
_id: "some-id2",
name: "Günther",
age: 24,
});
expect(result.current.elements).toContainEqual({
_id: "some-id3",
name: "Hans",
age: 30,
});
expect(server).toReceiveMessage(
JSON.stringify(["some-id", "some-id2", "some-id3"]),
);
await cleanup();
});
Remove one .only and the remaing test will pass. If both are executed with .only one test will fail (see following logs): Logs:
Logs of the different test executions
Single run 1:
PASS src/hooks/db/websocket.unit.ts
useLiveDbHook
✓ elements will be updated if update was received (33 ms)
○ skipped connects to WebSocket
○ skipped reconnect with WebSocket if connection was lost
○ skipped elements contains received data
○ skipped elements will not be effected if a update with not existing id was received
○ skipped elements will be deleted if delete was received
○ skipped elements will not be effected if a delete with not existing id was received
○ skipped setElements causes a subscription request containing ALL current ids
Single run 2:
PASS src/hooks/db/websocket.unit.ts
useLiveDbHook
✓ elements will not be effected if a update with not existing id was received (32 ms)
○ skipped connects to WebSocket
○ skipped reconnect with WebSocket if connection was lost
○ skipped elements contains received data
○ skipped elements will be updated if update was received
○ skipped elements will be deleted if delete was received
○ skipped elements will not be effected if a delete with not existing id was received
○ skipped setElements causes a subscription request containing ALL current ids
Together
FAIL src/hooks/db/websocket.unit.ts
useLiveDbHook
✓ elements will be updated if update was received (31 ms)
✕ elements will not be effected if a update with not existing id was received (11 ms)
○ skipped connects to WebSocket
○ skipped reconnect with WebSocket if connection was lost
○ skipped elements contains received data
○ skipped elements will be deleted if delete was received
○ skipped elements will not be effected if a delete with not existing id was received
○ skipped setElements causes a subscription request containing ALL current ids
● useLiveDbHook › elements will not be effected if a update with not existing id was received
expect(WS).toReceiveMessage(expected)
Expected the next received message to equal:
"[\"some-id\",\"some-id2\"]"
Received:
undefined
Difference:
Comparing two different types of values. Expected string but received undefined.
111 | );
112 |
> 113 | expect(server).toReceiveMessage(JSON.stringify(["some-id", "some-id2"]));
| ^
114 |
115 | server.send(
116 | JSON.stringify({
at src/hooks/db/websocket.unit.ts:113:20
at fulfilled (src/hooks/db/websocket.unit.ts:5:58)
● useLiveDbHook › elements will not be effected if a update with not existing id was received
expect(WS).toReceiveMessage(expected)
Expected the next received message to equal:
"[\"some-id2\",\"some-id\"]"
Received:
undefined
Difference:
Comparing two different types of values. Expected string but received undefined.
133 | });
134 |
> 135 | expect(server).toReceiveMessage(JSON.stringify(["some-id2", "some-id"])); // (elements.map(elem => elem._id)
| ^
136 | await cleanup();
137 | });
138 |
at src/hooks/db/websocket.unit.ts:135:20
at fulfilled (src/hooks/db/websocket.unit.ts:5:58)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 6 skipped, 1 passed, 8 total
Snapshots: 0 total
Time: 1.683 s
Ran all test suites.
Both tests are testing a react hook I wrote which connects to a websocket server. You can pass the endpoint name to the hook. The hook itself will use useAuth to determine the access token and add this to the websocket url : ws://<ip>/<endpoint>?token=<access_token>.
Further the hook provides a react state ( elements) and a setter (setElements).
Everytime the websocket receives a message from the server, the elements can change (depending on the message).
Everytime the elements change (covered by useEffect(() => ..., [elements]); inside of useLiveDbHook) the client sends a list of the _ids of the current elements to the server.
So if the server sends a element, then the elements change and the client answers with the old id list including the new element (if INSERTED).
I tested the logic manually and I'm sure it works. But the tests I build just fails if I execute them after each other but are passed if I run them separatly. I have no idea why...