summaryrefslogtreecommitdiff
path: root/frontend/src/lib/round2DashboardIntegration.test.ts
blob: 363e1dae3bbc501930b33760993912125a4b86fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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();
  });
});