/** Production worker + real ORT-Web WASM under Node. Canvas supplies retained * local RGB fixture pixels; this is not browser, GPU, CDN or mobile validation. */ import assert from 'node:assert/strict'; import { test } from 'node:test'; import { readFile } from 'node:fs/promises'; import vm from 'node:vm'; import ts from 'typescript'; import * as ort from 'onnxruntime-web/webgpu'; import { webcrypto } from 'node:crypto'; import { loadTypescript } from './support/load-typescript.mjs'; test('production worker executes the retained local model and releases its input', { timeout: 30000 }, async () => { const mask = await loadTypescript(new URL('../src/cutout/CutoutMask.ts', import.meta.url)); const preprocess = await loadTypescript(new URL('../src/cutout/U2NetPreprocess.ts', import.meta.url)); const model = await readFile(new URL('../public/models/u2netp/model.onnx', import.meta.url)); const rgba = await readFile(new URL('../docs/qa-countryside-cutout-2026-10-07/runtime/sample-320.rgba', import.meta.url)); // Only the host boundary is changed. The model and all preprocess, inference, // normalization and worker cleanup logic are the actual production code. ort.env.wasm.wasmPaths = new URL('../node_modules/onnxruntime-web/dist/', import.meta.url).href; ort.env.wasm.numThreads = 1; const wasm = new Proxy(ort.env.wasm, { set(target, key, value) { if (key !== 'wasmPaths') target[key] = value; return true; } }); const runtime = { ...ort, env: { ...ort.env, wasm } }; let listener, complete; const terminal = new Promise(resolve => { complete = resolve; }); const messages = [], requested = []; const image = { width: 415, height: 739, closes: 0, close() { this.closes++; } }; const source = await readFile(new URL('../src/cutout/cutout.worker.ts', import.meta.url), 'utf8'); vm.runInNewContext(ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.CommonJS } }).outputText, { exports: {}, require: name => name === 'onnxruntime-web/webgpu' ? runtime : name === './U2NetPreprocess' ? preprocess : mask, performance, crypto: webcrypto, navigator: {}, fetch: async (url, options) => { requested.push({ url, options }); return { ok: true, arrayBuffer: async () => model.buffer.slice(model.byteOffset, model.byteOffset + model.byteLength) }; }, OffscreenCanvas: class { constructor(width, height) { assert.equal(width, 320); assert.equal(height, 320); } getContext() { return { drawImage(input) { assert.equal(input, image); }, getImageData() { return { data: new Uint8ClampedArray(rgba) }; } }; } }, self: { addEventListener(_type, fn) { listener = fn; }, postMessage(message) { messages.push(message); if (['result', 'error', 'fallback'].includes(message.type)) complete(message); } }, }); listener({ data: { type: 'infer', id: 17, image, forceWasm: true } }); const result = await terminal; await new Promise(resolve => setImmediate(resolve)); assert.equal(result.type, 'result', result.message); assert.equal(result.id, 17); assert.equal(result.width, 415); assert.equal(result.height, 739); assert.equal(result.run.backend, 'wasm'); assert.equal(result.run.downloadBytes, 4574861); const alpha = new Uint8Array(result.alpha), analysis = mask.analyzeCutout(alpha, result.width, result.height); assert.equal(alpha.length, 415 * 739); assert.ok(alpha.some(value => value > 0 && value < 255), 'soft fringe is retained'); assert.ok(analysis.bounds.y0 > 0 && analysis.bounds.y1 < result.height); assert.equal(image.closes, 1); assert.equal(requested.length, 1); assert.equal(requested[0].url, '/models/u2netp/model.onnx'); assert.equal(requested[0].options.body, undefined); assert.equal(messages.filter(message => message.type === 'status').length, 2); });