Several web surfaces hard-coded German (the project card, roster and
activity status labels, the sidebar "Heute" label) or used German text as
the Lingui source message (sidebar sections, project timeline, bot picker,
voice entry, group stage, copy and read-aloud buttons). English users saw
German, and because production builds keep only message ids, none of these
strings could be translated per locale.
Convert them to English source messages, keeping the meaning:
- ProjectCreatedCard: Lingui Trans/Plural instead of literals.
- agent-activity: labels go through i18n._ with literal ids so the module
stays importable from plain unit tests; the extractor still collects them.
- Shell, ProjectSessionTimeline, bot-picker, StageVoiceEntry, OoStage:
English sources, reusing existing messages where one already fit
("just now", "{n}m ago", "Search", "No bots match", "Set up voice",
"Group conversation", "Transcript").
- The conversation picker matches its create entry against the translated
label instead of a fixed German string.
The German wording returns through the de catalog in the next commit.
Unit and E2E tests now assert the English labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
99 lines
4.4 KiB
TypeScript
99 lines
4.4 KiB
TypeScript
import { expect, type Locator, test } from "@playwright/test";
|
|
import { completeOnboarding, rpc, signup, unterhaltungenOnly } from "./helpers";
|
|
|
|
async function selectProjectSpace(projekte: Locator, name: string) {
|
|
const row = projekte.locator('[data-sidebar-group^="project-space:"]').filter({ hasText: name });
|
|
await row.getByRole("button", { name: `Select ${name}` }).click();
|
|
}
|
|
|
|
async function projectSidebarStart(projekte: Locator, name: string) {
|
|
const row = projekte.locator('[data-sidebar-group^="project-space:"]').filter({ hasText: name });
|
|
const groupAttr = await row.getAttribute("data-sidebar-group");
|
|
const spaceId = groupAttr?.match(/^project-space:([^:]+)/)?.[1];
|
|
if (!spaceId) throw new Error(`missing project space id for ${name}`);
|
|
return projekte.getByTestId(`project-start-${spaceId}`);
|
|
}
|
|
|
|
test("empty project shows Start instead of a fallback bot", async ({ page }) => {
|
|
const stamp = Date.now();
|
|
await signup(page, `empty-project-${stamp}@rakazo.test`, "password12", "Empty Project");
|
|
await completeOnboarding(page);
|
|
await page.goto("/app");
|
|
await page.waitForURL(/\/app\/[^/]+$/);
|
|
|
|
const projekte = page.locator(".sidebar-projekte");
|
|
await projekte.getByTestId("create-project-trigger").click();
|
|
const dialog = page.getByRole("dialog", { name: "New project" });
|
|
await dialog.getByLabel("Name").fill("Launch");
|
|
await dialog.getByRole("button", { name: "Create project", exact: true }).click();
|
|
await page.waitForURL(/\/app(?:\/)?$/);
|
|
|
|
await expect(projekte.getByRole("button", { name: /^Chief/ })).toHaveCount(0);
|
|
await expect(projekte.getByRole("button", { name: "Start", exact: true })).toBeVisible();
|
|
await expect(page.getByTestId("project-start-main")).toBeVisible();
|
|
|
|
await page.getByTestId("project-start-main").click();
|
|
await expect(page.getByTestId("side-panel")).toHaveAttribute("data-panel", "create");
|
|
});
|
|
|
|
test("Start in an onboarded project opens the group create flow", async ({ page }) => {
|
|
const stamp = Date.now();
|
|
await signup(page, `project-start-${stamp}@rakazo.test`, "password12", "Project Start");
|
|
await completeOnboarding(page);
|
|
|
|
const projekte = page.locator(".sidebar-projekte");
|
|
await projekte.getByTestId("create-project-trigger").click();
|
|
const dialog = page.getByRole("dialog", { name: "New project" });
|
|
await dialog.getByLabel("Name").fill("Website");
|
|
await dialog.getByRole("button", { name: "Create project", exact: true }).click();
|
|
await page.waitForURL(/\/app(?:\/)?$/);
|
|
await selectProjectSpace(projekte, "Website");
|
|
await page.waitForURL(/\/app(?:\/)?$/);
|
|
|
|
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true", {
|
|
timeout: 60_000,
|
|
});
|
|
await selectProjectSpace(projekte, "Website");
|
|
await page.waitForURL(/\/app(?:\/)?$/);
|
|
await expect(unterhaltungenOnly(page).getByRole("button", { name: /^Chief/ })).toHaveCount(1);
|
|
await expect(projekte.getByRole("button", { name: /^Chief/ })).toHaveCount(0);
|
|
const sidebarStart = await projectSidebarStart(projekte, "Website");
|
|
await expect(sidebarStart).toBeVisible({ timeout: 30_000 });
|
|
|
|
await sidebarStart.click();
|
|
await expect(page.getByTestId("side-panel")).toHaveAttribute("data-panel", "create-group", {
|
|
timeout: 30_000,
|
|
});
|
|
await expect(page.getByText("New group", { exact: true })).toBeVisible();
|
|
await expect(
|
|
page.getByTestId("side-panel").getByRole("button", { name: /^Chief/ }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("archiving the only bot keeps Start visible in the project sidebar", async ({ page }) => {
|
|
const stamp = Date.now();
|
|
await signup(page, `project-archive-${stamp}@rakazo.test`, "password12", "Project Archive");
|
|
await completeOnboarding(page);
|
|
|
|
const projekte = page.locator(".sidebar-projekte");
|
|
await projekte.getByTestId("create-project-trigger").click();
|
|
const dialog = page.getByRole("dialog", { name: "New project" });
|
|
await dialog.getByLabel("Name").fill("Side");
|
|
await dialog.getByRole("button", { name: "Create project", exact: true }).click();
|
|
await page.waitForURL(/\/app(?:\/)?$/);
|
|
|
|
const sideBot = await rpc<{ id: string }>(page, "bots/create", {
|
|
name: "Side bot",
|
|
title: "",
|
|
description: "",
|
|
notifyOnFinish: true,
|
|
computerMode: "team",
|
|
});
|
|
await rpc(page, "bots/archive", { botId: sideBot.id });
|
|
|
|
await page.goto("/app");
|
|
await page.waitForURL(/\/app(?:\/)?$/);
|
|
await expect(projekte.getByRole("button", { name: "Start", exact: true })).toBeVisible();
|
|
await expect(page.getByTestId("project-start-main")).toBeVisible();
|
|
});
|