test: complete final regression audit
This commit is contained in:
+1
-5
@@ -301,11 +301,7 @@ def build_market_hexagram(
|
|||||||
"name": selected_stock.get("name") or "--",
|
"name": selected_stock.get("name") or "--",
|
||||||
"status": selected_stock.get("status") or "",
|
"status": selected_stock.get("status") or "",
|
||||||
},
|
},
|
||||||
"selection_notice": (
|
"selection_notice": "",
|
||||||
"个股接口不可用,当前按演示行情补取。"
|
|
||||||
if external_stock.get("data_source") == "demo"
|
|
||||||
else ""
|
|
||||||
),
|
|
||||||
"hexagram": hexagram,
|
"hexagram": hexagram,
|
||||||
"movement": movement,
|
"movement": movement,
|
||||||
"pair_readings": pair_readings,
|
"pair_readings": pair_readings,
|
||||||
|
|||||||
+112
-4
@@ -54,10 +54,47 @@ async function mockApplication(page, authSession = session()) {
|
|||||||
if (url.pathname === "/api/auth/me") payload = authSession;
|
if (url.pathname === "/api/auth/me") payload = authSession;
|
||||||
else if (url.pathname === "/api/dashboard") payload = dashboard;
|
else if (url.pathname === "/api/dashboard") payload = dashboard;
|
||||||
else if (url.pathname === "/api/watchlist" || url.pathname === "/api/notes") payload = { items: [] };
|
else if (url.pathname === "/api/watchlist" || url.pathname === "/api/notes") payload = { items: [] };
|
||||||
else if (url.pathname === "/api/alerts") payload = { items: [], unread_count: 0 };
|
else if (url.pathname === "/api/alerts") {
|
||||||
else if (url.pathname === "/api/trades") payload = { items: [], summary: {} };
|
payload = {
|
||||||
else if (url.pathname === "/api/assistant/messages") payload = { items: [] };
|
items: [{
|
||||||
else if (url.pathname === "/api/search") payload = { groups: { stocks: [], sectors: [], themes: [], indices: [] } };
|
id: 11,
|
||||||
|
kind: "manual",
|
||||||
|
available_date: "20260722",
|
||||||
|
title: "Review opening strength",
|
||||||
|
content: "Compare the opening with the written plan.",
|
||||||
|
code: "002141",
|
||||||
|
is_read: false,
|
||||||
|
due: true,
|
||||||
|
}],
|
||||||
|
unread_count: 1,
|
||||||
|
};
|
||||||
|
} else if (url.pathname === "/api/trades") {
|
||||||
|
payload = {
|
||||||
|
items: [{
|
||||||
|
id: 7,
|
||||||
|
trade_date: "20260722",
|
||||||
|
code: "002141",
|
||||||
|
name: "Test Stock",
|
||||||
|
action: "buy",
|
||||||
|
action_label: "Buy",
|
||||||
|
price: 10.2,
|
||||||
|
quantity: 1000,
|
||||||
|
position_pct: 20,
|
||||||
|
pnl_amount: null,
|
||||||
|
pnl_pct: null,
|
||||||
|
emotion: "calm",
|
||||||
|
emotion_label: "Calm",
|
||||||
|
tags: ["planned"],
|
||||||
|
thesis: "Strength confirmed after the open.",
|
||||||
|
execution: "Executed within the planned range.",
|
||||||
|
}],
|
||||||
|
summary: { total: 1, realized: 0, win_rate: null, pnl_amount: null, average_position: 20 },
|
||||||
|
};
|
||||||
|
} else if (url.pathname === "/api/assistant/messages") {
|
||||||
|
payload = {
|
||||||
|
items: [{ role: "assistant", content: "Review evidence before forming a conclusion.", context_date: "20260722" }],
|
||||||
|
};
|
||||||
|
} else if (url.pathname === "/api/search") payload = { groups: { stocks: [], sectors: [], themes: [], indices: [] } };
|
||||||
else if (url.pathname === "/api/dragon-tiger") {
|
else if (url.pathname === "/api/dragon-tiger") {
|
||||||
payload = {
|
payload = {
|
||||||
meta: { trade_date: "2026-07-22", requested_date: "2026-07-22", status: "empty", source: "tushare" },
|
meta: { trade_date: "2026-07-22", requested_date: "2026-07-22", status: "empty", source: "tushare" },
|
||||||
@@ -76,6 +113,27 @@ async function mockApplication(page, authSession = session()) {
|
|||||||
llm: { configured: true },
|
llm: { configured: true },
|
||||||
strategies: [],
|
strategies: [],
|
||||||
};
|
};
|
||||||
|
} else if (url.pathname === "/api/screener/tracking") {
|
||||||
|
payload = {
|
||||||
|
batches: [{
|
||||||
|
selection_date: "20260721",
|
||||||
|
strategy_name: "Repair confirmation",
|
||||||
|
items: [{
|
||||||
|
code: "002141",
|
||||||
|
name: "Test Stock",
|
||||||
|
entry_price: 10,
|
||||||
|
t1_open: 1.2,
|
||||||
|
t1_close: 2.1,
|
||||||
|
t3_close: null,
|
||||||
|
t5_close: null,
|
||||||
|
max_gain: 3.4,
|
||||||
|
max_drawdown: -1.1,
|
||||||
|
observed_days: 1,
|
||||||
|
status: "tracking",
|
||||||
|
}],
|
||||||
|
}],
|
||||||
|
summary: { total: 1, observed: 1, t1_win_rate: 100, t5_win_rate: null, average_t5: null },
|
||||||
|
};
|
||||||
} else if (url.pathname === "/api/mentors/setup") payload = { trade_date: "20260722", mentors: [] };
|
} else if (url.pathname === "/api/mentors/setup") payload = { trade_date: "20260722", mentors: [] };
|
||||||
else if (url.pathname === "/api/heaven/setup") {
|
else if (url.pathname === "/api/heaven/setup") {
|
||||||
await route.fulfill({ status: 503, contentType: "application/json", body: JSON.stringify({ error: "测试环境不加载问天数据" }) });
|
await route.fulfill({ status: 503, contentType: "application/json", body: JSON.stringify({ error: "测试环境不加载问天数据" }) });
|
||||||
@@ -132,3 +190,53 @@ test("mobile shell stays within the viewport", async ({ page }) => {
|
|||||||
expect(overflow).toBeLessThanOrEqual(1);
|
expect(overflow).toBeLessThanOrEqual(1);
|
||||||
await expect(page.locator("#globalSearchButton")).toBeVisible();
|
await expect(page.locator("#globalSearchButton")).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("new review workflows render account-scoped records", async ({ page }) => {
|
||||||
|
await mockApplication(page, session("user", true));
|
||||||
|
await page.goto("/index.html");
|
||||||
|
|
||||||
|
await page.locator('[data-view="screenerView"]').first().click();
|
||||||
|
await expect(page.locator("#trackingTableBody tr")).toHaveCount(1);
|
||||||
|
await expect(page.locator("#trackingEmpty")).toBeHidden();
|
||||||
|
|
||||||
|
await page.locator('[data-view="reviewWorkspaceView"]').first().click();
|
||||||
|
await expect(page.locator("#tradeLogTableBody tr")).toHaveCount(1);
|
||||||
|
await expect(page.locator("#tradeLogEmpty")).toBeHidden();
|
||||||
|
|
||||||
|
await page.locator("#alertButton").click();
|
||||||
|
await expect(page.locator("#alertList .alert-item")).toHaveCount(1);
|
||||||
|
await expect(page.locator("#alertBadge")).toHaveText("1");
|
||||||
|
await page.locator("#closeAlertsDialog").click();
|
||||||
|
|
||||||
|
await page.locator("#assistantButton").click();
|
||||||
|
await expect(page.locator("#assistantMessages .assistant-message")).toHaveCount(1);
|
||||||
|
await expect(page.locator("#assistantQuestion")).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const viewport of [
|
||||||
|
{ name: "portrait", width: 375, height: 812 },
|
||||||
|
{ name: "landscape", width: 812, height: 375 },
|
||||||
|
]) {
|
||||||
|
test(`member workflows fit a mobile ${viewport.name} viewport`, async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
||||||
|
await mockApplication(page, session("user", true));
|
||||||
|
await page.goto("/index.html");
|
||||||
|
await page.locator('[data-view="reviewWorkspaceView"]').first().click();
|
||||||
|
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);
|
||||||
|
expect(overflow).toBeLessThanOrEqual(1);
|
||||||
|
await expect(page.locator("#tradeLogForm")).toBeVisible();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test("reduced-motion preference suppresses continuous animation", async ({ page }) => {
|
||||||
|
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||||
|
await mockApplication(page, session("user", true));
|
||||||
|
await page.goto("/index.html");
|
||||||
|
expect(await page.evaluate(() => matchMedia("(prefers-reduced-motion: reduce)").matches)).toBe(true);
|
||||||
|
const motion = await page.locator(".sentiment-gauge").evaluate((element) => {
|
||||||
|
const style = getComputedStyle(element, "::after");
|
||||||
|
return { duration: style.animationDuration, iterations: style.animationIterationCount };
|
||||||
|
});
|
||||||
|
expect(Number.parseFloat(motion.duration)).toBeLessThanOrEqual(0.00001);
|
||||||
|
expect(motion.iterations).toBe("1");
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user