Skip to content

Commit c915219

Browse files
authored
Merge pull request #1544 from silx-kit/vitest
Replace Jest with Vitest
2 parents bb56611 + c16b102 commit c915219

39 files changed

+1270
-1370
lines changed

.github/workflows/lint-test.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ jobs:
7676
run: pnpm install --frozen-lockfile
7777

7878
- name: Test 👓
79-
run: pnpm test -- --reporters="default" --reporters="github-actions"
80-
env:
81-
CI: true
79+
run: pnpm test -- --reporter default --reporter vitest-github-actions-reporter
8280

8381
packages:
8482
runs-on: ubuntu-latest

CONTRIBUTING.md

+18-14
Original file line numberDiff line numberDiff line change
@@ -198,27 +198,29 @@ install the recommended extensions.
198198

199199
## Testing
200200

201-
- `pnpm test` - run unit and feature tests with Jest
202-
- `pnpm test --watch` - run tests related to changed files in watch mode
203-
- `pnpm test --watchAll` - run all tests in watch mode
204-
- `pnpm --filter <project-name> test` - run Jest in a specific project
201+
- `pnpm test` - run unit and feature tests with [Vitest](https://vitest.dev/) in
202+
watch mode (or once when on the CI)
203+
- `pnpm test run` - run unit and feature tests once
204+
- `pnpm test [run] <filter>` - run tests matching the given filter
205+
- `pnpm test -- --project <lib|app|...>` - run Vitest on a specific project
206+
- `pnpm test:ui` - run tests inside the
207+
[Vitest UI](https://vitest.dev/guide/ui.html)
205208
- `pnpm cypress` - open the
206209
[Cypress](https://docs.cypress.io/guides/overview/why-cypress.html) end-to-end
207210
test runner (local dev server must be running in separate terminal)
208211
- `pnpm cypress:run` - run end-to-end tests once (local dev server must be
209212
running in separate terminal)
210213

211-
> Note that the workspace's `test` script doesn't recursively run the `test`
212-
> script in every project like (i.e. it is not equivalent to `pnpm -r test`).
213-
> Instead, it runs Jest globally using a
214-
> [`projects` configuration](https://jestjs.io/docs/configuration#projects-arraystring--projectconfig)
215-
> located in `jest.config.json`. This results in a nicer terminal output when
216-
> running tests on the entire workspace.
214+
> Vitest is able to run on the entire monorepo thanks to the
215+
> [workspace configuration](https://vitest.dev/guide/workspace.html) defined in
216+
> `vitest.workspace.ts`. It then uses each project's Vite configuration to
217+
> decide how to run the tests.
217218
218219
### Feature tests
219220

220221
The `@h5web/app` package includes feature tests written with
221-
[React Testing Library](https://testing-library.com/docs/react-testing-library/intro).
222+
[React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
223+
and running in a [JSDOM environment](https://vitest.dev/guide/environment.html).
222224
They are located under `src/__tests__`. Each file covers a particular subtree of
223225
components of H5Web.
224226

@@ -237,9 +239,11 @@ would normally; they just don't stick around in the DOM for long.
237239
This adds a bit of complexity when testing, as React doesn't like when something
238240
happens after a test has completed. In fact, we have to ensure that every
239241
component that suspends inside a test **finishes loading before the end of that
240-
test**. This is where Testing Library's
241-
[asynchronous methods](https://testing-library.com/docs/dom-testing-library/api-async)
242-
come in.
242+
test**. To do so, you can use Testing Library's asynchronous APIs for
243+
[finding elements](https://testing-library.com/docs/dom-testing-library/api-async/#findby-queries)
244+
and [interacting with them](https://testing-library.com/docs/user-event), as
245+
well as Vitest's [`waitFor``](https://vitest.dev/api/vi.html#vi-waitfor-0-34-5)
246+
utility.
243247

244248
#### Fake timers
245249

eslint.shared.js

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ module.exports = {
117117
}),
118118
createJestOverride({
119119
...dependencies,
120+
hasJest: /(app|lib|shared)$/u.test(cwd), // until Galex starts supporting Vitest
120121
rules: {
121122
'jest/no-focused-tests': 'warn', // warning instead of error
122123
'jest/prefer-strict-equal': 'off', // `toEqual` is shorter and sufficient in most cases

jest.config.js

-7
This file was deleted.

package.json

+6-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
"lint:cypress:tsc": "tsc --project cypress/tsconfig.json",
2929
"lint:root:eslint": "eslint \"**/*.{js,cjs,ts,tsx}\" --max-warnings=0",
3030
"prettier": "prettier . --cache --check",
31-
"test": "jest",
31+
"test": "vitest",
32+
"test:ui": "vitest --ui",
3233
"cypress": "cypress open --e2e --browser firefox",
3334
"cypress:run": "cypress run --e2e",
3435
"version": "pnpm -r sync-version && git add .",
@@ -37,18 +38,18 @@
3738
"devDependencies": {
3839
"@simonsmith/cypress-image-snapshot": "9.0.1",
3940
"@testing-library/cypress": "10.0.1",
40-
"@types/jest": "^29.5.11",
4141
"@types/node": "^20.10.5",
42+
"@vitest/ui": "1.1.3",
4243
"cypress": "13.6.1",
4344
"cypress-wait-for-stable-dom": "0.1.0",
4445
"eslint": "8.56.0",
4546
"eslint-config-galex": "4.5.2",
46-
"identity-obj-proxy": "3.0.0",
47-
"jest": "29.7.0",
4847
"npm-run-all": "4.1.5",
4948
"prettier": "3.1.1",
50-
"ts-jest": "29.1.1",
5149
"typescript": "5.0.4",
50+
"vitest": "1.1.3",
51+
"vitest-fail-on-console": "0.5.1",
52+
"vitest-github-actions-reporter": "0.11.1",
5253
"wait-on": "7.2.0"
5354
},
5455
"pnpm": {

packages/app/jest.config.js

-31
This file was deleted.

packages/app/package.json

+3-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"build:dts": "tsc --build tsconfig.build.json && rollup -c",
3535
"lint:eslint": "eslint \"**/*.{js,cjs,ts,tsx}\" --max-warnings=0",
3636
"lint:tsc": "tsc",
37-
"test": "jest",
3837
"analyze": "pnpm dlx source-map-explorer dist/index.js --no-border-checks",
3938
"prepack": "dot-json package.json -d type",
4039
"sync-version": "dot-json ../../package.json version | xargs dot-json package.json version"
@@ -85,15 +84,15 @@
8584
"dot-json": "1.3.0",
8685
"eslint": "8.56.0",
8786
"eslint-config-galex": "4.5.2",
88-
"jest": "29.7.0",
89-
"jest-environment-jsdom": "29.7.0",
87+
"jsdom": "23.2.0",
9088
"npm-run-all": "4.1.5",
9189
"react": "18.2.0",
9290
"react-dom": "18.2.0",
9391
"rimraf": "5.0.5",
9492
"rollup": "4.9.0",
9593
"rollup-plugin-dts": "6.1.0",
9694
"typescript": "5.0.4",
97-
"vite": "5.0.9"
95+
"vite": "5.0.9",
96+
"vitest": "1.1.3"
9897
}
9998
}

packages/app/src/__tests__/CorePack.test.tsx

+3-12
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
import { screen, within } from '@testing-library/react';
2+
import { expect, test } from 'vitest';
23

34
import { SLOW_TIMEOUT } from '../providers/mock/mock-api';
4-
import {
5-
getSelectedVisTab,
6-
getVisTabs,
7-
renderApp,
8-
waitForAllLoaders,
9-
} from '../test-utils';
5+
import { getSelectedVisTab, getVisTabs, renderApp } from '../test-utils';
106
import { Vis } from '../vis-packs/core/visualizations';
117

128
test('visualize raw dataset', async () => {
@@ -75,12 +71,7 @@ test('visualize 2D boolean dataset', async () => {
7571
});
7672

7773
test('visualize 2D complex dataset', async () => {
78-
const { user } = await renderApp({
79-
initialPath: '/nD_datasets/twoD_cplx',
80-
withFakeTimers: true, // required since React 18 upgrade (along with `waitForAllLoaders` below)
81-
});
82-
83-
await waitForAllLoaders();
74+
const { user } = await renderApp('/nD_datasets/twoD_cplx');
8475

8576
expect(getVisTabs()).toEqual([Vis.Matrix, Vis.Line, Vis.Heatmap]);
8677
expect(getSelectedVisTab()).toBe(Vis.Heatmap);

packages/app/src/__tests__/DimensionMapper.test.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { screen, waitFor, within } from '@testing-library/react';
1+
import { screen, within } from '@testing-library/react';
2+
import { expect, test, vi } from 'vitest';
23

34
import { renderApp, waitForAllLoaders } from '../test-utils';
45
import { Vis } from '../vis-packs/core/visualizations';
@@ -29,7 +30,7 @@ test('control mapping for X axis when visualizing 2D dataset as Line', async ()
2930

3031
// Change mapping from [0, 'x'] to ['x', 0]
3132
await user.click(xDimsButtons[0]);
32-
await waitFor(() => expect(xDimsButtons[0]).toBeChecked());
33+
await vi.waitFor(() => expect(xDimsButtons[0]).toBeChecked());
3334
expect(xDimsButtons[1]).not.toBeChecked();
3435

3536
// Ensure that the dimension slider is now for D1
@@ -62,7 +63,7 @@ test('control mapping for X and Y axes when visualizing 2D dataset as Heatmap',
6263

6364
// Change mapping from ['y', 'x'] to ['x', 'y']
6465
await user.click(xD0Button);
65-
await waitFor(() => expect(xD0Button).toBeChecked());
66+
await vi.waitFor(() => expect(xD0Button).toBeChecked());
6667
expect(xD1Button).not.toBeChecked();
6768
expect(yD0Button).not.toBeChecked();
6869
expect(yD1Button).toBeChecked();

packages/app/src/__tests__/DomainWidget.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { screen, within } from '@testing-library/react';
2+
import { expect, test } from 'vitest';
23

34
import { renderApp } from '../test-utils';
45

packages/app/src/__tests__/Explorer.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { screen } from '@testing-library/react';
2+
import { expect, test } from 'vitest';
23

34
import { SLOW_TIMEOUT } from '../providers/mock/mock-api';
45
import { renderApp } from '../test-utils';

packages/app/src/__tests__/MetadataViewer.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { screen } from '@testing-library/react';
2+
import { expect, test } from 'vitest';
23

34
import { renderApp } from '../test-utils';
45

packages/app/src/__tests__/NexusPack.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { screen } from '@testing-library/react';
2+
import { expect, test } from 'vitest';
23

34
import { SLOW_TIMEOUT } from '../providers/mock/mock-api';
45
import {

packages/app/src/__tests__/VisSelector.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { screen } from '@testing-library/react';
2+
import { expect, test } from 'vitest';
23

34
import { getSelectedVisTab, renderApp } from '../test-utils';
45
import { Vis } from '../vis-packs/core/visualizations';

packages/app/src/__tests__/Visualizer.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { screen } from '@testing-library/react';
2+
import { expect, test } from 'vitest';
23

34
import { SLOW_TIMEOUT } from '../providers/mock/mock-api';
45
import { mockConsoleMethod, renderApp } from '../test-utils';

packages/app/src/explorer/EntityItem.tsx

+18-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import { isGroup } from '@h5web/shared/guards';
22
import type { ChildEntity } from '@h5web/shared/hdf5-models';
33
import { useToggle } from '@react-hookz/web';
44
import type { CSSProperties, KeyboardEvent } from 'react';
5-
import { Suspense, useCallback, useEffect, useRef } from 'react';
5+
import {
6+
Suspense,
7+
useCallback,
8+
useEffect,
9+
useLayoutEffect,
10+
useRef,
11+
} from 'react';
612
import { ErrorBoundary } from 'react-error-boundary';
713
import { FiRefreshCw } from 'react-icons/fi';
814

@@ -32,17 +38,20 @@ function EntityItem(props: Props) {
3238

3339
const btnRef = useRef<HTMLButtonElement>(null);
3440

35-
const [isExpanded, toggleExpanded] = useToggle(false);
41+
// Group AND (selected OR parent of selected entity)
42+
const shouldBeExpanded =
43+
isGroup(entity) &&
44+
(selectedPath === path || selectedPath.startsWith(`${path}/`));
3645

37-
useEffect(() => {
38-
if (
39-
isGroup(entity) &&
40-
(selectedPath === path || selectedPath.startsWith(`${path}/`))
41-
) {
42-
// If group is selected or is parent of selected entity, expand it
46+
const [isExpanded, toggleExpanded] = useToggle(shouldBeExpanded);
47+
48+
useLayoutEffect(() => {
49+
if (shouldBeExpanded) {
50+
// Expand group if needed, notably when selected path changes
51+
// e.g. when navigating via NX attributes
4352
toggleExpanded(true);
4453
}
45-
}, [entity, path, selectedPath, toggleExpanded]);
54+
}, [shouldBeExpanded, toggleExpanded]);
4655

4756
// When tabbing in, restore focus on the selected element
4857
useEffect(() => {

packages/app/src/metadata-viewer/utils.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { describe, expect, it } from 'vitest';
2+
13
import { renderShape } from './utils';
24

35
describe('renderShape', () => {

packages/app/src/providers/h5grove/utils.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
uintType,
1010
unknownType,
1111
} from '@h5web/shared/hdf5-utils';
12+
import { describe, expect, it } from 'vitest';
1213

1314
import { convertH5GroveDtype } from './utils';
1415

packages/app/src/providers/hsds/utils.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
uintType,
1212
unknownType,
1313
} from '@h5web/shared/hdf5-utils';
14+
import { describe, expect, it } from 'vitest';
1415

1516
import type {
1617
HsdsArrayType,

packages/app/src/providers/mock/utils.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { group, scalar } from '@h5web/shared/mock-utils';
2+
import { describe, expect, it } from 'vitest';
23

34
import { findMockEntity } from './utils';
45

0 commit comments

Comments
 (0)