Skip to content

Commit f93e71d

Browse files
chore: migrate from Jest to Vitest
1 parent 9202bdf commit f93e71d

22 files changed

+1025
-2373
lines changed

jest.setup.js

Lines changed: 0 additions & 19 deletions
This file was deleted.

package.json

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
"jsnext:main": "lib-esm/index.js",
88
"module": "lib-esm/index.js",
99
"scripts": {
10-
"test": "jest",
11-
"test:debug": "node --inspect ./node_modules/.bin/jest --runInBand --watch",
10+
"test": "vitest run",
11+
"test:watch": "vitest",
12+
"test:ui": "vitest --ui",
1213
"test:downstream": "npm run build && test_downstream_projects",
1314
"start": "cross-env NODE_ENV=development webpack-dev-server --host 0.0.0.0 --port 8000 --config ./examples/typescript/webpack.config.js --history-api-fallback",
1415
"clean": "shx rm -rf _bundles lib lib-esm build _doc",
@@ -50,59 +51,34 @@
5051
"react": ">=16.8.0"
5152
},
5253
"devDependencies": {
53-
"@testing-library/jest-dom": "^5.14.1",
54+
"@testing-library/jest-dom": "^6.9.1",
5455
"@testing-library/react": "^12.0.0",
5556
"@types/classnames": "^2.3.1",
56-
"@types/jest": "^26.0.24",
5757
"@types/lodash": "^4.14.171",
5858
"@types/prop-types": "15.7.4",
5959
"@types/react": "17.0.14",
6060
"@types/react-dom": "17.0.9",
6161
"@uirouter/publish-scripts": "^2.6.4",
62-
"babel-jest": "^27.0.6",
62+
"@vitest/ui": "^4.0.16",
6363
"babel-polyfill": "^6.26.0",
6464
"babel-preset-es2015": "^6.24.1",
6565
"babel-preset-react": "^6.24.1",
6666
"cross-env": "^7.0.3",
6767
"husky": "^4.3.6",
68-
"jest": "27.0.6",
68+
"jsdom": "^27.4.0",
6969
"prettier": "^2.3.2",
7070
"pretty-quick": "^3.1.1",
7171
"react": "^17.0.2",
7272
"react-dom": "^17.0.2",
7373
"react-test-renderer": "^17.0.2",
74-
"ts-jest": "^27.0.4",
7574
"ts-loader": "^9.2.3",
76-
"ts-node": "^10.1.0",
7775
"tsconfig-paths-webpack-plugin": "^4.2.0",
7876
"typescript": "^4.3.5",
77+
"vitest": "^4.0.16",
7978
"webpack": "^5.101.3",
8079
"webpack-cli": "^6.0.1",
8180
"webpack-dev-server": "^5.2.2"
8281
},
83-
"jest": {
84-
"setupFiles": [
85-
"../jest.setup.js"
86-
],
87-
"rootDir": "src",
88-
"transform": {
89-
".(ts|tsx)": "ts-jest"
90-
},
91-
"testEnvironment": "jsdom",
92-
"moduleFileExtensions": [
93-
"js",
94-
"json",
95-
"ts",
96-
"tsx"
97-
],
98-
"globals": {
99-
"ts-jest": {
100-
"tsConfig": "./tsconfig.jest.json"
101-
}
102-
},
103-
"preset": "ts-jest",
104-
"restoreMocks": true
105-
},
10682
"husky": {
10783
"hooks": {
10884
"pre-commit": "pretty-quick --staged"

src/__tests__/core.test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
12
import { servicesPlugin, memoryLocationPlugin } from '@uirouter/core';
23

34
import { UIRouterReact, StartMethodCalledMoreThanOnceError } from '../index';
@@ -12,8 +13,8 @@ describe('UIRouterReact class', () => {
1213
});
1314

1415
it('starts the router with start() method', () => {
15-
let urlRouterListenSpy = jest.spyOn(router.urlService, 'listen');
16-
let urlRouterSyncSpy = jest.spyOn(router.urlService, 'sync');
16+
let urlRouterListenSpy = vi.spyOn(router.urlService, 'listen');
17+
let urlRouterSyncSpy = vi.spyOn(router.urlService, 'sync');
1718
router.start();
1819
expect(urlRouterListenSpy).toHaveBeenCalled();
1920
expect(urlRouterSyncSpy).toHaveBeenCalled();

src/__tests__/util.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import { describe, expect, it, vi } from 'vitest';
23
import { TransitionOptions, RawParams, StateOrName, TransitionPromise, memoryLocationPlugin } from '@uirouter/core';
34
import { render } from '@testing-library/react';
45
import { act } from 'react-dom/test-utils';
@@ -31,7 +32,7 @@ export const makeTestRouter = (states: ReactStateDeclaration[]) => {
3132

3233
// silence console errors that are logged by react-dom or other actors
3334
export function muteConsoleErrors() {
34-
jest.spyOn(console, 'error').mockImplementation(() => undefined);
35+
vi.spyOn(console, 'error').mockImplementation(() => undefined);
3536
}
3637

3738
export function defer<T = any>() {

src/components/__tests__/UIRouter.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
12
import { render } from '@testing-library/react';
23
import * as React from 'react';
34
import * as PropTypes from 'prop-types';
@@ -54,7 +55,7 @@ describe('<UIRouter>', () => {
5455
it('starts the router', () => {
5556
const router = new UIRouterReact();
5657
router.plugin(memoryLocationPlugin);
57-
const spy = jest.spyOn(router, 'start');
58+
const spy = vi.spyOn(router, 'start');
5859
render(
5960
<UIRouter router={router}>
6061
<UIRouterContext.Consumer>{(router) => <Child router={router} />}</UIRouterContext.Consumer>

src/components/__tests__/UISref.test.tsx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
12
import { fireEvent } from '@testing-library/react';
23
import * as React from 'react';
34
import { UISref, UIView } from '../../components';
@@ -22,10 +23,6 @@ const states = [
2223
];
2324

2425
describe('<UISref>', () => {
25-
let mockUseEffect: any;
26-
beforeEach(() => (mockUseEffect = jest.spyOn(React, 'useEffect').mockImplementation(React.useLayoutEffect)));
27-
afterEach(() => mockUseEffect.mockRestore());
28-
2926
let { router, routerGo, mountInRouter } = makeTestRouter([]);
3027
beforeEach(() => ({ router, routerGo, mountInRouter } = makeTestRouter(states)));
3128

@@ -36,7 +33,7 @@ describe('<UISref>', () => {
3633
</UISref>
3734
);
3835
await routerGo('state');
39-
const goSpy = jest.spyOn(router.stateService, 'go');
36+
const goSpy = vi.spyOn(router.stateService, 'go');
4037
const anchor = wrapper.getByTestId('anchor');
4138
expect(anchor.getAttribute('href').includes('/state2')).toBe(true);
4239
anchor.click();
@@ -51,8 +48,8 @@ describe('<UISref>', () => {
5148
it('registers and deregisters active state from parent UISrefActive when mounting/unmounting', async () => {
5249
await routerGo('state');
5350

54-
const deregisterFn = jest.fn();
55-
const parentUISrefActiveAddStateFn = jest.fn(() => deregisterFn);
51+
const deregisterFn = vi.fn();
52+
const parentUISrefActiveAddStateFn = vi.fn(() => deregisterFn);
5653

5754
mountInRouter(
5855
<UISrefActiveContext.Provider value={parentUISrefActiveAddStateFn}>
@@ -66,7 +63,7 @@ describe('<UISref>', () => {
6663
});
6764

6865
it('triggers a transition to target state', async () => {
69-
const goSpy = jest.spyOn(router.stateService, 'go');
66+
const goSpy = vi.spyOn(router.stateService, 'go');
7067
const rendered = mountInRouter(
7168
<UISref to="state2">
7269
<a data-testid="anchor" />
@@ -81,8 +78,8 @@ describe('<UISref>', () => {
8178

8279
it('calls the child elements onClick function first', async () => {
8380
const log = [];
84-
const goSpy = jest.spyOn(router.stateService, 'go').mockImplementation(() => log.push('go') as any);
85-
const onClickSpy = jest.fn(() => log.push('onClick'));
81+
const goSpy = vi.spyOn(router.stateService, 'go').mockImplementation(() => log.push('go') as any);
82+
const onClickSpy = vi.fn(() => log.push('onClick'));
8683
const rendered = mountInRouter(
8784
<UISref to="state2">
8885
<a data-testid="anchor" onClick={onClickSpy}>
@@ -98,8 +95,8 @@ describe('<UISref>', () => {
9895
});
9996

10097
it('calls the child elements onClick function and honors e.preventDefault()', async () => {
101-
const goSpy = jest.spyOn(router.stateService, 'go');
102-
const onClickSpy = jest.fn((e) => e.preventDefault());
98+
const goSpy = vi.spyOn(router.stateService, 'go');
99+
const onClickSpy = vi.fn((e) => e.preventDefault());
103100
const rendered = mountInRouter(
104101
<UISref to="state2">
105102
<a data-testid="anchor" onClick={onClickSpy}>
@@ -114,7 +111,7 @@ describe('<UISref>', () => {
114111
});
115112

116113
it("doesn't trigger a transition when middle-clicked", async () => {
117-
const stateServiceGoSpy = jest.spyOn(router.stateService, 'go');
114+
const stateServiceGoSpy = vi.spyOn(router.stateService, 'go');
118115
const rendered = mountInRouter(
119116
<UISref to="state2">
120117
<a data-testid="anchor">state2</a>
@@ -130,7 +127,7 @@ describe('<UISref>', () => {
130127
});
131128

132129
it("doesn't trigger a transition when ctrl/meta/shift/alt+clicked", async () => {
133-
const stateServiceGoSpy = jest.spyOn(router.stateService, 'go');
130+
const stateServiceGoSpy = vi.spyOn(router.stateService, 'go');
134131
const rendered = mountInRouter(
135132
<UISref to="state2">
136133
<a data-testid="anchor">state2</a>
@@ -155,7 +152,7 @@ describe('<UISref>', () => {
155152
});
156153

157154
it("doesn't trigger a transition when the anchor has a 'target' attribute", async () => {
158-
const stateServiceGoSpy = jest.spyOn(router.stateService, 'go');
155+
const stateServiceGoSpy = vi.spyOn(router.stateService, 'go');
159156
const rendered = mountInRouter(
160157
<UISref to="state2">
161158
<a data-testid="anchor" target="_blank">

src/components/__tests__/UISrefActive.test.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { render } from '@testing-library/react';
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { render, waitFor } from '@testing-library/react';
23
import * as React from 'react';
34
import { makeTestRouter } from '../../__tests__/util';
45
import { ReactStateDeclaration } from '../../index';
@@ -14,8 +15,6 @@ const states: ReactStateDeclaration[] = [
1415
describe('<UISrefActive>', () => {
1516
let { router, routerGo, mountInRouter } = makeTestRouter([]);
1617
beforeEach(() => ({ router, routerGo, mountInRouter } = makeTestRouter(states)));
17-
beforeEach(() => jest.spyOn(React, 'useEffect').mockImplementation(React.useLayoutEffect));
18-
afterEach(() => (React.useEffect as any).mockRestore());
1918

2019
function UISrefActiveTestComponent(props: {
2120
to?: string;
@@ -55,14 +54,14 @@ describe('<UISrefActive>', () => {
5554
});
5655

5756
it('registers onSuccess transition hook to listen for state changes', async () => {
58-
const onSuccessSpy = jest.spyOn(router.transitionService, 'onSuccess');
57+
const onSuccessSpy = vi.spyOn(router.transitionService, 'onSuccess');
5958
mountInRouter(<UISrefActiveTestComponent />);
6059
expect(onSuccessSpy).toHaveBeenCalled();
6160
});
6261

6362
it('deregisters the transition hook when unmounted', async () => {
64-
const deregisterSpy = jest.fn();
65-
jest.spyOn(router.transitionService, 'onSuccess').mockImplementation(() => deregisterSpy);
63+
const deregisterSpy = vi.fn();
64+
vi.spyOn(router.transitionService, 'onSuccess').mockImplementation(() => deregisterSpy);
6665
const Component = () => {
6766
const [show, setShow] = React.useState(true);
6867
return (
@@ -78,7 +77,7 @@ describe('<UISrefActive>', () => {
7877
const rendered = mountInRouter(<Component />);
7978
expect(deregisterSpy).not.toHaveBeenCalled();
8079
rendered.getByTestId('btn').click();
81-
expect(deregisterSpy).toHaveBeenCalled();
80+
await waitFor(() => expect(deregisterSpy).toHaveBeenCalled());
8281
});
8382

8483
it('works with state parameters', async () => {
@@ -200,15 +199,16 @@ describe('<UISrefActive>', () => {
200199
);
201200
};
202201

202+
await routerGo('parent.child1');
203+
const rendered = render(<Comp />);
204+
203205
const classFor = (testid: string) =>
204206
rendered.getByTestId(testid).getAttribute('class').split(/ +/).sort().join(' ');
205207

206-
await routerGo('parent.child1');
207-
const rendered = render(<Comp />);
208208
expect(classFor('div')).toBe('active baseclass');
209209

210210
rendered.getByTestId('hidebtn').click();
211-
expect(classFor('div')).toBe('baseclass');
211+
await waitFor(() => expect(classFor('div')).toBe('baseclass'));
212212
});
213213

214214
it('checks for exact state match when exact prop is provided', async () => {

src/components/__tests__/UIView.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
12
import { render } from '@testing-library/react';
23
import * as React from 'react';
34
import { act } from 'react-dom/test-utils';
4-
// import { mount } from 'enzyme';
55
import { Transition } from '@uirouter/core';
66

77
import { makeTestRouter, muteConsoleErrors } from '../../__tests__/util';
@@ -206,7 +206,7 @@ describe('<UIView>', () => {
206206
}
207207

208208
it('calls the uiCanExit function of a Class Component when unmounting', async () => {
209-
const uiCanExitSpy = jest.fn();
209+
const uiCanExitSpy = vi.fn();
210210
router.stateRegistry.register({ name: '__state', component: makeSpyComponent(uiCanExitSpy) } as any);
211211

212212
await routerGo('__state');
@@ -219,7 +219,7 @@ describe('<UIView>', () => {
219219
});
220220

221221
it('calls uiCanExit function of a React.forwardRef() Class Component when unmounting', async () => {
222-
const uiCanExitSpy = jest.fn();
222+
const uiCanExitSpy = vi.fn();
223223
const Comp = makeSpyComponent(uiCanExitSpy);
224224
const ForwardRef = React.forwardRef((props, ref: any) => <Comp {...props} ref={ref} />);
225225
router.stateRegistry.register({ name: '__state', component: ForwardRef } as ReactStateDeclaration);
@@ -234,7 +234,7 @@ describe('<UIView>', () => {
234234
});
235235

236236
it('does not transition if uiCanExit function of its State Component returns false', async () => {
237-
let uiCanExitSpy = jest.fn().mockImplementation(() => false);
237+
let uiCanExitSpy = vi.fn().mockImplementation(() => false);
238238
router.stateRegistry.register({ name: '__state', component: makeSpyComponent(uiCanExitSpy) } as any);
239239
await routerGo('__state');
240240
const rendered = mountInRouter(<UIView />);
@@ -250,8 +250,8 @@ describe('<UIView>', () => {
250250

251251
it('deregisters the UIView when unmounted', () => {
252252
const Component = (props) => <UIRouter router={router}>{props.show ? <UIView /> : <div />}</UIRouter>;
253-
const deregisterSpy = jest.fn();
254-
jest.spyOn(router.viewService, 'registerUIView').mockImplementation(() => deregisterSpy);
253+
const deregisterSpy = vi.fn();
254+
vi.spyOn(router.viewService, 'registerUIView').mockImplementation(() => deregisterSpy);
255255
const rendered = render(<Component show={true} />);
256256
rendered.rerender(<Component show={false} />);
257257
expect(deregisterSpy).toHaveBeenCalled();
@@ -268,8 +268,8 @@ describe('<UIView>', () => {
268268
});
269269

270270
it('unmounts the State Component when calling stateService.reload(true)', async () => {
271-
const componentDidMountSpy = jest.fn();
272-
const componentWillUnmountSpy = jest.fn();
271+
const componentDidMountSpy = vi.fn();
272+
const componentWillUnmountSpy = vi.fn();
273273
class TestUnmountComponent extends React.Component {
274274
componentDidMount = componentDidMountSpy;
275275
componentWillUnmount = componentWillUnmountSpy;

0 commit comments

Comments
 (0)