Publish Forma Engine 0.3.0 source with documentation and CI
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import vm from "node:vm";
|
||||
import { workerSource } from "../engine/script-host.ts";
|
||||
import { entity } from "../engine/schema.ts";
|
||||
function worker() {
|
||||
const messages: any[] = [];
|
||||
const context = vm.createContext({
|
||||
self: {},
|
||||
postMessage: (m: any) => messages.push(structuredClone(m)),
|
||||
structuredClone,
|
||||
Math,
|
||||
console,
|
||||
});
|
||||
vm.runInContext(workerSource, context);
|
||||
return {
|
||||
send: (data: any) => {
|
||||
context.self.onmessage({ data: structuredClone(data) });
|
||||
return messages.pop();
|
||||
},
|
||||
};
|
||||
}
|
||||
test("script field defaults, overrides and per-instance state remain independent", () => {
|
||||
const w = worker();
|
||||
const scripts = [
|
||||
{
|
||||
id: "counter",
|
||||
name: "Counter",
|
||||
fields: { step: { type: "number", default: 2 } },
|
||||
source:
|
||||
"({start(api){api.state.count=0},update(api){api.state.count+=api.params.step;api.patch(api.get().id,{components:{data:{count:api.state.count}}})}})",
|
||||
},
|
||||
];
|
||||
const a = entity(
|
||||
"Default",
|
||||
{ script: { scriptId: "counter" } },
|
||||
[0, 0, 0],
|
||||
"a",
|
||||
);
|
||||
const b = entity(
|
||||
"Override",
|
||||
{ script: { scriptId: "counter", params: { step: 5 } } },
|
||||
[0, 0, 0],
|
||||
"b",
|
||||
);
|
||||
w.send({ type: "init", entities: [a, b], scripts });
|
||||
for (let tick = 1; tick <= 3; tick++) {
|
||||
const frame = w.send({
|
||||
type: "tick",
|
||||
entities: [a, b],
|
||||
input: {},
|
||||
dt: 0.02,
|
||||
});
|
||||
assert.equal(
|
||||
frame.commands.find((c: any) => c.id === "a").patch.components.data.count,
|
||||
tick * 2,
|
||||
);
|
||||
assert.equal(
|
||||
frame.commands.find((c: any) => c.id === "b").patch.components.data.count,
|
||||
tick * 5,
|
||||
);
|
||||
}
|
||||
});
|
||||
test("newly spawned instances receive start and update; failing behavior is isolated", () => {
|
||||
const scripts = [
|
||||
{
|
||||
id: "good",
|
||||
name: "Good",
|
||||
source:
|
||||
'({start(api){api.state.ticks=0;api.log("start")},update(api){api.state.ticks++;api.log(api.state.ticks)}})',
|
||||
fields: {},
|
||||
},
|
||||
{
|
||||
id: "bad",
|
||||
name: "Bad",
|
||||
source: '({update(){throw Error("fixture failure")}})',
|
||||
fields: {},
|
||||
},
|
||||
],
|
||||
w = worker(),
|
||||
a = entity("A", { script: { scriptId: "good" } }, [0, 0, 0], "a");
|
||||
w.send({ type: "init", entities: [a], scripts });
|
||||
const b = entity("B", { script: { scriptId: "good" } }, [0, 0, 0], "b"),
|
||||
bad = entity("Bad", { script: { scriptId: "bad" } }, [0, 0, 0], "bad");
|
||||
const m = w.send({ type: "tick", entities: [a, b, bad], input: {}, dt: 0.1 });
|
||||
assert.equal(
|
||||
m.commands.filter((c: any) => c.id === "b" && c.message === "start").length,
|
||||
1,
|
||||
);
|
||||
assert.ok(m.commands.some((c: any) => c.id === "a" && c.message === "1"));
|
||||
assert.ok(m.commands.some((c: any) => c.type === "error"));
|
||||
const second = w.send({
|
||||
type: "tick",
|
||||
entities: [a, b, bad],
|
||||
input: {},
|
||||
dt: 0.1,
|
||||
});
|
||||
assert.ok(
|
||||
second.commands.some((c: any) => c.id === "b" && c.message === "2"),
|
||||
);
|
||||
assert.ok(!second.commands.some((c: any) => c.type === "error"));
|
||||
});
|
||||
Reference in New Issue
Block a user