1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// node --test javascript/src/compose/build.test.mjs (deno for the type checks; skipped without it)
import assert from "node:assert/strict";
import { execFileSync, spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { test } from "node:test";
import { compose } from "../../../examples/rust/compose/atlibs.modules.js";
import { composition } from "./build.js";
const example = new URL("../../../examples/rust/compose/", import.meta.url);
test("compose.ts writes the composition.json beside it", () => {
const out = execFileSync(process.execPath, ["compose.ts"], { cwd: example, encoding: "utf8" });
assert.equal(out, readFileSync(new URL("composition.json", example), "utf8"));
});
test("build() runs the hosts' load checks and points at the line that made the instance or route", async () => {
const lineOf = (re) => readFileSync(new URL(import.meta.url), "utf8").split("\n").findIndex((l) => re.test(l)) + 1;
const refused = async (c, msg, marker) => assert.rejects(c.build(), (e) => e.message.startsWith(`composition: ${msg}`) && e.message.endsWith(`build.test.mjs:${lineOf(marker)}:${e.message.split(":").at(-1)}`), msg);
const a = composition({ name: "a" });
a.route(a.instance("ui", compose), "com.example.compose.confirm", a.instance("x", compose)); // confirm-route
await refused(a, "edge ui com.example.compose.confirm: x (compose) does not implement com.example.compose.confirm", /confirm-route$/);
const b = composition({ name: "b" });
b.instance("x", compose, { input: { n: "0" } }); // string-n
await refused(b, "instance x: input n must be of type integer", /string-n$/);
const c = composition({ name: "c" });
const ui = c.instance("ui", compose);
const x = c.instance("x", compose);
c.route(ui, "com.example.compose.lookup", x);
c.route(ui, "com.example.compose.lookup", x); // twice
await refused(c, "edge ui com.example.compose.lookup: routed twice", /twice$/);
const ok = composition({ name: "ok" });
ok.route(ok.instance("ui", compose), "com.example.compose.lookup", ok.instance("x", compose, { input: { n: 1 } }));
assert.deepEqual((await ok.build()).edges, [{ from: "ui", nsid: "com.example.compose.lookup", to: "x", reason: "the example's lookup: another instance doubles n" }]);
});
const deno = spawnSync("deno", ["--version"]).status === 0;
test("types: wrong.ts's marked lines are type errors, compose.ts has none", { skip: !deno && "no deno" }, () => {
const check = (file) => spawnSync("deno", ["check", file], { cwd: example, encoding: "utf8", env: { ...process.env, NO_COLOR: "1" } });
assert.equal(check("compose.ts").status, 0);
const out = check("wrong.ts").stderr;
const marked = readFileSync(new URL("wrong.ts", example), "utf8").split("\n").flatMap((l, i) => (l.includes("// ✗") ? [i + 1] : []));
const errors = [...new Set([...out.matchAll(/wrong\.ts:(\d+):\d+/g)].map((m) => Number(m[1])))];
assert.deepEqual(errors, marked, out);
});