summaryrefslogtreecommitdiff
path: root/frontend/src/lib
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-18 09:52:14 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-18 09:52:14 +0800
commitc71930f79b102f5a3cade7877dba425462ed758a (patch)
treea56e55c076c0ef5238582f97cc2989c7b0217f13 /frontend/src/lib
parent0022c0748ada1e9022f63f7e985398d26111dc06 (diff)
downloadstrategy-lab-c71930f79b102f5a3cade7877dba425462ed758a.tar.gz
test(frontend): 第二轮首页聚合真实渲染集成测试
[变更性质] 测试补充,归入第二轮验证件。 [新增内容] mock listProjects/listDatasets/listRuns/getAIUsage 后渲染 ProjectsPage,断言 4 张 metric-card 与 2 处 sparkline-cell 的真实 DOM 输出。 [影响范围] frontend/src/lib/round2DashboardIntegration.test.ts(2 用例)。
Diffstat (limited to 'frontend/src/lib')
-rw-r--r--frontend/src/lib/round2DashboardIntegration.test.ts58
1 files changed, 58 insertions, 0 deletions
diff --git a/frontend/src/lib/round2DashboardIntegration.test.ts b/frontend/src/lib/round2DashboardIntegration.test.ts
new file mode 100644
index 0000000..363e1da
--- /dev/null
+++ b/frontend/src/lib/round2DashboardIntegration.test.ts
@@ -0,0 +1,58 @@
+// @ts-nocheck
+import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
+import { render, cleanup, waitFor } from '@testing-library/svelte';
+
+vi.mock('../lib/client', async (importOriginal) => {
+ const actual = await importOriginal<typeof import('../lib/client')>();
+ return {
+ ...actual,
+ listProjects: vi.fn(),
+ listDatasets: vi.fn(),
+ listRuns: vi.fn(),
+ getAIUsage: vi.fn()
+ };
+});
+
+import ProjectsPage from '../pages/ProjectsPage.svelte';
+import { listProjects, listDatasets, listRuns, getAIUsage } from '../lib/client';
+
+beforeEach(() => {
+ vi.mocked(listProjects).mockReset().mockResolvedValue({ items: [
+ { id: 'pA', name: '项目A', description: null, draft_code: '', draft_generation: 1, created_at: '2026-01-01T00:00:00Z', updated_at: '2026-01-01T00:00:00Z' },
+ { id: 'pB', name: '项目B', description: null, draft_code: '', draft_generation: 0, created_at: '2026-01-01T00:00:00Z', updated_at: '2026-01-01T00:00:00Z' }
+ ]});
+ vi.mocked(listDatasets).mockReset().mockResolvedValue({ items: [{ id: 'd1' }, { id: 'd2' }, { id: 'd3' }] });
+ vi.mocked(listRuns).mockReset().mockResolvedValue({ items: [
+ { id: 'r1', project_id: 'pA', status: 'succeeded', created_at: '2026-02-01T00:00:00Z', result: { equity: [{ equity: 100 }, { equity: 101 }, { equity: 112 }] } },
+ { id: 'r2', project_id: 'pB', status: 'succeeded', created_at: '2026-02-01T00:00:00Z', result: null }
+ ]});
+ vi.mocked(getAIUsage).mockReset().mockResolvedValue({ totals: { input_tokens: 500, output_tokens: 200, requests: 2 } });
+});
+
+afterEach(() => cleanup());
+
+// Leader round2: 登录后默认页 = 指标卡行 + 项目行迷你权益缩略图。
+describe('ProjectsPage dashboard round2 (metric row + row sparkline, real render)', () => {
+ it('renders the 4-card metric row with真实聚合 numbers', async () => {
+ render(ProjectsPage);
+ await waitFor(() => expect(vi.mocked(getAIUsage)).toHaveBeenCalled());
+ const cards = document.querySelectorAll('[data-testid="metric-card"]');
+ await waitFor(() => expect(cards.length).toBe(4));
+ const values = [...document.querySelectorAll('.metric-row .mvalue')].map((n) => n.textContent!.replace(/\s+/g, ' ').trim());
+ expect(values[0]).toBe('2');
+ expect(values[1]).toBe('3');
+ expect(values[2]).toContain('已完成');
+ expect(values[2]).toContain('2');
+ });
+
+ it('renders an inline sparkline row cell for projects whose latest run has equity, none for data-less ones', async () => {
+ render(ProjectsPage);
+ await waitFor(() => expect(vi.mocked(listRuns)).toHaveBeenCalled());
+ const rows = await waitFor(() => document.querySelectorAll('tbody tr'));
+ await waitFor(() => expect(document.querySelector('svg[data-testid="sparkline"]')).toBeTruthy());
+ const rowA = [...document.querySelectorAll('tbody tr')].find((r) => r.textContent!.includes('项目A'))!;
+ const rowB = [...document.querySelectorAll('tbody tr')].find((r) => r.textContent!.includes('项目B'))!;
+ expect(rowA.querySelector('svg[data-testid="sparkline"]'), '项目A has equity → sparkline renders').toBeTruthy();
+ expect(rowB.querySelector('svg[data-testid="sparkline"]'), '项目B has no equity → stays empty').toBeNull();
+ });
+});