Milestone v1 (v2.0.0): Mokosh — Session Capture #1
67
tests/offscreen/handshake.test.ts
Normal file
67
tests/offscreen/handshake.test.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
|
||||||
|
interface PortStub {
|
||||||
|
name: string;
|
||||||
|
postMessage: ReturnType<typeof vi.fn>;
|
||||||
|
onMessage: { addListener: ReturnType<typeof vi.fn> };
|
||||||
|
onDisconnect: { addListener: ReturnType<typeof vi.fn> };
|
||||||
|
disconnect: ReturnType<typeof vi.fn>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChromeStub {
|
||||||
|
runtime: {
|
||||||
|
id: string;
|
||||||
|
sendMessage: (m: unknown) => void;
|
||||||
|
onMessage: { addListener: ReturnType<typeof vi.fn> };
|
||||||
|
connect: () => PortStub;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GlobalWithChrome {
|
||||||
|
chrome?: ChromeStub;
|
||||||
|
MediaRecorder?: { isTypeSupported: (mime: string) => boolean };
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildChromeStub(calls: unknown[]): ChromeStub {
|
||||||
|
return {
|
||||||
|
runtime: {
|
||||||
|
id: 'ext-id-test',
|
||||||
|
sendMessage: (m: unknown) => {
|
||||||
|
calls.push(m);
|
||||||
|
},
|
||||||
|
onMessage: { addListener: vi.fn() },
|
||||||
|
connect: () => ({
|
||||||
|
name: 'video-keepalive',
|
||||||
|
postMessage: vi.fn(),
|
||||||
|
onMessage: { addListener: vi.fn() },
|
||||||
|
onDisconnect: { addListener: vi.fn() },
|
||||||
|
disconnect: vi.fn(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('OFFSCREEN_READY handshake', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetModules();
|
||||||
|
(globalThis as unknown as GlobalWithChrome).MediaRecorder = {
|
||||||
|
isTypeSupported: vi.fn().mockReturnValue(true),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sends OFFSCREEN_READY after listener registration', async () => {
|
||||||
|
const calls: unknown[] = [];
|
||||||
|
const stub = buildChromeStub(calls);
|
||||||
|
(globalThis as unknown as GlobalWithChrome).chrome = stub;
|
||||||
|
await import('../../src/offscreen/recorder');
|
||||||
|
expect(stub.runtime.onMessage.addListener).toHaveBeenCalled();
|
||||||
|
expect(calls).toEqual(
|
||||||
|
expect.arrayContaining([expect.objectContaining({ type: 'OFFSCREEN_READY' })])
|
||||||
|
);
|
||||||
|
const readyCount = calls.filter(
|
||||||
|
(m): m is { type: string } =>
|
||||||
|
typeof m === 'object' && m !== null && (m as { type?: unknown }).type === 'OFFSCREEN_READY'
|
||||||
|
).length;
|
||||||
|
expect(readyCount).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
89
tests/offscreen/port.test.ts
Normal file
89
tests/offscreen/port.test.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
|
||||||
|
interface PortStub {
|
||||||
|
name: string;
|
||||||
|
postMessage: ReturnType<typeof vi.fn>;
|
||||||
|
onMessage: { addListener: ReturnType<typeof vi.fn> };
|
||||||
|
onDisconnect: { addListener: (fn: () => void) => void };
|
||||||
|
disconnect: ReturnType<typeof vi.fn>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChromeStub {
|
||||||
|
runtime: {
|
||||||
|
id: string;
|
||||||
|
sendMessage: ReturnType<typeof vi.fn>;
|
||||||
|
onMessage: { addListener: ReturnType<typeof vi.fn> };
|
||||||
|
connect: () => PortStub;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GlobalWithChrome {
|
||||||
|
chrome?: ChromeStub;
|
||||||
|
MediaRecorder?: { isTypeSupported: (mime: string) => boolean };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('port reconnect', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetModules();
|
||||||
|
(globalThis as unknown as GlobalWithChrome).MediaRecorder = {
|
||||||
|
isTypeSupported: vi.fn().mockReturnValue(true),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('connects on module load', async () => {
|
||||||
|
let connectCount = 0;
|
||||||
|
const disconnectListeners: Array<() => void> = [];
|
||||||
|
const stub: ChromeStub = {
|
||||||
|
runtime: {
|
||||||
|
id: 'ext-id-test',
|
||||||
|
sendMessage: vi.fn(),
|
||||||
|
onMessage: { addListener: vi.fn() },
|
||||||
|
connect: () => {
|
||||||
|
connectCount++;
|
||||||
|
return {
|
||||||
|
name: 'video-keepalive',
|
||||||
|
postMessage: vi.fn(),
|
||||||
|
onMessage: { addListener: vi.fn() },
|
||||||
|
onDisconnect: {
|
||||||
|
addListener: (fn: () => void) => disconnectListeners.push(fn),
|
||||||
|
},
|
||||||
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
(globalThis as unknown as GlobalWithChrome).chrome = stub;
|
||||||
|
await import('../../src/offscreen/recorder');
|
||||||
|
expect(connectCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reconnects when port disconnects', async () => {
|
||||||
|
let connectCount = 0;
|
||||||
|
const disconnectListeners: Array<() => void> = [];
|
||||||
|
const stub: ChromeStub = {
|
||||||
|
runtime: {
|
||||||
|
id: 'ext-id-test',
|
||||||
|
sendMessage: vi.fn(),
|
||||||
|
onMessage: { addListener: vi.fn() },
|
||||||
|
connect: () => {
|
||||||
|
connectCount++;
|
||||||
|
return {
|
||||||
|
name: 'video-keepalive',
|
||||||
|
postMessage: vi.fn(),
|
||||||
|
onMessage: { addListener: vi.fn() },
|
||||||
|
onDisconnect: {
|
||||||
|
addListener: (fn: () => void) => disconnectListeners.push(fn),
|
||||||
|
},
|
||||||
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
(globalThis as unknown as GlobalWithChrome).chrome = stub;
|
||||||
|
await import('../../src/offscreen/recorder');
|
||||||
|
expect(connectCount).toBe(1);
|
||||||
|
// Fire the disconnect — module should reconnect
|
||||||
|
disconnectListeners.forEach((fn) => fn());
|
||||||
|
expect(connectCount).toBeGreaterThanOrEqual(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user