* feat(web): Phase 2 production readiness — locale, mobile, E2E matrix Localize onboarding focus facts by profile locale (DE assertion). Add mobile overflow/touch audits, deep-link matrix, extended console checks, and E2E for empty project, session unavailable, and teaching composer. Safe-area and Heute header layout on 390px viewports. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(e2e): stabilize Phase 2 specs for mobile shell and empty project Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(api): satisfy typecheck for focusFactValue Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(api): type-safe focusFactValue lookup Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(api): narrow focus fact locale key Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(api): use FocusOptionId union for fact lookup Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * test(web): align Shell header control assertions with touch targets Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * style(web): format desktop header control test Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): stabilize Phase 2 E2E (settings i18n, empty project, chart plot load) Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): empty project E2E simulates pre-start bootstrap; relax module recovery wait Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): format empty-project E2E; stabilize chart-links cold Plot load Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * test(web): run chart-links E2E serially to reuse warmed Plot module Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * style(web): format chart-links E2E Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
48 lines
1.9 KiB
TypeScript
48 lines
1.9 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { completeOnboarding, routePatchRpc, rpc, signup } from "./helpers";
|
|
|
|
test("empty project space offers Start before the main conversation exists", async ({ page }) => {
|
|
const stamp = Date.now();
|
|
await signup(page, `empty-project-${stamp}@rakazo.test`, "password12", "Empty Project");
|
|
await completeOnboarding(page);
|
|
|
|
const side = await rpc<{ id: string }>(page, "spaces/create", { name: "Empty project" });
|
|
|
|
// spaces/create provisions a main conversation server-side; strip it from bootstrap so the
|
|
// shell shows the pre-start empty project UI.
|
|
await routePatchRpc(page, "bootstrap", (json) => {
|
|
const groups = (json.groups as Array<{ spaceId: string }>).filter(
|
|
(group) => group.spaceId !== side.id,
|
|
);
|
|
const bots = (json.bots as Array<{ spaceId: string }>).filter((bot) => bot.spaceId !== side.id);
|
|
const spaces = (
|
|
json.spaces as Array<{
|
|
id: string;
|
|
bots: unknown[];
|
|
groups: unknown[];
|
|
hasContent: boolean;
|
|
}>
|
|
).map((space) =>
|
|
space.id === side.id ? { ...space, bots: [], groups: [], hasContent: false } : space,
|
|
);
|
|
return { ...json, groups, bots, spaces };
|
|
});
|
|
|
|
await page.evaluate((spaceId) => {
|
|
window.localStorage.setItem("rakazo:space-id", spaceId);
|
|
}, side.id);
|
|
await page.goto("/app", { waitUntil: "domcontentloaded" });
|
|
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true", {
|
|
timeout: 60_000,
|
|
});
|
|
|
|
const mainStart = page.getByTestId("project-start-main");
|
|
await expect(mainStart).toBeVisible({ timeout: 30_000 });
|
|
await expect(mainStart).toContainText(/Start|Starten/i);
|
|
|
|
const projekte = page.locator(".sidebar-projekte");
|
|
const sidebarStart = projekte.getByTestId(`project-start-${side.id}`);
|
|
await expect(sidebarStart).toBeVisible({ timeout: 30_000 });
|
|
await expect(sidebarStart).toContainText(/Start|Starten/i);
|
|
});
|