import { expect, test } from "@playwright/test"; import { readFile } from "node:fs/promises"; test("account → full sync → research → resync → PnL → filtered export → logout", async ({ page, }) => { const failures: string[] = []; page.on("pageerror", (error) => failures.push(error.message)); await page.goto("/"); await expect( page.getByRole("heading", { name: "登录研究工作空间" }), ).toBeVisible(); await page.getByLabel("密码", { exact: true }).fill("incorrect"); await page.getByRole("button", { name: "进入工作空间" }).click(); await expect(page.getByText("用户名或密码不正确")).toBeVisible(); await page.getByLabel("密码", { exact: true }).fill("browser-test-password"); await page.getByRole("button", { name: "进入工作空间" }).click(); await page.getByRole("button", { name: "个人信息", exact: true }).click(); const connectionSettings = page.getByRole("button", { name: "连接设置", exact: true, }); if ((await connectionSettings.getAttribute("aria-expanded")) === "false") await connectionSettings.click(); await page .getByRole("textbox", { name: "WorldQuant 邮箱" }) .fill("test@example.com"); await page .getByLabel("WorldQuant 密码", { exact: true }) .fill("synthetic-password"); await page.getByRole("button", { name: "保存凭据" }).click(); await expect(page.getByText("已保存", { exact: true })).toBeVisible(); await page .getByRole("button", { name: "连接 WorldQuant", exact: true }) .click(); await expect .poll( async () => (await (await page.request.get("/api/v1/account")).json()) .connection_status, ) .toBe("connected"); await page.keyboard.press("Escape"); await expect(page.locator(".job-panel")).not.toBeVisible(); await expect(page.locator(".permission-list li")).toHaveCount(10); await expect(page.locator(".session-summary")).toContainText("4 小时"); const simulation = page.getByRole("row", { name: /回测/ }); await expect(simulation).toContainText("10,000(本地设定)"); await expect(simulation).toContainText("9,997"); await page.getByRole("button", { name: "Alpha 管理", exact: true }).click(); await page.getByRole("button", { name: "同步平台数据" }).click(); await expect .poll( async () => (await (await page.request.get("/api/v1/alphas")).json()).total, { timeout: 20000 }, ) .toBe(620); await page.keyboard.press("Escape"); await expect(page.locator(".job-panel")).not.toBeVisible(); await expect(page.locator(".library-stats strong").first()).toHaveText("620"); await page.screenshot({ path: "../output/playwright/alpha-library.png", fullPage: true, }); await page.getByRole("textbox", { name: "搜索 Alpha" }).fill("TEST0007"); await page.getByRole("button", { name: "查询", exact: true }).click(); await expect(page.locator(".alpha-link")).toHaveCount(1); await page.locator(".alpha-link").click(); await expect( page.getByRole("heading", { name: "Selection", exact: true }), ).toBeVisible(); await expect( page.getByRole("heading", { name: "Combo", exact: true }), ).toBeVisible(); await page.getByRole("tab", { name: "研究记录" }).click(); await page .getByRole("textbox", { name: "研究备注" }) .fill("需要检验跨区域稳定性;保留这条研究假设。"); await page .getByRole("textbox", { name: "研究标签" }) .fill("组合研究, 低换手"); await page.getByText("收藏此 Alpha", { exact: true }).click(); await page.getByRole("button", { name: "保存研究记录" }).click(); await expect(page.getByText("研究记录已保存")).toBeVisible(); await page.getByRole("tab", { name: "PnL 曲线" }).click(); await page.getByRole("button", { name: "获取 PnL", exact: true }).click(); await expect .poll( async () => (await (await page.request.get("/api/v1/alphas/TEST0007/pnl")).json()) .cached, ) .toBe(true); await page.keyboard.press("Escape"); await expect(page.locator(".job-panel")).not.toBeVisible(); await expect(page.locator(".pnl-chart")).toBeVisible(); await page.screenshot({ path: "../output/playwright/alpha-detail.png", fullPage: true, }); await page.keyboard.press("Escape"); // Use the browser's authenticated API context to await the same durable task contract. const job = await ( await page.request.post("/api/v1/sync-jobs", { headers: { "X-WQ-Request": "1" }, data: { kind: "alpha_refresh", alpha_ids: ["TEST0007"] }, }) ).json(); await expect .poll( async () => (await (await page.request.get(`/api/v1/sync-jobs/${job.id}`)).json()) .status, ) .toBe("completed"); await page.reload(); await page.getByRole("textbox", { name: "搜索 Alpha" }).fill("TEST0007"); await page.getByRole("button", { name: "查询", exact: true }).click(); await expect(page.locator(".alpha-link")).toHaveCount(1); await page.locator(".alpha-link").click(); await page.getByRole("tab", { name: "研究记录" }).click(); await expect(page.getByRole("textbox", { name: "研究备注" })).toHaveValue( "需要检验跨区域稳定性;保留这条研究假设。", ); await expect( page.getByRole("checkbox", { name: "收藏此 Alpha" }), ).toBeChecked(); await page.keyboard.press("Escape"); await page.getByRole("button", { name: "重置", exact: true }).click(); await expect(page.locator(".alpha-link")).toHaveCount(25); const downloading = page.waitForEvent("download"); await page.getByRole("button", { name: /导出/ }).click(); const download = await downloading; const contents = await readFile((await download.path())!, "utf-8"); expect(contents).toContain("TEST0619"); expect(contents).toContain("TEST0000"); expect((contents.match(/TEST\d{4}/g) ?? []).length).toBe(620); await page.getByRole("button", { name: "退出登录" }).click(); await expect( page.getByRole("heading", { name: "登录研究工作空间" }), ).toBeVisible(); expect((await page.request.get("/api/v1/alphas")).status()).toBe(401); expect(failures).toEqual([]); }); test("batch tags, column visibility, server pagination and saved preferences", async ({ page, }) => { await page.goto("/"); await page.getByLabel("密码", { exact: true }).fill("browser-test-password"); await page.getByRole("button", { name: "进入工作空间" }).click(); await expect( page.getByRole("heading", { name: "Alpha 管理", exact: true }), ).toBeVisible(); // Each test can run alone against the isolated browser acceptance server. if ((await (await page.request.get("/api/v1/alphas")).json()).total !== 620) { const headers = { "X-WQ-Request": "1" }; await page.request.put("/api/v1/account/credentials", { headers, data: { email: "test@example.com", password: "synthetic-password" }, }); await page.request.post("/api/v1/account/connect", { headers }); await expect .poll( async () => (await (await page.request.get("/api/v1/account")).json()) .connection_status, ) .toBe("connected"); await page.request.post("/api/v1/sync-jobs", { headers, data: { kind: "full_sync" }, }); await expect .poll( async () => (await (await page.request.get("/api/v1/alphas")).json()).total, { timeout: 20000 }, ) .toBe(620); } await page.getByRole("textbox", { name: "搜索 Alpha" }).fill("TEST006"); await page.getByRole("button", { name: "查询", exact: true }).click(); await expect(page.locator(".alpha-link")).toHaveCount(10); const selectAll = page.getByRole("checkbox", { name: "Select all rows" }); await selectAll.focus(); await selectAll.press("Space"); await expect(selectAll).toBeChecked(); await page.getByRole("button", { name: "批量编辑", exact: true }).click(); await page.getByRole("textbox", { name: "批量添加标签" }).fill("批量验收"); await page .getByRole("dialog") .getByRole("button", { name: "confirm", exact: true }) .click(); await expect .poll( async () => ( await ( await page.request.get( "/api/v1/alphas?tag=" + encodeURIComponent("批量验收"), ) ).json() ).total, ) .toBe(10); await page.getByRole("button", { name: "显示列设置" }).click(); await page .locator(".columns-picker") .getByText("本地标签", { exact: true }) .click(); await expect( page.getByRole("columnheader", { name: "本地标签", exact: true }), ).toBeVisible(); await page.getByRole("button", { name: "显示列设置" }).click(); await page.getByRole("button", { name: "重置", exact: true }).click(); await expect(page.locator(".alpha-link")).toHaveCount(25); const firstId = await page.locator(".alpha-link").first().innerText(); await page.locator(".semi-page-item").filter({ hasText: /^2$/ }).click(); await expect(page.locator(".alpha-link").first()).not.toHaveText(firstId); await page.getByRole("button", { name: "个人信息", exact: true }).click(); await page.getByRole("textbox", { name: "显示名称" }).fill("Alpha 研究室"); await page.getByRole("button", { name: "保存偏好", exact: true }).click(); await expect(page.locator(".account-name")).toHaveText("Alpha 研究室"); await page.reload(); await expect(page.getByRole("textbox", { name: "显示名称" })).toHaveValue( "Alpha 研究室", ); await page.screenshot({ path: "../output/playwright/account.png", fullPage: true, }); });