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");
});