mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
091346dfe8
* wip * Remove obsolete snapshots * simplify * chore(test): Convert mocks to TypeScript and tighten fetch mock types Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Remove unneccessary patches * Migrate to msw instead of custom fetch mock * Address PR review comments - Split chained vi.useFakeTimers().setSystemTime() into separate calls. - Switch test setup to dynamic imports so EventEmitter.defaultMaxListeners assignment runs before module init (static imports were hoisted above it). - Drop redundant NODE_ENV guard in monkeyPatchSequelizeErrorsForJest; its sole caller already gates on env.isTest. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
114 lines
3.0 KiB
TypeScript
114 lines
3.0 KiB
TypeScript
import { Server } from "@hocuspocus/server";
|
|
import WebSocket from "ws";
|
|
import EDITOR_VERSION from "@shared/editor/version";
|
|
import { sleep } from "@shared/utils/timers";
|
|
import { ConnectionLimitExtension } from "./ConnectionLimitExtension";
|
|
import { EditorVersionExtension } from "./EditorVersionExtension";
|
|
|
|
vi.mock("@server/env", () => ({
|
|
default: {
|
|
COLLABORATION_MAX_CLIENTS_PER_DOCUMENT: 2,
|
|
},
|
|
COLLABORATION_MAX_CLIENTS_PER_DOCUMENT: 2,
|
|
}));
|
|
|
|
describe("ConnectionLimitExtension", () => {
|
|
let server: typeof Server;
|
|
let extension: ConnectionLimitExtension;
|
|
const port = 12345;
|
|
const url = `ws://127.0.0.1:${port}`;
|
|
const documentName = "test";
|
|
|
|
beforeEach(async () => {
|
|
extension = new ConnectionLimitExtension();
|
|
server = Server.configure({
|
|
port,
|
|
extensions: [extension, new EditorVersionExtension()],
|
|
quiet: true,
|
|
});
|
|
await server.listen();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await server.destroy();
|
|
});
|
|
|
|
const getConnections = () =>
|
|
extension.connectionsByDocument.get(documentName)?.size ?? 0;
|
|
|
|
const createWebSocket = (editorVersion = EDITOR_VERSION) =>
|
|
new Promise<WebSocket>((resolve, reject) => {
|
|
const ws = new WebSocket(
|
|
`${url}/${documentName}?editorVersion=${editorVersion}`
|
|
);
|
|
ws.on("open", () => resolve(ws));
|
|
ws.on("error", reject);
|
|
});
|
|
|
|
it("should allow connections within limit", async () => {
|
|
const ws1 = await createWebSocket();
|
|
const ws2 = await createWebSocket();
|
|
|
|
expect(ws1.readyState).toBe(WebSocket.OPEN);
|
|
expect(ws2.readyState).toBe(WebSocket.OPEN);
|
|
expect(getConnections()).toBe(2);
|
|
|
|
ws1.close();
|
|
ws2.close();
|
|
|
|
await sleep(250);
|
|
expect(getConnections()).toBe(0);
|
|
});
|
|
|
|
it("should close connections exceeding limit", async () => {
|
|
const ws1 = await createWebSocket();
|
|
const ws2 = await createWebSocket();
|
|
|
|
const ws3 = await createWebSocket();
|
|
await sleep(250);
|
|
|
|
expect(ws3.readyState).toBe(WebSocket.CLOSED);
|
|
expect(ws2.readyState).toBe(WebSocket.OPEN);
|
|
expect(ws1.readyState).toBe(WebSocket.OPEN);
|
|
expect(getConnections()).toBe(2);
|
|
|
|
ws1.close();
|
|
ws2.close();
|
|
|
|
await sleep(250);
|
|
expect(getConnections()).toBe(0);
|
|
});
|
|
|
|
it("should handle connections closed by other extensions", async () => {
|
|
const ws1 = await createWebSocket();
|
|
|
|
// Create a connection that will be closed by the EditorVersionExtension
|
|
const ws2 = await createWebSocket("1.0.0");
|
|
|
|
ws1.close();
|
|
ws2.close();
|
|
|
|
await sleep(250);
|
|
expect(getConnections()).toBe(0);
|
|
});
|
|
|
|
it("should allow new connection after disconnect", async () => {
|
|
const ws1 = await createWebSocket();
|
|
const ws2 = await createWebSocket();
|
|
|
|
ws1.close();
|
|
await sleep(250);
|
|
expect(getConnections()).toBe(1);
|
|
|
|
const ws3 = await createWebSocket();
|
|
expect(ws3.readyState).toBe(WebSocket.OPEN);
|
|
expect(getConnections()).toBe(2);
|
|
|
|
ws2.close();
|
|
ws3.close();
|
|
|
|
await sleep(250);
|
|
expect(getConnections()).toBe(0);
|
|
});
|
|
});
|