Some checks failed
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 36s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Security Scanning / Trivy Filesystem Scan (push) Failing after 30s
Deploy / Deploy to Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Rollback Staging (push) Has been skipped
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 6s
CI / E2E Tests (push) Has been skipped
Deploy / Build API Image (push) Failing after 13s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 4s
CI / AI Services (Python) — Smoke (push) Failing after 5s
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 57s
Deploy / Build Web Image (push) Failing after 6s
Deploy / Build AI Services Image (push) Failing after 6s
E2E Tests / Playwright E2E (push) Failing after 12s
Security Scanning / Trivy Scan — API Image (push) Failing after 51s
Security Scanning / Trivy Scan — Web Image (push) Failing after 35s
- price-area-chart + sparkline: replace non-existent `var(--color-signal-up)` with proper `hsl(var(--signal-up))` (and same for -down + border + muted-foreground). The previous tokens resolved to undefined, leaving the chart line + sparkline invisible against the dark background. - public/page: switch `currentPeriod()` from monthly (YYYY-MM) to quarterly (YYYY-Qn) to match the MarketIndex aggregation period — heatmap and district stats now find rows. - import-market-data: add `2026-Q2` to seeded periods so the current quarter has data on a freshly seeded dev DB. - new scripts/seed-bulk-listings-per-district.ts: top up the dev DB with 12 synthetic listings per district per 7-day window so the movers query (which requires >= 10 listings/district/window) has signal to compute against. - update price-area-chart.spec to match new color tokens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
import { render, screen } from '@testing-library/react';
|
|
import type { ReactNode } from 'react';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
import { PriceAreaChart } from '../price-area-chart';
|
|
|
|
vi.mock('recharts', () => ({
|
|
ResponsiveContainer: ({ children }: { children: ReactNode }) => (
|
|
<div data-testid="responsive-container">{children}</div>
|
|
),
|
|
AreaChart: ({
|
|
children,
|
|
data,
|
|
}: {
|
|
children: ReactNode;
|
|
data: unknown[];
|
|
}) => (
|
|
<div data-testid="area-chart" data-count={data.length}>
|
|
{children}
|
|
</div>
|
|
),
|
|
Area: ({ stroke, dataKey }: { stroke: string; dataKey: string }) => (
|
|
<div data-testid={`area-${dataKey}`} data-stroke={stroke} />
|
|
),
|
|
XAxis: ({ dataKey }: { dataKey: string }) => (
|
|
<div data-testid={`xaxis-${dataKey}`} />
|
|
),
|
|
YAxis: () => <div data-testid="yaxis" />,
|
|
CartesianGrid: () => <div data-testid="grid" />,
|
|
Tooltip: () => <div data-testid="tooltip" />,
|
|
}));
|
|
|
|
describe('PriceAreaChart', () => {
|
|
it('renders responsive container with chart, axes, grid and tooltip', () => {
|
|
render(
|
|
<PriceAreaChart
|
|
data={[
|
|
{ period: 'D1', avgPriceM2: 60_000_000 },
|
|
{ period: 'D2', avgPriceM2: 62_000_000 },
|
|
]}
|
|
/>,
|
|
);
|
|
expect(screen.getByTestId('responsive-container')).toBeInTheDocument();
|
|
expect(screen.getByTestId('area-chart')).toHaveAttribute('data-count', '2');
|
|
expect(screen.getByTestId('xaxis-period')).toBeInTheDocument();
|
|
expect(screen.getByTestId('yaxis')).toBeInTheDocument();
|
|
expect(screen.getByTestId('grid')).toBeInTheDocument();
|
|
expect(screen.getByTestId('tooltip')).toBeInTheDocument();
|
|
});
|
|
|
|
it('uses signal-up stroke color when last point >= first', () => {
|
|
render(
|
|
<PriceAreaChart
|
|
data={[
|
|
{ period: 'D1', avgPriceM2: 60_000_000 },
|
|
{ period: 'D2', avgPriceM2: 65_000_000 },
|
|
]}
|
|
/>,
|
|
);
|
|
expect(screen.getByTestId('area-avgPriceM2')).toHaveAttribute(
|
|
'data-stroke',
|
|
'hsl(var(--signal-up))',
|
|
);
|
|
});
|
|
|
|
it('uses signal-down stroke color when last point < first', () => {
|
|
render(
|
|
<PriceAreaChart
|
|
data={[
|
|
{ period: 'D1', avgPriceM2: 70_000_000 },
|
|
{ period: 'D2', avgPriceM2: 60_000_000 },
|
|
]}
|
|
/>,
|
|
);
|
|
expect(screen.getByTestId('area-avgPriceM2')).toHaveAttribute(
|
|
'data-stroke',
|
|
'hsl(var(--signal-down))',
|
|
);
|
|
});
|
|
|
|
it('defaults to signal-down stroke for single or empty data', () => {
|
|
render(<PriceAreaChart data={[]} />);
|
|
expect(screen.getByTestId('area-avgPriceM2')).toHaveAttribute(
|
|
'data-stroke',
|
|
'hsl(var(--signal-down))',
|
|
);
|
|
});
|
|
|
|
it('passes through className to wrapper div', () => {
|
|
const { container } = render(
|
|
<PriceAreaChart
|
|
data={[{ period: 'D1', avgPriceM2: 1 }]}
|
|
className="custom-wrap"
|
|
/>,
|
|
);
|
|
expect(container.querySelector('.custom-wrap')).not.toBeNull();
|
|
});
|
|
});
|