From c6e9350f78ac6f76b279a73c49cb1a7b674fb519 Mon Sep 17 00:00:00 2001 From: fabi Date: Tue, 28 Jul 2026 19:14:37 +0200 Subject: [PATCH] test(e2e): document why WebKit can't run the client-queue upload tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three 02-upload tests have been failing on `webkit-iphone` on main — `02-upload` was already in that project's testMatch, so this is pre-existing red, not something the audit work introduced. Root cause is the harness, not the app. Playwright's Linux WebKit build cannot store Blobs in IndexedDB at all: `put()` fails with "UnknownError: Error preparing Blob/File data to be stored in object store". Confirmed it is not about how Playwright delivers files — a Blob constructed in-page with `new Blob([bytes])` fails identically, while Chromium stores both that and a `setInputFiles` File without complaint. That breaks every test driving the composer (FAB → UploadSheet → /upload → submit), because `handleSubmit` awaits `addToQueue`, which persists the file before it can navigate. The symptom is a submit button stuck on "Wird hochgeladen…" and a timeout waiting for /feed — which reads like an app hang and cost real time to run down. Skip those four (the three above plus the new rejection-visible) on WebKit only, behind a named helper carrying the full explanation, so the next person gets the answer instead of the investigation. Deliberately narrow: WebKit still runs every API-driven upload test, all of 01-auth, 03-feed and 06-export — including the keepsake download, which only WebKit can meaningfully verify. Chromium continues to run all 14. Worth being explicit, since these tests exist to protect iOS: real Safari supports Blobs in IndexedDB, so this is NOT evidence that the offline upload queue is broken on the platform. It does mean that guarantee is currently unverifiable in CI and rests on Chromium coverage plus manual device testing. Co-Authored-By: Claude Opus 5 (1M context) --- e2e/helpers/webkit.ts | 29 +++++++++++++++++++ e2e/specs/02-upload/burst-queue.spec.ts | 5 ++++ e2e/specs/02-upload/gallery-path.spec.ts | 3 ++ e2e/specs/02-upload/rejection-visible.spec.ts | 3 ++ 4 files changed, 40 insertions(+) create mode 100644 e2e/helpers/webkit.ts diff --git a/e2e/helpers/webkit.ts b/e2e/helpers/webkit.ts new file mode 100644 index 0000000..9c98cd6 --- /dev/null +++ b/e2e/helpers/webkit.ts @@ -0,0 +1,29 @@ +import { test } from '@playwright/test'; + +/** + * Skip a test that depends on persisting a Blob/File in IndexedDB when running on + * Playwright's WebKit. + * + * The client upload queue (`frontend/src/lib/upload-queue.ts`) stores the file itself in + * IndexedDB so a backgrounded or reloaded phone can resume the upload. Playwright's Linux + * WebKit build cannot store Blobs in IndexedDB at all — `put()` fails with + * "UnknownError: Error preparing Blob/File data to be stored in object store". Verified to + * be the harness, not the app: a Blob constructed in-page with `new Blob([bytes])` fails + * exactly the same way, while Chromium stores both that and a `setInputFiles` File fine. + * Real iOS Safari supports Blobs in IndexedDB, so this is NOT evidence of a bug on the + * platform these tests exist to protect. + * + * Any test that drives the composer (FAB → UploadSheet → /upload → submit) hits this, + * because `handleSubmit` awaits `addToQueue`, which throws before it can navigate. + * + * This is deliberately narrow. WebKit still runs every API-driven upload test, the whole of + * 01-auth, 03-feed and 06-export — including the keepsake download, which only WebKit can + * meaningfully verify. If Playwright's WebKit ever gains IndexedDB Blob support, delete this + * helper and the four call sites. + */ +export function skipIfNoIdbBlobs(browserName: string) { + test.skip( + browserName === 'webkit', + "Playwright's Linux WebKit cannot store Blobs in IndexedDB (harness limitation, not an iOS one) — the client upload queue can't be exercised there" + ); +} diff --git a/e2e/specs/02-upload/burst-queue.spec.ts b/e2e/specs/02-upload/burst-queue.spec.ts index 8b538d5..fb9762f 100644 --- a/e2e/specs/02-upload/burst-queue.spec.ts +++ b/e2e/specs/02-upload/burst-queue.spec.ts @@ -26,6 +26,7 @@ * large fixture files. */ import { test, expect } from '../../fixtures/test'; +import { skipIfNoIdbBlobs } from '../../helpers/webkit'; import { FeedPage, UploadSheet } from '../../page-objects'; import { mkdtempSync, copyFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; @@ -100,7 +101,9 @@ test.describe('Upload — client queue under a burst', () => { guest, signIn, db, + browserName, }) => { + skipIfNoIdbBlobs(browserName); const g = await guest('BurstSerial'); await signIn(page, g); await warmUploadChunk(page); @@ -163,7 +166,9 @@ test.describe('Upload — client queue under a burst', () => { guest, signIn, db, + browserName, }) => { + skipIfNoIdbBlobs(browserName); const g = await guest('BurstResume'); await signIn(page, g); await warmUploadChunk(page); diff --git a/e2e/specs/02-upload/gallery-path.spec.ts b/e2e/specs/02-upload/gallery-path.spec.ts index 3eaa5d8..6c9b3a6 100644 --- a/e2e/specs/02-upload/gallery-path.spec.ts +++ b/e2e/specs/02-upload/gallery-path.spec.ts @@ -4,6 +4,7 @@ * IndexedDB queue resumption after refresh, and SSE `upload-processed`. */ import { test, expect } from '../../fixtures/test'; +import { skipIfNoIdbBlobs } from '../../helpers/webkit'; import { FeedPage, UploadSheet } from '../../page-objects'; import { SseListener } from '../../helpers/sse-listener'; import { join } from 'node:path'; @@ -49,7 +50,9 @@ test.describe('Upload — gallery path', () => { guest, signIn, db, + browserName, }) => { + skipIfNoIdbBlobs(browserName); // Previously fixme'd: the UI queue never fired a POST. Root cause was NOT a // navigation/blob timing quirk but an IndexedDB upgrade bug — the v1→v2 // `upgrade` callback opened a *new* transaction, which throws during a diff --git a/e2e/specs/02-upload/rejection-visible.spec.ts b/e2e/specs/02-upload/rejection-visible.spec.ts index 0ecc2d9..39a51ac 100644 --- a/e2e/specs/02-upload/rejection-visible.spec.ts +++ b/e2e/specs/02-upload/rejection-visible.spec.ts @@ -13,6 +13,7 @@ * queue row, no error text, and it never appeared in the feed. */ import { test, expect } from '../../fixtures/test'; +import { skipIfNoIdbBlobs } from '../../helpers/webkit'; import { FeedPage, UploadSheet } from '../../page-objects'; import { join } from 'node:path'; @@ -25,7 +26,9 @@ test.describe('Upload — a rejected upload is surfaced', () => { host, guest, signIn, + browserName, }) => { + skipIfNoIdbBlobs(browserName); const g = await guest('RejectedUploader'); await signIn(page, g);