diff --git a/package.json b/package.json index 97c9c98b..15aec89b 100644 --- a/package.json +++ b/package.json @@ -49,9 +49,9 @@ "preview": "vite preview", "preview:build": "yarn build && yarn preview", "preview:build:dev": "yarn build --watch & yarn preview", + "test": "vitest --coverage", "lint:js": "eslint --max-warnings=0 --ext=tsx --ext=ts --ext=js --ext=jsx --fix ./src", "serve:build": "yarn build && serve -l 5001 build", - "test": "craco test --env=jsdom --coverage --watchAll=false", "test:watch": "craco test --env=jsdom --watch", "playwright:test:mocked": "docker run -v $PWD:/test -w=/test $(node -e \"if(process.env.CI !== 'true'){if(process.platform === 'win32'){console.log('-it -u pwuser')}else{console.log('-it -u $(id -u):$(id -g)')}}else{console.log('-e CI')}\") --rm --ipc=host -p 9323:9323 --add-host host.docker.internal:host-gateway mcr.microsoft.com/playwright:v$(yarn info @playwright/test --name-only --json | sed -n 's/^.*:\\(.*\\)\"$/\\1/p') yarn playwright test", "playwright:test:real": "docker run -v $PWD:/test -w=/test -e \"USE_REAL_API=true\" $(node -e \"if(process.env.CI !== 'true'){if(process.platform === 'win32'){console.log('-it -u pwuser')}else{console.log('-it -u $(id -u):$(id -g)')}}else{console.log('-e CI')}\") --rm --ipc=host -p 9323:9323 --add-host host.docker.internal:host-gateway mcr.microsoft.com/playwright:v$(yarn info @playwright/test --name-only --json | sed -n 's/^.*:\\(.*\\)\"$/\\1/p') yarn playwright test", @@ -108,6 +108,7 @@ "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", "@typescript-eslint/typescript-estree": "7.17.0", + "@vitest/coverage-v8": "^2.0.5", "chart.js": "4.4.1", "chartjs-plugin-zoom": "2.0.0", "cross-env": "7.0.3", @@ -123,12 +124,15 @@ "husky": "9.1.1", "jest-canvas-mock": "2.5.0", "jest-fail-on-console": "3.3.0", + "jsdom": "^24.1.1", "lint-staged": "15.2.0", "msw": "2.3.5", "prettier": "3.3.3", "serve": "14.2.0", "serve-static": "1.15.0", - "start-server-and-test": "2.0.0" + "start-server-and-test": "2.0.0", + "vitest": "^2.0.5", + "vitest-canvas-mock": "^0.3.3" }, "msw": { "workerDirectory": "public" diff --git a/src/App.test.tsx b/src/App.test.tsx index 0f50c91d..86dbcbb2 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,10 +1,10 @@ -import React from 'react'; import { act } from '@testing-library/react'; -import App from './App'; +import React from 'react'; import { createRoot } from 'react-dom/client'; -import { flushPromises } from './setupTests'; +import App from './App'; +import { flushPromises } from './testUtils'; -jest.mock('loglevel'); +vi.mock('loglevel'); describe('App', () => { it('renders without crashing', async () => { diff --git a/src/api/channels.test.tsx b/src/api/channels.test.tsx index b22de0dd..444c39a4 100644 --- a/src/api/channels.test.tsx +++ b/src/api/channels.test.tsx @@ -1,22 +1,22 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import { renderHook, waitFor } from '@testing-library/react'; +import { http } from 'msw'; +import { FullChannelMetadata, timeChannelName } from '../app.types'; +import { server } from '../mocks/server'; +import { RootState } from '../state/store'; import { - useChannels, - useAvailableColumns, + getInitialState, + hooksWrapperWithProviders, + testChannels, +} from '../testUtils'; +import { + ChannelSummary, getScalarChannels, staticChannels, + useAvailableColumns, + useChannels, useChannelSummary, - ChannelSummary, } from './channels'; -import { FullChannelMetadata, timeChannelName } from '../app.types'; -import { - hooksWrapperWithProviders, - getInitialState, - testChannels, -} from '../setupTests'; -import { RootState } from '../state/store'; -import { server } from '../mocks/server'; -import { http } from 'msw'; describe('channels api functions', () => { afterEach(() => { diff --git a/src/api/experiment.test.tsx b/src/api/experiment.test.tsx index 4fd97df6..a917c26a 100644 --- a/src/api/experiment.test.tsx +++ b/src/api/experiment.test.tsx @@ -1,8 +1,8 @@ import { renderHook, waitFor } from '@testing-library/react'; -import { useExperiment } from './experiment'; import { ExperimentParams } from '../app.types'; -import { hooksWrapperWithProviders } from '../setupTests'; import experimentsJson from '../mocks/experiments.json'; +import { hooksWrapperWithProviders } from '../testUtils'; +import { useExperiment } from './experiment'; describe('channels api functions', () => { afterEach(() => { diff --git a/src/api/export.test.tsx b/src/api/export.test.tsx index 9a148a27..cdf437fa 100644 --- a/src/api/export.test.tsx +++ b/src/api/export.test.tsx @@ -1,8 +1,8 @@ -import axios from 'axios'; -import { useExportData } from './export'; import { renderHook, waitFor } from '@testing-library/react'; -import { hooksWrapperWithProviders, getInitialState } from '../setupTests'; +import axios from 'axios'; import { RootState } from '../state/store'; +import { getInitialState, hooksWrapperWithProviders } from '../testUtils'; +import { useExportData } from './export'; describe('useExportData', () => { let state: RootState; diff --git a/src/api/images.test.tsx b/src/api/images.test.tsx index 01ef0444..aa0b68d5 100644 --- a/src/api/images.test.tsx +++ b/src/api/images.test.tsx @@ -1,8 +1,7 @@ -import { waitFor } from '@testing-library/react'; -import { renderHook } from '@testing-library/react'; -import { hooksWrapperWithProviders, waitForRequest } from '../setupTests'; -import { useColourBar, useColourMaps, useImage } from './images'; +import { renderHook, waitFor } from '@testing-library/react'; import colourMapsJson from '../mocks/colourMaps.json'; +import { hooksWrapperWithProviders, waitForRequest } from '../testUtils'; +import { useColourBar, useColourMaps, useImage } from './images'; describe('images api functions', () => { afterEach(() => { diff --git a/src/api/records.test.tsx b/src/api/records.test.tsx index 60986bf5..7115a1e2 100644 --- a/src/api/records.test.tsx +++ b/src/api/records.test.tsx @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { renderHook, waitFor } from '@testing-library/react'; +import { parseISO } from 'date-fns'; import { PlotDataset, Record, @@ -7,28 +9,26 @@ import { SelectedPlotChannel, timeChannelName, } from '../app.types'; +import { operators, parseFilter, Token } from '../filtering/filterParser'; +import recordsJson from '../mocks/records.json'; +import { MAX_SHOTS_VALUES } from '../search/components/maxShots.component'; +import { RootState } from '../state/store'; import { - hooksWrapperWithProviders, - getInitialState, createTestQueryClient, + getInitialState, + hooksWrapperWithProviders, waitForRequest, -} from '../setupTests'; -import { renderHook, waitFor } from '@testing-library/react'; +} from '../testUtils'; import { getFormattedAxisData, + useDateToShotnumConverter, + useIncomingRecordCount, usePlotRecords, useRecordCount, - useIncomingRecordCount, useRecordsPaginated, - useThumbnails, useShotnumToDateConverter, - useDateToShotnumConverter, + useThumbnails, } from './records'; -import { RootState } from '../state/store'; -import { parseISO } from 'date-fns'; -import { operators, parseFilter, Token } from '../filtering/filterParser'; -import { MAX_SHOTS_VALUES } from '../search/components/maxShots.component'; -import recordsJson from '../mocks/records.json'; describe('records api functions', () => { let state: RootState; diff --git a/src/api/sessions.test.tsx b/src/api/sessions.test.tsx index 74911669..d2456dae 100644 --- a/src/api/sessions.test.tsx +++ b/src/api/sessions.test.tsx @@ -1,4 +1,7 @@ import { renderHook, waitFor } from '@testing-library/react'; +import { Session, SessionListItem } from '../app.types'; +import sessionsListJSON from '../mocks/sessionsList.json'; +import { hooksWrapperWithProviders } from '../testUtils'; import { useDeleteSession, useEditSession, @@ -6,9 +9,6 @@ import { useSession, useSessionList, } from './sessions'; -import { Session, SessionListItem } from '../app.types'; -import { hooksWrapperWithProviders } from '../setupTests'; -import sessionsListJSON from '../mocks/sessionsList.json'; describe('session api functions', () => { let mockData: Session; diff --git a/src/api/userPreferences.test.tsx b/src/api/userPreferences.test.tsx index 13a9e8b0..0ae4d7a1 100644 --- a/src/api/userPreferences.test.tsx +++ b/src/api/userPreferences.test.tsx @@ -1,9 +1,9 @@ import { renderHook, waitFor } from '@testing-library/react'; -import { hooksWrapperWithProviders } from '../setupTests'; -import { useUpdateUserPreference, useUserPreference } from './userPreferences'; -import { PREFERRED_COLOUR_MAP_PREFERENCE_NAME } from '../settingsMenuItems.component'; import axios from 'axios'; import { setMockedPreferredColourMap } from '../mocks/handlers'; +import { PREFERRED_COLOUR_MAP_PREFERENCE_NAME } from '../settingsMenuItems.component'; +import { hooksWrapperWithProviders } from '../testUtils'; +import { useUpdateUserPreference, useUserPreference } from './userPreferences'; describe('user preferences api functions', () => { const axiosPost = jest.spyOn(axios, 'post'); diff --git a/src/api/waveforms.test.tsx b/src/api/waveforms.test.tsx index 153545e1..7ea9f4d2 100644 --- a/src/api/waveforms.test.tsx +++ b/src/api/waveforms.test.tsx @@ -1,6 +1,5 @@ -import { waitFor } from '@testing-library/react'; -import { renderHook } from '@testing-library/react'; -import { hooksWrapperWithProviders } from '../setupTests'; +import { renderHook, waitFor } from '@testing-library/react'; +import { hooksWrapperWithProviders } from '../testUtils'; import { useWaveform } from './waveforms'; describe('waveform api functions', () => { diff --git a/src/channels/channelMetadataPanel.component.test.tsx b/src/channels/channelMetadataPanel.component.test.tsx index 9319a555..8d9e398e 100644 --- a/src/channels/channelMetadataPanel.component.test.tsx +++ b/src/channels/channelMetadataPanel.component.test.tsx @@ -1,12 +1,11 @@ +import { QueryClient } from '@tanstack/react-query'; import { screen } from '@testing-library/react'; -import React from 'react'; -import ChannelMetadataPanel from './channelMetadataPanel.component'; +import userEvent from '@testing-library/user-event'; +import { staticChannels } from '../api/channels'; import { FullChannelMetadata } from '../app.types'; -import { QueryClient } from '@tanstack/react-query'; -import { renderComponentWithProviders } from '../setupTests'; import { RootState } from '../state/store'; -import { staticChannels } from '../api/channels'; -import userEvent from '@testing-library/user-event'; +import { renderComponentWithProviders } from '../testUtils'; +import ChannelMetadataPanel from './channelMetadataPanel.component'; describe('Channel Metadata Panel', () => { let displayedChannel: FullChannelMetadata | undefined; diff --git a/src/channels/channelSearch.component.test.tsx b/src/channels/channelSearch.component.test.tsx index 6a3f4d69..9fd9a6d3 100644 --- a/src/channels/channelSearch.component.test.tsx +++ b/src/channels/channelSearch.component.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { testChannels } from '../setupTests'; +import { testChannels } from '../testUtils'; import ChannelSearch from './channelSearch.component'; describe('Channel Search', () => { diff --git a/src/channels/channelsDialogue.component.test.tsx b/src/channels/channelsDialogue.component.test.tsx index 1086bc62..0ae26992 100644 --- a/src/channels/channelsDialogue.component.test.tsx +++ b/src/channels/channelsDialogue.component.test.tsx @@ -3,12 +3,12 @@ import { act, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { staticChannels } from '../api/channels'; +import { RootState } from '../state/store'; import { getInitialState, renderComponentWithProviders, testChannels, -} from '../setupTests'; -import { RootState } from '../state/store'; +} from '../testUtils'; import ChannelsDialogue, { selectChannelTree, TreeNode, diff --git a/src/export/exportButton.component.test.tsx b/src/export/exportButton.component.test.tsx index bae886d5..114a7988 100644 --- a/src/export/exportButton.component.test.tsx +++ b/src/export/exportButton.component.test.tsx @@ -1,8 +1,7 @@ import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import ExportButton from './exportButton.component'; -import React from 'react'; describe('ExportButton', () => { let user: ReturnType; diff --git a/src/export/exportDialogue.component.test.tsx b/src/export/exportDialogue.component.test.tsx index 5dc39c4a..9632bb7d 100644 --- a/src/export/exportDialogue.component.test.tsx +++ b/src/export/exportDialogue.component.test.tsx @@ -1,7 +1,7 @@ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useExportData } from '../api/export'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import ExportDialogue from './exportDialogue.component'; jest.mock('../api/export', () => ({ diff --git a/src/filtering/filterDialogue.component.test.tsx b/src/filtering/filterDialogue.component.test.tsx index 4efcc135..cf662e06 100644 --- a/src/filtering/filterDialogue.component.test.tsx +++ b/src/filtering/filterDialogue.component.test.tsx @@ -6,8 +6,8 @@ import { http } from 'msw'; import React from 'react'; import recordsJson from '../mocks/records.json'; import { server } from '../mocks/server'; -import { getInitialState, renderComponentWithProviders } from '../setupTests'; import { RootState } from '../state/store'; +import { getInitialState, renderComponentWithProviders } from '../testUtils'; import FilterDialogue from './filterDialogue.component'; import { operators, Token } from './filterParser'; diff --git a/src/images/falseColourPanel.component.test.tsx b/src/images/falseColourPanel.component.test.tsx index 291bc686..234053fb 100644 --- a/src/images/falseColourPanel.component.test.tsx +++ b/src/images/falseColourPanel.component.test.tsx @@ -1,7 +1,7 @@ import { fireEvent, screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { flushPromises, renderComponentWithProviders } from '../setupTests'; +import { flushPromises, renderComponentWithProviders } from '../testUtils'; import FalseColourPanel from './falseColourPanel.component'; describe('False colour panel component', () => { diff --git a/src/images/imageView.component.test.tsx b/src/images/imageView.component.test.tsx index 2488ab01..98a1e4bb 100644 --- a/src/images/imageView.component.test.tsx +++ b/src/images/imageView.component.test.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react'; -import { flushPromises } from '../setupTests'; +import { flushPromises } from '../testUtils'; import ImageView, { ImageViewProps } from './imageView.component'; describe('Image view component', () => { diff --git a/src/images/imageWindow.component.test.tsx b/src/images/imageWindow.component.test.tsx index 9f99c424..31f3110c 100644 --- a/src/images/imageWindow.component.test.tsx +++ b/src/images/imageWindow.component.test.tsx @@ -3,8 +3,8 @@ import userEvent from '@testing-library/user-event'; import { http } from 'msw'; import { DEFAULT_WINDOW_VARS } from '../app.types'; import { server } from '../mocks/server'; -import { renderComponentWithProviders } from '../setupTests'; import { TraceOrImageWindow } from '../state/slices/windowSlice'; +import { renderComponentWithProviders } from '../testUtils'; import ImageWindow from './imageWindow.component'; jest.mock('../windows/windowPortal.component', () => { diff --git a/src/plotting/plot.component.test.tsx b/src/plotting/plot.component.test.tsx index 531c3964..48f12b19 100644 --- a/src/plotting/plot.component.test.tsx +++ b/src/plotting/plot.component.test.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react'; import React from 'react'; -import { testPlotDatasets } from '../setupTests'; +import { testPlotDatasets } from '../testUtils'; import Plot, { PlotProps } from './plot.component'; import { deepCopySelectedPlotChannels } from './util'; diff --git a/src/plotting/plotList.component.test.tsx b/src/plotting/plotList.component.test.tsx index 0a9bc05d..7ca8ac94 100644 --- a/src/plotting/plotList.component.test.tsx +++ b/src/plotting/plotList.component.test.tsx @@ -1,7 +1,7 @@ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { getInitialState, renderComponentWithStore } from '../setupTests'; import { RootState } from '../state/store'; +import { getInitialState, renderComponentWithStore } from '../testUtils'; import PlotList from './plotList.component'; describe('Plot List component', () => { diff --git a/src/plotting/plotSettings/moreOptions/moreOptionsBox.component.test.tsx b/src/plotting/plotSettings/moreOptions/moreOptionsBox.component.test.tsx index 16c1d724..1478c2d4 100644 --- a/src/plotting/plotSettings/moreOptions/moreOptionsBox.component.test.tsx +++ b/src/plotting/plotSettings/moreOptions/moreOptionsBox.component.test.tsx @@ -2,7 +2,7 @@ import type { RenderResult } from '@testing-library/react'; import { fireEvent, render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { SelectedPlotChannel } from '../../../app.types'; -import { testPlotDatasets } from '../../../setupTests'; +import { testPlotDatasets } from '../../../testUtils'; import { deepCopySelectedPlotChannels } from '../../util'; import type { MoreOptionsProps } from './moreOptionsBox.component'; import MoreOptionsBox from './moreOptionsBox.component'; diff --git a/src/plotting/plotSettings/moreOptions/moreOptionsToggle.component.test.tsx b/src/plotting/plotSettings/moreOptions/moreOptionsToggle.component.test.tsx index 06277727..4efb7b4e 100644 --- a/src/plotting/plotSettings/moreOptions/moreOptionsToggle.component.test.tsx +++ b/src/plotting/plotSettings/moreOptions/moreOptionsToggle.component.test.tsx @@ -2,7 +2,7 @@ import type { RenderResult } from '@testing-library/react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { SelectedPlotChannel } from '../../../app.types'; -import { testPlotDatasets } from '../../../setupTests'; +import { testPlotDatasets } from '../../../testUtils'; import type { MoreOptionsProps } from './moreOptionsBox.component'; import MoreOptionsToggle from './moreOptionsToggle.component'; diff --git a/src/plotting/plotSettings/plotSettingsController.component.test.tsx b/src/plotting/plotSettings/plotSettingsController.component.test.tsx index 7fc708d6..d8c122fb 100644 --- a/src/plotting/plotSettings/plotSettingsController.component.test.tsx +++ b/src/plotting/plotSettings/plotSettingsController.component.test.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { staticChannels } from '../../api/channels'; import { FullScalarChannelMetadata } from '../../app.types'; -import { testScalarChannels } from '../../setupTests'; +import { testScalarChannels } from '../../testUtils'; import type { PlotSettingsControllerProps } from './plotSettingsController.component'; describe('Plot Settings component', () => { diff --git a/src/plotting/plotSettings/xAxisTab.component.test.tsx b/src/plotting/plotSettings/xAxisTab.component.test.tsx index 8986dd0d..d5426c5a 100644 --- a/src/plotting/plotSettings/xAxisTab.component.test.tsx +++ b/src/plotting/plotSettings/xAxisTab.component.test.tsx @@ -6,7 +6,7 @@ import { applyDatePickerWorkaround, cleanupDatePickerWorkaround, testScalarChannels, -} from '../../setupTests'; +} from '../../testUtils'; import type { XAxisTabProps } from './xAxisTab.component'; import XAxisTab from './xAxisTab.component'; diff --git a/src/plotting/plotSettings/yAxisTab.component.test.tsx b/src/plotting/plotSettings/yAxisTab.component.test.tsx index 49812652..9e7bdf3e 100644 --- a/src/plotting/plotSettings/yAxisTab.component.test.tsx +++ b/src/plotting/plotSettings/yAxisTab.component.test.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { staticChannels } from '../../api/channels'; import { FullScalarChannelMetadata } from '../../app.types'; -import { testScalarChannels } from '../../setupTests'; +import { testScalarChannels } from '../../testUtils'; import { COLOUR_ORDER } from './colourGenerator'; import type { YAxisTabProps } from './yAxisTab.component'; import YAxisTab from './yAxisTab.component'; diff --git a/src/plotting/plotWindow.component.test.tsx b/src/plotting/plotWindow.component.test.tsx index b7a3eab9..827d06b3 100644 --- a/src/plotting/plotWindow.component.test.tsx +++ b/src/plotting/plotWindow.component.test.tsx @@ -2,13 +2,13 @@ import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { http } from 'msw'; import { server } from '../mocks/server'; +import { PlotConfig } from '../state/slices/plotSlice'; +import { RootState } from '../state/store'; import { getInitialState, renderComponentWithProviders, testPlotConfigs, -} from '../setupTests'; -import { PlotConfig } from '../state/slices/plotSlice'; -import { RootState } from '../state/store'; +} from '../testUtils'; import PlotWindow from './plotWindow.component'; jest.mock('../windows/windowPortal.component', () => { diff --git a/src/search/components/dateTime.component.test.tsx b/src/search/components/dateTime.component.test.tsx index 70e941eb..72e15112 100644 --- a/src/search/components/dateTime.component.test.tsx +++ b/src/search/components/dateTime.component.test.tsx @@ -8,7 +8,7 @@ import experimentsJSON from '../../mocks/experiments.json'; import { applyDatePickerWorkaround, cleanupDatePickerWorkaround, -} from '../../setupTests'; +} from '../../testUtils'; import DateTime, { CustomPickersDay, datesEqual, diff --git a/src/search/searchBar.component.test.tsx b/src/search/searchBar.component.test.tsx index b968dd95..0f9f3b80 100644 --- a/src/search/searchBar.component.test.tsx +++ b/src/search/searchBar.component.test.tsx @@ -5,14 +5,14 @@ import { http } from 'msw'; import React from 'react'; import recordsJson from '../mocks/records.json'; import { server } from '../mocks/server'; +import { formatDateTimeForApi } from '../state/slices/searchSlice'; +import { RootState } from '../state/store'; import { applyDatePickerWorkaround, cleanupDatePickerWorkaround, getInitialState, renderComponentWithProviders, -} from '../setupTests'; -import { formatDateTimeForApi } from '../state/slices/searchSlice'; -import { RootState } from '../state/store'; +} from '../testUtils'; import { MAX_SHOTS_VALUES } from './components/maxShots.component'; import SearchBar from './searchBar.component'; diff --git a/src/session/deleteSessionDialogue.component.test.tsx b/src/session/deleteSessionDialogue.component.test.tsx index 406d47a0..1f42517f 100644 --- a/src/session/deleteSessionDialogue.component.test.tsx +++ b/src/session/deleteSessionDialogue.component.test.tsx @@ -1,6 +1,6 @@ import { RenderResult, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import DeleteSessionDialogue, { DeleteSessionDialogueProps, } from './deleteSessionDialogue.component'; diff --git a/src/session/sessionDialogue.component.test.tsx b/src/session/sessionDialogue.component.test.tsx index 4700bdf6..9cc37ee8 100644 --- a/src/session/sessionDialogue.component.test.tsx +++ b/src/session/sessionDialogue.component.test.tsx @@ -1,6 +1,6 @@ import { RenderResult, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import SessionDialogue, { SessionDialogueProps, } from './sessionDialogue.component'; diff --git a/src/session/sessionDrawer.component.test.tsx b/src/session/sessionDrawer.component.test.tsx index 4a8cd9d5..bc76f746 100644 --- a/src/session/sessionDrawer.component.test.tsx +++ b/src/session/sessionDrawer.component.test.tsx @@ -1,7 +1,7 @@ import { screen, waitFor, type RenderResult } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import SessionsListJSON from '../mocks/sessionsList.json'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import SessionsDrawer, { SessionDrawerProps } from './sessionDrawer.component'; describe('session Drawer', () => { diff --git a/src/session/sessionSaveButtons.component.test.tsx b/src/session/sessionSaveButtons.component.test.tsx index ba0e155d..ac741bbb 100644 --- a/src/session/sessionSaveButtons.component.test.tsx +++ b/src/session/sessionSaveButtons.component.test.tsx @@ -7,7 +7,7 @@ import { } from '@testing-library/react'; import { useEditSession, useSaveSession } from '../api/sessions'; import { timeChannelName } from '../app.types'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import SessionSaveButtons, { AUTO_SAVE_INTERVAL_MS, SessionsSaveButtonsProps, diff --git a/src/settingsMenuItems.component.test.tsx b/src/settingsMenuItems.component.test.tsx index 56861d69..ae088f9a 100644 --- a/src/settingsMenuItems.component.test.tsx +++ b/src/settingsMenuItems.component.test.tsx @@ -2,8 +2,8 @@ import { act, screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { setMockedPreferredColourMap } from './mocks/handlers'; import SettingsMenuItems from './settingsMenuItems.component'; -import { renderComponentWithProviders } from './setupTests'; import { RootState } from './state/store'; +import { renderComponentWithProviders } from './testUtils'; describe('Settings Menu Items component', () => { let settings; diff --git a/src/setupTests.ts b/src/setupTests.ts new file mode 100644 index 00000000..b14d7973 --- /dev/null +++ b/src/setupTests.ts @@ -0,0 +1,80 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; +import crypto from 'crypto'; +// TODO JOEL: Is this still needed? - Also in vite config +// need to mock for plotting +import 'vitest-canvas-mock'; +// TODO JOEL: Replace with vitest-fail-on-console +import failOnConsole from 'jest-fail-on-console'; +import { TextEncoder } from 'util'; +import { server } from './mocks/server'; + +// TODO JOEL: Is this still needed? - same for failOnConsole below +global.TextEncoder = TextEncoder; + +failOnConsole(); + +vi.setConfig({ testTimeout: 15000 }); + +// Establish API mocking before all tests. +beforeAll(() => server.listen()); + +// Reset any request handlers that we may add during the tests, +// so they don't affect other tests. +afterEach(() => server.resetHandlers()); + +// Clean up after the tests are finished. +afterAll(() => server.close()); + +// TODO JOEL: Check if a all of the below is still needed + +if (typeof window.URL.createObjectURL === 'undefined') { + // required as work-around for enzyme/jest environment not implementing window.URL.createObjectURL method + Object.defineProperty(window.URL, 'createObjectURL', { + value: () => 'testObjectUrl', + }); +} + +if (typeof window.URL.revokeObjectURL === 'undefined') { + // required as work-around for enzyme/jest environment not implementing window.URL.createObjectURL method + Object.defineProperty(window.URL, 'revokeObjectURL', { + value: () => {}, + }); +} + +// this is needed because of https://github.com/facebook/jest/issues/8987 +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +let mockActualReact; +vi.doMock('react', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (!mockActualReact) { + mockActualReact = await vi.importActual('react'); + } + return mockActualReact; +}); + +if (typeof window.URL.createObjectURL === 'undefined') { + // required as work-around for enzyme/jest environment not implementing window.URL.createObjectURL method + Object.defineProperty(window.URL, 'createObjectURL', { + value: () => 'testObjectUrl', + }); +} + +if (typeof window.URL.revokeObjectURL === 'undefined') { + // required as work-around for enzyme/jest environment not implementing window.URL.revokeObjectURL method + Object.defineProperty(window.URL, 'revokeObjectURL', { + value: () => { + // no-op + }, + }); +} + +// jest doesn't implement web crypto so set up nodejs crypto as a default +Object.defineProperty(global, 'crypto', { + value: Object.setPrototypeOf({ subtle: crypto.subtle }, crypto), +}); diff --git a/src/state/slices/configSlice.test.tsx b/src/state/slices/configSlice.test.tsx index 66e98340..3b555bb2 100644 --- a/src/state/slices/configSlice.test.tsx +++ b/src/state/slices/configSlice.test.tsx @@ -1,13 +1,13 @@ +import { setSettings } from '../../settings'; +import { actions, dispatch, resetActions } from '../../testUtils'; import ConfigReducer, { configureApp, - settingsLoaded, - loadUrls, - loadPluginHostSetting, initialState, + loadPluginHostSetting, loadRecordLimitWarningSetting, + loadUrls, + settingsLoaded, } from './configSlice'; -import { actions, resetActions, dispatch } from '../../setupTests'; -import { setSettings } from '../../settings'; jest.mock('loglevel'); diff --git a/src/state/slices/plotSlice.test.tsx b/src/state/slices/plotSlice.test.tsx index 945d0b66..42c34947 100644 --- a/src/state/slices/plotSlice.test.tsx +++ b/src/state/slices/plotSlice.test.tsx @@ -1,13 +1,13 @@ +import { DEFAULT_WINDOW_VARS } from '../../app.types'; +import { COLOUR_ORDER } from '../../plotting/plotSettings/colourGenerator'; +import { testPlotConfigs } from '../../testUtils'; import PlotReducer, { - initialState, - createPlot, closePlot, - savePlot, + createPlot, + initialState, PlotConfig, + savePlot, } from './plotSlice'; -import { testPlotConfigs } from '../../setupTests'; -import { COLOUR_ORDER } from '../../plotting/plotSettings/colourGenerator'; -import { DEFAULT_WINDOW_VARS } from '../../app.types'; describe('plotSlice', () => { describe('Reducer', () => { diff --git a/src/table/headerRenderers/dataHeader.component.test.tsx b/src/table/headerRenderers/dataHeader.component.test.tsx index fd11de22..a05c9536 100644 --- a/src/table/headerRenderers/dataHeader.component.test.tsx +++ b/src/table/headerRenderers/dataHeader.component.test.tsx @@ -7,7 +7,7 @@ import { within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { flushPromises } from '../../setupTests'; +import { flushPromises } from '../../testUtils'; import DataHeader, { DataHeaderProps } from './dataHeader.component'; describe('Data Header', () => { diff --git a/src/table/table.component.test.tsx b/src/table/table.component.test.tsx index 87f49c4b..1d4f7602 100644 --- a/src/table/table.component.test.tsx +++ b/src/table/table.component.test.tsx @@ -2,7 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'; import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { RecordRow } from '../app.types'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import Table, { TableProps } from './table.component'; describe('Table', () => { diff --git a/src/setupTests.tsx b/src/testUtils.tsx similarity index 82% rename from src/setupTests.tsx rename to src/testUtils.tsx index c92f0469..9e5227e5 100644 --- a/src/setupTests.tsx +++ b/src/testUtils.tsx @@ -8,12 +8,9 @@ import { Action, ThunkAction } from '@reduxjs/toolkit'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { RenderOptions } from '@testing-library/react'; import { render } from '@testing-library/react'; -import crypto from 'crypto'; import 'jest-canvas-mock'; -import failOnConsole from 'jest-fail-on-console'; import { matchRequestUrl } from 'msw'; import { Provider } from 'react-redux'; -import { TextEncoder } from 'util'; import { staticChannels } from './api/channels'; import { DEFAULT_WINDOW_VARS, @@ -37,36 +34,6 @@ import { initialState as initialTableState } from './state/slices/tableSlice'; import { initialState as initialWindowsState } from './state/slices/windowSlice'; import { AppStore, RootState, setupStore } from './state/store'; -global.TextEncoder = TextEncoder; - -failOnConsole(); - -jest.setTimeout(15000); - -// Establish API mocking before all tests. -beforeAll(() => server.listen()); - -// Reset any request handlers that we may add during the tests, -// so they don't affect other tests. -afterEach(() => server.resetHandlers()); - -// Clean up after the tests are finished. -afterAll(() => server.close()); - -if (typeof window.URL.createObjectURL === 'undefined') { - // required as work-around for enzyme/jest environment not implementing window.URL.createObjectURL method - Object.defineProperty(window.URL, 'createObjectURL', { - value: () => 'testObjectUrl', - }); -} - -if (typeof window.URL.revokeObjectURL === 'undefined') { - // required as work-around for enzyme/jest environment not implementing window.URL.createObjectURL method - Object.defineProperty(window.URL, 'revokeObjectURL', { - value: () => {}, - }); -} - /** * Waits for msw request - * @param method string representing the HTTP method @@ -139,19 +106,6 @@ export function waitForRequest(method: string, url: string) { }); } -// this is needed because of https://github.com/facebook/jest/issues/8987 -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -let mockActualReact; -jest.doMock('react', () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - if (!mockActualReact) { - mockActualReact = jest.requireActual('react'); - } - return mockActualReact; -}); - export let actions: Action[] = []; export const resetActions = (): void => { actions = []; @@ -176,27 +130,6 @@ export const dispatch = ( } }; -if (typeof window.URL.createObjectURL === 'undefined') { - // required as work-around for enzyme/jest environment not implementing window.URL.createObjectURL method - Object.defineProperty(window.URL, 'createObjectURL', { - value: () => 'testObjectUrl', - }); -} - -if (typeof window.URL.revokeObjectURL === 'undefined') { - // required as work-around for enzyme/jest environment not implementing window.URL.revokeObjectURL method - Object.defineProperty(window.URL, 'revokeObjectURL', { - value: () => { - // no-op - }, - }); -} - -// jest doesn't implement web crypto so set up nodejs crypto as a default -Object.defineProperty(global, 'crypto', { - value: Object.setPrototypeOf({ subtle: crypto.subtle }, crypto), -}); - // This type interface extends the default options for render from RTL, as well // as allows the user to specify other things such as initialState, store. interface ExtendedRenderOptions extends Omit { diff --git a/src/traces/traceWindow.component.test.tsx b/src/traces/traceWindow.component.test.tsx index 673aacd8..3ef6367a 100644 --- a/src/traces/traceWindow.component.test.tsx +++ b/src/traces/traceWindow.component.test.tsx @@ -3,8 +3,8 @@ import userEvent from '@testing-library/user-event'; import { http } from 'msw'; import { DEFAULT_WINDOW_VARS } from '../app.types'; import { server } from '../mocks/server'; -import { renderComponentWithProviders } from '../setupTests'; import { TraceOrImageWindow } from '../state/slices/windowSlice'; +import { renderComponentWithProviders } from '../testUtils'; import TraceWindow from './traceWindow.component'; jest.mock('../windows/windowPortal.component', () => { diff --git a/src/views/dataView.component.test.tsx b/src/views/dataView.component.test.tsx index bfa952a3..d4bbd960 100644 --- a/src/views/dataView.component.test.tsx +++ b/src/views/dataView.component.test.tsx @@ -9,12 +9,12 @@ import { } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { operators, Token } from '../filtering/filterParser'; +import { RootState } from '../state/store'; import { flushPromises, getInitialState, renderComponentWithProviders, -} from '../setupTests'; -import { RootState } from '../state/store'; +} from '../testUtils'; import DataView from './dataView.component'; describe('Data View', () => { diff --git a/src/views/recordTable.component.test.tsx b/src/views/recordTable.component.test.tsx index 05c903e8..042e8e12 100644 --- a/src/views/recordTable.component.test.tsx +++ b/src/views/recordTable.component.test.tsx @@ -12,14 +12,14 @@ import { DEFAULT_WINDOW_VARS } from '../app.types'; import { operators, type Token } from '../filtering/filterParser'; import recordsJson from '../mocks/records.json'; import { server } from '../mocks/server'; +import { deselectColumn, selectColumn } from '../state/slices/tableSlice'; +import { RootState } from '../state/store'; import { applyDatePickerWorkaround, cleanupDatePickerWorkaround, getInitialState, renderComponentWithProviders, -} from '../setupTests'; -import { deselectColumn, selectColumn } from '../state/slices/tableSlice'; -import { RootState } from '../state/store'; +} from '../testUtils'; import RecordTable, { extractChannelsFromTokens, } from './recordTable.component'; diff --git a/src/views/viewTabs.component.test.tsx b/src/views/viewTabs.component.test.tsx index b5614ebe..0237b6f4 100644 --- a/src/views/viewTabs.component.test.tsx +++ b/src/views/viewTabs.component.test.tsx @@ -1,6 +1,6 @@ import { screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { renderComponentWithProviders } from '../setupTests'; +import { renderComponentWithProviders } from '../testUtils'; import ViewTabs from './viewTabs.component'; describe('View Tabs', () => { diff --git a/src/windows/openWindows.component.test.tsx b/src/windows/openWindows.component.test.tsx index 4e27a4aa..4ce98d94 100644 --- a/src/windows/openWindows.component.test.tsx +++ b/src/windows/openWindows.component.test.tsx @@ -1,10 +1,10 @@ import { DEFAULT_WINDOW_VARS } from '../app.types'; +import { RootState } from '../state/store'; import { getInitialState, renderComponentWithStore, testPlotConfigs, -} from '../setupTests'; -import { RootState } from '../state/store'; +} from '../testUtils'; import OpenWindows from './openWindows.component'; // need to mock to avoid errors diff --git a/src/windows/thumbnailSelector.component.test.tsx b/src/windows/thumbnailSelector.component.test.tsx index 67e7f533..5e6eb4d9 100644 --- a/src/windows/thumbnailSelector.component.test.tsx +++ b/src/windows/thumbnailSelector.component.test.tsx @@ -2,8 +2,8 @@ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { http } from 'msw'; import { server } from '../mocks/server'; -import { getInitialState, renderComponentWithProviders } from '../setupTests'; import { RootState } from '../state/store'; +import { getInitialState, renderComponentWithProviders } from '../testUtils'; import ThumbnailSelector from './thumbnailSelector.component'; describe('Thumbnail selector component', () => { diff --git a/vite.config.ts b/vite.config.ts index 504f84cb..fc694a84 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -37,6 +37,15 @@ function jsonHMR(): PluginOption { }; } +// Obtain default coverage config from vitest when not building for production +// (to avoid importing vitest during build as its a dev dependency) +let coverageConfigDefaultsExclude: string[] = []; +if (process.env.NODE_ENV !== 'production') { + await import('vitest/config').then((vitestConfig) => { + coverageConfigDefaultsExclude = vitestConfig.coverageConfigDefaults.exclude; + }); +} + // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); @@ -122,12 +131,12 @@ export default defineConfig(({ mode }) => { // // Use browserslist config // config.build.target = browserslistToEsbuild(); + // TODO JOEL: Does this need the options shown in https://www.npmjs.com/package/vitest-canvas-mock? return { ...config, test: { globals: true, environment: 'jsdom', - globalSetup: './globalSetup.js', setupFiles: ['src/setupTests.ts'], coverage: { reporter: [ @@ -140,9 +149,10 @@ export default defineConfig(({ mode }) => { ['lcov', { outputFile: 'lcov.info', silent: true }], ], exclude: [ + ...coverageConfigDefaultsExclude, 'public/*', 'server/*', - 'cypress/*', + 'playwright.config.js', // Leave handlers to show up unused code 'src/mocks/browser.ts', 'src/mocks/server.ts', diff --git a/yarn.lock b/yarn.lock index d95a3edf..e2cbe9f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,6 +29,16 @@ __metadata: languageName: node linkType: hard +"@ampproject/remapping@npm:^2.3.0": + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": version: 7.23.5 resolution: "@babel/code-frame@npm:7.23.5" @@ -551,6 +561,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.4": + version: 7.25.3 + resolution: "@babel/parser@npm:7.25.3" + dependencies: + "@babel/types": "npm:^7.25.2" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/874b01349aedb805d6694f867a752fdc7469778fad76aca4548d2cc6ce96087c3ba5fb917a6f8d05d2d1a74aae309b5f50f1a4dba035f5a2c9fcfe6e106d2c4e + languageName: node + linkType: hard + "@babel/parser@npm:^7.24.7, @babel/parser@npm:^7.24.8": version: 7.24.8 resolution: "@babel/parser@npm:7.24.8" @@ -1848,6 +1869,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.24.0, @babel/types@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/types@npm:7.25.2" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.8" + "@babel/helper-validator-identifier": "npm:^7.24.7" + to-fast-properties: "npm:^2.0.0" + checksum: 10c0/e489435856be239f8cc1120c90a197e4c2865385121908e5edb7223cfdff3768cba18f489adfe0c26955d9e7bbb1fb10625bc2517505908ceb0af848989bd864 + languageName: node + linkType: hard + "@babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.24.9": version: 7.24.9 resolution: "@babel/types@npm:7.24.9" @@ -1859,6 +1891,13 @@ __metadata: languageName: node linkType: hard +"@bcoe/v8-coverage@npm:^0.2.3": + version: 0.2.3 + resolution: "@bcoe/v8-coverage@npm:0.2.3" + checksum: 10c0/6b80ae4cb3db53f486da2dc63b6e190a74c8c3cca16bb2733f234a0b6a9382b09b146488ae08e2b22cf00f6c83e20f3e040a2f7894f05c045c946d6a090b1d52 + languageName: node + linkType: hard + "@bundled-es-modules/cookie@npm:^2.0.0": version: 2.0.0 resolution: "@bundled-es-modules/cookie@npm:2.0.0" @@ -2458,6 +2497,13 @@ __metadata: languageName: node linkType: hard +"@istanbuljs/schema@npm:^0.1.2": + version: 0.1.3 + resolution: "@istanbuljs/schema@npm:0.1.3" + checksum: 10c0/61c5286771676c9ca3eb2bd8a7310a9c063fb6e0e9712225c8471c582d157392c88f5353581c8c9adbe0dff98892317d2fdfc56c3499aa42e0194405206a963a + languageName: node + linkType: hard + "@jest/expect-utils@npm:^29.7.0": version: 29.7.0 resolution: "@jest/expect-utils@npm:29.7.0" @@ -2540,6 +2586,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/sourcemap-codec@npm:^1.5.0": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18 + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.21 resolution: "@jridgewell/trace-mapping@npm:0.3.21" @@ -2550,7 +2603,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": +"@jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: @@ -3379,7 +3432,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.5": +"@types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": version: 1.0.5 resolution: "@types/estree@npm:1.0.5" checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d @@ -3809,6 +3862,91 @@ __metadata: languageName: node linkType: hard +"@vitest/coverage-v8@npm:^2.0.5": + version: 2.0.5 + resolution: "@vitest/coverage-v8@npm:2.0.5" + dependencies: + "@ampproject/remapping": "npm:^2.3.0" + "@bcoe/v8-coverage": "npm:^0.2.3" + debug: "npm:^4.3.5" + istanbul-lib-coverage: "npm:^3.2.2" + istanbul-lib-report: "npm:^3.0.1" + istanbul-lib-source-maps: "npm:^5.0.6" + istanbul-reports: "npm:^3.1.7" + magic-string: "npm:^0.30.10" + magicast: "npm:^0.3.4" + std-env: "npm:^3.7.0" + test-exclude: "npm:^7.0.1" + tinyrainbow: "npm:^1.2.0" + peerDependencies: + vitest: 2.0.5 + checksum: 10c0/a95eef744d2a541f5d9d0287243cbcb596802c04e0250404947e36a669c477abe86607afb8d8ddb3d31bf12633b3ffa3d9a313e489e4ab7998b3c1620ad60e00 + languageName: node + linkType: hard + +"@vitest/expect@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/expect@npm:2.0.5" + dependencies: + "@vitest/spy": "npm:2.0.5" + "@vitest/utils": "npm:2.0.5" + chai: "npm:^5.1.1" + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/08cb1b0f106d16a5b60db733e3d436fa5eefc68571488eb570dfe4f599f214ab52e4342273b03dbe12331cc6c0cdc325ac6c94f651ad254cd62f3aa0e3d185aa + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:2.0.5, @vitest/pretty-format@npm:^2.0.5": + version: 2.0.5 + resolution: "@vitest/pretty-format@npm:2.0.5" + dependencies: + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/236c0798c5170a0b5ad5d4bd06118533738e820b4dd30079d8fbcb15baee949d41c60f42a9f769906c4a5ce366d7ef11279546070646c0efc03128c220c31f37 + languageName: node + linkType: hard + +"@vitest/runner@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/runner@npm:2.0.5" + dependencies: + "@vitest/utils": "npm:2.0.5" + pathe: "npm:^1.1.2" + checksum: 10c0/d0ed3302a7e015bf44b7c0df9d8f7da163659e082d86f9406944b5a31a61ab9ddc1de530e06176d1f4ef0bde994b44bff4c7dab62aacdc235c8fc04b98e4a72a + languageName: node + linkType: hard + +"@vitest/snapshot@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/snapshot@npm:2.0.5" + dependencies: + "@vitest/pretty-format": "npm:2.0.5" + magic-string: "npm:^0.30.10" + pathe: "npm:^1.1.2" + checksum: 10c0/7bf38474248f5ae0aac6afad511785d2b7a023ac5158803c2868fd172b5b9c1a569fb1dd64a09a49e43fd342cab71ea485ada89b7f08d37b1622a5a0ac00271d + languageName: node + linkType: hard + +"@vitest/spy@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/spy@npm:2.0.5" + dependencies: + tinyspy: "npm:^3.0.0" + checksum: 10c0/70634c21921eb271b54d2986c21d7ab6896a31c0f4f1d266940c9bafb8ac36237846d6736638cbf18b958bd98e5261b158a6944352742accfde50b7818ff655e + languageName: node + linkType: hard + +"@vitest/utils@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/utils@npm:2.0.5" + dependencies: + "@vitest/pretty-format": "npm:2.0.5" + estree-walker: "npm:^3.0.3" + loupe: "npm:^3.1.1" + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/0d1de748298f07a50281e1ba058b05dcd58da3280c14e6f016265e950bd79adab6b97822de8f0ea82d3070f585654801a9b1bcf26db4372e51cf7746bf86d73b + languageName: node + linkType: hard + "@zeit/schemas@npm:2.29.0": version: 2.29.0 resolution: "@zeit/schemas@npm:2.29.0" @@ -4131,6 +4269,13 @@ __metadata: languageName: node linkType: hard +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8 + languageName: node + linkType: hard + "ast-types-flow@npm:^0.0.8": version: 0.0.8 resolution: "ast-types-flow@npm:0.0.8" @@ -4478,6 +4623,13 @@ __metadata: languageName: node linkType: hard +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10 + languageName: node + linkType: hard + "cacache@npm:^18.0.0": version: 18.0.2 resolution: "cacache@npm:18.0.2" @@ -4551,6 +4703,19 @@ __metadata: languageName: node linkType: hard +"chai@npm:^5.1.1": + version: 5.1.1 + resolution: "chai@npm:5.1.1" + dependencies: + assertion-error: "npm:^2.0.1" + check-error: "npm:^2.1.1" + deep-eql: "npm:^5.0.1" + loupe: "npm:^3.1.0" + pathval: "npm:^2.0.0" + checksum: 10c0/e7f00e5881e3d5224f08fe63966ed6566bd9fdde175863c7c16dd5240416de9b34c4a0dd925f4fd64ad56256ca6507d32cf6131c49e1db65c62578eb31d4566c + languageName: node + linkType: hard + "chalk-template@npm:0.4.0": version: 0.4.0 resolution: "chalk-template@npm:0.4.0" @@ -4625,6 +4790,13 @@ __metadata: languageName: node linkType: hard +"check-error@npm:^2.1.1": + version: 2.1.1 + resolution: "check-error@npm:2.1.1" + checksum: 10c0/979f13eccab306cf1785fa10941a590b4e7ea9916ea2a4f8c87f0316fc3eab07eabefb6e587424ef0f88cbcd3805791f172ea739863ca3d7ce2afc54641c7f0e + languageName: node + linkType: hard + "check-more-types@npm:2.24.0, check-more-types@npm:^2.24.0": version: 2.24.0 resolution: "check-more-types@npm:2.24.0" @@ -4994,6 +5166,15 @@ __metadata: languageName: node linkType: hard +"cssstyle@npm:^4.0.1": + version: 4.0.1 + resolution: "cssstyle@npm:4.0.1" + dependencies: + rrweb-cssom: "npm:^0.6.0" + checksum: 10c0/cadf9a8b23e11f4c6d63f21291096a0b0be868bd4ab9c799daa2c5b18330e39e5281605f01da906e901b42f742df0f3b3645af6465e83377ff7d15a88ee432a0 + languageName: node + linkType: hard + "csstype@npm:^3.0.2, csstype@npm:^3.1.3": version: 3.1.3 resolution: "csstype@npm:3.1.3" @@ -5086,6 +5267,16 @@ __metadata: languageName: node linkType: hard +"data-urls@npm:^5.0.0": + version: 5.0.0 + resolution: "data-urls@npm:5.0.0" + dependencies: + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + checksum: 10c0/1b894d7d41c861f3a4ed2ae9b1c3f0909d4575ada02e36d3d3bc584bdd84278e20709070c79c3b3bff7ac98598cb191eb3e86a89a79ea4ee1ef360e1694f92ad + languageName: node + linkType: hard + "date-fns@npm:3.6.0": version: 3.6.0 resolution: "date-fns@npm:3.6.0" @@ -5130,6 +5321,32 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.3.5": + version: 4.3.6 + resolution: "debug@npm:4.3.6" + dependencies: + ms: "npm:2.1.2" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/3293416bff072389c101697d4611c402a6bacd1900ac20c0492f61a9cdd6b3b29750fc7f5e299f8058469ef60ff8fb79b86395a30374fbd2490113c1c7112285 + languageName: node + linkType: hard + +"decimal.js@npm:^10.4.3": + version: 10.4.3 + resolution: "decimal.js@npm:10.4.3" + checksum: 10c0/6d60206689ff0911f0ce968d40f163304a6c1bc739927758e6efc7921cfa630130388966f16bf6ef6b838cb33679fbe8e7a78a2f3c478afce841fd55ac8fb8ee + languageName: node + linkType: hard + +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247 + languageName: node + linkType: hard + "deep-equal@npm:^2.0.5": version: 2.2.3 resolution: "deep-equal@npm:2.2.3" @@ -5379,6 +5596,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -5992,6 +6216,15 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -6069,7 +6302,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:8.0.1": +"execa@npm:8.0.1, execa@npm:^8.0.1": version: 8.0.1 resolution: "execa@npm:8.0.1" dependencies: @@ -6538,6 +6771,13 @@ __metadata: languageName: node linkType: hard +"get-func-name@npm:^2.0.1": + version: 2.0.2 + resolution: "get-func-name@npm:2.0.2" + checksum: 10c0/89830fd07623fa73429a711b9daecdb304386d237c71268007f788f113505ef1d4cc2d0b9680e072c5082490aec9df5d7758bf5ac6f1c37062855e8e3dc0b9df + languageName: node + linkType: hard + "get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2": version: 1.2.2 resolution: "get-intrinsic@npm:1.2.2" @@ -6634,6 +6874,22 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.4.1": + version: 10.4.5 + resolution: "glob@npm:10.4.5" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e + languageName: node + linkType: hard + "glob@npm:^7.1.3": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -6818,6 +7074,22 @@ __metadata: languageName: node linkType: hard +"html-encoding-sniffer@npm:^4.0.0": + version: 4.0.0 + resolution: "html-encoding-sniffer@npm:4.0.0" + dependencies: + whatwg-encoding: "npm:^3.1.1" + checksum: 10c0/523398055dc61ac9b34718a719cb4aa691e4166f29187e211e1607de63dc25ac7af52ca7c9aead0c4b3c0415ffecb17326396e1202e2e86ff4bca4c0ee4c6140 + languageName: node + linkType: hard + +"html-escaper@npm:^2.0.0": + version: 2.0.2 + resolution: "html-escaper@npm:2.0.2" + checksum: 10c0/208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" @@ -6848,6 +7120,16 @@ __metadata: languageName: node linkType: hard +"http-proxy-agent@npm:^7.0.2": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + "http-signature@npm:~1.3.6": version: 1.3.6 resolution: "http-signature@npm:1.3.6" @@ -6869,6 +7151,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.5": + version: 7.0.5 + resolution: "https-proxy-agent@npm:7.0.5" + dependencies: + agent-base: "npm:^7.0.2" + debug: "npm:4" + checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c + languageName: node + linkType: hard + "human-signals@npm:^1.1.1": version: 1.1.1 resolution: "human-signals@npm:1.1.1" @@ -6908,7 +7200,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:^0.6.2": +"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -7244,6 +7536,13 @@ __metadata: languageName: node linkType: hard +"is-potential-custom-element-name@npm:^1.0.1": + version: 1.0.1 + resolution: "is-potential-custom-element-name@npm:1.0.1" + checksum: 10c0/b73e2f22bc863b0939941d369486d308b43d7aef1f9439705e3582bfccaa4516406865e32c968a35f97a99396dac84e2624e67b0a16b0a15086a785e16ce7db9 + languageName: node + linkType: hard + "is-regex@npm:^1.1.4": version: 1.1.4 resolution: "is-regex@npm:1.1.4" @@ -7388,6 +7687,45 @@ __metadata: languageName: node linkType: hard +"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.2": + version: 3.2.2 + resolution: "istanbul-lib-coverage@npm:3.2.2" + checksum: 10c0/6c7ff2106769e5f592ded1fb418f9f73b4411fd5a084387a5410538332b6567cd1763ff6b6cadca9b9eb2c443cce2f7ea7d7f1b8d315f9ce58539793b1e0922b + languageName: node + linkType: hard + +"istanbul-lib-report@npm:^3.0.0, istanbul-lib-report@npm:^3.0.1": + version: 3.0.1 + resolution: "istanbul-lib-report@npm:3.0.1" + dependencies: + istanbul-lib-coverage: "npm:^3.0.0" + make-dir: "npm:^4.0.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/84323afb14392de8b6a5714bd7e9af845cfbd56cfe71ed276cda2f5f1201aea673c7111901227ee33e68e4364e288d73861eb2ed48f6679d1e69a43b6d9b3ba7 + languageName: node + linkType: hard + +"istanbul-lib-source-maps@npm:^5.0.6": + version: 5.0.6 + resolution: "istanbul-lib-source-maps@npm:5.0.6" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.23" + debug: "npm:^4.1.1" + istanbul-lib-coverage: "npm:^3.0.0" + checksum: 10c0/ffe75d70b303a3621ee4671554f306e0831b16f39ab7f4ab52e54d356a5d33e534d97563e318f1333a6aae1d42f91ec49c76b6cd3f3fb378addcb5c81da0255f + languageName: node + linkType: hard + +"istanbul-reports@npm:^3.1.7": + version: 3.1.7 + resolution: "istanbul-reports@npm:3.1.7" + dependencies: + html-escaper: "npm:^2.0.0" + istanbul-lib-report: "npm:^3.0.0" + checksum: 10c0/a379fadf9cf8dc5dfe25568115721d4a7eb82fbd50b005a6672aff9c6989b20cc9312d7865814e0859cd8df58cbf664482e1d3604be0afde1f7fc3ccc1394a51 + languageName: node + linkType: hard + "iterator.prototype@npm:^1.1.2": version: 1.1.2 resolution: "iterator.prototype@npm:1.1.2" @@ -7414,6 +7752,19 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 + languageName: node + linkType: hard + "jest-canvas-mock@npm:2.5.0": version: 2.5.0 resolution: "jest-canvas-mock@npm:2.5.0" @@ -7424,6 +7775,16 @@ __metadata: languageName: node linkType: hard +"jest-canvas-mock@npm:~2.5.2": + version: 2.5.2 + resolution: "jest-canvas-mock@npm:2.5.2" + dependencies: + cssfontparser: "npm:^1.2.1" + moo-color: "npm:^1.0.2" + checksum: 10c0/6a4190354b1e9aedcb3045273f13f6f1d2d1efb00cfe6458707fae538a8f91f6afdf72b9e201b653666863054edc783428bdc0c1a2c71d66d9ac364b4893f6d6 + languageName: node + linkType: hard + "jest-diff@npm:^29.7.0": version: 29.7.0 resolution: "jest-diff@npm:29.7.0" @@ -7531,6 +7892,40 @@ __metadata: languageName: node linkType: hard +"jsdom@npm:^24.1.1": + version: 24.1.1 + resolution: "jsdom@npm:24.1.1" + dependencies: + cssstyle: "npm:^4.0.1" + data-urls: "npm:^5.0.0" + decimal.js: "npm:^10.4.3" + form-data: "npm:^4.0.0" + html-encoding-sniffer: "npm:^4.0.0" + http-proxy-agent: "npm:^7.0.2" + https-proxy-agent: "npm:^7.0.5" + is-potential-custom-element-name: "npm:^1.0.1" + nwsapi: "npm:^2.2.12" + parse5: "npm:^7.1.2" + rrweb-cssom: "npm:^0.7.1" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^4.1.4" + w3c-xmlserializer: "npm:^5.0.0" + webidl-conversions: "npm:^7.0.0" + whatwg-encoding: "npm:^3.1.1" + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + ws: "npm:^8.18.0" + xml-name-validator: "npm:^5.0.0" + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + checksum: 10c0/02d6bfe32f09f26329c0e53ad9f9883a3c671fc1f75725167d2089ca412f5b7ca85ff8aa62327d1cc6fc70ffbb3b18dfc7642c4b2096c2c8b19aaf9a48473eb3 + languageName: node + linkType: hard + "jsesc@npm:^2.5.1": version: 2.5.2 resolution: "jsesc@npm:2.5.2" @@ -7865,6 +8260,15 @@ __metadata: languageName: node linkType: hard +"loupe@npm:^3.1.0, loupe@npm:^3.1.1": + version: 3.1.1 + resolution: "loupe@npm:3.1.1" + dependencies: + get-func-name: "npm:^2.0.1" + checksum: 10c0/99f88badc47e894016df0c403de846fedfea61154aadabbf776c8428dd59e8d8378007135d385d737de32ae47980af07d22ba7bec5ef7beebd721de9baa0a0af + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": version: 10.1.0 resolution: "lru-cache@npm:10.1.0" @@ -7872,6 +8276,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^10.2.0": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -7890,6 +8301,35 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.10": + version: 0.30.11 + resolution: "magic-string@npm:0.30.11" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + checksum: 10c0/b9eb370773d0bd90ca11a848753409d8e5309b1ad56d2a1aa49d6649da710a6d2fe7237ad1a643c5a5d3800de2b9946ed9690acdfc00e6cc1aeafff3ab1752c4 + languageName: node + linkType: hard + +"magicast@npm:^0.3.4": + version: 0.3.4 + resolution: "magicast@npm:0.3.4" + dependencies: + "@babel/parser": "npm:^7.24.4" + "@babel/types": "npm:^7.24.0" + source-map-js: "npm:^1.2.0" + checksum: 10c0/7ebaaac397b13c31ca05e6d9649296751d76749b945d10a0800107872119fbdf267acdb604571d25e38ec6fd7ab3568a951b6e76eaef1caba9eaa11778fd9783 + languageName: node + linkType: hard + +"make-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "make-dir@npm:4.0.0" + dependencies: + semver: "npm:^7.5.3" + checksum: 10c0/69b98a6c0b8e5c4fe9acb61608a9fbcfca1756d910f51e5dbe7a9e5cfb74fca9b8a0c8a0ffdf1294a740826c1ab4871d5bf3f62f72a3049e5eac6541ddffed68 + languageName: node + linkType: hard + "make-fetch-happen@npm:^13.0.0": version: 13.0.0 resolution: "make-fetch-happen@npm:13.0.0" @@ -8129,6 +8569,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 + languageName: node + linkType: hard + "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -8296,6 +8743,13 @@ __metadata: languageName: node linkType: hard +"nwsapi@npm:^2.2.12": + version: 2.2.12 + resolution: "nwsapi@npm:2.2.12" + checksum: 10c0/95e9623d63df111405503df8c5d800e26f71675d319e2c9c70cddfa31e5ace1d3f8b6d98d354544fc156a1506d920ec291e303fab761e4f99296868e199a466e + languageName: node + linkType: hard + "object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -8470,6 +8924,7 @@ __metadata: "@typescript-eslint/parser": "npm:7.17.0" "@typescript-eslint/typescript-estree": "npm:7.17.0" "@vitejs/plugin-react": "npm:^4.3.1" + "@vitest/coverage-v8": "npm:^2.0.5" axios: "npm:1.7.2" chart.js: "npm:4.4.1" chartjs-plugin-zoom: "npm:2.0.0" @@ -8489,6 +8944,7 @@ __metadata: husky: "npm:9.1.1" jest-canvas-mock: "npm:2.5.0" jest-fail-on-console: "npm:3.3.0" + jsdom: "npm:^24.1.1" lint-staged: "npm:15.2.0" loglevel: "npm:1.9.1" msw: "npm:2.3.5" @@ -8503,6 +8959,8 @@ __metadata: start-server-and-test: "npm:2.0.0" typescript: "npm:5.5.3" vite: "npm:^5.3.5" + vitest: "npm:^2.0.5" + vitest-canvas-mock: "npm:^0.3.3" web-vitals: "npm:3.5.1" languageName: unknown linkType: soft @@ -8569,6 +9027,13 @@ __metadata: languageName: node linkType: hard +"package-json-from-dist@npm:^1.0.0": + version: 1.0.0 + resolution: "package-json-from-dist@npm:1.0.0" + checksum: 10c0/e3ffaf6ac1040ab6082a658230c041ad14e72fabe99076a2081bb1d5d41210f11872403fc09082daf4387fc0baa6577f96c9c0e94c90c394fd57794b66aa4033 + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -8590,6 +9055,15 @@ __metadata: languageName: node linkType: hard +"parse5@npm:^7.1.2": + version: 7.1.2 + resolution: "parse5@npm:7.1.2" + dependencies: + entities: "npm:^4.4.0" + checksum: 10c0/297d7af8224f4b5cb7f6617ecdae98eeaed7f8cbd78956c42785e230505d5a4f07cef352af10d3006fa5c1544b76b57784d3a22d861ae071bbc460c649482bf4 + languageName: node + linkType: hard + "parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -8649,6 +9123,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d + languageName: node + linkType: hard + "path-to-regexp@npm:0.1.7": version: 0.1.7 resolution: "path-to-regexp@npm:0.1.7" @@ -8677,6 +9161,20 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 + languageName: node + linkType: hard + +"pathval@npm:^2.0.0": + version: 2.0.0 + resolution: "pathval@npm:2.0.0" + checksum: 10c0/602e4ee347fba8a599115af2ccd8179836a63c925c23e04bd056d0674a64b39e3a081b643cc7bc0b84390517df2d800a46fcc5598d42c155fe4977095c2f77c5 + languageName: node + linkType: hard + "pause-stream@npm:0.0.11": version: 0.0.11 resolution: "pause-stream@npm:0.0.11" @@ -8772,6 +9270,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.4.40": + version: 8.4.41 + resolution: "postcss@npm:8.4.41" + dependencies: + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.0.1" + source-map-js: "npm:^1.2.0" + checksum: 10c0/c1828fc59e7ec1a3bf52b3a42f615dba53c67960ed82a81df6441b485fe43c20aba7f4e7c55425762fd99c594ecabbaaba8cf5b30fd79dfec5b52a9f63a2d690 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -8920,7 +9429,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1": +"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 @@ -9478,6 +9987,20 @@ __metadata: languageName: node linkType: hard +"rrweb-cssom@npm:^0.6.0": + version: 0.6.0 + resolution: "rrweb-cssom@npm:0.6.0" + checksum: 10c0/3d9d90d53c2349ea9c8509c2690df5a4ef930c9cf8242aeb9425d4046f09d712bb01047e00da0e1c1dab5db35740b3d78fd45c3e7272f75d3724a563f27c30a3 + languageName: node + linkType: hard + +"rrweb-cssom@npm:^0.7.1": + version: 0.7.1 + resolution: "rrweb-cssom@npm:0.7.1" + checksum: 10c0/127b8ca6c8aac45e2755abbae6138d4a813b1bedc2caabf79466ae83ab3cfc84b5bfab513b7033f0aa4561c7753edf787d0dd01163ceacdee2e8eb1b6bf7237e + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -9540,6 +10063,15 @@ __metadata: languageName: node linkType: hard +"saxes@npm:^6.0.0": + version: 6.0.0 + resolution: "saxes@npm:6.0.0" + dependencies: + xmlchars: "npm:^2.2.0" + checksum: 10c0/3847b839f060ef3476eb8623d099aa502ad658f5c40fd60c105ebce86d244389b0d76fcae30f4d0c728d7705ceb2f7e9b34bb54717b6a7dbedaf5dad2d9a4b74 + languageName: node + linkType: hard + "scheduler@npm:^0.23.2": version: 0.23.2 resolution: "scheduler@npm:0.23.2" @@ -9695,6 +10227,13 @@ __metadata: languageName: node linkType: hard +"siginfo@npm:^2.0.0": + version: 2.0.0 + resolution: "siginfo@npm:2.0.0" + checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34 + languageName: node + linkType: hard + "signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -9866,6 +10405,13 @@ __metadata: languageName: node linkType: hard +"stackback@npm:0.0.2": + version: 0.0.2 + resolution: "stackback@npm:0.0.2" + checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983 + languageName: node + linkType: hard + "start-server-and-test@npm:2.0.0": version: 2.0.0 resolution: "start-server-and-test@npm:2.0.0" @@ -9893,6 +10439,13 @@ __metadata: languageName: node linkType: hard +"std-env@npm:^3.7.0": + version: 3.7.0 + resolution: "std-env@npm:3.7.0" + checksum: 10c0/60edf2d130a4feb7002974af3d5a5f3343558d1ccf8d9b9934d225c638606884db4a20d2fe6440a09605bca282af6b042ae8070a10490c0800d69e82e478f41e + languageName: node + linkType: hard + "stop-iteration-iterator@npm:^1.0.0": version: 1.0.0 resolution: "stop-iteration-iterator@npm:1.0.0" @@ -10118,6 +10671,13 @@ __metadata: languageName: node linkType: hard +"symbol-tree@npm:^3.2.4": + version: 3.2.4 + resolution: "symbol-tree@npm:3.2.4" + checksum: 10c0/dfbe201ae09ac6053d163578778c53aa860a784147ecf95705de0cd23f42c851e1be7889241495e95c37cabb058edb1052f141387bef68f705afc8f9dd358509 + languageName: node + linkType: hard + "synckit@npm:^0.9.1": version: 0.9.1 resolution: "synckit@npm:0.9.1" @@ -10142,6 +10702,17 @@ __metadata: languageName: node linkType: hard +"test-exclude@npm:^7.0.1": + version: 7.0.1 + resolution: "test-exclude@npm:7.0.1" + dependencies: + "@istanbuljs/schema": "npm:^0.1.2" + glob: "npm:^10.4.1" + minimatch: "npm:^9.0.4" + checksum: 10c0/6d67b9af4336a2e12b26a68c83308c7863534c65f27ed4ff7068a56f5a58f7ac703e8fc80f698a19bb154fd8f705cdf7ec347d9512b2c522c737269507e7b263 + languageName: node + linkType: hard + "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -10170,6 +10741,34 @@ __metadata: languageName: node linkType: hard +"tinybench@npm:^2.8.0": + version: 2.9.0 + resolution: "tinybench@npm:2.9.0" + checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c + languageName: node + linkType: hard + +"tinypool@npm:^1.0.0": + version: 1.0.0 + resolution: "tinypool@npm:1.0.0" + checksum: 10c0/71b20b9c54366393831c286a0772380c20f8cad9546d724c484edb47aea3228f274c58e98cf51d28c40869b39f5273209ef3ea94a9d2a23f8b292f4731cd3e4e + languageName: node + linkType: hard + +"tinyrainbow@npm:^1.2.0": + version: 1.2.0 + resolution: "tinyrainbow@npm:1.2.0" + checksum: 10c0/7f78a4b997e5ba0f5ecb75e7ed786f30bab9063716e7dff24dd84013fb338802e43d176cb21ed12480561f5649a82184cf31efb296601a29d38145b1cdb4c192 + languageName: node + linkType: hard + +"tinyspy@npm:^3.0.0": + version: 3.0.0 + resolution: "tinyspy@npm:3.0.0" + checksum: 10c0/eb0dec264aa5370efd3d29743825eb115ed7f1ef8a72a431e9a75d5c9e7d67e99d04b0d61d86b8cd70c79ec27863f241ad0317bc453f78762e0cbd76d2c332d0 + languageName: node + linkType: hard + "tmp@npm:~0.2.3": version: 0.2.3 resolution: "tmp@npm:0.2.3" @@ -10224,6 +10823,15 @@ __metadata: languageName: node linkType: hard +"tr46@npm:^5.0.0": + version: 5.0.0 + resolution: "tr46@npm:5.0.0" + dependencies: + punycode: "npm:^2.3.1" + checksum: 10c0/1521b6e7bbc8adc825c4561480f9fe48eb2276c81335eed9fa610aa4c44a48a3221f78b10e5f18b875769eb3413e30efbf209ed556a17a42aa8d690df44b7bee + languageName: node + linkType: hard + "ts-api-utils@npm:^1.3.0": version: 1.3.0 resolution: "ts-api-utils@npm:1.3.0" @@ -10619,6 +11227,64 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:2.0.5": + version: 2.0.5 + resolution: "vite-node@npm:2.0.5" + dependencies: + cac: "npm:^6.7.14" + debug: "npm:^4.3.5" + pathe: "npm:^1.1.2" + tinyrainbow: "npm:^1.2.0" + vite: "npm:^5.0.0" + bin: + vite-node: vite-node.mjs + checksum: 10c0/affcc58ae8d45bce3e8bc3b5767acd57c24441634e2cd967cf97f4e5ed2bcead1714b60150cdf7ee153ebad47659c5cd419883207e1a95b69790331e3243749f + languageName: node + linkType: hard + +"vite@npm:^5.0.0": + version: 5.4.0 + resolution: "vite@npm:5.4.0" + dependencies: + esbuild: "npm:^0.21.3" + fsevents: "npm:~2.3.3" + postcss: "npm:^8.4.40" + rollup: "npm:^4.13.0" + peerDependencies: + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/122de7795e1c3c08cd0acc7d77296f908398266b424492be7310400107f37a3cf4c9506f2b4b16619e57299ca2859b8ca187aac5e25f8e66d84f9204a1d72d18 + languageName: node + linkType: hard + "vite@npm:^5.3.5": version: 5.3.5 resolution: "vite@npm:5.3.5" @@ -10659,6 +11325,75 @@ __metadata: languageName: node linkType: hard +"vitest-canvas-mock@npm:^0.3.3": + version: 0.3.3 + resolution: "vitest-canvas-mock@npm:0.3.3" + dependencies: + jest-canvas-mock: "npm:~2.5.2" + peerDependencies: + vitest: "*" + checksum: 10c0/c14eec888d06e0a91706c2902cba115c6563de132d1b4c0f87897c550345674849cac3f62b36c4b3c1180ed352d25dd53525ccd2267d164ac1926557f58708b9 + languageName: node + linkType: hard + +"vitest@npm:^2.0.5": + version: 2.0.5 + resolution: "vitest@npm:2.0.5" + dependencies: + "@ampproject/remapping": "npm:^2.3.0" + "@vitest/expect": "npm:2.0.5" + "@vitest/pretty-format": "npm:^2.0.5" + "@vitest/runner": "npm:2.0.5" + "@vitest/snapshot": "npm:2.0.5" + "@vitest/spy": "npm:2.0.5" + "@vitest/utils": "npm:2.0.5" + chai: "npm:^5.1.1" + debug: "npm:^4.3.5" + execa: "npm:^8.0.1" + magic-string: "npm:^0.30.10" + pathe: "npm:^1.1.2" + std-env: "npm:^3.7.0" + tinybench: "npm:^2.8.0" + tinypool: "npm:^1.0.0" + tinyrainbow: "npm:^1.2.0" + vite: "npm:^5.0.0" + vite-node: "npm:2.0.5" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@types/node": ^18.0.0 || >=20.0.0 + "@vitest/browser": 2.0.5 + "@vitest/ui": 2.0.5 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 10c0/b4e6cca00816bf967a8589111ded72faa12f92f94ccdd0dcd0698ffcfdfc52ec662753f66b387549c600ac699b993fd952efbd99dc57fcf4d1c69a2f1022b259 + languageName: node + linkType: hard + +"w3c-xmlserializer@npm:^5.0.0": + version: 5.0.0 + resolution: "w3c-xmlserializer@npm:5.0.0" + dependencies: + xml-name-validator: "npm:^5.0.0" + checksum: 10c0/8712774c1aeb62dec22928bf1cdfd11426c2c9383a1a63f2bcae18db87ca574165a0fbe96b312b73652149167ac6c7f4cf5409f2eb101d9c805efe0e4bae798b + languageName: node + linkType: hard + "wait-on@npm:7.0.1": version: 7.0.1 resolution: "wait-on@npm:7.0.1" @@ -10681,6 +11416,39 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^7.0.0": + version: 7.0.0 + resolution: "webidl-conversions@npm:7.0.0" + checksum: 10c0/228d8cb6d270c23b0720cb2d95c579202db3aaf8f633b4e9dd94ec2000a04e7e6e43b76a94509cdb30479bd00ae253ab2371a2da9f81446cc313f89a4213a2c4 + languageName: node + linkType: hard + +"whatwg-encoding@npm:^3.1.1": + version: 3.1.1 + resolution: "whatwg-encoding@npm:3.1.1" + dependencies: + iconv-lite: "npm:0.6.3" + checksum: 10c0/273b5f441c2f7fda3368a496c3009edbaa5e43b71b09728f90425e7f487e5cef9eb2b846a31bd760dd8077739c26faf6b5ca43a5f24033172b003b72cf61a93e + languageName: node + linkType: hard + +"whatwg-mimetype@npm:^4.0.0": + version: 4.0.0 + resolution: "whatwg-mimetype@npm:4.0.0" + checksum: 10c0/a773cdc8126b514d790bdae7052e8bf242970cebd84af62fb2f35a33411e78e981f6c0ab9ed1fe6ec5071b09d5340ac9178e05b52d35a9c4bcf558ba1b1551df + languageName: node + linkType: hard + +"whatwg-url@npm:^14.0.0": + version: 14.0.0 + resolution: "whatwg-url@npm:14.0.0" + dependencies: + tr46: "npm:^5.0.0" + webidl-conversions: "npm:^7.0.0" + checksum: 10c0/ac32e9ba9d08744605519bbe9e1371174d36229689ecc099157b6ba102d4251a95e81d81f3d80271eb8da182eccfa65653f07f0ab43ea66a6934e643fd091ba9 + languageName: node + linkType: hard + "which-boxed-primitive@npm:^1.0.2": version: 1.0.2 resolution: "which-boxed-primitive@npm:1.0.2" @@ -10761,6 +11529,18 @@ __metadata: languageName: node linkType: hard +"why-is-node-running@npm:^2.3.0": + version: 2.3.0 + resolution: "why-is-node-running@npm:2.3.0" + dependencies: + siginfo: "npm:^2.0.0" + stackback: "npm:0.0.2" + bin: + why-is-node-running: cli.js + checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054 + languageName: node + linkType: hard + "widest-line@npm:^4.0.1": version: 4.0.1 resolution: "widest-line@npm:4.0.1" @@ -10821,6 +11601,35 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.18.0": + version: 8.18.0 + resolution: "ws@npm:8.18.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/25eb33aff17edcb90721ed6b0eb250976328533ad3cd1a28a274bd263682e7296a6591ff1436d6cbc50fa67463158b062f9d1122013b361cec99a05f84680e06 + languageName: node + linkType: hard + +"xml-name-validator@npm:^5.0.0": + version: 5.0.0 + resolution: "xml-name-validator@npm:5.0.0" + checksum: 10c0/3fcf44e7b73fb18be917fdd4ccffff3639373c7cb83f8fc35df6001fecba7942f1dbead29d91ebb8315e2f2ff786b508f0c9dc0215b6353f9983c6b7d62cb1f5 + languageName: node + linkType: hard + +"xmlchars@npm:^2.2.0": + version: 2.2.0 + resolution: "xmlchars@npm:2.2.0" + checksum: 10c0/b64b535861a6f310c5d9bfa10834cf49127c71922c297da9d4d1b45eeaae40bf9b4363275876088fbe2667e5db028d2cd4f8ee72eed9bede840a67d57dab7593 + languageName: node + linkType: hard + "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8"