92 lines
4.0 KiB
TypeScript
92 lines
4.0 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
||
import { render, screen } from '@testing-library/react';
|
||
import { TauriBarChart, TauriLineChart, type ChartPoint } from './TauriCharts';
|
||
|
||
const zero: ChartPoint[] = Array.from({ length: 7 }, (_, i) => ({ label: `روز ${i}`, value: 0 }));
|
||
const real: ChartPoint[] = [
|
||
{ label: '۷ خرداد', value: 15 },
|
||
{ label: '۸ خرداد', value: 40 },
|
||
{ label: '۹ خرداد', value: 48 },
|
||
];
|
||
|
||
const EMPTY = 'دادهای برای نمایش نیست';
|
||
|
||
describe('TauriBarChart', () => {
|
||
it('shows the empty state when every value is zero', () => {
|
||
render(<TauriBarChart data={zero} />);
|
||
expect(screen.getByText(EMPTY)).toBeInTheDocument();
|
||
});
|
||
|
||
it('shows the empty state when there is no data', () => {
|
||
render(<TauriBarChart data={[]} />);
|
||
expect(screen.getByText(EMPTY)).toBeInTheDocument();
|
||
});
|
||
|
||
it('renders the chart (x labels, no empty state) with real data', () => {
|
||
render(<TauriBarChart data={real} />);
|
||
expect(screen.queryByText(EMPTY)).not.toBeInTheDocument();
|
||
expect(screen.getByText('۸ خرداد')).toBeInTheDocument();
|
||
});
|
||
|
||
it('renders one bar per day of a full Jalali month', () => {
|
||
const month: ChartPoint[] = Array.from({ length: 31 }, (_, i) => ({ label: String(i + 1), value: i % 5 }));
|
||
const { container } = render(<TauriBarChart data={month} />);
|
||
expect(container.querySelectorAll('.bg-\\[\\#5559CE\\]')).toHaveLength(31);
|
||
});
|
||
|
||
/**
|
||
* A fixed-width bar makes its column's intrinsic min-width 24px, so a 31-day
|
||
* month sums past the plot width and the row overflows out of the card
|
||
* (bars land on the neighbouring chart). Columns must be shrinkable and the
|
||
* bar fluid-but-capped.
|
||
*/
|
||
it('keeps a dense month inside the card: shrinkable columns, fluid bars', () => {
|
||
const month: ChartPoint[] = Array.from({ length: 31 }, (_, i) => ({ label: String(i + 1), value: i % 5 }));
|
||
const { container } = render(<TauriBarChart data={month} />);
|
||
|
||
const bar = container.querySelector('.bg-\\[\\#5559CE\\]') as HTMLElement;
|
||
// کسری از ستون، نه تمام آن — وگرنه میلهها بدون فاصله به هم میچسبند
|
||
expect(bar.className).toMatch(/\bw-\[\d+%\]/);
|
||
expect(bar.className.split(/\s+/)).not.toContain('w-full');
|
||
expect(bar.className).toContain('max-w-[24px]');
|
||
// فقط سقف عرض، نه عرض ثابت (max-w-[24px] خودش شامل رشتهی w-[24px] است)
|
||
expect(bar.className.split(/\s+/)).not.toContain('w-[24px]');
|
||
|
||
const column = bar.parentElement as HTMLElement;
|
||
expect(column.className).toContain('min-w-0');
|
||
|
||
const plot = container.querySelector('.relative.flex-1') as HTMLElement;
|
||
expect(plot.className).toContain('overflow-hidden');
|
||
});
|
||
|
||
/**
|
||
* styles.css ships an unlayered legacy `.flex { align-items: center }` that
|
||
* beats Tailwind's `items-*` utilities and collapses the plot column to zero
|
||
* height. The frame must pin alignment inline, or the chart renders blank.
|
||
*/
|
||
it('pins flex alignment inline so the legacy global .flex cannot collapse it', () => {
|
||
const { container } = render(<TauriBarChart data={real} />);
|
||
const frame = container.querySelector('.h-\\[300px\\]') as HTMLElement;
|
||
expect(frame.style.alignItems).toBe('stretch');
|
||
expect((frame.firstElementChild as HTMLElement).style.alignItems).toBe('stretch');
|
||
});
|
||
});
|
||
|
||
describe('TauriLineChart', () => {
|
||
it('shows the empty state when every value is zero', () => {
|
||
render(<TauriLineChart data={zero} />);
|
||
expect(screen.getByText(EMPTY)).toBeInTheDocument();
|
||
});
|
||
|
||
it('shows the empty state with fewer than two points', () => {
|
||
render(<TauriLineChart data={[{ label: 'x', value: 5 }]} />);
|
||
expect(screen.getByText(EMPTY)).toBeInTheDocument();
|
||
});
|
||
|
||
it('renders the chart with real data', () => {
|
||
const { container } = render(<TauriLineChart data={real} />);
|
||
expect(screen.queryByText(EMPTY)).not.toBeInTheDocument();
|
||
expect(container.querySelector('svg path')).toBeTruthy();
|
||
});
|
||
});
|