open-standards/wai/wai-quantum-js/test/smoke.mjs
Transaction Science 51e89d4e20
All checks were successful
wai-quantum docs, course and locales / does this change touch it (pull_request) Successful in 6s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 9s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 8s
WAI energy receipts / does this change touch it (pull_request) Successful in 10s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 7s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (pull_request) Successful in 37s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Successful in 1m13s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (pull_request) Successful in 2m49s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 3m6s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 3m7s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 5m7s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 6m33s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 8m31s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 9m6s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m53s
wai-quantum docs, course and locales / the course and the command line's languages · linux (pull_request) Successful in 12m23s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (pull_request) Successful in 1h4m5s
wai-quantum for JavaScript: the engine as the npm package @transaction-science/wai-quantum 0.1.0
wai/wai-quantum-js/ packs the job service's engine for WebAssembly (wai-web
with its quantum_engine feature, the engine of wai-quantum 0.7.0) and its
bindings as an ES module with its TypeScript declarations and no dependencies,
for a page (init() fetches the .wasm beside the module) or for Node (init is
given its bytes). The package keeps its own version line, as the Python
package does.

- build.sh: wai-web built for wasm32 with paths remapped (as the views build
  does), wasm-bindgen 0.2.127 (refused if it is not the version wai-web's lock
  file pins), package.json, README and the licence copied, the build refused if
  a local path is left in the bindings or the binary, then packed.
- test/smoke.mjs, on the package unpacked: a job run with a fresh 32-byte key
  and its receipt verified with this engine's did:key; a forged result that
  does not verify; a program linted and drawn; a refused program with its
  diagnostic code (Q310).
- test/install.mjs: the README's Node example, run in an empty app that
  installed the tarball with npm, the package found by name and its .wasm by
  the subpath it exports.
- ci/check.sh runs them all and holds the tarball to the package's allow-list
  (the seven files and nothing else).
- wai-quantum-js.yml runs ci/check.sh on Linux. wai-quantum-js-release.yml runs
  it on a wai-quantum-cli-v* tag and attaches the tarball and its SHA-256 to the
  release. Nothing is published to a registry from CI.

On the M3 Ultra: the .wasm is 5,928,153 bytes, the tarball 2.26 MB, and every
check passes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 08:14:24 -04:00

56 lines
3 KiB
JavaScript

// The package as an installer leaves it: its bindings and its WebAssembly, loaded in
// Node with nothing else installed.
//
// node wai/wai-quantum-js/test/smoke.mjs PACKAGE_DIR
//
// Prints one line per check and exits non-zero on the first that fails.
import assert from 'node:assert/strict';
import { randomBytes } from 'node:crypto';
import { readFile } from 'node:fs/promises';
import { join, resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
const dir = resolve(process.argv[2] ?? '.');
const pkg = JSON.parse(await readFile(join(dir, 'package.json'), 'utf8'));
const wq = await import(pathToFileURL(join(dir, pkg.main)).href);
// In Node the module is given its WebAssembly's bytes; a page lets it fetch them.
await wq.default({ module_or_path: await readFile(join(dir, 'wai_quantum_bg.wasm')) });
console.log('node', process.versions.node, pkg.name, pkg.version);
const BELL = 'OPENQASM 3.0; qubit[2] q; bit[2] c; h q[0]; cx q[0], q[1]; c = measure q;';
// A job run with a fresh key, and its receipt checked.
const engine = new wq.QuantumEngine(randomBytes(32), 256);
const signer = engine.signer_did();
assert.match(signer, /^did:key:z6Mk/, signer);
const job = JSON.parse(engine.run(JSON.stringify({ qasm: BELL, shots: 1000, seed: 7 })));
assert.equal(job.status, 'done', JSON.stringify(job).slice(0, 400));
const counts = job.result.counts;
assert.ok(Object.keys(counts).length > 0 && Object.keys(counts).every((k) => k === '00' || k === '11'), JSON.stringify(counts));
const v = JSON.parse(wq.engine_verify(JSON.stringify(job)));
assert.equal(v.valid, true, JSON.stringify(v));
assert.equal(v.signer, signer, JSON.stringify(v));
console.log(`run and verify: ${job.method}, ${Object.values(counts).reduce((a, b) => a + b, 0)} shots, signed by this engine's key`);
// A result changed after it was sealed does not verify.
const forged = structuredClone(job);
const k = Object.keys(forged.result.counts)[0];
forged.result.counts[k] += 1;
assert.notEqual(JSON.parse(wq.engine_verify(JSON.stringify(forged))).valid, true);
console.log('a forged result does not verify');
// A program read and drawn.
const lint = JSON.parse(wq.engine_lint(BELL));
assert.equal(lint.ok, true, JSON.stringify(lint));
assert.equal(lint.qubits, 2, JSON.stringify(lint));
const drawn = JSON.parse(wq.engine_draw(BELL, 80));
assert.ok(typeof drawn.text === 'string' && drawn.text.trim().length > 0, JSON.stringify(drawn));
console.log(`lint and draw: ${lint.qubits} qubits, ${lint.gates} gates; drawn in ${drawn.text.trimEnd().split('\n').length} lines`);
// A program the engine refuses says why, with its diagnostic code.
const WHILE = 'OPENQASM 3.0; qubit[1] q; bit[1] c; c[0] = measure q[0]; while (c[0]) { x q[0]; c[0] = measure q[0]; }';
const refused = JSON.parse(engine.run(JSON.stringify({ qasm: WHILE, shots: 10 })));
assert.ok(typeof refused.error === 'string' && /^Q\d{3}$/.test(refused.code ?? ''), JSON.stringify(refused));
console.log(`a refused program says why: [${refused.code}] ${refused.meaning}`);
console.log('smoke: every check passed');