Files
easy_tdx_max/web-ui/playwright.config.ts
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

71 lines
2.6 KiB
TypeScript
Raw Permalink 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.
// Playwright E2E 配置:mock 模式的 easy-tdx serve + 已构建的前端 dist。
//
// 运行前置:
// 1. `npm run build`serve 从仓库根 web-ui/dist 托管前端,SPA fallback);
// 2. 后端可用(仓库根 `pip install -e ".[web]"`)——自动探测仓库 .venv
// 否则可用 EASY_TDX_PYTHON 指定解释器(CI 里是 `python`)。
//
// 行情全部来自合成数据(EASY_TDX_E2E_MOCK=1,见 src/easy_tdx/web/e2e_mock.py),
// 不连真实通达信服务器、不受交易时段限制;回测/WF/评估/自选/策略库走真实后端。
// 详见 e2e/README.md。
import { existsSync, mkdtempSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { defineConfig } from '@playwright/test'
const PORT = Number(process.env.E2E_PORT ?? 8001)
const BASE_URL = `http://127.0.0.1:${PORT}`
const WEB_UI_DIR = path.dirname(fileURLToPath(import.meta.url))
/** 启动 serve 的 Python 解释器:优先仓库 .venv(开发态 editable 安装),
* 没有则回退 EASY_TDX_PYTHON / 系统 pythonCI 态 pip install -e 之后)。 */
function resolvePython(): string {
const repoRoot = path.resolve(WEB_UI_DIR, '..')
if (existsSync(path.join(repoRoot, '.venv/Scripts/python.exe'))) {
return path.join(repoRoot, '.venv/Scripts/python.exe')
}
if (existsSync(path.join(repoRoot, '.venv/bin/python'))) {
return path.join(repoRoot, '.venv/bin/python')
}
return process.env.EASY_TDX_PYTHON ?? 'python'
}
// 每次运行独立的临时配置目录:watchlist.db / strategies.db / tasks.db 写在这里,
// 不污染真实 ~/.easy_tdx,且每轮 E2E 从空自选、空策略库开始(断言可写死)。
const RUNTIME_CONFIG_DIR = mkdtempSync(path.join(tmpdir(), 'easy-tdx-e2e-'))
export default defineConfig({
testDir: './e2e',
timeout: 180_000,
// 单 worker 串行:全部用例共享同一个 serve(SQLite 自选/策略库会互相干扰)
workers: 1,
fullyParallel: false,
retries: process.env.CI ? 1 : 0,
reporter: [['list']],
use: {
baseURL: BASE_URL,
headless: true,
locale: 'zh-CN',
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
actionTimeout: 15_000,
},
expect: {
timeout: 20_000,
},
outputDir: './e2e/.results',
webServer: {
command: `${resolvePython()} -m easy_tdx serve --host 127.0.0.1 --port ${PORT} --no-open-browser`,
url: `${BASE_URL}/api/v1/backtest/strategies`,
reuseExistingServer: !process.env.CI,
timeout: 120_000,
env: {
EASY_TDX_E2E_MOCK: '1',
EASY_TDX_CONFIG_DIR: RUNTIME_CONFIG_DIR,
},
},
})