Harden Heute route and German voice onboarding E2E
Rebased onto main with Expo SDK 57 typecheck fixes. Voice options expose stable test ids; Shell keeps /app/heute across bootstrap and redirects legacy /app/heute bot URLs. Heute coach E2E asserts URL after reload. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
This commit is contained in:
parent
057e039e83
commit
83ec966a67
@ -49,12 +49,10 @@ test("German voice step lists German voices after choosing Deutsch", async ({ pa
|
|||||||
await expect(page.getByText(/Loading voices|Stimmen werden geladen/i)).toHaveCount(0, {
|
await expect(page.getByText(/Loading voices|Stimmen werden geladen/i)).toHaveCount(0, {
|
||||||
timeout: 30_000,
|
timeout: 30_000,
|
||||||
});
|
});
|
||||||
const germanVoice = page.getByRole("button", { name: /Eva|Bernd/i });
|
await expect(page.getByTestId("onboarding-voice-df_eva")).toBeVisible({ timeout: 30_000 });
|
||||||
await expect(germanVoice.first()).toBeVisible({ timeout: 30_000 });
|
await expect(page.getByTestId("onboarding-voice-dm_bernd")).toBeVisible();
|
||||||
await expect(page.getByRole("button", { name: "Alloy", exact: true })).toHaveCount(0);
|
await expect(page.getByTestId("onboarding-voice-af_alloy")).toHaveCount(0);
|
||||||
await expect(
|
await expect(page.getByTestId("onboarding-voice-df_eva")).toHaveAttribute("aria-pressed", "true");
|
||||||
page.getByRole("button", { name: /Eva|Bernd/i, pressed: true }).first(),
|
|
||||||
).toBeVisible();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("main conversation does not show a group subtitle for one Oo", async ({ page }) => {
|
test("main conversation does not show a group subtitle for one Oo", async ({ page }) => {
|
||||||
|
|||||||
@ -84,8 +84,7 @@ test("Heute shows the coach's brief, habits and goals, checks habits off and set
|
|||||||
await expect(page.getByTestId(`heute-habit-streak-${habit.id}`)).toHaveText("3 days");
|
await expect(page.getByTestId(`heute-habit-streak-${habit.id}`)).toHaveText("3 days");
|
||||||
await captureScreenshot(page, testInfo, "heute-coach");
|
await captureScreenshot(page, testInfo, "heute-coach");
|
||||||
|
|
||||||
await page.reload();
|
await page.reload({ waitUntil: "domcontentloaded" });
|
||||||
await page.goto("/app/heute", { waitUntil: "domcontentloaded" });
|
|
||||||
await expect(page).toHaveURL(/\/app\/heute$/);
|
await expect(page).toHaveURL(/\/app\/heute$/);
|
||||||
await expect(page.getByTestId("heute-brief")).toBeVisible();
|
await expect(page.getByTestId("heute-brief")).toBeVisible();
|
||||||
await expect(page.getByTestId(`heute-habit-${habit.id}`).getByRole("checkbox")).toBeChecked();
|
await expect(page.getByTestId(`heute-habit-${habit.id}`).getByRole("checkbox")).toBeChecked();
|
||||||
|
|||||||
@ -92,6 +92,7 @@ export function OnboardingVoiceStep({
|
|||||||
<button
|
<button
|
||||||
key={voice.id}
|
key={voice.id}
|
||||||
type="button"
|
type="button"
|
||||||
|
data-testid={`onboarding-voice-${voice.id}`}
|
||||||
onClick={() => onSelectedVoiceIdChange(voice.id)}
|
onClick={() => onSelectedVoiceIdChange(voice.id)}
|
||||||
aria-pressed={selectedVoiceId === voice.id}
|
aria-pressed={selectedVoiceId === voice.id}
|
||||||
className={`rounded-xl border-2 px-3 py-3 text-left text-sm font-medium transition-all ${
|
className={`rounded-xl border-2 px-3 py-3 text-left text-sm font-medium transition-all ${
|
||||||
|
|||||||
@ -273,6 +273,11 @@ export function ShellPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const onHeuteRoute = isHeuteAppPath(location.pathname);
|
const onHeuteRoute = isHeuteAppPath(location.pathname);
|
||||||
|
useEffect(() => {
|
||||||
|
if (botId === "heute") {
|
||||||
|
navigate(HEUTE_APP_PATH, { replace: true });
|
||||||
|
}
|
||||||
|
}, [botId, navigate]);
|
||||||
const [activeNavPillar, setActiveNavPillar] = useState<NavPillar>(() => {
|
const [activeNavPillar, setActiveNavPillar] = useState<NavPillar>(() => {
|
||||||
if (isHeuteAppPath(location.pathname)) return "heute";
|
if (isHeuteAppPath(location.pathname)) return "heute";
|
||||||
if (groupId) return "projekte";
|
if (groupId) return "projekte";
|
||||||
@ -620,8 +625,12 @@ export function ShellPage() {
|
|||||||
const recordingSkill = activeTaughtSkills.find((skill) => skill.status === "recording") ?? null;
|
const recordingSkill = activeTaughtSkills.find((skill) => skill.status === "recording") ?? null;
|
||||||
const routeBotId = useRef<string | undefined>(botId);
|
const routeBotId = useRef<string | undefined>(botId);
|
||||||
routeBotId.current = botId;
|
routeBotId.current = botId;
|
||||||
|
const routePathname = useRef(location.pathname);
|
||||||
|
routePathname.current = location.pathname;
|
||||||
const routeOnHeute = useRef(onHeuteRoute);
|
const routeOnHeute = useRef(onHeuteRoute);
|
||||||
routeOnHeute.current = onHeuteRoute;
|
routeOnHeute.current = onHeuteRoute;
|
||||||
|
const holdingHeuteRoute = () =>
|
||||||
|
routeOnHeute.current || isHeuteAppPath(routePathname.current);
|
||||||
const routeGroupId = useRef<string | undefined>(groupId);
|
const routeGroupId = useRef<string | undefined>(groupId);
|
||||||
routeGroupId.current = groupId;
|
routeGroupId.current = groupId;
|
||||||
const activeBotId = useRef<string | undefined>(inGroup ? undefined : active?.id);
|
const activeBotId = useRef<string | undefined>(inGroup ? undefined : active?.id);
|
||||||
@ -756,7 +765,7 @@ export function ShellPage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!currentBotId || !list.some((bot) => bot.id === currentBotId)) {
|
if (!currentBotId || !list.some((bot) => bot.id === currentBotId)) {
|
||||||
if (routeOnHeute.current) return;
|
if (holdingHeuteRoute()) return;
|
||||||
navigate(firstThreadRoute(list, groupList, inProject), { replace: true });
|
navigate(firstThreadRoute(list, groupList, inProject), { replace: true });
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -1004,11 +1013,11 @@ export function ShellPage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (inProject && !botId) {
|
if (inProject && !botId) {
|
||||||
if (routeOnHeute.current) return;
|
if (holdingHeuteRoute()) return;
|
||||||
navigate(firstThreadRoute(bootstrap.bots, groupList, true), { replace: true });
|
navigate(firstThreadRoute(bootstrap.bots, groupList, true), { replace: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (routeOnHeute.current) return;
|
if (holdingHeuteRoute()) return;
|
||||||
const selectedBotId = bootstrap.thread?.botId ?? bootstrap.bots[0]?.id;
|
const selectedBotId = bootstrap.thread?.botId ?? bootstrap.bots[0]?.id;
|
||||||
if (selectedBotId && selectedBotId !== botId) {
|
if (selectedBotId && selectedBotId !== botId) {
|
||||||
navigate(`/app/${selectedBotId}`, { replace: true });
|
navigate(`/app/${selectedBotId}`, { replace: true });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user