Files
openworker/surfaces/gui/e2e/onboarding.spec.ts
T
Rohit C PrasadandDevika 2b45018ffa OpenWorker: initial import
Imported from andrewyng/aisuite@1b4bbf303e
(contents of its platform/ directory, hoisted to the repo root).
Development history prior to this commit lives in that repository.

Co-authored-by: Devika <devikaverma11@gmail.com>
2026-07-21 11:09:41 -07:00

157 lines
8.1 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.
// First-run onboarding (UX-DECISIONS §24 → §29 → §39): model → your tools → go.
// §39: step 1 is a provider GALLERY (cards wear their own state; a card opens its key
// form inside a fixed-height swap region; Test verifies, SAVES, and returns) and step 2
// is a two-state tools page (why-paragraph + sign-in → mini connector gallery with live
// one-click connects). Entered here via the REPLAY path (Settings ▸ Appearance ▸ "Run
// setup again") — which is itself under test.
import { expect } from "@playwright/test";
import { test } from "./fixtures";
async function openOnboarding(page) {
await page.goto("/");
await page.getByTestId("account-row").click();
await page.getByTestId("account-menu").getByRole("button", { name: "Settings" }).click();
await page.getByRole("button", { name: "Run setup again" }).click();
await expect(page.getByTestId("ob-step-model")).toBeVisible();
}
test("provider gallery: cards wear their state; Next arms off stored credentials", async ({
page,
}) => {
await openOnboarding(page);
// Every card carries its own status with zero clicks (the 2026-07-16 confusion —
// "is OpenAI already connected?" — is answered by the gallery itself).
await expect(page.getByTestId("ob-provider-openai")).toContainText("✓ Connected");
await expect(page.getByTestId("ob-provider-anthropic")).toContainText("✓ Connected");
await expect(page.getByTestId("ob-provider-zai")).toContainText("Not set up");
await expect(page.getByTestId("ob-provider-ollama")).toContainText("No key needed");
// Recognition-first order: anthropic before openai before the OpenAI-compat tail.
const names = await page
.getByTestId("ob-provider-gallery")
.locator("[data-testid^=ob-provider-]")
.evaluateAll((els) => els.map((e) => e.getAttribute("data-testid")));
expect(names.indexOf("ob-provider-anthropic")).toBeLessThan(names.indexOf("ob-provider-openai"));
expect(names.indexOf("ob-provider-openai")).toBeLessThan(names.indexOf("ob-provider-zai"));
// A configured provider already arms Next — no form visit required.
await expect(page.getByTestId("ob-continue")).toBeEnabled();
await page.getByTestId("ob-continue").click();
await expect(page.getByTestId("ob-step-tools")).toBeVisible();
});
test("key form: Test verifies, saves, and returns to the gallery with the ✓", async ({
page,
}) => {
await openOnboarding(page);
await page.getByTestId("ob-provider-zai").click();
// The header stays put (§39 fixed frame): the welcome headline is still on screen.
await expect(page.getByRole("heading", { name: "Welcome to OpenWorker" })).toBeVisible();
// Optional endpoint is a quiet disclosure with no explainer copy (owner call 2026-07-18).
await expect(page.getByTestId("ob-field-base_url")).toHaveCount(0);
await page.getByTestId("ob-endpoint-link").click();
await expect(page.getByTestId("ob-field-base_url")).toHaveValue(/api\.z\.ai/);
// Bad key: the error is a line, not a navigation.
await page.getByTestId("ob-field-api_key").fill("bad-key");
await page.getByTestId("ob-test").click();
await expect(page.getByText("Invalid API key.")).toBeVisible();
// Good key: state lands IN the field ("✓ Tested & saved" pill), then the form
// auto-returns to the gallery where the Z AI card now wears its ✓.
await page.getByTestId("ob-field-api_key").fill("zk-good");
await page.getByTestId("ob-test").click();
await expect(page.getByTestId("ob-saved-pill")).toBeVisible();
await expect(page.getByTestId("ob-provider-zai")).toContainText("✓ Connected", {
timeout: 5_000,
});
await expect(page.getByTestId("ob-continue")).toBeEnabled();
});
test("key form: revisiting a connected provider shows the in-field saved state; drafts survive switching", async ({
page,
}) => {
await openOnboarding(page);
// Revisit a configured provider: green in-field pill + masked placeholder — the old
// empty-password-field-reads-as-not-set-up trap (owner complaint 2026-07-16) is gone.
await page.getByTestId("ob-provider-openai").click();
await expect(page.getByTestId("ob-saved-pill")).toBeVisible();
await expect(page.getByTestId("ob-field-api_key")).toHaveAttribute("placeholder", "••••••••");
// Typed-but-unsaved input survives a peek at another provider (drafts).
await page.getByTestId("ob-back").click();
await page.getByTestId("ob-provider-zai").click();
await page.getByTestId("ob-field-api_key").fill("zk-draft");
await page.getByTestId("ob-back").click();
await page.getByTestId("ob-provider-openai").click();
await expect(page.getByTestId("ob-saved-pill")).toBeVisible();
await page.getByTestId("ob-back").click();
await page.getByTestId("ob-provider-zai").click();
await expect(page.getByTestId("ob-field-api_key")).toHaveValue("zk-draft");
// Next from a dirty form auto-verifies and saves first (2026-07-12: no hidden
// Test-then-Continue two-step), then advances.
await page.getByTestId("ob-field-api_key").fill("zk-good");
await page.getByTestId("ob-continue").click();
await expect(page.getByTestId("ob-step-tools")).toBeVisible();
});
test("tools page: sign-in morphs the page into the connector gallery; a card connects one-click", async ({
page,
}) => {
await openOnboarding(page);
await page.getByTestId("ob-continue").click();
await expect(page.getByTestId("ob-step-tools")).toBeVisible();
// Pre-sign-in (§41): the benefit rows are already there (no Connect buttons yet),
// the combined Google row says Coming soon, the band asks for sign-in, and the one
// footer button is the quiet "Continue without sign-in".
await expect(page.getByText("Chat can only advise")).toBeVisible();
await expect(page.getByTestId("ob-tool-outlook")).toContainText("Stay on top of email");
await expect(page.getByTestId("ob-tool-outlook").getByRole("button")).toHaveCount(0);
await expect(page.getByTestId("ob-tool-attio")).toContainText("Track every relationship");
await expect(page.getByTestId("ob-tool-google-soon")).toContainText("Coming soon");
await expect(page.getByText("Sign in for one-click connections")).toBeVisible();
await expect(page.getByTestId("ob-tools-skip")).toContainText("Continue without sign-in");
// Sign-in lands out-of-band; the band's SLOT stays put and flips to the congrats
// (zero layout shift), and every row grows its Connect pill.
await page.getByTestId("ob-cloud-signin").click();
await expect(page.getByTestId("ob-tools-signedin")).toBeVisible({ timeout: 10_000 });
await expect(page.getByTestId("ob-tools-signedin")).toContainText("Youre signed in");
await expect(
page.getByTestId("ob-tool-attio").getByRole("button", { name: "Connect" }),
).toBeVisible();
await expect(page.getByTestId("ob-tool-google-soon").getByRole("button")).toHaveCount(0);
// One-click connect: the consent completes in the (mock) browser; the poll flips the
// row to ✓ Connected. Next was armed the whole time — connecting is optional.
await page.getByTestId("ob-tool-outlook").getByRole("button", { name: "Connect" }).click();
await expect(page.getByTestId("ob-tool-outlook")).toContainText("✓ Connected", {
timeout: 10_000,
});
await expect(page.getByTestId("ob-continue-tools")).toBeEnabled();
await page.getByTestId("ob-continue-tools").click();
// Done step: the automation CTA lands on the Automations quickstart.
await expect(page.getByTestId("ob-step-done")).toBeVisible();
await page.getByTestId("ob-cta-automation").click();
await expect(page.getByTestId("onboarding")).toHaveCount(0);
await expect(page.getByRole("heading", { name: "Automations" })).toBeVisible();
});
test("tools page skips cleanly; Start working lands in a session with the panel open", async ({
page,
}) => {
await openOnboarding(page);
await page.getByTestId("ob-continue").click();
await page.getByTestId("ob-tools-skip").click();
await expect(page.getByTestId("ob-step-done")).toBeVisible();
await page.getByTestId("ob-start").click();
await expect(page.getByTestId("onboarding")).toHaveCount(0);
// §32: "Start working" lands with the rail's Access section expanded (the drawer is gone).
await expect(page.getByRole("region", { name: "Session access" })).toBeVisible();
});