diff --git a/.changeset/catch-initial-background-load.md b/.changeset/catch-initial-background-load.md new file mode 100644 index 0000000..f26d4ee --- /dev/null +++ b/.changeset/catch-initial-background-load.md @@ -0,0 +1,5 @@ +--- +'@livekit/track-processors': patch +--- + +Log a failing background image passed to the processor's constructor, instead of raising an unhandled promise rejection diff --git a/e2e/README.md b/e2e/README.md index 84c78e7..99ce1f1 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -40,7 +40,7 @@ Seventeen cases across eleven concerns. | `capability.spec.ts` | A1, A1b, A3, A4 | Support predicates; both pipelines selected and working | | `lifecycle.spec.ts` | B1, B2 | Attach produces blurred frames; detach restores them | | `modes.spec.ts` | C1, C1b, C3 | Switching lands correctly, publishes no intermediate frame, and `disabled` is true passthrough | -| `background.spec.ts` | D1, D5 | Image composited behind the subject; fetched once | +| `background.spec.ts` | D1, D5, D6 | Image composited behind the subject; fetched once; a failing image at construction is logged | | `geometry.spec.ts` | E1 | Output dimensions follow the source at three resolutions | | `performance.spec.ts` | G1 | `onFrameProcessed` timings are coherent at a usable frame rate | diff --git a/e2e/specs/background.spec.ts b/e2e/specs/background.spec.ts index 688bda3..4827a0e 100644 --- a/e2e/specs/background.spec.ts +++ b/e2e/specs/background.spec.ts @@ -110,4 +110,28 @@ test.describe('virtual background', () => { // this asserts only about repeated switches within a single processor session. expect(requests, `bg-solid.png was fetched ${requests} times`).toBe(1); }); + + test('D6: an image that fails to load at construction is logged, not thrown', async ({ app }) => { + const { page } = app; + + let requests = 0; + await page.route('**/missing-bg.png', (route) => { + requests += 1; + return route.fulfill({ status: 404 }); + }); + + // `mode` and `bg` are read when the harness constructs the processor, so the failing image + // goes through the constructor rather than switchTo(). + await app.goto({ mode: 'virtual-background', bg: '/missing-bg.png', backdrop: 'flat' }); + await startCamera(page); + await attachProcessor(page); + + // The failure must actually have happened, or a clean page would be trivially true. + expect(requests, 'missing-bg.png was never requested').toBeGreaterThan(0); + + // Regression guard for #141. A rejection from the constructor reaches the page as an + // uncaught error with no message. + expect(app.pageErrors, 'uncaught page errors').toEqual([]); + expect(await page.evaluate(() => window.harness.lastError()), 'harness logged an error').toBeNull(); + }); }); diff --git a/src/transformers/BackgroundTransformer.ts b/src/transformers/BackgroundTransformer.ts index adb1ea3..8c8823a 100644 --- a/src/transformers/BackgroundTransformer.ts +++ b/src/transformers/BackgroundTransformer.ts @@ -51,7 +51,9 @@ export default class BackgroundProcessor extends VideoTransformer + this.log.error('Error while applying initial processor options: ', err), + ); } async init({ outputCanvas, inputElement: inputVideo }: VideoTransformerInitOptions) {