Skip to content

Commit

Permalink
Merge pull request #1026 from rainlanguage/11/26/24-Order-Charts-1
Browse files Browse the repository at this point in the history
  • Loading branch information
hardyjosh authored Dec 1, 2024
2 parents 3ded605 + 6f0b3c9 commit 8ecda48
Show file tree
Hide file tree
Showing 29 changed files with 868 additions and 950 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import ChartTimeFilters from '../lib/components/charts/ChartTimeFilters.svelte';
import { writable } from 'svelte/store';
export let timeDeltaStore = writable(60 * 60 * 24 * 365); // Default to 1 year
</script>

<ChartTimeFilters bind:timeDelta={$timeDeltaStore} />
67 changes: 67 additions & 0 deletions packages/ui-components/src/__tests__/ChartTimeFilters.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { render, fireEvent, screen } from '@testing-library/svelte';
import { get, writable } from 'svelte/store';
import { test, expect } from 'vitest';
import ChartTimeFiltersTest from './ChartTimeFilters.test.svelte';

const TIME_DELTA_24_HOURS = 60 * 60 * 24;
const TIME_DELTA_7_DAYS = TIME_DELTA_24_HOURS * 7;
const TIME_DELTA_30_DAYS = TIME_DELTA_24_HOURS * 30;
const TIME_DELTA_1_YEAR = TIME_DELTA_24_HOURS * 365;

test('initial timeDelta is set to 1 year', async () => {
const timeDeltaStore = writable(TIME_DELTA_1_YEAR);

render(ChartTimeFiltersTest, { timeDeltaStore });

const yearButton = screen.getByText('1 Year');
expect(yearButton).toBeDisabled();
expect(get(timeDeltaStore)).toBe(TIME_DELTA_1_YEAR);
});

test('clicking 30 Days button updates timeDelta', async () => {
const timeDeltaStore = writable(TIME_DELTA_1_YEAR);

render(ChartTimeFiltersTest, { timeDeltaStore });

const thirtyDaysButton = screen.getByText('30 Days');
await fireEvent.click(thirtyDaysButton);

expect(thirtyDaysButton).toBeDisabled();
expect(get(timeDeltaStore)).toBe(TIME_DELTA_30_DAYS);
});

test('clicking 7 Days button updates timeDelta', async () => {
const timeDeltaStore = writable(TIME_DELTA_1_YEAR);

render(ChartTimeFiltersTest, { timeDeltaStore });

const sevenDaysButton = screen.getByText('7 Days');
await fireEvent.click(sevenDaysButton);

expect(sevenDaysButton).toBeDisabled();
expect(get(timeDeltaStore)).toBe(TIME_DELTA_7_DAYS);
});

test('clicking 24 Hours button updates timeDelta', async () => {
const timeDeltaStore = writable(TIME_DELTA_1_YEAR);

render(ChartTimeFiltersTest, { timeDeltaStore });

const twentyFourHoursButton = screen.getByText('24 Hours');
await fireEvent.click(twentyFourHoursButton);

expect(twentyFourHoursButton).toBeDisabled();
expect(get(timeDeltaStore)).toBe(TIME_DELTA_24_HOURS);
});

test('clicking 1 Year button updates timeDelta', async () => {
const timeDeltaStore = writable(TIME_DELTA_30_DAYS);

render(ChartTimeFiltersTest, { timeDeltaStore });

const yearButton = screen.getByText('1 Year');
await fireEvent.click(yearButton);

expect(yearButton).toBeDisabled();
expect(get(timeDeltaStore)).toBe(TIME_DELTA_1_YEAR);
});
277 changes: 277 additions & 0 deletions packages/ui-components/src/__tests__/LightweightChart.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
import { act, fireEvent, render, screen, waitFor } from '@testing-library/svelte';
import { test, vi } from 'vitest';
import { expect } from '../lib/test/matchers';
import LightweightChart from '../lib/components/charts/LightweightChart.svelte';
import { type IChartApi, type UTCTimestamp } from 'lightweight-charts';
import { lightweightChartsTheme } from '../lib/stores/darkMode';
const setDataMock = vi.fn();
const applyOptionsMock = vi.fn();
const setVisibleRangeMock = vi.fn();
const removeMock = vi.fn();

vi.mock('lightweight-charts', async (importOriginal) => ({
...((await importOriginal()) as object),
createChart: vi.fn(() => ({
addLineSeries: vi.fn(() => ({
setData: setDataMock
})),
remove: removeMock,
applyOptions: applyOptionsMock,
timeScale: vi.fn(() => ({
setVisibleRange: setVisibleRangeMock
}))
}))
}));

vi.mock('../lib/stores/darkMode', async (importOriginal) => {
const { readable } = await import('svelte/store');
return {
...((await importOriginal()) as object),
lightweightChartsTheme: readable({ test: 'test' })
};
});

test('renders without data correctly', async () => {
const title = 'test title';
const emptyMessage = 'empty message';
let loading = true;
const priceSymbol = '$';
const createSeries = (chart: IChartApi) => chart.addLineSeries();

const { component } = render(LightweightChart, {
title,
emptyMessage,
loading,
priceSymbol,
createSeries,
lightweightChartsTheme
});

await waitFor(() => {
expect(screen.getByTestId('lightweightChartTitle')).toHaveTextContent(title);
expect(screen.getByTestId('lightweightChartSpinner')).toBeInTheDocument();
});

loading = false;

await act(() => component.$set({ loading: false }));

await waitFor(() => {
expect(screen.getByTestId('lightweightChartEmptyMessage')).toHaveTextContent(emptyMessage);
});
});

