-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1026 from rainlanguage/11/26/24-Order-Charts-1
- Loading branch information
Showing
29 changed files
with
868 additions
and
950 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
packages/ui-components/src/__tests__/ChartTimeFilters.test.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
67
packages/ui-components/src/__tests__/ChartTimeFilters.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
277
packages/ui-components/src/__tests__/LightweightChart.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
}); | ||
}); |
Oops, something went wrong.