rebuild(runtime): govern market operations and job truth

This commit is contained in:
leefer
2026-07-30 10:14:29 +08:00
parent 4fc8691eee
commit d8f0dd930c
39 changed files with 2224 additions and 79 deletions
+104
View File
@@ -0,0 +1,104 @@
const { expect, test } = require("@playwright/test");
async function authenticate(page) {
await page.goto("/");
await page.getByLabel("账号名").fill("stage4admin");
await page.getByLabel("密码").fill("Stage4-pass-123!");
await page.getByRole("button", { name: "登录", exact: true }).click();
await expect(page.locator(".sidebar, .field-error")).toBeVisible();
if (!(await page.locator(".sidebar").isVisible())) {
await page.getByRole("tab", { name: "注册" }).click();
await page.getByRole("button", { name: "注册并登录" }).click();
}
}
test("administrator can audit jobs, backfill and govern market events", async ({ page }) => {
const calls = [];
const job = {
id: 7,
kind: "market.refresh",
run_key: "2026-07-30:final:1",
requested_date: "2026-07-30",
trigger: "after-close",
status: "failed",
attempt: 1,
started_at: "2026-07-30T15:10:00+08:00",
finished_at: "2026-07-30T15:10:02+08:00",
duration_ms: 2000,
coverage: null,
source_set: [],
output_version: "",
payload: {},
error_code: "ProviderError",
error_message: "上游暂不可用,保留最后成功快照",
};
await page.route("**/api/admin/system/credentials", (route) => route.fulfill({
contentType: "application/json",
body: JSON.stringify([
{ name: "tushare_token", configured: true, updated_at: "2026-07-30T09:00:00+08:00" },
{ name: "ifind_refresh_token", configured: true, updated_at: "2026-07-30T09:00:00+08:00" },
{ name: "ifind_access_token", configured: true, updated_at: "2026-07-30T09:00:00+08:00" },
]),
}));
await page.route("**/api/admin/operations/jobs", (route) => route.fulfill({
contentType: "application/json", body: JSON.stringify([job]),
}));
await page.route("**/api/admin/operations/backfill", async (route) => {
calls.push({ kind: "backfill", payload: route.request().postDataJSON() });
await route.fulfill({ contentType: "application/json", body: JSON.stringify({ completed: 2 }) });
});
await page.route("**/api/admin/operations/events/supplement?*", async (route) => {
calls.push({ kind: "supplement" });
await route.fulfill({ contentType: "application/json", body: JSON.stringify({ matched: 3 }) });
});
await page.route("**/api/admin/operations/events/*/*/history", (route) => route.fulfill({
contentType: "application/json",
body: JSON.stringify([{
id: 2,
created_at: "2026-07-30T15:20:00+08:00",
source: "admin",
event_type: "limit_up",
reason: "人工核验原因",
created_by_name: "stage4admin",
}]),
}));
await page.route("**/api/admin/operations/events/*/*", async (route) => {
calls.push({ kind: "revision", payload: route.request().postDataJSON() });
await route.fulfill({ contentType: "application/json", body: JSON.stringify({ id: 2 }) });
});
await authenticate(page);
await page.getByRole("button", { name: "系统管理" }).click();
await expect(page.getByRole("heading", { name: "后台任务状态" })).toBeVisible();
await expect(page.getByText("上游暂不可用,保留最后成功快照")).toBeVisible();
const backfill = page.locator(".operation-form");
await backfill.getByLabel("开始日期").fill("2026-07-29");
await backfill.getByLabel("结束日期").fill("2026-07-30");
await backfill.getByRole("button", { name: "开始回补" }).click();
await expect(page.getByRole("status")).toContainText("历史数据回补已完成");
const event = page.locator(".event-form");
await event.getByLabel("数据日期").fill("2026-07-30");
await event.getByLabel("股票代码").fill("000001.SZ");
await event.getByLabel("原因").fill("人工核验原因");
await event.getByRole("button", { name: "保存修订" }).click();
await expect(page.getByText("人工核验原因", { exact: true })).toBeVisible();
await event.getByRole("button", { name: "自动补充" }).click();
await expect(page.getByRole("status")).toContainText("事件原因补充完成");
expect(calls).toEqual([
{ kind: "backfill", payload: { start_date: "2026-07-29", end_date: "2026-07-30" } },
{
kind: "revision",
payload: {
event_type: "limit_up",
reason: "人工核验原因",
first_time: "",
last_time: "",
open_times: null,
},
},
{ kind: "supplement" },
]);
});