Files
quixos-protocol/test/prepared-presentations.test.ts
Timothy J. Aveni b95cd149c6 Correct Reader producer completion and prepare only the active source
Route durable completion to the initiating PresentationMount, guarded against stale navigation and unrelated fan-out. Publish Gutenberg passages directly, preserve unfinished manual drafts, and open completed documents in the main reader pane. Prepare the selected provider and explicitly opened inspector only. Consolidate Studio factory contracts so optional execution placement is determined by implementations. Support typed stateful presentation props and local-module role selection in the React build layer. Update integration, browser, portal, and authoring documentation.
2026-09-28 21:54:18 -07:00

197 lines
9.6 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "node:test";
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/index.js";
import type { InterfaceRevision, PackageRevision } from "../src/capability-model/types.js";
import { compileQuery } from "../src/query/compile.js";
import { compileQueryComposition } from "../src/query/composition.js";
import { defaultQueryBudgets, type CheckedQuery } from "../src/query/types.js";
import {
presentationDeclarations,
preparationArtifact,
type ReactPreparationArtifact,
} from "../src/react-build/declarations.js";
import { completeWorkspace } from "../src/react-build/workspace.js";
const source = { repository: "https://example.test/prepared", commit: "a".repeat(40) };
async function fixture(replacement = "First", change?: (artifact: ReactPreparationArtifact) => void) {
const interfaces = new Map<string, InterfaceRevision>();
const resource = (text: string) => {
const result = compileCapabilityResourceSource(text, {
source,
environment: { interfaces, interfaceClosure: [...interfaces.values()] },
});
assert.ok(result.ok, JSON.stringify(result.diagnostics));
return result.resource;
};
for (const text of [
'interface Row id "row" revision "row@1" { queryable value title id "title" : string {get id "title:get" execution snapshot;} queryable value detail id "detail" : string {get id "detail:get" execution snapshot;} }',
'import interface Row; interface Library id "library" revision "library@1" { queryable relation selected id "selected" : optional-one interface Row {resolve id "selected:get" execution snapshot;} }',
'import interface Row; interface RowRole id "row-role" revision "row-role@1" { module render id "row-render" contract "org.quixos.react.subject-only/1" subject interface Row; }',
'import interface Library; interface LibraryRole id "library-role" revision "library-role@1" { module render id "library-render" contract "org.quixos.react.subject-only/1" subject interface Library; }',
]) {
const result = resource(text);
assert.equal(result.kind, "interface");
if (result.kind === "interface") interfaces.set(result.revision.displayName, result.revision);
}
const result = resource(
'import interface Row; import interface Library; import interface RowRole; import interface LibraryRole; package UI id "ui" revision "ui@1" { module LibraryCard id "library-card" implements LibraryRole.render; module First id "first" implements RowRole.render; module Second id "second" implements RowRole.render; }',
);
assert.equal(result.kind, "package");
if (result.kind !== "package") throw Error("package expected");
const pkg: PackageRevision = result.revision;
const checked: CheckedQuery[] = [];
for (const [name, iface, fields] of [
["LibraryData", "library@1", "selected {_camino {ref atom}}"],
["Title", "row@1", "title"],
["Detail", "row@1", "detail"],
]) {
for (const local of [false, true]) {
const id = name + (local ? "" : "Inputs");
checked.push(
await compileQuery(
{
id,
displayName: id,
root: {
kind: "object",
interface: [...interfaces.values()].find((entry) => entry.revisionId === iface)!.revisionId,
},
document: id + ".graphql",
operation: id,
fragments: [],
views: [],
allowances: [],
budgets: { ...defaultQueryBudgets },
watch: local,
placement: local ? { kind: "local", sourceQueryId: name + "Inputs" } : { kind: "replica" },
},
[...interfaces.values()],
async () => `query ${id} {root {${fields}}}`,
),
);
}
}
pkg.checkedQueries = checked;
pkg.queries = checked.map((query) => query.declaration);
const input = (query: string) => ({
name: "data",
query,
root: { from: "input", path: ["subject"] },
arguments: { record: {} },
});
const authored = {
modules: {
LibraryCard: {
inputs: [input("LibraryData")],
children: [
{
name: "selected",
subject: "Row",
slot: "selected",
with: { from: "result", name: "data", path: ["root", "selected"] },
root: { from: "item", path: ["_camino", "ref"] },
role: { interface: "RowRole", member: "render" },
},
],
},
First: { inputs: [input("Title")] },
Second: { inputs: [input("Detail")] },
},
};
const declarations = presentationDeclarations(JSON.stringify(authored), pkg, [...interfaces.values()]);
change?.(declarations.artifact);
pkg.buildArtifacts = { [preparationArtifact]: declarations.artifact };
pkg.queryCompositions = declarations.compositions.map((composition) =>
compileQueryComposition(composition, new Map(checked.map((query) => [query.declaration.id, query]))),
);
const workspace = compileCapabilitySource(
`workspace Example id "example" revision "example@1" commit "${source.commit}" {
import interface Row; import interface Library; import interface RowRole; import interface LibraryRole; import package UI;
atom A id "a"; atom B id "b";
conform A as Row id "a-row" {private state TitleA id "title-A" on A : string policy register default "title"; private state DetailA id "detail-A" on A : string policy register default "detail"; bind title.get to state TitleA.read; bind detail.get to state DetailA.read;}
conform B as Row id "b-row" {private state TitleB id "title-B" on B : string policy register default "title"; private state DetailB id "detail-B" on B : string policy register default "detail"; bind title.get to state TitleB.read; bind detail.get to state DetailB.read;}
conform A as RowRole id "a-role" {bind render to UI.${replacement};}
conform B as RowRole id "b-role" {bind render to UI.Second;}
}`,
"workspace.qx",
{ interfaces, interfaceClosure: [...interfaces.values()], packages: new Map([["UI", pkg]]) },
);
assert.ok(workspace.ok, JSON.stringify(workspace.diagnostics));
await completeWorkspace(workspace.workspace);
return { workspace: workspace.workspace, pkg: workspace.workspace.packageImports[0]!, authored, interfaces };
}
test("a local module names its checked role without a synthetic import alias", async () => {
const { pkg, authored, interfaces } = await fixture();
const source = structuredClone(authored) as any;
source.modules.LibraryCard.children[0].role = { module: "First" };
const declared = presentationDeclarations(JSON.stringify(source), pkg, [...interfaces.values()]);
assert.deepEqual(declared.artifact.modules[0]!.children[0]!.role, { interface: "row-role@1", member: "row-render" });
source.modules.LibraryCard.children[0].role = { module: "Missing" };
assert.throws(
() => presentationDeclarations(JSON.stringify(source), pkg, [...interfaces.values()]),
/local module role/,
);
});
test("workspace expands distinct providers' private inputs without parent field declarations", async () => {
const { pkg } = await fixture();
const parent = pkg.checkedQueries!.find((query) => query.declaration.id === "react:input:library-card:data")!;
const acquisition = pkg.checkedQueries!.find(
(query) =>
query.declaration.id ===
(parent.declaration.placement?.kind === "local" ? parent.declaration.placement.sourceQueryId : ""),
)!;
assert.match(acquisition.document, /title/);
assert.match(acquisition.document, /detail/);
const plan = pkg.queryCompositions!.find((composition) => composition.id === "react:inputs:library-card")!;
assert.equal(plan.steps[0]!.query, parent.declaration.id);
assert.equal(Object.keys(parent.fragmentContracts ?? {}).length, 2);
assert(!pkg.queryCompositions!.some((composition) => composition.id.endsWith(":discovery")));
const original = pkg.checkedQueries!.find((query) => query.declaration.id === "LibraryData")!;
assert.deepEqual(parent.output, original.output, "Acquisition-only child fields are not parent requirements");
assert(Object.values(parent.fragmentContracts!).every((entry) => entry.mode === "reference"));
});
test("eager cycles and wrongly typed child bindings fail before runtime", async () => {
await assert.rejects(
fixture("First", (artifact) => {
artifact.modules
.find((module) => module.module === "first")!
.children.push({
name: "again",
subject: "row@1",
slot: "again",
root: { from: "input", path: ["subject"] },
role: { interface: "row-role@1", member: "render" },
});
}),
/Eager React preparation cycle/,
);
await assert.rejects(
fixture("First", (artifact) => {
artifact.modules.find((module) => module.module === "library-card")!.children[0]!.root = {
literal: "not a reference",
};
}),
/child root must be/,
);
});
test("workspace replacement changes acquisition requirements without changing the parent", async () => {
const { pkg } = await fixture("Second");
const parent = pkg.checkedQueries!.find((query) => query.declaration.id === "react:input:library-card:data")!;
const acquisition = pkg.checkedQueries!.find(
(query) =>
query.declaration.id ===
(parent.declaration.placement?.kind === "local" ? parent.declaration.placement.sourceQueryId : ""),
)!;
assert.doesNotMatch(acquisition.document, /\btitle\b/);
assert.match(acquisition.document, /detail/);
assert.equal(Object.keys(parent.fragmentContracts ?? {}).length, 1);
const previous = (await fixture()).pkg.checkedQueries!.find(
(query) => query.declaration.id === parent.declaration.id,
)!;
assert.deepEqual(parent.output, previous.output);
});