import { describe, expect, it } from "bun:test";
import { $getRoot, $isElementNode } from "lexical";
import { importPlan } from "../convert";
import { $isQuestionnaireNode } from "./questionnaire";
import { editor, ID, OPEN, REGISTRY, through } from "./questionnaire.test-fixtures";
describe("questionnaire", () => {
it("round-trips an open questionnaire", () => {
let out = through(OPEN);
expect(through(out)).toBe(out);
expect(out).toContain(`id="${ID}"`);
expect(out).toContain('header="Rollout"');
expect(out).toContain('label="Canary"');
expect(out).toContain('description="Small percentage first."');
expect(out).toContain('multiple="false"');
});
it("round-trips a resolved answer projection", () => {
let source = OPEN.replace(
"",
`\n`,
);
let out = through(source);
expect(through(out)).toBe(out);
expect(out).toContain(' {
let source = OPEN.replace(
"",
`\n`,
);
let answer = through(source).split("\n").find(line => line.includes(" {
let instance = editor();
importPlan(instance, OPEN, { registry: REGISTRY });
instance.getEditorState().read(() => {
let node = $getRoot().getFirstChild();
expect($isQuestionnaireNode(node)).toBe(true);
if (!$isQuestionnaireNode(node)) return;
// A decorator, not an element: there is no editable subtree inside.
expect($isElementNode(node)).toBe(false);
let value = node.getQuestionnaire();
expect(value.id).toBe(ID);
expect(value.questions).toHaveLength(1);
expect(value.questions[0]!.options.map(option => option.label)).toEqual([
"Canary",
"Blue-green",
]);
expect(value.questions[0]!.answer).toBeUndefined();
});
});
it("exposes the resolved answer to renderers", () => {
let instance = editor();
importPlan(
instance,
OPEN.replace("", `\n`),
{ registry: REGISTRY },
);
instance.getEditorState().read(() => {
let node = $getRoot().getFirstChild();
if (!$isQuestionnaireNode(node)) throw new Error("expected questionnaire");
expect(node.getQuestionnaire().questions[0]!.answer).toBe("Canary");
});
});
/**
* On the questionnaire rather than on each answer: it resolves as a unit,
* so every answer would otherwise repeat the same handle and the same
* moment. `` records its provenance the same way.
*/
it("round-trips who settled it and when", () => {
let source = OPEN
.replace(
``,
``,
)
.replace("", `\n`);
let out = through(source);
expect(through(out)).toBe(out);
expect(out).toContain('by="ana"');
expect(out).toContain('at="2026-07-28T10:14:00Z"');
let instance = editor();
importPlan(instance, source, { registry: REGISTRY });
instance.getEditorState().read(() => {
let node = $getRoot().getFirstChild();
if (!$isQuestionnaireNode(node)) throw new Error("expected questionnaire");
expect(node.getQuestionnaire()).toMatchObject({ by: "ana", at: "2026-07-28T10:14:00Z" });
});
});
/** One answered before any of this was recorded has neither, for good. */
it("carries no provenance when none was recorded", () => {
let out = through(OPEN);
expect(out).not.toContain("by=");
expect(out).not.toContain("at=");
});
it("omits optional option descriptions", () => {
let out = through(OPEN);
let blue = out.split("\n").find(line => line.includes("Blue-green"));
expect(blue).not.toContain("description=");
});
});