fix(01-review): WR-01+WR-02 stable capture error codes + pure assertCodecSupported
This commit is contained in:
@@ -17,14 +17,23 @@ describe('codec strict mode', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('throws on unsupported vp9 and emits RECORDING_ERROR', async () => {
|
||||
// WR-02 fix: assertCodecSupported is a pure predicate that throws.
|
||||
// The previous spec expected a RECORDING_ERROR broadcast from inside
|
||||
// the assertion; that side-effect was removed (single-responsibility +
|
||||
// it double-emitted with startRecording's catch block). The notify is
|
||||
// now solely the caller's (startRecording's) responsibility — exercised
|
||||
// via integration through `classifyCaptureError` rather than from this
|
||||
// unit test, since `startRecording` requires a full getDisplayMedia
|
||||
// stub that jsdom does not provide.
|
||||
it('throws on unsupported vp9 (pure assertion, no side-effect)', async () => {
|
||||
(globalThis as unknown as GlobalWithChrome).MediaRecorder = {
|
||||
isTypeSupported: vi.fn().mockReturnValue(false),
|
||||
};
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(() => mod.assertCodecSupported()).toThrow(/vp9 unsupported/);
|
||||
const stub = (globalThis as unknown as GlobalWithChrome).chrome!;
|
||||
expect(stub.runtime.sendMessage).toHaveBeenCalledWith(
|
||||
// The assertion itself MUST NOT emit RECORDING_ERROR.
|
||||
expect(stub.runtime.sendMessage).not.toHaveBeenCalledWith(
|
||||
expect.objectContaining({ type: 'RECORDING_ERROR' })
|
||||
);
|
||||
});
|
||||
@@ -41,3 +50,74 @@ describe('codec strict mode', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// WR-01 fix: classifyCaptureError maps DOMException / Error shapes to a
|
||||
// stable string union. The popup / SW route can switch on the code
|
||||
// instead of substring-matching DOMException.message — message text
|
||||
// changes between Chrome versions and locales, name and prototype do not.
|
||||
describe('classifyCaptureError (WR-01 stable error codes)', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
(globalThis as unknown as GlobalWithChrome).chrome = {
|
||||
runtime: { sendMessage: vi.fn() },
|
||||
};
|
||||
(globalThis as unknown as GlobalWithChrome).MediaRecorder = {
|
||||
isTypeSupported: vi.fn().mockReturnValue(true),
|
||||
};
|
||||
});
|
||||
|
||||
function makeDomError(name: string, message: string): Error {
|
||||
const e = new Error(message);
|
||||
(e as { name: string }).name = name;
|
||||
return e;
|
||||
}
|
||||
|
||||
it('codec error → "codec-unsupported"', async () => {
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(mod.classifyCaptureError(new Error('vp9 unsupported. UA=<test>'))).toBe(
|
||||
'codec-unsupported',
|
||||
);
|
||||
});
|
||||
|
||||
it('NotAllowedError (no system hint) → "user-cancelled"', async () => {
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(
|
||||
mod.classifyCaptureError(makeDomError('NotAllowedError', 'Permission denied by user')),
|
||||
).toBe('user-cancelled');
|
||||
});
|
||||
|
||||
it('NotAllowedError with "system" in message → "permission-denied"', async () => {
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(
|
||||
mod.classifyCaptureError(makeDomError('NotAllowedError', 'Permission denied by system')),
|
||||
).toBe('permission-denied');
|
||||
});
|
||||
|
||||
it('SecurityError → "permission-denied"', async () => {
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(mod.classifyCaptureError(makeDomError('SecurityError', 'blocked'))).toBe(
|
||||
'permission-denied',
|
||||
);
|
||||
});
|
||||
|
||||
it('NotFoundError → "no-source-selected"', async () => {
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(mod.classifyCaptureError(makeDomError('NotFoundError', 'no source'))).toBe(
|
||||
'no-source-selected',
|
||||
);
|
||||
});
|
||||
|
||||
it('AbortError → "capture-failed"', async () => {
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(mod.classifyCaptureError(makeDomError('AbortError', 'aborted'))).toBe(
|
||||
'capture-failed',
|
||||
);
|
||||
});
|
||||
|
||||
it('arbitrary error → "unknown"', async () => {
|
||||
const mod = await import('../../src/offscreen/recorder');
|
||||
expect(mod.classifyCaptureError(new Error('totally novel failure'))).toBe('unknown');
|
||||
expect(mod.classifyCaptureError('a bare string')).toBe('unknown');
|
||||
expect(mod.classifyCaptureError(null)).toBe('unknown');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user