- onboarding-intake.spec walks focus, goal (after typing into the composer, which still works), check-ins, quiet hours and the notifications card when the browser offers it, with the onboarding-intake-goal, -rhythm and -done screenshots. - completeOnboarding and the wizard specs drop the preferences step; the scan step is optional (skipped when it asks, otherwise it advances by itself). - The user-profile spec now checks the browser-filled profile and the focus fact; the conversation spec checks the shorter app suggestion and the following goal question. - The hover spec measures a reply that fills its row (a bot row's rail sits at the row's end, so the old long onboarding line was what made it pass) and scopes Send to the composer, since an open goal card has its own. - Mobile shows a choice card as its question and answer instead of an empty bubble. - The focus options drop their unused summary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
84 lines
3.4 KiB
TypeScript
84 lines
3.4 KiB
TypeScript
/**
|
||
* E2E: after the wizard the main bot gets to know the user in the main conversation, one card
|
||
* after each answer, without ever blocking the composer.
|
||
*/
|
||
import { expect, type Page, test } from "@playwright/test";
|
||
import { captureScreenshot, completeOnboarding, rpc, signup } from "./helpers";
|
||
|
||
function card(page: Page, step: string) {
|
||
return page.locator(`[data-testid="choice-card"][data-step="${step}"]`);
|
||
}
|
||
|
||
test("the main bot asks focus, goal, check-ins and quiet hours, then says what is next", async ({
|
||
page,
|
||
}, testInfo) => {
|
||
await signup(page, `intake-${Date.now()}@rakazo.test`, "password12", "Intake Tester");
|
||
await completeOnboarding(page, undefined, { mainConversation: true });
|
||
|
||
await page.getByTestId("focus-choice-day").click();
|
||
const goal = card(page, "goal");
|
||
await expect(goal).toContainText("What’s one thing you want to get done in the next few weeks?");
|
||
|
||
// Typing instead of answering goes to the main bot, and the card stays answerable.
|
||
const composer = page.getByRole("combobox", { name: "Message" });
|
||
await composer.fill("Quick question first");
|
||
await composer.press("Enter");
|
||
await expect(page.getByTestId("transcript")).toContainText(/on it|handled/i, {
|
||
timeout: 60_000,
|
||
});
|
||
const goalInput = goal.getByRole("textbox", {
|
||
name: "What’s one thing you want to get done in the next few weeks?",
|
||
});
|
||
await goalInput.fill("Run a 10K");
|
||
await goal.scrollIntoViewIfNeeded();
|
||
await page.mouse.move(1, 1);
|
||
await captureScreenshot(page, testInfo, "onboarding-intake-goal");
|
||
await goalInput.press("Enter");
|
||
await expect(goal.getByTestId("choice-answer")).toHaveText("Run a 10K");
|
||
|
||
const rhythm = card(page, "rhythm");
|
||
await expect(rhythm).toContainText("When should I check in with you?");
|
||
await rhythm.scrollIntoViewIfNeeded();
|
||
await page.mouse.move(1, 1);
|
||
await captureScreenshot(page, testInfo, "onboarding-intake-rhythm");
|
||
await rhythm.getByTestId("rhythm-choice-morning").click();
|
||
await expect(rhythm.getByTestId("choice-answer")).toContainText("Every morning");
|
||
|
||
const quiet = card(page, "quiet_hours");
|
||
await expect(quiet).toContainText("When should I stay quiet?");
|
||
await quiet.getByTestId("quiet_hours-choice-22-07").click();
|
||
|
||
// Only a browser that can still turn push on is asked about notifications.
|
||
const closing = page.getByText(/^All set\. I’ll check in (today|tomorrow) at 8:00\sAM\.$/);
|
||
const notifications = card(page, "notifications");
|
||
await expect(notifications.or(closing).first()).toBeVisible();
|
||
if (await notifications.isVisible()) {
|
||
await notifications.getByTestId("notifications-choice-later").click();
|
||
}
|
||
await expect(closing).toBeVisible();
|
||
await expect(
|
||
page.locator('[data-testid="choice-card"]:not(:has([data-testid="choice-answer"]))'),
|
||
).toHaveCount(0);
|
||
await closing.scrollIntoViewIfNeeded();
|
||
await page.mouse.move(1, 1);
|
||
await captureScreenshot(page, testInfo, "onboarding-intake-done");
|
||
|
||
const settings = await rpc<{ quietHours: { start: string; end: string } | null }>(
|
||
page,
|
||
"notifications/settings/get",
|
||
null,
|
||
);
|
||
expect(settings.quietHours).toEqual({ start: "22:00", end: "07:00" });
|
||
const profile = await rpc<{ facts: Array<{ value: string; source: string }> }>(
|
||
page,
|
||
"profile/get",
|
||
null,
|
||
);
|
||
expect(profile.facts).toContainEqual(
|
||
expect.objectContaining({
|
||
value: "Wants help with day-to-day work first",
|
||
source: "onboarding",
|
||
}),
|
||
);
|
||
});
|