test('renders with data correctly', async () => {
const title = 'test title';
const emptyMessage = 'empty message';
const loading = true;
const priceSymbol = '$';

const createSeries = (chart: IChartApi) => chart.addLineSeries();

const data: { value: number; time: UTCTimestamp; color?: string }[] = [
{
value: 10,
time: 1529899200 as UTCTimestamp
},
{
value: 20,
time: 1529899300 as UTCTimestamp
},
{
value: 5,
time: 1529899500 as UTCTimestamp
}
];

render(LightweightChart, {
title,
emptyMessage,
loading,
priceSymbol,
createSeries,
data,
lightweightChartsTheme
});

await waitFor(() => {
expect(screen.getByTestId('lightweightChartTitle')).toHaveTextContent(title);
expect(screen.getByTestId('lightweightChartSpinner')).toBeInTheDocument();
expect(screen.getByTestId('lightweightChartElement')).toBeInTheDocument();
expect(screen.queryByTestId('lightweightChartYearButtons')).toBeInTheDocument();

expect(setDataMock).toHaveBeenCalledWith(data);
});
});

test('updates data correctly when props change', async () => {
const title = 'test title';
const emptyMessage = 'empty message';
const loading = false;
const priceSymbol = '$';
const createSeries = (chart: IChartApi) => chart.addLineSeries();

const initialData: { value: number; time: UTCTimestamp; color?: string }[] = [
{ value: 10, time: 1529899200 as UTCTimestamp },
{ value: 20, time: 1529899300 as UTCTimestamp }
];

const newData: { value: number; time: UTCTimestamp; color?: string }[] = [
{ value: 15, time: 1529900000 as UTCTimestamp },
{ value: 25, time: 1529900300 as UTCTimestamp }
];

const { component } = render(LightweightChart, {
title,
emptyMessage,
loading,
priceSymbol,
createSeries,
data: initialData,
lightweightChartsTheme
});

await waitFor(() => {
expect(setDataMock).toHaveBeenCalledWith(initialData);
});

// Update data prop
await act(() => component.$set({ data: newData }));

await waitFor(() => {
expect(setDataMock).toHaveBeenCalledWith(newData);
});
});

test('setOptions is called correctly', async () => {
const title = 'test title';
const emptyMessage = 'empty message';
const loading = false;
const priceSymbol = '$';

render(LightweightChart, {
title,
emptyMessage,
loading,
priceSymbol,
createSeries: (chart: IChartApi) => chart.addLineSeries(),
lightweightChartsTheme
});

await waitFor(() => {
expect(applyOptionsMock).toHaveBeenCalled();

const callArgs = applyOptionsMock.mock.calls[0][0];
expect(callArgs).toMatchObject({
test: 'test'
});
});
});

test('setTimeScale is called correctly', async () => {
const title = 'test title';
const emptyMessage = 'empty message';
const loading = false;
const priceSymbol = '$';

const data: { value: number; time: UTCTimestamp; color?: string }[] = [
{
value: 10,
time: 1529899200 as UTCTimestamp
},
{
value: 20,
time: 1529899300 as UTCTimestamp
},
{
value: 5,
time: 1529899500 as UTCTimestamp
}
];

render(LightweightChart, {
title,
emptyMessage,
loading,
priceSymbol,
createSeries: (chart: IChartApi) => chart.addLineSeries(),
data,
lightweightChartsTheme
});

// Simulate clicking the "30 Days" button to change the timeDelta
await waitFor(async () => {
const timeDeltaButton = screen.getByText('30 Days');
await act(() => fireEvent.click(timeDeltaButton));
});

const timeDelta = 60 * 60 * 24 * 30; // 30 days in seconds
const timeTo = Math.floor(new Date().getTime() / 1000) as UTCTimestamp;
const timeFrom = (timeTo - timeDelta) as UTCTimestamp;

await waitFor(() => {
expect(setVisibleRangeMock).toHaveBeenCalledWith({
from: timeFrom,
to: timeTo
});
});
});

test('setupChart is called correctly', async () => {
const title = 'test title';
const emptyMessage = 'empty message';
const loading = false;
const priceSymbol = '$';

const data: { value: number; time: UTCTimestamp; color?: string }[] = [
{
value: 10,
time: 1529899200 as UTCTimestamp
},
{
value: 20,
time: 1529899300 as UTCTimestamp
},
{
value: 5,
time: 1529899500 as UTCTimestamp
}
];

render(LightweightChart, {
title,
emptyMessage,
loading,
priceSymbol,
createSeries: (chart: IChartApi) => chart.addLineSeries(),
data,
lightweightChartsTheme
});

await waitFor(() => {
expect(screen.getByTestId('lightweightChartElement')).toBeInTheDocument();
expect(setDataMock).toHaveBeenCalledWith(data);
});
});

test('destroyChart is called correctly', async () => {
const title = 'test title';
const emptyMessage = 'empty message';
const loading = false;
const priceSymbol = '$';

const { component } = render(LightweightChart, {
title,
emptyMessage,
loading,
priceSymbol,
createSeries: (chart: IChartApi) => chart.addLineSeries(),
lightweightChartsTheme
});

component.$destroy();

await waitFor(() => {
expect(removeMock).toHaveBeenCalled();
});
});
Loading

0 comments on commit 8ecda48

Please sign in to comment.