import { expect, test } from "@playwright/test"; import { answerBlockerThroughUi } from "./blocker-input.js"; test("answers every page of a saved question set", async ({ page }) => { await page.setContent(`
`); await answerBlockerThroughUi(page, { kind: "ask_user_questions", payload: { questionSet: { schema: "paperclip.question_set.v1", questions: [ { id: "scope", answerMode: "text" }, { id: "audience", answerMode: "text" }, ] }, } }, "New direction"); expect(await page.evaluate(() => (window as any).answers)).toEqual(["New direction", "New direction"]); }); for (const kind of ["request_confirmation", "request_checkbox_confirmation"]) { for (const reason of [true, false]) { test(`declines ${kind} with saved scope change (reason=${reason})`, async ({ page }) => { await page.setContent(`
`); const answer = answerBlockerThroughUi(page, { id: "decision", kind, payload: { rejectLabel: "Cancel request", allowDeclineReason: reason, } }, "Change of scope"); if (!reason) { await expect(answer).rejects.toThrow("confirmation has no rejection reason field"); await expect(page.locator("#decline")).toBeVisible(); await expect(page.getByTestId("task-chat-composer-input")).toHaveCount(0); return; } await answer; expect(await page.evaluate(() => ({ accepted: (window as any).accepted, reply: (window as any).reply }))) .toEqual({ accepted: false, reply: reason ? undefined : "Change of scope" }); if (reason) expect(await page.evaluate(() => (window as any).reason)).toBe("Change of scope"); }); } } for (const mode of ["single_select", "multi_select"]) { test(`diagnoses ${mode} without a custom answer before any page is submitted`, async ({ page }) => { await page.setContent(``); await expect(answerBlockerThroughUi(page, { kind: "ask_user_questions", payload: { questionSet: { schema: "paperclip.question_set.v1", questions: [ { id: "first", answerMode: "text" }, { id: "closed", answerMode: mode, options: [{ id: "yes", label: "Yes" }] }, ] }, } }, "New scope")).rejects.toThrow("closed-choice question closed has no custom answer"); expect(await page.evaluate(() => (window as any).clicked)).toBeUndefined(); }); test(`answers ${mode} with an explicit custom answer`, async ({ page }) => { await page.setContent(`
`); await answerBlockerThroughUi(page, { kind: "ask_user_questions", payload: { questionSet: { schema: "paperclip.question_set.v1", questions: [ { id: "scope", answerMode: mode, customAnswer: { enabled: true, label: "My answer" } }, ] }, } }, "New scope"); expect(await page.evaluate(() => (window as any).answer)).toBe("New scope"); }); } test("legacy choices retain the production form's implicit Other answer", async ({ page }) => { await page.setContent(`
`); await answerBlockerThroughUi(page, { kind: "ask_user_questions", payload: { questions: [{ id: "scope", prompt: "Choose scope", options: [{ id: "yes", label: "Yes" }] }], } }, "New scope"); expect(await page.evaluate(() => (window as any).answer)).toBe("New scope"); });