import assert from "node:assert/strict"; import fs from "node:fs"; import factory from "../../web/app/src/vendor/blender/web_engine.js"; const root = new URL("../../", import.meta.url); const wasmBinary = fs.readFileSync(new URL("web/app/src/vendor/blender/web_engine.wasm", root)); const fixture = fs.readFileSync(new URL("tests/files/web/compositor_scene.blend", root)); function open(engine, handle, bytes) { const pointer = engine._malloc(bytes.byteLength); try { engine.HEAPU8.set(bytes, pointer); assert.equal(engine._web_engine_open_blend(handle, pointer, bytes.byteLength), 0, engine.UTF8ToString(engine._web_engine_last_error_message())); } finally { engine._free(pointer); } } function snapshot(engine, handle) { const dataOut = engine._malloc(4); const lengthOut = engine._malloc(4); try { assert.equal(engine._web_engine_get_scene_snapshot(handle, dataOut, lengthOut), 0, engine.UTF8ToString(engine._web_engine_last_error_message())); const pointer = engine.HEAPU32[dataOut >>> 2]; const length = engine.HEAPU32[lengthOut >>> 2]; return JSON.parse(new TextDecoder().decode(engine.HEAPU8.slice(pointer, pointer + length))); } finally { engine._free(dataOut); engine._free(lengthOut); } } const engine = await factory({ wasmBinary: wasmBinary.slice() }); const handle = engine._web_engine_create(); open(engine, handle, fixture); const scene = snapshot(engine, handle).scenes.find((candidate) => candidate.name === "CompositorScene"); assert.equal(scene?.compositorStatus, "AVAILABLE"); const graph = scene.compositorGraph; assert.equal(graph.schemaVersion, 1); assert.equal(graph.nodes.length, 6); assert.equal(graph.links.length, 4); const color = graph.nodes.find((node) => node.name === "WebConstantColor"); assert.equal(color.type, "CONSTANT_COLOR"); assert.deepEqual(color.properties.color, [0.125, 0.25, 0.5, 0.75]); const exposure = graph.nodes.find((node) => node.name === "WebExposure"); assert.equal(exposure.type, "EXPOSURE"); assert.equal(exposure.properties.exposure, 1); const invert = graph.nodes.find((node) => node.name === "WebInvert"); assert.equal(invert.type, "INVERT"); assert.deepEqual(invert.properties, {}); assert.ok(graph.links.some((link) => link.toNodeId === invert.id && link.toSocket === "Image")); assert.equal(graph.nodes.find((node) => node.name === "WebViewer").type, "VIEWER"); const composite = graph.nodes.find((node) => node.name === "WebComposite"); assert.equal(composite.type, "COMPOSITE"); assert.equal(graph.outputNodeId, composite.id); assert.ok(graph.links.some((link) => link.toNodeId === composite.id && link.toSocket === "Image")); const unsupported = graph.nodes.find((node) => node.name === "PreservedUnsupportedGlare"); assert.equal(unsupported.type, "UNSUPPORTED"); assert.equal(unsupported.blenderType, "CompositorNodeGlare"); assert.ok(graph.links.every((link) => graph.nodes.some((node) => node.id === link.fromNodeId) && graph.nodes.some((node) => node.id === link.toNodeId))); engine._web_engine_destroy(handle); process.stdout.write("compositor-main-reader-ok graph-structure=passed exposure-invert-parameters=passed socket-links=passed unsupported-preserved=passed\n");