/** * E2E: onboarding answers land in the user profile, and Settings → About you shows every * fact with its origin, confirms a pending one, and forgets one or all of them. */ import { expect, test } from "@playwright/test"; import { captureScreenshot, openUserSettings, rpc, signup, waitForChatComposer } from "./helpers"; test.use({ timezoneId: "Europe/Vienna" }); test.beforeEach(async ({ page }) => { // Walk the full emoji-first flow, including the preferences step. await page.route("**/rpc/integrationSetup/get", (route) => route.fulfill({ json: { json: { canConfigure: true, needsSetup: false, webUrl: "https://example.test/integrations/setup", providers: [{ id: "composio", configured: true }], }, }, }), ); }); test("onboarding feeds the profile; facts can be confirmed and forgotten", async ({ page, }, testInfo) => { const stamp = Date.now(); await signup(page, `profile-${stamp}@rakazo.test`, "password12", "Profile Tester"); await expect(page.getByRole("heading", { name: /Design your Oo/i })).toBeVisible({ timeout: 30_000, }); await page.getByRole("button", { name: "Continue", exact: true }).click(); await expect(page.getByRole("heading", { name: /Tell us about yourself/i })).toBeVisible(); await expect(page.getByLabel("Timezone")).toHaveValue("Europe/Vienna"); await page.getByPlaceholder("Your name").fill("Pat Example"); await page.getByRole("button", { name: "Music", exact: true }).click(); await page.getByRole("button", { name: "Deep-dive focused" }).click(); await page.getByRole("button", { name: "Direct & concise" }).click(); await page.getByRole("button", { name: "Continue", exact: true }).click(); await expect(page.getByRole("heading", { name: /Choose your language/i })).toBeVisible(); await page.getByRole("button", { name: "English", exact: true }).click(); await expect(page.getByRole("heading", { name: /Pick a voice/i })).toBeVisible(); await page.getByRole("button", { name: "Skip", exact: true }).click(); await page.waitForURL(/\/app\/[^/]+/, { timeout: 30_000 }); await waitForChatComposer(page); // The answers no longer overwrite a bot's instructions. const bots = await rpc>(page, "bots/list", null); expect(bots.length).toBeGreaterThan(0); for (const bot of bots) expect(bot.instructions).not.toContain("User Context"); expect((await rpc<{ name: string }>(page, "me", null)).name).toBe("Pat Example"); // Sensitive facts from anywhere but the user wait for confirmation. await rpc(page, "profile/update", { addFacts: [{ category: "health", value: "Allergic to peanuts", source: "onboarding" }], }); const settings = await openUserSettings(page, "profile"); await expect(settings).toHaveAttribute("data-settings-section", "profile"); const profile = settings.getByTestId("user-profile-settings"); await expect(profile.getByTestId("profile-field-timeZone")).toContainText("Europe/Vienna"); await expect(profile.getByTestId("profile-field-language")).toContainText("English"); await expect(profile.getByTestId("profile-field-locale")).toContainText("United States"); await expect(profile.getByTestId("profile-field-communicationStyle")).toContainText( "Direct and concise", ); const music = profile.getByTestId("user-fact").filter({ hasText: "Interested in music" }); await expect(music).toContainText("Onboarding"); await expect(profile.getByTestId("user-facts-habits")).toContainText( "Prefers focused deep dives", ); const allergy = profile.getByTestId("user-fact").filter({ hasText: "Allergic to peanuts" }); await expect(allergy).toHaveAttribute("data-status", "pending"); await captureScreenshot(page, testInfo, "user-profile-pending"); await allergy.getByRole("button", { name: "Confirm" }).click(); await expect(allergy).toHaveAttribute("data-status", "active"); await expect(allergy.getByRole("button", { name: "Confirm" })).toHaveCount(0); await music.getByRole("button", { name: "Delete" }).click(); await expect(music).toHaveCount(0); await captureScreenshot(page, testInfo, "user-profile-settings"); const afterDelete = await rpc<{ facts: Array<{ value: string; status: string }> }>( page, "profile/get", null, ); expect(afterDelete.facts).toEqual( expect.not.arrayContaining([expect.objectContaining({ value: "Interested in music" })]), ); expect(afterDelete.facts).toContainEqual( expect.objectContaining({ value: "Allergic to peanuts", status: "active" }), ); await profile.getByRole("button", { name: "Forget everything" }).click(); await page.getByRole("alertdialog").getByRole("button", { name: "Forget", exact: true }).click(); await expect(profile).toContainText("Nothing yet"); expect(await rpc<{ facts: unknown[] }>(page, "profile/get", null)).toMatchObject({ facts: [] }); });