import { test, expect } from "@playwright/test"; import { readFileSync } from "node:fs"; const snapshot = JSON.parse(readFileSync(new URL("../../src/data/papers.json", import.meta.url))); const errors = new WeakMap(); test.beforeEach(async ({ page }) => { errors.set(page, []); page.on("pageerror", error => errors.get(page).push(error.message)); }); test.afterEach(async ({ page }) => { expect(errors.get(page)).toEqual([]); expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true); }); test("sample index has working pagination and returns to the same list", async ({ page }, info) => { await page.goto("/"); await expect(page.getByRole("heading", { level: 1 })).toContainText("好研究"); await expect(page.getByRole("note")).toContainText("前 20 条记录"); await expect(page.locator(".paper-row")).toHaveCount(8); await expect(page.getByRole("link", { name: "登录", exact: true })).toBeVisible(); const first = await page.locator(".paper-row h3").first().innerText(); await page.screenshot({ path: info.outputPath("home.png"), fullPage: true }); await page.getByRole("link", { name: "下一页" }).click(); await expect(page).toHaveURL(/cursor=/); await expect(page.locator(".paper-row h3").first()).not.toHaveText(first); await page.getByRole("link", { name: "上一页" }).click(); await expect(page.locator(".paper-row h3").first()).toHaveText(first); await page.getByRole("link", { name: "下一页" }).click(); await page.getByRole("link", { name: "下一页" }).click(); await expect(page.locator(".paper-row")).toHaveCount(4); await expect(page.getByRole("navigation", { name: "论文分页" })).toContainText("本页 4 篇"); await expect(page.getByRole("link", { name: "下一页" })).toHaveCount(0); }); test("search, empty results, author scope and category filters work", async ({ page }) => { await page.goto("/"); await page.getByRole("textbox", { name: "搜索论文", exact: true }).fill("no-paper-matches-this-query-92871"); await page.getByRole("button", { name: "搜索论文", exact: true }).click(); await expect(page.getByRole("heading", { name: "没有找到符合条件的论文" })).toBeVisible(); await page.getByRole("link", { name: "查看全部论文" }).click(); await expect(page.getByRole("textbox", {name:"搜索论文",exact:true})).toHaveValue(""); await expect(page.locator(".paper-row")).toHaveCount(8); const author = snapshot.papers[0].authors[0]; await page.getByRole("combobox", { name: "搜索范围", exact: true }).selectOption("author"); await page.getByRole("textbox", { name: "搜索论文", exact: true }).fill(author); await page.getByRole("button", { name: "搜索论文", exact: true }).click(); await expect(page).toHaveURL(/searchIn=author/); await expect(page.locator(".paper-row").first()).toContainText(author); await page.getByRole("link", { name: "清除筛选" }).click(); const topic = snapshot.papers[0].topics[0]; await page.getByRole("link", { name: topic, exact: true }).click(); await expect(page).toHaveURL(new RegExp("topic=" + encodeURIComponent(topic).replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))); for (const row of await page.locator(".paper-meta").all()) await expect(row).toContainText(topic); }); test("article preserves original abstract and offers citation copying", async ({ page, baseURL }, info) => { const paper = snapshot.papers[0]; await page.goto(`/papers/${paper.id}`); await expect(page.getByRole("heading", { level: 1 })).toHaveText(paper.title); await expect(page.locator("#abstract")).toContainText(paper.abstract.replace(/\n/g, " ")); await expect(page.getByRole("link", { name: new RegExp(paper.sources[0].externalId.replaceAll(".", "\\.")) })).toHaveAttribute("href", paper.sources[0].url); await page.getByRole("button", { name: "复制引用" }).click(); await expect(page.getByText("已复制引用信息", { exact: true })).toBeVisible(); await expect.poll(() => page.evaluate(() => navigator.clipboard.readText())).toContain(paper.title); await expect(page.getByRole("link", { name: "登录", exact: true })).toBeVisible(); await page.screenshot({ path: info.outputPath("article.png"), fullPage: true }); await page.getByRole("link", { name: "返回论文索引" }).click(); await expect(page).toHaveURL(new URL("/", baseURL).href); }); test("all reading themes apply and persist through a reload", async ({ page }) => { await page.goto("/"); const theme = page.getByRole("combobox", { name: "阅读主题" }); for (const value of ["editorial", "tufte", "vignelli"]) { await theme.selectOption(value); await expect(page.locator("html")).toHaveAttribute("data-theme", value); await page.reload(); await expect(theme).toHaveValue(value); const login = page.getByRole("link", { name: "登录", exact: true }); await expect(login).toBeVisible(); expect(await login.evaluate(el => { const expected = getComputedStyle(document.body).backgroundColor; return getComputedStyle(el).color === expected; })).toBe(true); await expect(page.locator("html")).toHaveAttribute("data-theme", value); } }); test("login and registration forms remain usable without sending credentials", async ({ page }, info) => { await page.goto("/login"); await expect(page.getByRole("button", { name: "Google", exact: true })).toBeVisible(); await expect(page.getByRole("button", { name: "Slack", exact: true })).toBeVisible(); await page.getByRole("button", { name: "创建账户", exact: true }).click(); await expect(page.getByRole("heading", { name: "创建账户" })).toBeVisible(); await expect(page.getByLabel("密码", { exact: true })).toHaveAttribute("minlength", "12"); await page.getByRole("button", { name: "显示密码" }).click(); await expect(page.getByLabel("密码", { exact: true })).toHaveAttribute("type", "text"); await page.screenshot({ path: info.outputPath("register.png"), fullPage: true }); await page.getByRole("button", { name: "登录", exact: true }).last().click(); await expect(page.getByRole("heading", { name: "继续你的阅读。" })).toBeVisible(); }); test("missing paper shows recovery navigation instead of an empty article", async ({ page }) => { await page.goto("/papers/999999999"); await expect(page.getByRole("heading", { name: "这篇论文不在当前索引里。" })).toBeVisible(); await page.getByRole("link", { name: "返回论文索引" }).click(); await expect(page.getByRole("heading", { level: 1 })).toContainText("好研究"); });