Files
dotfiles/.pi/agent/extensions/question-core.test.mjs
alex wiesner 18245c778e changes
2026-04-09 11:31:06 +01:00

181 lines
5.3 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import {
SOMETHING_ELSE_LABEL,
SOMETHING_ELSE_VALUE,
allQuestionsAnswered,
createAnsweredResult,
createCancelledResult,
createCustomAnswer,
createPredefinedAnswer,
nextTabAfterAnswer,
normalizeQuestions,
summarizeAnswers,
wrapPrefixedText,
} from "./question-core.mjs";
test("normalizeQuestions adds default labels and appends the Something else option", () => {
const [question] = normalizeQuestions([
{
id: "scope",
prompt: "Which scope fits best?",
options: [{ value: "small", label: "Small change" }],
},
]);
assert.equal(question.label, "Q1");
assert.deepEqual(question.options[0], { value: "small", label: "Small change" });
assert.deepEqual(question.options.at(-1), {
value: SOMETHING_ELSE_VALUE,
label: SOMETHING_ELSE_LABEL,
});
});
test("normalizeQuestions keeps provided labels and descriptions intact before the synthetic option", () => {
const [question] = normalizeQuestions([
{
id: "priority",
label: "Priority",
prompt: "Which priority?",
options: [
{ value: "p0", label: "P0", description: "Need this now" },
{ value: "p1", label: "P1" },
],
},
]);
assert.equal(question.label, "Priority");
assert.deepEqual(question.options.slice(0, 2), [
{ value: "p0", label: "P0", description: "Need this now" },
{ value: "p1", label: "P1" },
]);
assert.equal(question.options[2].label, SOMETHING_ELSE_LABEL);
});
test("answer helpers preserve machine values and summary lines distinguish predefined vs custom answers", () => {
const questions = normalizeQuestions([
{
id: "scope",
label: "Scope",
prompt: "Which scope fits best?",
options: [{ value: "small", label: "Small change" }],
},
{
id: "notes",
label: "Notes",
prompt: "Anything else?",
options: [{ value: "none", label: "No extra notes" }],
},
]);
const predefined = createPredefinedAnswer("scope", questions[0].options[0], 1);
const custom = createCustomAnswer("notes", "Needs to work with tmux");
assert.deepEqual(predefined, {
id: "scope",
value: "small",
label: "Small change",
wasCustom: false,
index: 1,
});
assert.deepEqual(custom, {
id: "notes",
value: "Needs to work with tmux",
label: "Needs to work with tmux",
wasCustom: true,
});
assert.deepEqual(summarizeAnswers(questions, [predefined, custom]), [
"Scope: user selected: 1. Small change",
"Notes: user wrote: Needs to work with tmux",
]);
});
test("createCancelledResult returns a structured cancelled payload", () => {
const questions = normalizeQuestions([
{
id: "scope",
prompt: "Which scope fits best?",
options: [{ value: "small", label: "Small change" }],
},
]);
assert.deepEqual(createCancelledResult(questions), {
questions,
answers: [],
cancelled: true,
});
});
test("createAnsweredResult keeps answers in question order", () => {
const questions = normalizeQuestions([
{
id: "scope",
label: "Scope",
prompt: "Which scope fits best?",
options: [{ value: "small", label: "Small change" }],
},
{
id: "notes",
label: "Notes",
prompt: "Anything else?",
options: [{ value: "none", label: "No extra notes" }],
},
]);
const second = createCustomAnswer("notes", "Custom note");
const first = createPredefinedAnswer("scope", questions[0].options[0], 1);
const result = createAnsweredResult(questions, [second, first]);
assert.equal(result.cancelled, false);
assert.deepEqual(result.answers.map((answer) => answer.id), ["scope", "notes"]);
});
test("allQuestionsAnswered only returns true when every question has an answer", () => {
const questions = normalizeQuestions([
{
id: "scope",
prompt: "Scope?",
options: [{ value: "small", label: "Small" }],
},
{
id: "priority",
prompt: "Priority?",
options: [{ value: "p1", label: "P1" }],
},
]);
const answers = new Map([
["scope", createPredefinedAnswer("scope", questions[0].options[0], 1)],
]);
assert.equal(allQuestionsAnswered(questions, answers), false);
answers.set("priority", createCustomAnswer("priority", "Ship this week"));
assert.equal(allQuestionsAnswered(questions, answers), true);
});
test("nextTabAfterAnswer advances through questions and then to the submit tab", () => {
assert.equal(nextTabAfterAnswer(0, 3), 1);
assert.equal(nextTabAfterAnswer(1, 3), 2);
assert.equal(nextTabAfterAnswer(2, 3), 3);
});
test("wrapPrefixedText wraps long prompts and keeps the prefix on continuation lines", () => {
assert.deepEqual(wrapPrefixedText("Pick the best rollout strategy for this change", 18, " "), [
" Pick the best",
" rollout strategy",
" for this change",
]);
});
test("wrapPrefixedText supports a different continuation prefix for wrapped option labels", () => {
assert.deepEqual(wrapPrefixedText("Very long option label", 16, "> 1. ", " "), [
"> 1. Very long",
" option",
" label",
]);
});
test("wrapPrefixedText breaks oversized words when there is no whitespace boundary", () => {
assert.deepEqual(wrapPrefixedText("supercalifragilistic", 8), ["supercal", "ifragili", "stic"]);
});