import { expect, test } from "@playwright/test"; import fs from "node:fs"; import path from "node:path"; const fixture = JSON.parse(fs.readFileSync( path.resolve(import.meta.dirname, "../../../tests/golden/M12-01D/catalog-v1.json"), "utf8", )) as unknown; test("M12-01H preserves catalog order and asset identity across page and Worker restarts", async ({ page }) => { await page.goto("/"); const databaseName = `m12-01h-${Date.now()}`; const baseline = await page.evaluate(async ({ databaseName, source }) => { const storage = await import("/src/storage/asset-catalog-indexeddb.ts"); const database = await new Promise((resolve, reject) => { const request = indexedDB.open(databaseName, 1); request.onupgradeneeded = () => { request.result.createObjectStore("setting", { keyPath: "id" }); request.result.createObjectStore("migration", { keyPath: "id" }); }; request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); const transaction = database.transaction("setting", "readwrite"); transaction.objectStore("setting").put({ id: storage.ASSET_CATALOG_INDEX_V1_ID, value: source }); await new Promise((resolve, reject) => { transaction.oncomplete = () => resolve(); transaction.onerror = () => reject(transaction.error); transaction.onabort = () => reject(transaction.error); }); const snapshot = await storage.loadAssetCatalogIndexedDBSnapshot(database); database.close(); return snapshot; }, { databaseName, source: fixture }); await page.reload(); const pageRestart = await page.evaluate(async (name) => { const storage = await import("/src/storage/asset-catalog-indexeddb.ts"); const database = await new Promise((resolve, reject) => { const request = indexedDB.open(name); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); const snapshot = await storage.loadAssetCatalogIndexedDBSnapshot(database); database.close(); return snapshot; }, databaseName); const workerSnapshot = async () => page.evaluate((name) => new Promise((resolve, reject) => { const worker = new Worker("/src/workers/asset-catalog-restart-test.worker.ts", { type: "module" }); worker.onmessage = (event) => { worker.terminate(); event.data.ok ? resolve(event.data.snapshot) : reject(new Error(event.data.error)); }; worker.onerror = (event) => { worker.terminate(); reject(new Error(event.message)); }; worker.postMessage({ databaseName: name }); }), databaseName); const firstWorker = await workerSnapshot(); const secondWorker = await workerSnapshot(); expect(pageRestart).toEqual(baseline); expect(firstWorker).toEqual(baseline); expect(secondWorker).toEqual(baseline); expect(baseline).toEqual({ schemaVersion: 1, revision: 7, manifestSha256: "0c08ed1af1dd0998c809f76d969fd21d8fdae28ad37cf5571bdc99b16bf3ec90", catalogOrder: [ { catalogId: "44444444-4444-4444-8444-444444444444", path: "Animation" }, { catalogId: "fe3ca14c-95d7-549f-a13b-1bb4c07b6074", path: "Characters" }, { catalogId: "b4bb3608-9267-5aba-bb9e-9e97b006d5ab", path: "Characters/Heroes" }, ], assetOrder: [ "asset:ac88c6147ada877adccf4df8ca54d64e1a9cb50a13514212f6d19b1da1660f8d", "asset:bb91ef0dddf69bb7d87dd4217a01e7f549b50ad628db0367d3896c6840b3a326", ], assetIdentities: [ { assetId: "asset:ac88c6147ada877adccf4df8ca54d64e1a9cb50a13514212f6d19b1da1660f8d", assetLibraryIdentifier: null, relativeAssetIdentifier: "Action/Legacy Walk", }, { assetId: "asset:bb91ef0dddf69bb7d87dd4217a01e7f549b50ad628db0367d3896c6840b3a326", assetLibraryIdentifier: null, relativeAssetIdentifier: "Object/Legacy Hero", }, ], }); await page.evaluate((name) => indexedDB.deleteDatabase(name), databaseName); });