feat: add Super Alpha research, management and MCP workflows
Deploy production / deploy (push) Successful in 56s

This commit is contained in:
yuxuanhui
2026-09-13 12:32:16 +08:00
parent 7c8188df9c
commit e256d6fef1
59 changed files with 3766 additions and 125 deletions
+21 -12
View File
@@ -63,17 +63,26 @@ test("sidebar geometry, recent navigation, user menu and compact tools", async (
await page.getByRole("button", { name: "同步任务", exact: true }).click();
await expect(page.locator(".job-panel")).toBeVisible();
// The drawer must receive pointer events where the global tools sit behind it.
await expect.poll(() =>
page.getByRole("toolbar").getByRole("button").evaluateAll((buttons) =>
buttons.every((button) => {
const rect = button.getBoundingClientRect();
return Boolean(document.elementFromPoint(
rect.x + rect.width / 2,
rect.y + rect.height / 2,
)?.closest(".job-panel"));
}),
),
).toBe(true);
await expect
.poll(() =>
page
.getByRole("toolbar")
.getByRole("button")
.evaluateAll((buttons) =>
buttons.every((button) => {
const rect = button.getBoundingClientRect();
return Boolean(
document
.elementFromPoint(
rect.x + rect.width / 2,
rect.y + rect.height / 2,
)
?.closest(".job-panel"),
);
}),
),
)
.toBe(true);
await page.locator(".job-panel .semi-sidesheet-close").click();
await expect(page.locator(".job-panel")).not.toBeVisible();
await page.getByRole("button", { name: "切换研究助手" }).click();
@@ -85,7 +94,7 @@ test("sidebar geometry, recent navigation, user menu and compact tools", async (
await page.keyboard.press("Control+k");
await page
.getByRole("dialog")
.getByRole("button", { name: "Alpha 管理" })
.getByRole("button", { name: "Alpha 管理", exact: true })
.click();
await expect(
page.getByRole("tab", { name: "待提交", exact: true }),
+219
View File
@@ -0,0 +1,219 @@
import { expect, test } from "@playwright/test";
const headers = { "X-WQ-Request": "1" };
test("Super Alpha web lifecycle, generic simulation, evidence and type routing", async ({
page,
}) => {
const errors: string[] = [];
page.on("pageerror", (e) => errors.push(e.message));
await page.goto("/#superalpha-research");
await page.getByLabel("密码", { exact: true }).fill("browser-test-password");
await page.getByRole("button", { name: "进入工作空间" }).click();
await expect(
page.getByRole("button", { name: "新建 Super Alpha 方案", exact: true }),
).toBeVisible();
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
.getByRole("button", { name: "新建 Super Alpha 方案", exact: true })
.click();
await page.getByLabel("方案名称", { exact: true }).fill("浏览器 SUPER 验收");
await page
.getByLabel("研究假设", { exact: true })
.fill("比较低换手组件与等权基线");
await page
.getByLabel("Selection", { exact: true })
.fill("turnover < {threshold}");
await page.getByLabel("Combo", { exact: true }).fill("alpha");
await page
.getByLabel("参数候选 JSON", { exact: true })
.fill('{"threshold":{"kind":"number","values":[0.1,0.2]}}');
await page.getByRole("button", { name: "同步合法设置", exact: true }).click();
await page.getByRole("button", { name: "选择组合", exact: true }).click();
await page.getByRole("combobox", { name: "Region", exact: true }).click();
await page.getByRole("option").filter({ hasText: /^USA$/ }).click();
await page.getByRole("combobox", { name: "Universe", exact: true }).click();
await page
.getByRole("option")
.filter({ hasText: /^TOP3000$/ })
.click();
await page.getByRole("button", { name: "应用组合", exact: true }).click();
await page.getByRole("button", { name: "保存方案", exact: true }).click();
await expect(page.getByText("已保存版本 1", { exact: true })).toBeVisible();
await page
.getByRole("button", { name: "预览 Selection(首组参数)", exact: true })
.click();
await expect(page.locator(".super-components")).toContainText("已核实 2 个");
await page.getByRole("tab", { name: "固定候选", exact: true }).click();
const building = page.waitForResponse(
(r) =>
r.url().endsWith("/superalpha/candidates") &&
r.request().method() === "POST",
);
await page.getByRole("button", { name: "展开固定候选", exact: true }).click();
const experiment = await (await building).json();
expect(experiment.total).toBe(4);
const table = page.locator(
".super-research .semi-tabs-pane-active .workspace-table",
);
await expect(table.locator("tbody tr.semi-table-row")).toHaveCount(4);
expect(
Math.round(
(await table.locator("tbody tr.semi-table-row").first().boundingBox())!
.height,
),
).toBe(40);
await table.locator("thead .semi-checkbox").click();
await page
.getByRole("button", { name: "预览回测(4)", exact: true })
.click();
await expect(
page.getByText(/浏览器 SUPER 验收 · 4 条候选 · 4 个平台批次/),
).toBeVisible();
await expect(
page.getByText("SUPER · Selection: turnover < 0.1 · Combo: alpha", {
exact: true,
}),
).toBeVisible();
await page.getByRole("button", { name: "确认启动回测", exact: true }).click();
await expect(page.getByText("4 / 4 已保存", { exact: true })).toBeVisible({
timeout: 25000,
});
const result = await (
await page.request.get(
`/api/v1/superalpha/experiments/${experiment.id}/results`,
)
).json();
expect(
result.items.every(
(i: { persistence_status: string }) => i.persistence_status === "saved",
),
).toBe(true);
const alpha = result.items[0].alpha_id;
await page.goto(`/#alphas?alpha_id=${alpha}`);
await expect(
page.getByRole("button", { name: "Super Alpha 管理", exact: true }),
).toHaveAttribute("aria-current", "page");
await expect(page.locator(".alpha-detail")).toContainText(
"Selection rationale",
);
await page.getByRole("tab", { name: "组件证据", exact: true }).click();
await expect(page.locator(".alpha-detail .super-components")).toContainText(
"已核实 2 个",
);
await page
.getByRole("button", { name: "复制为研究方案", exact: true })
.click();
await expect(page.getByLabel("Selection", { exact: true })).toHaveValue(
result.items[0].selection,
);
await page.goto(`/#superalpha-research?experiment_id=${experiment.id}`);
await page.getByRole("tab", { name: "回测对照", exact: true }).click();
await expect(page.getByText("4 个回测项", { exact: true })).toBeVisible();
const checks = page.locator(
".super-research .semi-tabs-pane-active tbody input[type=checkbox]",
);
await checks.nth(0).focus();
await page.keyboard.press("Space");
await checks.nth(1).focus();
await page.keyboard.press("Space");
await page.getByRole("button", { name: "对照两项(2)" }).click();
await expect(page.getByRole("dialog")).toContainText("同池对照");
await page.keyboard.press("Escape");
await expect(page.getByRole("dialog")).not.toBeVisible();
for (const width of [1440, 850, 390]) {
await page.setViewportSize({ width, height: 950 });
expect(
await page.evaluate(
() => document.documentElement.scrollWidth <= innerWidth,
),
).toBe(true);
await page.screenshot({
path: `../output/playwright/superalpha-${width}.png`,
});
}
expect(errors).toEqual([]);
});
test("Super management scopes, saved views and cross-page selection", async ({
page,
}) => {
await page.goto("/#superalphas");
await page.getByLabel("密码", { exact: true }).fill("browser-test-password");
await page.getByRole("button", { name: "进入工作空间" }).click();
await expect(
page.getByRole("tab", { name: "待提交", exact: true }),
).toBeVisible();
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");
const job = await (
await page.request.post("/api/v1/sync-jobs", {
headers,
data: {
kind: "daily_sync",
submission: "UNSUBMITTED",
date_from: "2025-01-01",
date_to: "2025-01-01",
},
})
).json();
await expect
.poll(
async () =>
(await (await page.request.get(`/api/v1/sync-jobs/${job.id}`)).json())
.status,
)
.toBe("completed");
await page.reload();
const panel = page.locator(".alpha-page-view:not([hidden])");
await expect(panel.locator(".alpha-link").first()).toBeVisible();
const data = await (
await page.request.get(
"/api/v1/alphas?management_scope=super&submission=UNSUBMITTED",
)
).json();
expect(
data.items.every((a: { alpha_type: string }) => a.alpha_type === "SUPER"),
).toBe(true);
await panel.locator("tbody .semi-checkbox").first().click();
await panel.locator(".semi-page-item").filter({ hasText: /^2$/ }).click();
await expect(panel.getByText("已选择 1 条", { exact: false })).toBeVisible();
await panel.getByRole("button", { name: "保存为新视图" }).click();
await page.getByLabel("视图名称").fill("SUPER 隔离视图");
await page.getByRole("button", { name: "保存视图", exact: true }).click();
await expect(
panel.getByRole("tab", { name: /SUPER 隔离视图/ }),
).toBeVisible();
await page.getByRole("button", { name: "Alpha 管理", exact: true }).click();
await expect(
page.getByRole("tab", { name: /SUPER 隔离视图/ }),
).not.toBeVisible();
const regular = await (
await page.request.get("/api/v1/alphas?management_scope=non_super")
).json();
expect(
regular.items.every(
(a: { alpha_type: string }) => a.alpha_type !== "SUPER",
),
).toBe(true);
});
+14 -15
View File
@@ -65,7 +65,7 @@ test("account → scoped sync → research → resync → PnL → filtered expor
async () =>
(
await (
await page.request.get("/api/v1/alphas?submission=UNSUBMITTED")
await page.request.get("/api/v1/alphas?submission=UNSUBMITTED&q=TEST")
).json()
).total,
)
@@ -77,28 +77,26 @@ test("account → scoped sync → research → resync → PnL → filtered expor
await expect
.poll(
async () =>
(await (await page.request.get("/api/v1/alphas")).json()).total,
(await (await page.request.get("/api/v1/alphas?q=TEST")).json()).total,
{ timeout: 20000 },
)
.toBe(620);
await page.keyboard.press("Escape");
await expect(page.locator(".job-panel")).not.toBeVisible();
await page.getByRole("tab", { name: "待提交", exact: true }).click();
await expect(page.locator(".alpha-table-meta .count-pill")).toHaveText("413");
// Alpha 管理 now excludes SUPER; the upstream sync still imports both types.
await expect(page.locator(".alpha-page-view:not([hidden]) .alpha-table-meta .count-pill")).toHaveText("354");
await page.screenshot({
path: "../output/playwright/alpha-library.png",
fullPage: true,
});
await page.getByRole("button", { name: "筛选 Alpha", exact: true }).click();
await page.getByRole("textbox", { name: "搜索 Alpha" }).fill("TEST0007");
await page.getByRole("textbox", { name: "搜索 Alpha" }).fill("TEST0008");
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 }),
page.getByRole("heading", { name: "表达式", exact: true }),
).toBeVisible();
await page.getByRole("tab", { name: "研究信息" }).click();
await page
@@ -115,7 +113,7 @@ test("account → scoped sync → research → resync → PnL → filtered expor
await expect
.poll(
async () =>
(await (await page.request.get("/api/v1/alphas/TEST0007/pnl")).json())
(await (await page.request.get("/api/v1/alphas/TEST0008/pnl")).json())
.cached,
)
.toBe(true);
@@ -131,7 +129,7 @@ test("account → scoped sync → research → resync → PnL → filtered expor
const job = await (
await page.request.post("/api/v1/sync-jobs", {
headers: { "X-WQ-Request": "1" },
data: { kind: "alpha_refresh", alpha_ids: ["TEST0007"] },
data: { kind: "alpha_refresh", alpha_ids: ["TEST0008"] },
})
).json();
await expect
@@ -143,7 +141,7 @@ test("account → scoped sync → research → resync → PnL → filtered expor
.toBe("completed");
await page.reload();
await page.getByRole("button", { name: "筛选 Alpha", exact: true }).click();
await page.getByRole("textbox", { name: "搜索 Alpha" }).fill("TEST0007");
await page.getByRole("textbox", { name: "搜索 Alpha" }).fill("TEST0008");
await page.getByRole("button", { name: "查询", exact: true }).click();
await expect(page.locator(".alpha-link")).toHaveCount(1);
await page.locator(".alpha-link").click();
@@ -165,13 +163,14 @@ test("account → scoped sync → research → resync → PnL → filtered expor
expect(contents).toContain("TEST0619");
expect(contents).toContain("TEST0001");
expect(contents).not.toContain("TEST0000");
expect((contents.match(/TEST\d{4}/g) ?? []).length).toBe(413);
expect(contents).not.toContain("TEST0007");
expect((contents.match(/TEST\d{4}/g) ?? []).length).toBe(354);
await page.getByRole("button", { name: "用户菜单" }).click();
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((await page.request.get("/api/v1/alphas?q=TEST")).status()).toBe(401);
expect(failures).toEqual([]);
});
@@ -185,7 +184,7 @@ test("batch tags, column visibility, server pagination and saved preferences", a
page.getByRole("tab", { name: "待提交", 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) {
if ((await (await page.request.get("/api/v1/alphas?q=TEST")).json()).total !== 620) {
const headers = { "X-WQ-Request": "1" };
await page.request.put("/api/v1/account/credentials", {
headers,
@@ -215,7 +214,7 @@ test("batch tags, column visibility, server pagination and saved preferences", a
await expect
.poll(
async () =>
(await (await page.request.get("/api/v1/alphas")).json()).total,
(await (await page.request.get("/api/v1/alphas?q=TEST")).json()).total,
{ timeout: 20000 },
)
.toBe(620);