evOo-local/apps/web/e2e/onboarding-intake.spec.ts
Claude 97210805be
test(onboarding): walk the onboarding questions end to end; mobile reads cards as text
- 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
2026-10-03 14:09:56 +00:00

84 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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