From 9ab404b2e6e35b83e8c3863da4a60e9b7d979032 Mon Sep 17 00:00:00 2001 From: James Brunton Date: Fri, 5 Jun 2026 12:34:32 +0100 Subject: [PATCH] Fix intermittently failing Playwright tests in main (#6541) # Description of Changes [#6474](https://github.com/Stirling-Tools/Stirling-PDF/pull/6474) updated the IndexedDB schema number to v9, but a couple of Playwright tests were explicitly creating a DB in v4 schema, which then caused inconsistently failing tests because the DB upgrade process is asynchronous and sometimes was too slow to upgrade, causing the test to get into an invalid state. Also fixes the screenshots directory exclusion since the frontend folder was restructured. --- .gitignore | 2 +- .../stubbed/files-page-screenshots.spec.ts | 120 +++++++++-------- .../src/core/tests/stubbed/files-page.spec.ts | 122 ++++++++++-------- 3 files changed, 130 insertions(+), 114 deletions(-) diff --git a/.gitignore b/.gitignore index 9e221c7eb..fb4c7b642 100644 --- a/.gitignore +++ b/.gitignore @@ -279,4 +279,4 @@ docs/type3/signatures/ *.playwright-mcp.png # Local screenshot artifacts from *-screenshots.spec.ts -frontend/screenshots/ +frontend/editor/screenshots/ diff --git a/frontend/editor/src/core/tests/stubbed/files-page-screenshots.spec.ts b/frontend/editor/src/core/tests/stubbed/files-page-screenshots.spec.ts index 081af705a..1805f5d65 100644 --- a/frontend/editor/src/core/tests/stubbed/files-page-screenshots.spec.ts +++ b/frontend/editor/src/core/tests/stubbed/files-page-screenshots.spec.ts @@ -1,6 +1,7 @@ import { test, expect } from "@app/tests/helpers/stub-test-base"; import type { Page, Route } from "@playwright/test"; import path from "node:path"; +import { DATABASE_CONFIGS } from "@app/services/indexedDBManager"; /** Screenshot review of /files surfaces; dumps PNGs to screenshots/files-page. */ @@ -34,62 +35,69 @@ async function seedFiles(page: Page, files: SeedFile[]): Promise { await page.route("**/api/v1/storage/files", (route: Route) => route.fulfill({ json: serverFiles }), ); - await page.addInitScript((records) => { - const open = window.indexedDB.open("stirling-pdf-files", 4); - open.onupgradeneeded = (event) => { - const db = (event.target as IDBOpenDBRequest).result; - // Create both `files` and `folders` stores on this DB. - if (!db.objectStoreNames.contains("files")) { - const store = db.createObjectStore("files", { keyPath: "id" }); - store.createIndex("name", "name", { unique: false }); - store.createIndex("folderId", "folderId", { unique: false }); - store.createIndex("originalFileId", "originalFileId", { - unique: false, - }); - } - if (!db.objectStoreNames.contains("folders")) { - const fStore = db.createObjectStore("folders", { keyPath: "id" }); - fStore.createIndex("parentFolderId", "parentFolderId", { - unique: false, - }); - fStore.createIndex("name", "name", { unique: false }); - } - }; - open.onsuccess = () => { - const db = open.result; - const tx = db.transaction("files", "readwrite"); - const store = tx.objectStore("files"); - const now = Date.now(); - for (const f of records) { - store.put({ - id: f.id, - fileId: f.id, - quickKey: f.id, - name: f.name, - type: "application/pdf", - size: 1024, - lastModified: now, - createdAt: now, - data: new ArrayBuffer(8), - thumbnail: null, - isLeaf: true, - versionNumber: 1, - originalFileId: f.id, - parentFileId: null, - toolHistory: [], - folderId: f.folderId ?? null, - remoteStorageId: f.remoteStorageId, - remoteStorageUpdatedAt: f.remoteStorageId ? now : null, - remoteOwnerUsername: f.remoteStorageId ? "testuser" : null, - remoteOwnedByCurrentUser: f.remoteStorageId ? true : null, - remoteAccessRole: f.remoteStorageId ? "owner" : null, - remoteSharedViaLink: false, - remoteHasShareLinks: false, - remoteShareToken: null, - }); - } - }; - }, files); + await page.addInitScript( + ({ records, dbVersion }) => { + const open = window.indexedDB.open("stirling-pdf-files", dbVersion); + open.onupgradeneeded = (event) => { + const db = (event.target as IDBOpenDBRequest).result; + // Create both `files` and `folders` stores on this DB. + if (!db.objectStoreNames.contains("files")) { + const store = db.createObjectStore("files", { keyPath: "id" }); + store.createIndex("name", "name", { unique: false }); + store.createIndex("folderId", "folderId", { unique: false }); + store.createIndex("originalFileId", "originalFileId", { + unique: false, + }); + } + if (!db.objectStoreNames.contains("folders")) { + const fStore = db.createObjectStore("folders", { keyPath: "id" }); + fStore.createIndex("parentFolderId", "parentFolderId", { + unique: false, + }); + fStore.createIndex("name", "name", { unique: false }); + } + }; + open.onsuccess = () => { + const db = open.result; + // Yield the connection if the app ever needs to upgrade, and drop it + // once the writes commit, so the seed never blocks the app's open. + db.onversionchange = () => db.close(); + const tx = db.transaction("files", "readwrite"); + const store = tx.objectStore("files"); + const now = Date.now(); + for (const f of records) { + store.put({ + id: f.id, + fileId: f.id, + quickKey: f.id, + name: f.name, + type: "application/pdf", + size: 1024, + lastModified: now, + createdAt: now, + data: new ArrayBuffer(8), + thumbnail: null, + isLeaf: true, + versionNumber: 1, + originalFileId: f.id, + parentFileId: null, + toolHistory: [], + folderId: f.folderId ?? null, + remoteStorageId: f.remoteStorageId, + remoteStorageUpdatedAt: f.remoteStorageId ? now : null, + remoteOwnerUsername: f.remoteStorageId ? "testuser" : null, + remoteOwnedByCurrentUser: f.remoteStorageId ? true : null, + remoteAccessRole: f.remoteStorageId ? "owner" : null, + remoteSharedViaLink: false, + remoteHasShareLinks: false, + remoteShareToken: null, + }); + } + tx.oncomplete = () => db.close(); + }; + }, + { records: files, dbVersion: DATABASE_CONFIGS.FILES.version }, + ); } async function stubStorageApis( diff --git a/frontend/editor/src/core/tests/stubbed/files-page.spec.ts b/frontend/editor/src/core/tests/stubbed/files-page.spec.ts index d1bda5720..081d1c83f 100644 --- a/frontend/editor/src/core/tests/stubbed/files-page.spec.ts +++ b/frontend/editor/src/core/tests/stubbed/files-page.spec.ts @@ -1,5 +1,6 @@ import { test, expect } from "@app/tests/helpers/stub-test-base"; import type { Page, Route } from "@playwright/test"; +import { DATABASE_CONFIGS } from "@app/services/indexedDBManager"; /** Stubbed coverage for the /files page UI invariants. */ @@ -34,63 +35,70 @@ async function seedFiles(page: Page, files: SeedFile[]): Promise { await page.route("**/api/v1/storage/files", (route: Route) => route.fulfill({ json: serverFiles }), ); - await page.addInitScript((records) => { - const open = window.indexedDB.open("stirling-pdf-files", 4); - open.onupgradeneeded = (event) => { - const db = (event.target as IDBOpenDBRequest).result; - // Create both `files` and `folders` stores on this DB. - if (!db.objectStoreNames.contains("files")) { - const store = db.createObjectStore("files", { keyPath: "id" }); - store.createIndex("name", "name", { unique: false }); - store.createIndex("folderId", "folderId", { unique: false }); - store.createIndex("originalFileId", "originalFileId", { - unique: false, - }); - } - if (!db.objectStoreNames.contains("folders")) { - const fStore = db.createObjectStore("folders", { keyPath: "id" }); - fStore.createIndex("parentFolderId", "parentFolderId", { - unique: false, - }); - fStore.createIndex("name", "name", { unique: false }); - } - }; - open.onsuccess = () => { - const db = open.result; - const tx = db.transaction("files", "readwrite"); - const store = tx.objectStore("files"); - const now = Date.now(); - for (const f of records) { - store.put({ - id: f.id, - fileId: f.id, - quickKey: f.id, - name: f.name, - type: "application/pdf", - size: 1024, - lastModified: now, - createdAt: now, - // Placeholder; opening would need real bytes. - data: new ArrayBuffer(8), - thumbnail: null, - isLeaf: true, - versionNumber: f.versionNumber ?? 1, - originalFileId: f.id, - parentFileId: null, - toolHistory: f.toolHistory ?? [], - folderId: null, - remoteStorageId: f.remoteStorageId, - remoteStorageUpdatedAt: f.remoteStorageId ? now : null, - remoteOwnerUsername: f.remoteStorageId ? "testuser" : null, - remoteOwnedByCurrentUser: f.remoteStorageId ? true : null, - remoteAccessRole: f.remoteStorageId ? "owner" : null, - remoteSharedViaLink: false, - remoteHasShareLinks: false, - remoteShareToken: null, - }); - } - }; - }, files); + await page.addInitScript( + ({ records, dbVersion }) => { + const open = window.indexedDB.open("stirling-pdf-files", dbVersion); + open.onupgradeneeded = (event) => { + const db = (event.target as IDBOpenDBRequest).result; + // Create both `files` and `folders` stores on this DB. + if (!db.objectStoreNames.contains("files")) { + const store = db.createObjectStore("files", { keyPath: "id" }); + store.createIndex("name", "name", { unique: false }); + store.createIndex("folderId", "folderId", { unique: false }); + store.createIndex("originalFileId", "originalFileId", { + unique: false, + }); + } + if (!db.objectStoreNames.contains("folders")) { + const fStore = db.createObjectStore("folders", { keyPath: "id" }); + fStore.createIndex("parentFolderId", "parentFolderId", { + unique: false, + }); + fStore.createIndex("name", "name", { unique: false }); + } + }; + open.onsuccess = () => { + const db = open.result; + // Yield the connection if the app ever needs to upgrade, and drop it + // once the writes commit, so the seed never blocks the app's open. + db.onversionchange = () => db.close(); + const tx = db.transaction("files", "readwrite"); + const store = tx.objectStore("files"); + const now = Date.now(); + for (const f of records) { + store.put({ + id: f.id, + fileId: f.id, + quickKey: f.id, + name: f.name, + type: "application/pdf", + size: 1024, + lastModified: now, + createdAt: now, + // Placeholder; opening would need real bytes. + data: new ArrayBuffer(8), + thumbnail: null, + isLeaf: true, + versionNumber: f.versionNumber ?? 1, + originalFileId: f.id, + parentFileId: null, + toolHistory: f.toolHistory ?? [], + folderId: null, + remoteStorageId: f.remoteStorageId, + remoteStorageUpdatedAt: f.remoteStorageId ? now : null, + remoteOwnerUsername: f.remoteStorageId ? "testuser" : null, + remoteOwnedByCurrentUser: f.remoteStorageId ? true : null, + remoteAccessRole: f.remoteStorageId ? "owner" : null, + remoteSharedViaLink: false, + remoteHasShareLinks: false, + remoteShareToken: null, + }); + } + tx.oncomplete = () => db.close(); + }; + }, + { records: files, dbVersion: DATABASE_CONFIGS.FILES.version }, + ); } /** Stub the storage + config endpoints hit on mount. */