Files
easy_tdx_max/web-ui/e2e/backtest.spec.ts
T
GitHub 211052f0e3 feat(e2e): Playwright E2E 前端测试基建 — 后端合成数据 mock 模式 + 5 用例 + CI
- web/e2e_mock.py:EASY_TDX_E2E_MOCK=1 时 lifespan 替换 TDX/MAC 客户端为
  确定性合成数据(CRC32 播种随机游走,分页语义对齐真实 /bars);回测/WF/
  评估/自选/策略库仍走真实后端,SSE 由 QuoteStreamer 真轮询(mock 下 2s 一拍)
- web-ui:@playwright/test + playwright.config.ts(webServer 自动起 serve,
  EASY_TDX_CONFIG_DIR 指向每轮临时目录);e2e/ 5 用例覆盖看板五指数/SSE、
  自选增删、回测全流程、附加分析(WF 柱状图+一条龙评估卡)、策略库保存
- package.json 加 test:e2e;CI frontend job 追加 E2E;verify_ci.sh 补前端段
- tests/unit/test_e2e_mock.py(11 例)守护 mock 契约;本地 npx playwright test 全绿
2026-09-01 22:56:38 +08:00

55 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 回测页 E2E:选策略 → 开始回测(自动取行情)→ 净值图 + 绩效表 + 成交记录。
//
// 行情来自 mock /bars(确定性合成 OHLCV),回测跑真实引擎;
// URL query 指定较短日期区间加快取数(页面 onMounted 回填 startDate/endDate)。
import { expect, test } from '@playwright/test'
test('回测全流程出净值图与绩效表', async ({ page }) => {
await page.goto('/backtest?startDate=2024-01-01&endDate=2025-12-31')
// 策略下拉加载出内置策略,默认 ma_cross
const strategySelect = page.locator('.strategy-picker select')
await expect(strategySelect).toHaveValue('ma_cross')
const optionCount = await strategySelect.locator('option').count()
expect(optionCount).toBeGreaterThanOrEqual(18)
// 取行情(mock /bars)+ 回测(真实引擎)
await page.getByRole('button', { name: '开始回测' }).click()
// 报告区:净值曲线(echarts canvas+ 绩效指标 + 成交记录
await expect(page.getByRole('heading', { name: '净值曲线与回撤' })).toBeVisible({ timeout: 60_000 })
await expect(page.locator('.report-section canvas').first()).toBeVisible()
await expect(page.getByRole('heading', { name: '绩效指标' })).toBeVisible()
await expect(page.getByRole('heading', { name: /成交记录(\d+ 笔)/ })).toBeVisible()
// 绩效表渲染出具体数值(总收益/夏普等指标行)
const perfSection = page.locator('.report-section', { hasText: '绩效指标' })
await expect(perfSection.locator('td, .metric-value, .mono').first()).toBeVisible()
})
test('勾选附加分析后出现 WF 逐窗柱状图与一条龙评估卡', async ({ page }) => {
await page.goto('/backtest?startDate=2023-01-01&endDate=2025-12-31')
// 勾选两个「附加分析」开关(v1.27 新增)
await page.getByLabel('Walk-Forward 样本外验证').check()
await expect(page.getByLabel('一条龙评估')).toBeVisible()
await page.getByLabel('一条龙评估').check()
await page.getByRole('button', { name: '开始回测' }).click()
// WF:先出现「验证中…」区块,随后逐窗柱状图(echarts canvas+ 稳定性汇总
await expect(page.getByRole('heading', { name: 'Walk-Forward 样本外验证' })).toBeVisible({
timeout: 60_000,
})
await expect(page.locator('.wf-chart canvas')).toBeVisible({ timeout: 120_000 })
await expect(page.getByText('盈利窗占比', { exact: true })).toBeVisible()
await expect(page.locator('.wf-summary .stat')).toHaveCount(6)
// 一条龙评估:综合评分 + 高适配徽标 + 基准对比
await expect(page.locator('.eval-panel')).toBeVisible({ timeout: 120_000 })
await expect(page.getByText('综合评分')).toBeVisible()
await expect(page.getByText('对比买入持有')).toBeVisible()
await expect(page.getByText(/适配性体检 \d+\/\d+/)).toBeVisible()
})