complete project using prettier!
This commit is contained in:
@@ -6,7 +6,10 @@ import { PriceHistoryChart } from './PriceHistoryChart';
|
||||
import { useUserData } from '../../hooks/useUserData';
|
||||
import * as apiClient from '../../services/apiClient';
|
||||
import type { MasterGroceryItem, HistoricalPriceDataPoint } from '../../types';
|
||||
import { createMockMasterGroceryItem, createMockHistoricalPriceDataPoint } from '../../tests/utils/mockFactories';
|
||||
import {
|
||||
createMockMasterGroceryItem,
|
||||
createMockHistoricalPriceDataPoint,
|
||||
} from '../../tests/utils/mockFactories';
|
||||
|
||||
// Mock the apiClient
|
||||
vi.mock('../../services/apiClient');
|
||||
@@ -24,19 +27,24 @@ vi.mock('../../services/logger', () => ({
|
||||
|
||||
// Mock the recharts library to prevent rendering complex SVGs in jsdom
|
||||
vi.mock('recharts', () => ({
|
||||
ResponsiveContainer: ({ children }: { children: React.ReactNode }) => <div data-testid="responsive-container">{children}</div>,
|
||||
ResponsiveContainer: ({ children }: { children: React.ReactNode }) => (
|
||||
<div data-testid="responsive-container">{children}</div>
|
||||
),
|
||||
// Expose the data prop for testing data transformations
|
||||
LineChart: ({ children, data }: { children: React.ReactNode; data: any[] }) => (
|
||||
<div data-testid="line-chart" data-chartdata={JSON.stringify(data)}>
|
||||
{children}
|
||||
</div>),
|
||||
</div>
|
||||
),
|
||||
CartesianGrid: () => <div data-testid="cartesian-grid" />,
|
||||
XAxis: () => <div data-testid="x-axis" />,
|
||||
YAxis: () => <div data-testid="y-axis" />,
|
||||
Tooltip: () => <div data-testid="tooltip" />,
|
||||
Legend: () => <div data-testid="legend" />,
|
||||
// Fix: Use dataKey if name is not explicitly provided, as the component relies on dataKey
|
||||
Line: ({ name, dataKey }: { name?: string; dataKey?: string }) => <div data-testid={`line-${name || dataKey}`} />,
|
||||
Line: ({ name, dataKey }: { name?: string; dataKey?: string }) => (
|
||||
<div data-testid={`line-${name || dataKey}`} />
|
||||
),
|
||||
}));
|
||||
|
||||
const mockWatchedItems: MasterGroceryItem[] = [
|
||||
@@ -45,10 +53,26 @@ const mockWatchedItems: MasterGroceryItem[] = [
|
||||
];
|
||||
|
||||
const mockPriceHistory: HistoricalPriceDataPoint[] = [
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-01', avg_price_in_cents: 110 }),
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-08', avg_price_in_cents: 99 }),
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 2, summary_date: '2024-10-01', avg_price_in_cents: 350 }),
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 2, summary_date: '2024-10-08', avg_price_in_cents: 349 }),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-01',
|
||||
avg_price_in_cents: 110,
|
||||
}),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-08',
|
||||
avg_price_in_cents: 99,
|
||||
}),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 2,
|
||||
summary_date: '2024-10-01',
|
||||
avg_price_in_cents: 350,
|
||||
}),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 2,
|
||||
summary_date: '2024-10-08',
|
||||
avg_price_in_cents: 349,
|
||||
}),
|
||||
];
|
||||
|
||||
describe('PriceHistoryChart', () => {
|
||||
@@ -75,7 +99,9 @@ describe('PriceHistoryChart', () => {
|
||||
error: null,
|
||||
});
|
||||
render(<PriceHistoryChart />);
|
||||
expect(screen.getByText('Add items to your watchlist to see their price trends over time.')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Add items to your watchlist to see their price trends over time.'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display a loading state while fetching data', () => {
|
||||
@@ -95,16 +121,24 @@ describe('PriceHistoryChart', () => {
|
||||
});
|
||||
|
||||
it('should display a message if no historical data is returned', async () => {
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(new Response(JSON.stringify([])));
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(
|
||||
new Response(JSON.stringify([])),
|
||||
);
|
||||
render(<PriceHistoryChart />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Not enough historical data for your watched items. Process more flyers to build a trend.')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Not enough historical data for your watched items. Process more flyers to build a trend.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the chart with data on successful fetch', async () => {
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(new Response(JSON.stringify(mockPriceHistory)));
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(
|
||||
new Response(JSON.stringify(mockPriceHistory)),
|
||||
);
|
||||
render(<PriceHistoryChart />);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -139,7 +173,9 @@ describe('PriceHistoryChart', () => {
|
||||
});
|
||||
|
||||
it('should clear the chart when the watchlist becomes empty', async () => {
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(new Response(JSON.stringify(mockPriceHistory)));
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(
|
||||
new Response(JSON.stringify(mockPriceHistory)),
|
||||
);
|
||||
const { rerender } = render(<PriceHistoryChart />);
|
||||
|
||||
// Initial render with items
|
||||
@@ -160,18 +196,34 @@ describe('PriceHistoryChart', () => {
|
||||
|
||||
// Chart should be gone, placeholder should appear
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Add items to your watchlist to see their price trends over time.')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Add items to your watchlist to see their price trends over time.'),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('line-chart')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter out items with only one data point', async () => {
|
||||
const dataWithSinglePoint: HistoricalPriceDataPoint[] = [
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-01', avg_price_in_cents: 110 }),
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-08', avg_price_in_cents: 99 }),
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 2, summary_date: '2024-10-01', avg_price_in_cents: 350 }), // Almond Milk only has one point
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-01',
|
||||
avg_price_in_cents: 110,
|
||||
}),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-08',
|
||||
avg_price_in_cents: 99,
|
||||
}),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 2,
|
||||
summary_date: '2024-10-01',
|
||||
avg_price_in_cents: 350,
|
||||
}), // Almond Milk only has one point
|
||||
];
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(new Response(JSON.stringify(dataWithSinglePoint)));
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(
|
||||
new Response(JSON.stringify(dataWithSinglePoint)),
|
||||
);
|
||||
render(<PriceHistoryChart />);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -182,37 +234,65 @@ describe('PriceHistoryChart', () => {
|
||||
|
||||
it('should process data to only keep the lowest price for a given day', async () => {
|
||||
const dataWithDuplicateDate: HistoricalPriceDataPoint[] = [
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-01', avg_price_in_cents: 110 }),
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-01', avg_price_in_cents: 105 }), // Lower price
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-08', avg_price_in_cents: 99 }),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-01',
|
||||
avg_price_in_cents: 110,
|
||||
}),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-01',
|
||||
avg_price_in_cents: 105,
|
||||
}), // Lower price
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-08',
|
||||
avg_price_in_cents: 99,
|
||||
}),
|
||||
];
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(new Response(JSON.stringify(dataWithDuplicateDate)));
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(
|
||||
new Response(JSON.stringify(dataWithDuplicateDate)),
|
||||
);
|
||||
render(<PriceHistoryChart />);
|
||||
|
||||
await waitFor(() => {
|
||||
const chart = screen.getByTestId('line-chart');
|
||||
const chartData = JSON.parse(chart.getAttribute('data-chartdata')!);
|
||||
|
||||
|
||||
// The date gets formatted to 'Oct 1'
|
||||
const dataPointForOct1 = chartData.find((d: any) => d.date === 'Oct 1');
|
||||
|
||||
|
||||
expect(dataPointForOct1['Organic Bananas']).toBe(105);
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter out data points with a price of zero', async () => {
|
||||
const dataWithZeroPrice: HistoricalPriceDataPoint[] = [
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-01', avg_price_in_cents: 110 }),
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-08', avg_price_in_cents: 0 }), // Zero price should be filtered
|
||||
createMockHistoricalPriceDataPoint({ master_item_id: 1, summary_date: '2024-10-15', avg_price_in_cents: 105 }),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-01',
|
||||
avg_price_in_cents: 110,
|
||||
}),
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-08',
|
||||
avg_price_in_cents: 0,
|
||||
}), // Zero price should be filtered
|
||||
createMockHistoricalPriceDataPoint({
|
||||
master_item_id: 1,
|
||||
summary_date: '2024-10-15',
|
||||
avg_price_in_cents: 105,
|
||||
}),
|
||||
];
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(new Response(JSON.stringify(dataWithZeroPrice)));
|
||||
vi.mocked(apiClient.fetchHistoricalPriceData).mockResolvedValue(
|
||||
new Response(JSON.stringify(dataWithZeroPrice)),
|
||||
);
|
||||
render(<PriceHistoryChart />);
|
||||
|
||||
await waitFor(() => {
|
||||
const chart = screen.getByTestId('line-chart');
|
||||
const chartData = JSON.parse(chart.getAttribute('data-chartdata')!);
|
||||
|
||||
|
||||
// The date 'Oct 8' should not be in the chart data at all
|
||||
const dataPointForOct8 = chartData.find((d: any) => d.date === 'Oct 8');
|
||||
expect(dataPointForOct8).toBeUndefined();
|
||||
@@ -221,4 +301,4 @@ describe('PriceHistoryChart', () => {
|
||||
expect(chartData).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user