import { expect, test } from "@playwright/test"; import path from "node:path"; const basicBlend = path.resolve(import.meta.dirname, "../../../tests/files/web/basic_scene.blend"); test("M7-12 removes only one project's unreferenced content-addressed assets", async ({ page }) => { await page.goto("/"); await expect(page.getByTestId("engine-status")).toContainText("ready, open a .blend file", { timeout: 20_000 }); await page.getByTestId("blend-file-input").setInputFiles(basicBlend); await expect(page.getByText("Cube", { exact: true })).toBeVisible(); const download = page.waitForEvent("download"); await page.getByRole("button", { name: "保存项目" }).click(); await download; const orphanA = "a".repeat(64); const orphanB = "b".repeat(64); const referenced = await page.evaluate(async ({ orphanA, orphanB }) => { const { StorageClient } = await import("/src/storage/StorageClient.ts"); const storage = new StorageClient(); const keptA = await storage.putAsset("basic_scene", new Uint8Array(5).buffer, "image/png", "media/kept.png"); await storage.putAsset("cleanup-other", new Uint8Array(6).buffer, "image/png", "media/other.png"); const root = await navigator.storage.getDirectory(); const writeOrphan = async (projectId: string, hash: string, size: number) => { let current = root; for (const segment of ["projects", projectId, "assets", "sha256", hash.slice(0, 2)]) current = await current.getDirectoryHandle(segment, { create: true }); const handle = await current.getFileHandle(hash, { create: true }); const writer = await handle.createWritable(); await writer.write(new Uint8Array(size)); await writer.close(); }; await writeOrphan("basic_scene", orphanA, 19); await writeOrphan("cleanup-other", orphanB, 23); storage.terminate(); return { keptA: keptA.sha256, orphanA, orphanB }; }, { orphanA, orphanB }); await page.reload(); await expect(page.getByTestId("engine-status")).toContainText("ready, open a .blend file", { timeout: 20_000 }); await page.getByTestId("cleanup-project-assets").click(); await expect(page.locator(".status-bar")).toContainText("removed 1 orphan asset(s), 19 bytes"); const files = await page.evaluate(async ({ orphanA, orphanB, keptA }) => { const root = await navigator.storage.getDirectory(); const read = async (projectId: string, hash: string) => { try { let current = root; for (const segment of ["projects", projectId, "assets", "sha256", hash.slice(0, 2)]) current = await current.getDirectoryHandle(segment); await current.getFileHandle(hash); return true; } catch { return false; } }; return { orphanA: await read("basic_scene", orphanA), orphanB: await read("cleanup-other", orphanB), keptA: await read("basic_scene", keptA) }; }, referenced); expect(files).toEqual({ orphanA: false, orphanB: true, keptA: true }); });