A single-page 28-chapter manual generated from manual.json covers the 11 workspaces, all React editors, OPFS save/reopen, explicit local downloads, import/export routes, preferences/keymap and the capability matrix. It reuses verified course screenshots and adds 14 fresh Chromium captures for shell, storage, area, camera, preferences, IO and troubleshooting chapters. Manual-driven fixes: Save As now states OPFS-only, GLTF import is restored, quick toolbar honors its preference, startup workspace is applied, Properties tabs jump to sections, Outliner fallback search filters, and the editor-header ⋮ opens the area menu. Help and the tutorial landing link the new manual; the PDF remains as an archive. Co-Authored-By: Claude Code <noreply@anthropic.com>
46 lines
2.5 KiB
TypeScript
46 lines
2.5 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
test.use({ viewport: { width: 1600, height: 900 } });
|
|
|
|
test("HTML manual has chapters, figures, working search and no overflow", async ({ page }) => {
|
|
test.setTimeout(240_000);
|
|
await page.goto("/manuals/index.html", { waitUntil: "load" });
|
|
await expect(page.locator(".manual-chapter")).toHaveCount(28);
|
|
await expect(page.locator(".manual-nav a[data-nav-id]")).toHaveCount(32);
|
|
await expect(page.getByLabel("搜索手册", { exact: true })).toBeVisible();
|
|
await expect(page.locator("figure img").first()).toBeVisible();
|
|
const firstImage = await page.locator("figure img").first().evaluate((element) => ({ complete: (element as HTMLImageElement).complete, width: (element as HTMLImageElement).naturalWidth }));
|
|
expect(firstImage.complete).toBe(true);
|
|
expect(firstImage.width).toBeGreaterThan(0);
|
|
|
|
await page.getByLabel("搜索手册", { exact: true }).fill("相机");
|
|
await expect(page.locator(".manual-search-status")).toContainText("匹配");
|
|
await expect.poll(async () => page.locator(".manual-nav a[data-nav-id][hidden]").count()).toBeGreaterThan(0);
|
|
await page.getByLabel("搜索手册", { exact: true }).fill("");
|
|
await expect(page.locator(".manual-search-status")).toHaveText("");
|
|
|
|
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);
|
|
expect(overflow).toBeLessThanOrEqual(1);
|
|
});
|
|
|
|
test("manual is responsive and reachable from Help", async ({ page, context }) => {
|
|
test.setTimeout(240_000);
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
await page.goto("/manuals/index.html", { waitUntil: "load" });
|
|
await expect(page.locator(".manual-menu-toggle")).toBeVisible();
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBeLessThanOrEqual(1);
|
|
|
|
await page.setViewportSize({ width: 1600, height: 900 });
|
|
await page.goto("/?ui=web", { waitUntil: "domcontentloaded" });
|
|
await page.locator("main.blender-app").waitFor({ timeout: 120_000 });
|
|
await page.getByRole("button", { name: "帮助", exact: true }).click();
|
|
const entry = page.getByRole("menuitem", { name: "使用手册(网页版)", exact: true });
|
|
await expect(entry).toBeVisible();
|
|
const popupPromise = context.waitForEvent("page", { timeout: 30_000 });
|
|
await entry.click();
|
|
const popup = await popupPromise;
|
|
await popup.waitForLoadState("domcontentloaded");
|
|
expect(new URL(popup.url()).pathname).toBe("/manuals/index.html");
|
|
await expect(popup.locator(".manual-chapter")).toHaveCount(28);
|
|
});
|