From e6005dd115bf5df72f176c50cf7ecb180db56468 Mon Sep 17 00:00:00 2001 From: Sen Chang Date: Wed, 21 Oct 2026 11:29:54 -0700 Subject: [PATCH] Log a failing initial background image instead of rejecting unhandled The constructor called the async update() without awaiting or catching it, so an imagePath that failed to load surfaced as an unhandled promise rejection that callers had no way to handle. It is now caught and logged, matching how init() handles the same failure. Adds e2e case D6, which constructs the processor with a 404ing image and asserts the page reports no uncaught error. Fixes #141 --- .changeset/catch-initial-background-load.md | 5 +++++ e2e/README.md | 2 +- e2e/specs/background.spec.ts | 24 +++++++++++++++++++++ src/transformers/BackgroundTransformer.ts | 4 +++- 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 .changeset/catch-initial-background-load.md 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) {