/** @vitest-environment node */ import { mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; import { build } from "vite"; async function listFiles(directory: string): Promise { const entries = await readdir(directory, { withFileTypes: true }); const files = await Promise.all(entries.map(async (entry) => { const path = join(directory, entry.name); return entry.isDirectory() ? listFiles(path) : [path]; })); return files.flat(); } describe("model import worker Vite integration", () => { it("uses the prebundled browser worker instead of publishing TypeScript as an asset", async () => { const workerDirectory = dirname(fileURLToPath(import.meta.url)); const clientSource = await readFile( join(workerDirectory, "model-import-worker-client.ts"), "utf8", ); expect(clientSource).toContain( 'new URL("./model-import.worker.bundle.js", import.meta.url)', ); expect(clientSource).toContain( "const WorkerConstructor = globalThis.Worker", ); expect(clientSource).toContain( 'new WorkerConstructor(defaultWorkerAssetUrl(), { type: "module" })', ); expect(clientSource).not.toContain( 'new URL("./model-import.worker.ts", import.meta.url)', ); const workerSource = await readFile( join(workerDirectory, "model-import.worker.bundle.js"), "utf8", ); expect(workerSource).toContain( "Generated by scripts/build-model-import-worker.mjs. Do not edit.", ); expect(workerSource).toMatch(/data:application\/wasm;base64,[A-Za-z0-9+/=]+/u); expect(workerSource).not.toMatch( /(?:^|\n)\s*import\s+(?:[^"'\n]+\s+from\s+)?["'][^"']+["'];?/u, ); expect(workerSource).not.toMatch(/node:(?:fs|path)/u); expect(workerSource).not.toContain("draco3dgltf"); }); // Browser execution remains a later coordinator acceptance hook; this slice // proves the production asset graph without introducing a second test app. it("emits the opaque worker asset and resolves the inline Draco WASM payload", async () => { const workerDirectory = dirname(fileURLToPath(import.meta.url)); const packageRoot = resolve(workerDirectory, "../../.."); const outputRoot = await mkdtemp(join(tmpdir(), "toolcraft-model-worker-vite-")); const outputDirectory = join(outputRoot, "dist"); const entryPath = join(outputRoot, "entry.mjs"); try { await writeFile(entryPath, [ `import { createToolcraftModelWorkerClient } from ${JSON.stringify( join(workerDirectory, "model-import-worker-client.ts"), )};`, "globalThis.__createToolcraftModelWorkerClient = createToolcraftModelWorkerClient;", ].join("\n")); await build({ build: { emptyOutDir: true, minify: false, outDir: outputDirectory, rollupOptions: { input: entryPath, }, }, configFile: false, logLevel: "silent", root: packageRoot, }); const emittedFiles = await listFiles(outputDirectory); const workerChunkPath = emittedFiles.find((path) => /model-import\.worker\.bundle-[^/]+\.js$/u.test(path) ); expect(workerChunkPath, emittedFiles.join("\n")).toBeDefined(); const javaScriptFiles = emittedFiles.filter((path) => path.endsWith(".js")); expect(javaScriptFiles.length).toBeGreaterThanOrEqual(2); const sources = await Promise.all( javaScriptFiles.map((path) => readFile(path, "utf8")), ); const entrySource = sources.find((source) => source.includes("__createToolcraftModelWorkerClient") ); expect(entrySource).toContain("new WorkerConstructor(defaultWorkerAssetUrl()"); expect(entrySource).toMatch(/model-import\.worker\.bundle-[^"']+\.js/u); expect(entrySource).toContain("import.meta.url"); expect(entrySource).toMatch(/\{\s*type:\s*["']module["']\s*\}/u); expect(entrySource).not.toContain( "Repair plan envelope payload is invalid UTF-8 JSON.", ); const workerSource = await readFile(workerChunkPath!, "utf8"); expect(workerSource).toMatch( /^\/\/ Generated by scripts\/build-model-import-worker\.mjs\. Do not edit\./u, ); expect(workerSource).toMatch(/data:application\/wasm;base64,[A-Za-z0-9+/=]+/u); expect(emittedFiles.some((path) => path.endsWith(".wasm"))).toBe(false); expect(workerSource).not.toMatch( /(?:from\s+|import\()\s*["'][^"']+\?url&inline/u, ); expect(workerSource).not.toMatch( /(?:^|\n)\s*import\s+(?:[^"'\n]+\s+from\s+)?["'][^"']+["'];?/u, ); expect(workerSource).not.toMatch( /import\(\s*["']draco3dgltf(?:["'/])/u, ); expect(workerSource).not.toMatch(/require\(["'](?:fs|path)["']\)/u); expect(workerSource).not.toMatch(/node:(?:fs|path)/u); expect(workerSource).not.toContain("draco3dgltf"); expect(workerSource).toContain( "Repair plan envelope payload is invalid UTF-8 JSON.", ); } finally { await rm(outputRoot, { force: true, recursive: true }); } }, 30_000); });