mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-08 01:14:52 +00:00
fix(website): enable the language menu after hydration (#9046)
The server-rendered trigger accepted clicks before its handler existed. Tie its enabled state to hydration and cover delayed scripts so an early click cannot silently disappear. Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,23 @@ async function chooseLanguage(page: Page, language: string) {
|
||||
await page.getByRole("menuitemradio", { name: language }).click();
|
||||
}
|
||||
|
||||
async function withPageScriptsHeld(page: Page, run: (release: () => void) => Promise<void>) {
|
||||
let releaseScripts!: () => void;
|
||||
const scriptsReleased = new Promise<void>((resolve) => {
|
||||
releaseScripts = resolve;
|
||||
});
|
||||
await page.route("**/*.js", async (route) => {
|
||||
await scriptsReleased;
|
||||
await route.continue();
|
||||
});
|
||||
try {
|
||||
await run(releaseScripts);
|
||||
} finally {
|
||||
releaseScripts();
|
||||
await page.unrouteAll({ behavior: "wait" });
|
||||
}
|
||||
}
|
||||
|
||||
function describeAlternates(links: Element[]): string[] {
|
||||
return links.map((link) => `${link.getAttribute("hreflang")} ${link.getAttribute("href")}`);
|
||||
}
|
||||
@@ -114,6 +131,7 @@ test("shows the language as an abbreviation and lists every language by name", a
|
||||
|
||||
test("switches language from the keyboard", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await expect(languageButton(page)).toBeEnabled();
|
||||
await languageButton(page).focus();
|
||||
await page.keyboard.press("Enter");
|
||||
await expect(page.getByRole("menuitemradio", { name: "English" })).toBeFocused();
|
||||
@@ -183,3 +201,15 @@ test("shows the changelog in Chinese", async ({ page }) => {
|
||||
await expect(page.getByRole("heading", { name: "新增" }).first()).toBeVisible();
|
||||
await expect(page.getByRole("note")).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("waits for scripts before enabling the language menu", async ({ page }) => {
|
||||
await withPageScriptsHeld(page, async (releaseScripts) => {
|
||||
await page.goto("/docs/cli#running-agents", { waitUntil: "commit" });
|
||||
await expect(languageButton(page)).toBeVisible();
|
||||
await expect(languageButton(page)).toBeDisabled();
|
||||
|
||||
releaseScripts();
|
||||
await languageButton(page).click();
|
||||
await expect(page.getByRole("menuitemradio", { name: "English" })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useLocation, useNavigate } from "@tanstack/react-router";
|
||||
import { useHydrated, useLocation, useNavigate } from "@tanstack/react-router";
|
||||
import { AnimatePresence, motion, type Transition } from "framer-motion";
|
||||
import { Check, ChevronDown, Languages } from "lucide-react";
|
||||
import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
||||
@@ -33,6 +33,7 @@ type OpenFocus = "current" | "first" | "last";
|
||||
* the menu button pattern: arrows move between languages, Escape and outside presses close it.
|
||||
*/
|
||||
export function LanguageSelector() {
|
||||
const hydrated = useHydrated();
|
||||
const { t } = useTranslation();
|
||||
const locale = useLocale();
|
||||
const location = useLocation();
|
||||
@@ -125,6 +126,7 @@ export function LanguageSelector() {
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
disabled={!hydrated}
|
||||
aria-label={t("languageSelector.current", { language: LANGUAGE_NAMES[locale] })}
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={open}
|
||||
|
||||
Reference in New Issue
Block a user