mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-08 17:34:51 +00:00
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>
216 lines
8.3 KiB
TypeScript
216 lines
8.3 KiB
TypeScript
import { expect, test, type Page } from "./fixtures";
|
|
|
|
function languageButton(page: Page) {
|
|
return page.getByRole("button", { name: /^(Language|语言)/ }).first();
|
|
}
|
|
|
|
async function chooseLanguage(page: Page, language: string) {
|
|
await languageButton(page).click();
|
|
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")}`);
|
|
}
|
|
|
|
test.describe("server-rendered Chinese pages", () => {
|
|
test.use({ javaScriptEnabled: false });
|
|
|
|
test("render in Chinese with matching language metadata before any script runs", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/zh-CN/docs/cli");
|
|
|
|
await expect(page.locator("html")).toHaveAttribute("lang", "zh-CN");
|
|
await expect(page).toHaveTitle("CLI 参考 - Paseo 文档");
|
|
await expect(page.getByRole("heading", { level: 1 })).toHaveText(/CLI 参考$/);
|
|
await expect(page.locator('link[rel="canonical"]')).toHaveAttribute(
|
|
"href",
|
|
"https://paseo.sh/zh-CN/docs/cli",
|
|
);
|
|
const alternates = await page
|
|
.locator('link[rel="alternate"][hreflang]')
|
|
.evaluateAll(describeAlternates);
|
|
expect(alternates).toEqual([
|
|
"en https://paseo.sh/docs/cli",
|
|
"zh-CN https://paseo.sh/zh-CN/docs/cli",
|
|
"x-default https://paseo.sh/docs/cli",
|
|
]);
|
|
await expect(page.locator('meta[property="og:locale"]')).toHaveAttribute("content", "zh_CN");
|
|
});
|
|
|
|
test("keep English pages at their unprefixed URLs", async ({ page }) => {
|
|
await page.goto("/docs/cli");
|
|
|
|
await expect(page.locator("html")).toHaveAttribute("lang", "en");
|
|
await expect(page.getByRole("heading", { level: 1 })).toHaveText(/CLI reference$/);
|
|
});
|
|
|
|
test("land translated anchors on the English section ids", async ({ page }) => {
|
|
await page.goto("/zh-CN/docs/cli#running-agents");
|
|
|
|
await expect(page.locator("#running-agents")).toHaveText(/运行 Agent/);
|
|
await expect(page.locator("main")).not.toContainText("{#");
|
|
});
|
|
|
|
test("show the app's Chinese labels in the homepage mockup", async ({ page }) => {
|
|
await page.goto("/zh-CN");
|
|
|
|
const mockup = page.getByRole("img", {
|
|
name: "Paseo 桌面应用,并排打开了编程 Agent、一段对话和一份代码 diff",
|
|
});
|
|
await expect(mockup).toContainText("新建工作区");
|
|
await expect(mockup).toContainText("待查看");
|
|
await expect(mockup).toContainText("给 Agent 发消息");
|
|
await expect(mockup).not.toContainText("Ready to review");
|
|
});
|
|
|
|
test("keep no space after full-width punctuation in the homepage subtitle", async ({ page }) => {
|
|
await page.goto("/zh-CN");
|
|
|
|
await expect(page.getByText(/^同时运行多个编程 Agent/)).toHaveText(
|
|
"同时运行多个编程 Agent,在任何机器上。在桌前,也在手机上。",
|
|
);
|
|
});
|
|
});
|
|
|
|
test("switches language on the same page, keeping the query and then every link", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/plugins/all?q=dark");
|
|
await chooseLanguage(page, "简体中文");
|
|
|
|
await expect(page).toHaveURL(/\/zh-CN\/plugins\/all\?q=dark$/);
|
|
await expect(page.locator("html")).toHaveAttribute("lang", "zh-CN");
|
|
await expect(page.getByRole("searchbox", { name: "搜索插件" })).toHaveValue("dark");
|
|
|
|
await page.getByRole("link", { name: "文档", exact: true }).first().click();
|
|
await expect(page).toHaveURL(/\/zh-CN\/docs$/);
|
|
|
|
await chooseLanguage(page, "English");
|
|
await expect(page).toHaveURL(/\/docs$/);
|
|
await expect(page.locator("html")).toHaveAttribute("lang", "en");
|
|
});
|
|
|
|
test("shows the language as an abbreviation and lists every language by name", async ({ page }) => {
|
|
await page.goto("/docs/cli#running-agents");
|
|
const button = languageButton(page);
|
|
await expect(button).toHaveText("EN");
|
|
await expect(button).toHaveAccessibleName("Language: English");
|
|
|
|
await button.click();
|
|
await expect(page.getByRole("menuitemradio", { name: "English" })).toHaveAttribute(
|
|
"aria-checked",
|
|
"true",
|
|
);
|
|
const chinese = page.getByRole("menuitemradio", { name: /简体中文/ });
|
|
await expect(chinese).toHaveAttribute("aria-checked", "false");
|
|
await expect(page.getByRole("menu")).toBeInViewport({ ratio: 1 });
|
|
await expect(chinese).toHaveAttribute("href", "/zh-CN/docs/cli#running-agents");
|
|
|
|
await page.mouse.click(5, 400);
|
|
await expect(page.getByRole("menu")).toHaveCount(0);
|
|
});
|
|
|
|
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();
|
|
|
|
await page.keyboard.press("Escape");
|
|
await expect(page.getByRole("menu")).toHaveCount(0);
|
|
await expect(languageButton(page)).toBeFocused();
|
|
|
|
await page.keyboard.press("ArrowDown");
|
|
await page.keyboard.press("ArrowDown");
|
|
await expect(page.getByRole("menuitemradio", { name: /简体中文/ })).toBeFocused();
|
|
await page.keyboard.press("Enter");
|
|
|
|
await expect(page).toHaveURL(/\/zh-CN$/);
|
|
await expect(languageButton(page)).toHaveText("ZH");
|
|
await expect(languageButton(page)).toBeFocused();
|
|
});
|
|
|
|
test.describe("on a phone", () => {
|
|
test.use({ viewport: { width: 390, height: 844 }, hasTouch: true });
|
|
|
|
const cases = [
|
|
{ from: "/", choose: "简体中文", to: "/zh-CN", abbreviation: "ZH" },
|
|
{ from: "/zh-CN", choose: "English", to: "/", abbreviation: "EN" },
|
|
{ from: "/docs/cli", choose: "简体中文", to: "/zh-CN/docs/cli", abbreviation: "ZH" },
|
|
];
|
|
for (const { from, choose, to, abbreviation } of cases) {
|
|
test(`switches from ${from} to ${to} with taps`, async ({ page, baseURL }) => {
|
|
await page.goto(from);
|
|
await languageButton(page).tap();
|
|
await expect(page.getByRole("menu")).toBeInViewport({ ratio: 1 });
|
|
await page.getByRole("menuitemradio", { name: choose }).tap();
|
|
|
|
await expect(page).toHaveURL(new URL(to, baseURL).href);
|
|
await expect(languageButton(page)).toHaveText(abbreviation);
|
|
});
|
|
}
|
|
});
|
|
|
|
test("finds plugins by their Chinese and English listing text", async ({ page }) => {
|
|
await page.goto(`/zh-CN/plugins/all?q=${encodeURIComponent("深色")}`);
|
|
await expect(page.getByRole("link", { name: /Dracula/ })).toBeVisible();
|
|
|
|
await page.goto(`/zh-CN/plugins/all?q=${encodeURIComponent("传令官")}`);
|
|
await expect(page.getByRole("link", { name: /传令官/ })).toBeVisible();
|
|
|
|
await page.goto("/zh-CN/plugins/all?q=herald");
|
|
await expect(page.getByRole("link", { name: /传令官/ })).toBeVisible();
|
|
});
|
|
|
|
test("shows a translated plugin overview, or the English one under a notice", async ({ page }) => {
|
|
await page.goto("/zh-CN/plugins/omercnet/dracula");
|
|
await expect(page.getByRole("heading", { name: "行为" })).toBeVisible();
|
|
await expect(page.getByRole("note")).toHaveCount(0);
|
|
|
|
await page.goto("/zh-CN/plugins/gpambrozio/herald");
|
|
await expect(page.getByRole("heading", { level: 1 })).toHaveText("传令官");
|
|
await expect(page.getByRole("note")).toHaveText(
|
|
"该插件的概览尚未翻译为你的语言,因此以英文显示。",
|
|
);
|
|
await expect(page.getByRole("heading", { name: "Behavior" })).toBeVisible();
|
|
});
|
|
|
|
test("shows the changelog in Chinese", async ({ page }) => {
|
|
await page.goto("/zh-CN/changelog");
|
|
|
|
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();
|
|
});
|
|
});
|