192 lines · 4.8 KB · TypeScript
RawDownload
import { describe, expect, it } from "vitest"; import {  buildPendingUserInputAnswers,  countAnsweredPendingUserInputQuestions,  derivePendingUserInputProgress,  findFirstUnansweredPendingUserInputQuestionIndex,  resolvePendingUserInputAnswer,  setPendingUserInputCustomAnswer,} from "./pendingUserInput"; describe("resolvePendingUserInputAnswer", () => {  it("prefers a custom answer over a selected option", () => {    expect(      resolvePendingUserInputAnswer({        selectedOptionLabel: "Keep current envelope",        customAnswer: "Keep the existing envelope for one release",      }),    ).toBe("Keep the existing envelope for one release");  });   it("falls back to the selected option", () => {    expect(      resolvePendingUserInputAnswer({        selectedOptionLabel: "Scaffold only",      }),    ).toBe("Scaffold only");  });   it("clears the preset selection when a custom answer is entered", () => {    expect(      setPendingUserInputCustomAnswer(        {          selectedOptionLabel: "Preserve existing tags",        },        "doesn't matter",      ),    ).toEqual({      selectedOptionLabel: undefined,      customAnswer: "doesn't matter",    });  });}); describe("buildPendingUserInputAnswers", () => {  it("returns a canonical answer map for complete prompts", () => {    expect(      buildPendingUserInputAnswers(        [          {            id: "scope",            header: "Scope",            question: "What should the plan target first?",            options: [              {                label: "Orchestration-first",                description: "Focus on orchestration first",              },            ],          },          {            id: "compat",            header: "Compat",            question: "How strict should compatibility be?",            options: [              {                label: "Keep current envelope",                description: "Preserve current wire format",              },            ],          },        ],        {          scope: {            selectedOptionLabel: "Orchestration-first",          },          compat: {            customAnswer: "Keep the current envelope for one release window",          },        },      ),    ).toEqual({      scope: "Orchestration-first",      compat: "Keep the current envelope for one release window",    });  });   it("returns null when any question is unanswered", () => {    expect(      buildPendingUserInputAnswers(        [          {            id: "scope",            header: "Scope",            question: "What should the plan target first?",            options: [              {                label: "Orchestration-first",                description: "Focus on orchestration first",              },            ],          },        ],        {},      ),    ).toBeNull();  });}); describe("pending user input question progress", () => {  const questions = [    {      id: "scope",      header: "Scope",      question: "What should the plan target first?",      options: [        {          label: "Orchestration-first",          description: "Focus on orchestration first",        },      ],    },    {      id: "compat",      header: "Compat",      question: "How strict should compatibility be?",      options: [        {          label: "Keep current envelope",          description: "Preserve current wire format",        },      ],    },  ] as const;   it("counts only answered questions", () => {    expect(      countAnsweredPendingUserInputQuestions(questions, {        scope: {          selectedOptionLabel: "Orchestration-first",        },      }),    ).toBe(1);  });   it("finds the first unanswered question", () => {    expect(      findFirstUnansweredPendingUserInputQuestionIndex(questions, {        scope: {          selectedOptionLabel: "Orchestration-first",        },      }),    ).toBe(1);  });   it("returns the last question index when all answers are complete", () => {    expect(      findFirstUnansweredPendingUserInputQuestionIndex(questions, {        scope: {          selectedOptionLabel: "Orchestration-first",        },        compat: {          customAnswer: "Keep it for one release window",        },      }),    ).toBe(1);  });   it("derives the active question and advancement state", () => {    expect(      derivePendingUserInputProgress(        questions,        {          scope: {            selectedOptionLabel: "Orchestration-first",          },        },        0,      ),    ).toMatchObject({      questionIndex: 0,      activeQuestion: questions[0],      selectedOptionLabel: "Orchestration-first",      customAnswer: "",      resolvedAnswer: "Orchestration-first",      answeredQuestionCount: 1,      isLastQuestion: false,      isComplete: false,      canAdvance: true,    });  });});