Skip to content

Use Vitest browser to test react-admin #10479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -87,6 +87,8 @@ jobs:
cache: 'yarn'
- name: Install dependencies
run: yarn
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Unit Tests
run: make test-unit
env:
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -23,3 +23,4 @@ cypress/screenshots
!.yarn/releases
!.yarn/sdks
!.yarn/versions
__screenshots__
15 changes: 0 additions & 15 deletions __mocks__/@popperjs/core.ts

This file was deleted.

41 changes: 0 additions & 41 deletions jest.config.js

This file was deleted.

19 changes: 8 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -4,9 +4,9 @@
"scripts": {
"build": "lerna run build",
"watch": "lerna run --parallel watch",
"test-unit": "cross-env NODE_ENV=test cross-env BABEL_ENV=cjs NODE_ICU_DATA=./node_modules/full-icu jest",
"test-unit-ci": "cross-env NODE_ENV=test cross-env BABEL_ENV=cjs NODE_ICU_DATA=./node_modules/full-icu jest --runInBand",
"test-e2e": "yarn run -s build && cross-env NODE_ENV=test && cd cypress && yarn test",
"test-unit": "cross-env NODE_ENV=test cross-env BABEL_ENV=cjs NODE_ICU_DATA=./node_modules/full-icu vitest run --no-file-parallelism --browser.headless",
"test-unit-ci": "cross-env NODE_ENV=test cross-env BABEL_ENV=cjs NODE_ICU_DATA=./node_modules/full-icu vitest run --no-file-parallelism",
"test-e2e": "yarn run -s build && cross-env NODE_ENV=test && cd cypress && yarn test",
"test-e2e-local": "cd cypress && yarn start",
"test": "yarn test-unit && yarn test-e2e",
"doc": "cd docs && jekyll server . --watch --host 0.0.0.0",
@@ -32,10 +32,11 @@
"@storybook/react": "^8.4.4",
"@storybook/react-webpack5": "^8.4.4",
"@storybook/source-loader": "patch:@storybook/source-loader@npm%3A8.4.4#~/.yarn/patches/@storybook-source-loader-npm-8.4.4-55dafc88e2.patch",
"@types/jest": "^29.5.2",
"@types/react": "^18.3.3",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/browser": "^3.0.4",
"cross-env": "^5.2.0",
"eslint": "^8.19.0",
"eslint-config-prettier": "^9.1.0",
@@ -44,23 +45,19 @@
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-testing-library": "^5.11.0",
"full-icu": "^1.3.1",
"global-jsdom": "^9.0.1",
"husky": "^2.3.0",
"jest": "^29.5.0",
"jest-circus": "29.5.0",
"jest-environment-jsdom": "^29.5.0",
"jest-resolve": "29.5.0",
"jest-watch-typeahead": "2.2.2",
"lerna": "~7.1.3",
"lint-staged": "^13.0.3",
"lolex": "~2.3.2",
"playwright": "^1.50.0",
"prettier": "~3.2.5",
"raf": "~3.4.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"storybook": "^8.4.4",
"ts-jest": "^29.1.0",
"typescript": "^5.1.3",
"vitest": "^3.0.4",
"vitest-browser-react": "^0.0.4",
"whatwg-fetch": "^3.0.0"
},
"workspaces": [
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import { Routes, Route, useLocation } from 'react-router-dom';
@@ -20,12 +20,12 @@ describe('<Authenticated>', () => {
const authProvider = {
login: () => Promise.reject('bad method'),
logout: () => Promise.reject('bad method'),
checkAuth: jest.fn().mockResolvedValueOnce(''),
checkAuth: vi.fn().mockResolvedValueOnce(''),
checkError: () => Promise.reject('bad method'),
getPermissions: () => Promise.reject('bad method'),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

render(
<CoreAdminContext authProvider={authProvider} store={store}>
@@ -40,14 +40,14 @@ describe('<Authenticated>', () => {

it('should logout, redirect to login and show a notification after a tick if the auth fails', async () => {
const authProvider = {
login: jest.fn().mockResolvedValue(''),
logout: jest.fn().mockResolvedValue(''),
checkAuth: jest.fn().mockRejectedValue(undefined),
checkError: jest.fn().mockResolvedValue(''),
getPermissions: jest.fn().mockResolvedValue(''),
login: vi.fn().mockResolvedValue(''),
logout: vi.fn().mockResolvedValue(''),
checkAuth: vi.fn().mockRejectedValue(undefined),
checkError: vi.fn().mockResolvedValue(''),
getPermissions: vi.fn().mockResolvedValue(''),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');
const history = createMemoryHistory();

const Login = () => {
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { TestMemoryRouter } from 'react-admin';
import { Routes, Route, useLocation } from 'react-router-dom';
@@ -20,12 +20,12 @@ describe('<Authenticated>', () => {
const authProvider = {
login: () => Promise.reject('bad method'),
logout: () => Promise.reject('bad method'),
checkAuth: jest.fn().mockResolvedValueOnce(''),
checkAuth: vi.fn().mockResolvedValueOnce(''),
checkError: () => Promise.reject('bad method'),
getPermissions: () => Promise.reject('bad method'),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

render(
<CoreAdminContext authProvider={authProvider} store={store}>
@@ -40,14 +40,14 @@ describe('<Authenticated>', () => {

it('should logout, redirect to login and show a notification after a tick if the auth fails', async () => {
const authProvider = {
login: jest.fn().mockResolvedValue(''),
logout: jest.fn().mockResolvedValue(''),
checkAuth: jest.fn().mockRejectedValue(undefined),
checkError: jest.fn().mockResolvedValue(''),
getPermissions: jest.fn().mockResolvedValue(''),
login: vi.fn().mockResolvedValue(''),
logout: vi.fn().mockResolvedValue(''),
checkAuth: vi.fn().mockRejectedValue(undefined),
checkError: vi.fn().mockResolvedValue(''),
getPermissions: vi.fn().mockResolvedValue(''),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

const Login = () => {
const location = useLocation();
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import {
screen,
waitFor,
} from '@testing-library/react';
import expect from 'expect';
import { expect } from 'vitest';
import { createMemoryHistory } from 'history';
import * as React from 'react';
import { MemoryRouter, Route, Routes } from 'react-router';
@@ -40,7 +40,7 @@ describe('useEditController', () => {
};

it('should call the dataProvider.getOne() function on mount', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -60,7 +60,7 @@ describe('useEditController', () => {
});

it('should decode the id from the route params', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 'test?', title: 'hello' } })
@@ -95,7 +95,7 @@ describe('useEditController', () => {
});

it('should use the id provided through props if any', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -130,7 +130,7 @@ describe('useEditController', () => {
});

it('should return the `redirect` provided through props or the default', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -157,13 +157,13 @@ describe('useEditController', () => {

describe('queryOptions', () => {
it('should accept custom client query options', async () => {
const mock = jest
const mock = vi
.spyOn(console, 'error')
.mockImplementation(() => {});
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() => Promise.reject(new Error()));
const onError = jest.fn();
const onError = vi.fn();
const dataProvider = { getOne } as unknown as DataProvider;
render(
<CoreAdminContext dataProvider={dataProvider}>
@@ -184,7 +184,7 @@ describe('useEditController', () => {
});

it('should accept a meta in query options', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -211,7 +211,7 @@ describe('useEditController', () => {
});

it('should call the dataProvider.update() function on save', async () => {
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -255,7 +255,7 @@ describe('useEditController', () => {

it('should return an undoable save callback by default', async () => {
let post = { id: 12, test: 'previous' };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -307,7 +307,7 @@ describe('useEditController', () => {

it('should return an immediate save callback when mutationMode is pessimistic', async () => {
let post = { id: 12 };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -392,7 +392,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -430,7 +430,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -468,7 +468,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -499,13 +499,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -538,13 +538,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in optimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -591,7 +591,7 @@ describe('useEditController', () => {

it('should accept meta in mutationOptions', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -629,7 +629,7 @@ describe('useEditController', () => {

it('should accept meta as a save option', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -669,8 +669,8 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccessSave = jest.fn();
const onSuccess = vi.fn();
const onSuccessSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -710,7 +710,7 @@ describe('useEditController', () => {
});

it('should execute error side effects on error in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
@@ -749,14 +749,14 @@ describe('useEditController', () => {
});

it('should allow the save onError option to override the failure side effects override', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onErrorSave = jest.fn();
const onError = vi.fn();
const onErrorSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -797,7 +797,7 @@ describe('useEditController', () => {

it('should allow transform to transform the data before save', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -806,7 +806,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -839,7 +839,7 @@ describe('useEditController', () => {

it('should allow the save transform option to override the transform side effect', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -848,8 +848,8 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn();
const transformSave = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn();
const transformSave = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -889,7 +889,7 @@ describe('useEditController', () => {

it('should allow to register middlewares', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -899,7 +899,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
});
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = jest.fn(
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = vi.fn(
(resource, params, options, next) => {
return next(
resource,
@@ -964,7 +964,7 @@ describe('useEditController', () => {

it('should return errors from the update call in pessimistic mode', async () => {
let post = { id: 12 };
const update = jest.fn().mockImplementationOnce(() => {
const update = vi.fn().mockImplementationOnce(() => {
return Promise.reject({ body: { errors: { foo: 'invalid' } } });
});
const dataProvider = {
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import {
screen,
waitFor,
} from '@testing-library/react';
import expect from 'expect';
import { expect } from 'vitest';
import { TestMemoryRouter } from 'react-admin';
import * as React from 'react';
import { MemoryRouter, Route, Routes } from 'react-router';
@@ -40,7 +40,7 @@ describe('useEditController', () => {
};

it('should call the dataProvider.getOne() function on mount', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -60,7 +60,7 @@ describe('useEditController', () => {
});

it('should decode the id from the route params', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 'test?', title: 'hello' } })
@@ -94,7 +94,7 @@ describe('useEditController', () => {
});

it('should use the id provided through props if any', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -128,7 +128,7 @@ describe('useEditController', () => {
});

it('should return the `redirect` provided through props or the default', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -155,13 +155,13 @@ describe('useEditController', () => {

describe('queryOptions', () => {
it('should accept custom client query options', async () => {
const mock = jest
const mock = vi
.spyOn(console, 'error')
.mockImplementation(() => {});
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() => Promise.reject(new Error()));
const onError = jest.fn();
const onError = vi.fn();
const dataProvider = { getOne } as unknown as DataProvider;
render(
<CoreAdminContext dataProvider={dataProvider}>
@@ -182,7 +182,7 @@ describe('useEditController', () => {
});

it('should accept a meta in query options', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -209,7 +209,7 @@ describe('useEditController', () => {
});

it('should call the dataProvider.update() function on save', async () => {
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -253,7 +253,7 @@ describe('useEditController', () => {

it('should return an undoable save callback by default', async () => {
let post = { id: 12, test: 'previous' };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -305,7 +305,7 @@ describe('useEditController', () => {

it('should return an immediate save callback when mutationMode is pessimistic', async () => {
let post = { id: 12 };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -390,7 +390,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -428,7 +428,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -466,7 +466,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -497,13 +497,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -536,13 +536,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in optimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -589,7 +589,7 @@ describe('useEditController', () => {

it('should accept meta in mutationOptions', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -627,7 +627,7 @@ describe('useEditController', () => {

it('should accept meta as a save option', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -667,8 +667,8 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccessSave = jest.fn();
const onSuccess = vi.fn();
const onSuccessSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -708,7 +708,7 @@ describe('useEditController', () => {
});

it('should execute error side effects on error in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
@@ -747,14 +747,14 @@ describe('useEditController', () => {
});

it('should allow the save onError option to override the failure side effects override', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onErrorSave = jest.fn();
const onError = vi.fn();
const onErrorSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -795,7 +795,7 @@ describe('useEditController', () => {

it('should allow transform to transform the data before save', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -804,7 +804,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -837,7 +837,7 @@ describe('useEditController', () => {

it('should allow the save transform option to override the transform side effect', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -846,8 +846,8 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn();
const transformSave = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn();
const transformSave = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -887,7 +887,7 @@ describe('useEditController', () => {

it('should allow to register middlewares', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -897,7 +897,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
});
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = jest.fn(
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = vi.fn(
(resource, params, options, next) => {
return next(
resource,
@@ -962,7 +962,7 @@ describe('useEditController', () => {

it('should return errors from the update call in pessimistic mode', async () => {
let post = { id: 12 };
const update = jest.fn().mockImplementationOnce(() => {
const update = vi.fn().mockImplementationOnce(() => {
return Promise.reject({ body: { errors: { foo: 'invalid' } } });
});
const dataProvider = {
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import {
screen,
waitFor,
} from '@testing-library/react';
import expect from 'expect';
import { expect } from 'vitest';
import { createMemoryHistory } from 'history';
import * as React from 'react';
import { MemoryRouter, Route, Routes } from 'react-router';
@@ -40,7 +40,7 @@ describe('useEditController', () => {
};

it('should call the dataProvider.getOne() function on mount', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -60,7 +60,7 @@ describe('useEditController', () => {
});

it('should decode the id from the route params', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 'test?', title: 'hello' } })
@@ -95,7 +95,7 @@ describe('useEditController', () => {
});

it('should use the id provided through props if any', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -130,7 +130,7 @@ describe('useEditController', () => {
});

it('should return the `redirect` provided through props or the default', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -157,13 +157,13 @@ describe('useEditController', () => {

describe('queryOptions', () => {
it('should accept custom client query options', async () => {
const mock = jest
const mock = vi
.spyOn(console, 'error')
.mockImplementation(() => {});
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() => Promise.reject(new Error()));
const onError = jest.fn();
const onError = vi.fn();
const dataProvider = { getOne } as unknown as DataProvider;
render(
<CoreAdminContext dataProvider={dataProvider}>
@@ -184,7 +184,7 @@ describe('useEditController', () => {
});

it('should accept a meta in query options', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -211,7 +211,7 @@ describe('useEditController', () => {
});

it('should call the dataProvider.update() function on save', async () => {
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -255,7 +255,7 @@ describe('useEditController', () => {

it('should return an undoable save callback by default', async () => {
let post = { id: 12, test: 'previous' };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -307,7 +307,7 @@ describe('useEditController', () => {

it('should return an immediate save callback when mutationMode is pessimistic', async () => {
let post = { id: 12 };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -392,7 +392,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -430,7 +430,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -468,7 +468,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -499,13 +499,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -538,13 +538,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in optimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -591,7 +591,7 @@ describe('useEditController', () => {

it('should accept meta in mutationOptions', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -629,7 +629,7 @@ describe('useEditController', () => {

it('should accept meta as a save option', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -669,8 +669,8 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccessSave = jest.fn();
const onSuccess = vi.fn();
const onSuccessSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -710,7 +710,7 @@ describe('useEditController', () => {
});

it('should execute error side effects on error in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
@@ -749,14 +749,14 @@ describe('useEditController', () => {
});

it('should allow the save onError option to override the failure side effects override', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onErrorSave = jest.fn();
const onError = vi.fn();
const onErrorSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -797,7 +797,7 @@ describe('useEditController', () => {

it('should allow transform to transform the data before save', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -806,7 +806,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -839,7 +839,7 @@ describe('useEditController', () => {

it('should allow the save transform option to override the transform side effect', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -848,8 +848,8 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn();
const transformSave = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn();
const transformSave = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -889,7 +889,7 @@ describe('useEditController', () => {

it('should allow to register middlewares', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -899,7 +899,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
});
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = jest.fn(
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = vi.fn(
(resource, params, options, next) => {
return next(
resource,
@@ -964,7 +964,7 @@ describe('useEditController', () => {

it('should return errors from the update call in pessimistic mode', async () => {
let post = { id: 12 };
const update = jest.fn().mockImplementationOnce(() => {
const update = vi.fn().mockImplementationOnce(() => {
return Promise.reject({ body: { errors: { foo: 'invalid' } } });
});
const dataProvider = {
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import {
screen,
waitFor,
} from '@testing-library/react';
import expect from 'expect';
import { expect } from 'vitest';
import { createMemoryHistory } from 'history';
import * as React from 'react';
import { Route, Routes } from 'react-router';
@@ -42,7 +42,7 @@ describe('useEditController', () => {
};

it('should call the dataProvider.getOne() function on mount', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -62,7 +62,7 @@ describe('useEditController', () => {
});

it('should decode the id from the route params', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 'test?', title: 'hello' } })
@@ -97,7 +97,7 @@ describe('useEditController', () => {
});

it('should use the id provided through props if any', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -132,7 +132,7 @@ describe('useEditController', () => {
});

it('should return the `redirect` provided through props or the default', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 12, title: 'hello' } })
@@ -159,13 +159,13 @@ describe('useEditController', () => {

describe('queryOptions', () => {
it('should accept custom client query options', async () => {
const mock = jest
const mock = vi
.spyOn(console, 'error')
.mockImplementation(() => {});
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() => Promise.reject(new Error()));
const onError = jest.fn();
const onError = vi.fn();
const dataProvider = { getOne } as unknown as DataProvider;
render(
<CoreAdminContext dataProvider={dataProvider}>
@@ -186,7 +186,7 @@ describe('useEditController', () => {
});

it('should accept a meta in query options', async () => {
const getOne = jest
const getOne = vi
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: { id: 0, title: 'hello' } })
@@ -213,7 +213,7 @@ describe('useEditController', () => {
});

it('should call the dataProvider.update() function on save', async () => {
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -257,7 +257,7 @@ describe('useEditController', () => {

it('should return an undoable save callback by default', async () => {
let post = { id: 12, test: 'previous' };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -309,7 +309,7 @@ describe('useEditController', () => {

it('should return an immediate save callback when mutationMode is pessimistic', async () => {
let post = { id: 12 };
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { data, previousData }) => {
post = { ...previousData, ...data };
@@ -394,7 +394,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -432,7 +432,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -470,7 +470,7 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -501,13 +501,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -540,13 +540,13 @@ describe('useEditController', () => {
});

it('should allow mutationOptions to override the default failure side effects in optimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -593,7 +593,7 @@ describe('useEditController', () => {

it('should accept meta in mutationOptions', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -631,7 +631,7 @@ describe('useEditController', () => {

it('should accept meta as a save option', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
@@ -671,8 +671,8 @@ describe('useEditController', () => {
update: (_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } }),
} as unknown as DataProvider;
const onSuccess = jest.fn();
const onSuccessSave = jest.fn();
const onSuccess = vi.fn();
const onSuccessSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -712,7 +712,7 @@ describe('useEditController', () => {
});

it('should execute error side effects on error in pessimistic mode', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
@@ -751,14 +751,14 @@ describe('useEditController', () => {
});

it('should allow the save onError option to override the failure side effects override', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update: () => Promise.reject({ message: 'not good' }),
} as unknown as DataProvider;
const onError = jest.fn();
const onErrorSave = jest.fn();
const onError = vi.fn();
const onErrorSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -799,7 +799,7 @@ describe('useEditController', () => {

it('should allow transform to transform the data before save', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -808,7 +808,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -841,7 +841,7 @@ describe('useEditController', () => {

it('should allow the save transform option to override the transform side effect', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -850,8 +850,8 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
} as unknown as DataProvider;
const transform = jest.fn();
const transformSave = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn();
const transformSave = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -891,7 +891,7 @@ describe('useEditController', () => {

it('should allow to register middlewares', async () => {
let saveCallback;
const update = jest
const update = vi
.fn()
.mockImplementationOnce((_, { id, data }) =>
Promise.resolve({ data: { id, ...data } })
@@ -901,7 +901,7 @@ describe('useEditController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } }),
update,
});
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = jest.fn(
const middleware: Middleware<ReturnType<typeof useUpdate>[0]> = vi.fn(
(resource, params, options, next) => {
return next(
resource,
@@ -966,7 +966,7 @@ describe('useEditController', () => {

it('should return errors from the update call in pessimistic mode', async () => {
let post = { id: 12 };
const update = jest.fn().mockImplementationOnce(() => {
const update = vi.fn().mockImplementationOnce(() => {
return Promise.reject({ body: { errors: { foo: 'invalid' } } });
});
const dataProvider = {
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineTest } from 'jscodeshift/dist/testUtils';

jest.autoMockOff();
vi.autoMockOff();

defineTest(
__dirname,
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineTest } from 'jscodeshift/dist/testUtils';

jest.autoMockOff();
vi.autoMockOff();

defineTest(
__dirname,
1 change: 0 additions & 1 deletion packages/ra-core/package.json
Original file line number Diff line number Diff line change
@@ -29,7 +29,6 @@
"devDependencies": {
"@hookform/resolvers": "^3.2.0",
"@testing-library/react": "^15.0.7",
"@types/jest": "^29.5.2",
"@types/jscodeshift": "^0.11.11",
"@types/node": "^20.10.7",
"@types/node-polyglot": "^0.4.31",
24 changes: 12 additions & 12 deletions packages/ra-core/src/auth/Authenticated.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { Routes, Route, useLocation } from 'react-router-dom';

@@ -28,13 +28,13 @@ describe('<Authenticated>', () => {
});

it('should not render its child when checkAuth raises an error', async () => {
const NeverDisplayedComponent = jest.fn(() => (
const NeverDisplayedComponent = vi.fn(() => (
<div>It should not be called</div>
));

const authProvider = {
checkAuth: jest.fn().mockRejectedValue(undefined),
logout: jest.fn().mockResolvedValue(undefined),
checkAuth: vi.fn().mockRejectedValue(undefined),
logout: vi.fn().mockResolvedValue(undefined),
} as any;

render(
@@ -58,12 +58,12 @@ describe('<Authenticated>', () => {
const authProvider = {
login: () => Promise.reject('bad method'),
logout: () => Promise.reject('bad method'),
checkAuth: jest.fn().mockResolvedValueOnce(''),
checkAuth: vi.fn().mockResolvedValueOnce(''),
checkError: () => Promise.reject('bad method'),
getPermissions: () => Promise.reject('bad method'),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

render(
<CoreAdminContext authProvider={authProvider} store={store}>
@@ -78,14 +78,14 @@ describe('<Authenticated>', () => {

it('should logout, redirect to login and show a notification if the auth fails', async () => {
const authProvider = {
login: jest.fn().mockResolvedValue(''),
logout: jest.fn().mockResolvedValue(''),
checkAuth: jest.fn().mockRejectedValue(undefined),
checkError: jest.fn().mockResolvedValue(''),
getPermissions: jest.fn().mockResolvedValue(''),
login: vi.fn().mockResolvedValue(''),
logout: vi.fn().mockResolvedValue(''),
checkAuth: vi.fn().mockRejectedValue(undefined),
checkError: vi.fn().mockResolvedValue(''),
getPermissions: vi.fn().mockResolvedValue(''),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

const Login = () => {
const location = useLocation();
36 changes: 18 additions & 18 deletions packages/ra-core/src/auth/addRefreshAuthToAuthProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -4,20 +4,20 @@ import { addRefreshAuthToAuthProvider } from './addRefreshAuthToAuthProvider';

describe('addRefreshAuthToAuthProvider', () => {
const authProvider: AuthProvider = {
login: jest.fn(),
logout: jest.fn(),
checkAuth: jest.fn(),
checkError: jest.fn(),
getIdentity: jest.fn(),
getPermissions: jest.fn(),
login: vi.fn(),
logout: vi.fn(),
checkAuth: vi.fn(),
checkError: vi.fn(),
getIdentity: vi.fn(),
getPermissions: vi.fn(),
};

it('should call refreshAuth before calling checkAuth', async () => {
let resolvePromise;
const refreshAuthPromise = new Promise<void>(resolve => {
resolvePromise = resolve;
});
const refreshAuth = jest.fn(() => refreshAuthPromise);
const refreshAuth = vi.fn(() => refreshAuthPromise);

const wrappedAuthProvider = addRefreshAuthToAuthProvider(
authProvider,
@@ -37,7 +37,7 @@ describe('addRefreshAuthToAuthProvider', () => {
const refreshAuthPromise = new Promise<void>(resolve => {
resolvePromise = resolve;
});
const refreshAuth = jest.fn(() => refreshAuthPromise);
const refreshAuth = vi.fn(() => refreshAuthPromise);

const wrappedAuthProvider = addRefreshAuthToAuthProvider(
authProvider,
@@ -55,14 +55,14 @@ describe('addRefreshAuthToAuthProvider', () => {

it('should not provide getIdentity if getIdentity is not implemented in the authProvider', async () => {
const authProvider: AuthProvider = {
login: jest.fn(),
logout: jest.fn(),
checkAuth: jest.fn(),
checkError: jest.fn(),
getPermissions: jest.fn(),
login: vi.fn(),
logout: vi.fn(),
checkAuth: vi.fn(),
checkError: vi.fn(),
getPermissions: vi.fn(),
};

const refreshAuth = jest.fn();
const refreshAuth = vi.fn();
const wrappedAuthProvider = addRefreshAuthToAuthProvider(
authProvider,
refreshAuth
@@ -76,7 +76,7 @@ describe('addRefreshAuthToAuthProvider', () => {
const refreshAuthPromise = new Promise<void>(resolve => {
resolvePromise = resolve;
});
const refreshAuth = jest.fn(() => refreshAuthPromise);
const refreshAuth = vi.fn(() => refreshAuthPromise);

const wrappedAuthProvider = addRefreshAuthToAuthProvider(
authProvider,
@@ -92,7 +92,7 @@ describe('addRefreshAuthToAuthProvider', () => {
});

it('should not call refreshAuth before calling login', async () => {
const refreshAuth = jest.fn();
const refreshAuth = vi.fn();

const wrappedAuthProvider = addRefreshAuthToAuthProvider(
authProvider,
@@ -104,7 +104,7 @@ describe('addRefreshAuthToAuthProvider', () => {
});

it('should not call refreshAuth before calling logout', async () => {
const refreshAuth = jest.fn();
const refreshAuth = vi.fn();

const wrappedAuthProvider = addRefreshAuthToAuthProvider(
authProvider,
@@ -116,7 +116,7 @@ describe('addRefreshAuthToAuthProvider', () => {
});

it('should not call refreshAuth before calling checkError', async () => {
const refreshAuth = jest.fn();
const refreshAuth = vi.fn();

const wrappedAuthProvider = addRefreshAuthToAuthProvider(
authProvider,
6 changes: 3 additions & 3 deletions packages/ra-core/src/auth/useAuthState.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { waitFor, render, screen } from '@testing-library/react';
import { CoreAdminContext } from '../core/CoreAdminContext';

@@ -49,9 +49,9 @@ describe('useAuthState', () => {
});

it('should abort the request if the query is canceled', async () => {
const abort = jest.fn();
const abort = vi.fn();
const authProvider = {
checkAuth: jest.fn(
checkAuth: vi.fn(
({ signal }) =>
new Promise(() => {
signal.addEventListener('abort', () => {
26 changes: 13 additions & 13 deletions packages/ra-core/src/auth/useAuthenticated.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { Routes, Route, useLocation } from 'react-router-dom';
import { memoryStore } from '../store';
@@ -21,12 +21,12 @@ describe('useAuthenticated', () => {
const authProvider = {
login: () => Promise.reject('bad method'),
logout: () => Promise.reject('bad method'),
checkAuth: jest.fn().mockResolvedValueOnce(''),
checkAuth: vi.fn().mockResolvedValueOnce(''),
checkError: () => Promise.reject('bad method'),
getPermissions: () => Promise.reject('bad method'),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');
render(
<CoreAdminContext authProvider={authProvider} store={store}>
<Authenticated>
@@ -51,12 +51,12 @@ describe('useAuthenticated', () => {
const authProvider = {
login: () => Promise.reject('bad method'),
logout: () => Promise.reject('bad method'),
checkAuth: jest.fn().mockResolvedValue(''),
checkAuth: vi.fn().mockResolvedValue(''),
checkError: () => Promise.reject('bad method'),
getPermissions: () => Promise.reject('bad method'),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

const FooWrapper = props => (
<CoreAdminContext authProvider={authProvider} store={store}>
@@ -79,12 +79,12 @@ describe('useAuthenticated', () => {
const authProvider = {
login: () => Promise.reject('bad method'),
logout: () => Promise.reject('bad method'),
checkAuth: jest.fn().mockResolvedValue(''),
checkAuth: vi.fn().mockResolvedValue(''),
checkError: () => Promise.reject('bad method'),
getPermissions: () => Promise.reject('bad method'),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

render(
<CoreAdminContext authProvider={authProvider} store={store}>
@@ -99,14 +99,14 @@ describe('useAuthenticated', () => {

it('should logout, redirect to login and show a notification after a tick if the auth fails', async () => {
const authProvider = {
login: jest.fn().mockResolvedValue(''),
logout: jest.fn().mockResolvedValue(''),
checkAuth: jest.fn().mockRejectedValue(undefined),
checkError: jest.fn().mockResolvedValue(''),
getPermissions: jest.fn().mockResolvedValue(''),
login: vi.fn().mockResolvedValue(''),
logout: vi.fn().mockResolvedValue(''),
checkAuth: vi.fn().mockRejectedValue(undefined),
checkError: vi.fn().mockResolvedValue(''),
getPermissions: vi.fn().mockResolvedValue(''),
};
const store = memoryStore();
const reset = jest.spyOn(store, 'reset');
const reset = vi.spyOn(store, 'reset');

const Login = () => {
const location = useLocation();
6 changes: 3 additions & 3 deletions packages/ra-core/src/auth/useCanAccess.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { waitFor, render, screen } from '@testing-library/react';

import { QueryClient } from '@tanstack/react-query';
@@ -96,9 +96,9 @@ describe('useCanAccess', () => {
});

it('should abort the request if the query is canceled', async () => {
const abort = jest.fn();
const abort = vi.fn();
const authProvider = {
canAccess: jest.fn(
canAccess: vi.fn(
({ signal }) =>
new Promise(() => {
signal.addEventListener('abort', () => {
6 changes: 3 additions & 3 deletions packages/ra-core/src/auth/useCanAccessCallback.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { waitFor, render, fireEvent, screen } from '@testing-library/react';
import { Basic } from './useCanAccessCallback.stories';

describe('useCanAccessCallback', () => {
it('should return a function allowing to call authProvider.canAccess', async () => {
const canAccess = jest
const canAccess = vi
.fn()
.mockImplementation(async ({ action }) => action === 'read');
const authProvider = {
@@ -54,7 +54,7 @@ describe('useCanAccessCallback', () => {
});

it('should reject when an error is thrown by canAccess', async () => {
const canAccess = jest
const canAccess = vi
.fn()
.mockRejectedValue(new Error('uh oh, something went wrong'));
const authProvider = {
6 changes: 3 additions & 3 deletions packages/ra-core/src/auth/useCanAccessResources.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { Basic } from './useCanAccessResources.stories';

describe('useCanAccessResources', () => {
it('should call authProvider.canAccess for every resource', async () => {
const canAccess = jest.fn().mockImplementation(async () => true);
const canAccess = vi.fn().mockImplementation(async () => true);
const authProvider = {
login: () => Promise.reject('bad method'),
logout: () => Promise.reject('bad method'),
@@ -47,7 +47,7 @@ describe('useCanAccessResources', () => {
});

it('should grant access to each resource based on canAccess result', async () => {
const canAccess = jest
const canAccess = vi
.fn()
.mockImplementation(
async ({ resource }) => resource !== 'posts.id'
6 changes: 3 additions & 3 deletions packages/ra-core/src/auth/useCheckAuth.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { screen, render, waitFor } from '@testing-library/react';
import { Location } from 'react-router-dom';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
@@ -12,9 +12,9 @@ import { BasenameContextProvider, TestMemoryRouter } from '../routing';
import { useNotify } from '../notification/useNotify';
import { AuthProvider } from '../types';

jest.mock('../notification/useNotify');
vi.mock('../notification/useNotify');

const notify = jest.fn();
const notify = vi.fn();
useNotify.mockImplementation(() => notify);

const TestComponent = ({
6 changes: 3 additions & 3 deletions packages/ra-core/src/auth/useGetIdentity.spec.tsx
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ describe('useGetIdentity', () => {
await screen.findByText('John Doe');
});
it('should return the authProvider error', async () => {
jest.spyOn(console, 'error').mockImplementationOnce(() => {});
vi.spyOn(console, 'error').mockImplementationOnce(() => {});
render(<ErrorCase />);
await screen.findByText('Error');
});
@@ -58,9 +58,9 @@ describe('useGetIdentity', () => {
});

it('should abort the request if the query is canceled', async () => {
const abort = jest.fn();
const abort = vi.fn();
const authProvider = {
getIdentity: jest.fn(
getIdentity: vi.fn(
({ signal }) =>
new Promise(() => {
signal.addEventListener('abort', () => {
8 changes: 4 additions & 4 deletions packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { Route, Routes } from 'react-router-dom';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
@@ -42,7 +42,7 @@ const authProvider: AuthProvider = {

describe('useHandleAuthCallback', () => {
afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});

it('should redirect to the home route by default when the callback was successfully handled', async () => {
@@ -121,10 +121,10 @@ describe('useHandleAuthCallback', () => {
});

it('should abort the request if the query is canceled', async () => {
const abort = jest.fn();
const abort = vi.fn();
const testAuthProvider = {
...authProvider,
handleCallback: jest.fn(
handleCallback: vi.fn(
({ signal }) =>
new Promise(() => {
signal.addEventListener('abort', () => {
2 changes: 1 addition & 1 deletion packages/ra-core/src/auth/useLogin.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { Routes, Route } from 'react-router-dom';
import expect from 'expect';
import { expect } from 'vitest';

import { CoreAdminContext } from '../core/CoreAdminContext';
import useLogin from './useLogin';
2 changes: 1 addition & 1 deletion packages/ra-core/src/auth/useLogout.spec.tsx
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import * as React from 'react';
import { render, fireEvent, screen } from '@testing-library/react';
import { Routes, Route } from 'react-router-dom';
import { QueryClient } from '@tanstack/react-query';
import expect from 'expect';
import { expect } from 'vitest';

import { useGetOne } from '../dataProvider';
import useLogout from './useLogout';
10 changes: 5 additions & 5 deletions packages/ra-core/src/auth/useLogoutIfAccessDenied.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { useEffect, useState } from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { Routes, Route } from 'react-router-dom';

@@ -19,7 +19,7 @@ const authProvider: AuthProvider = {
loggedIn = true;
return Promise.resolve();
},
logout: jest.fn(() => {
logout: vi.fn(() => {
loggedIn = false;
return Promise.resolve();
}),
@@ -47,15 +47,15 @@ const TestComponent = ({ error }: { error?: any }) => {
return <div>{loggedOut ? '' : 'logged in'}</div>;
};

jest.mock('./useLogout');
jest.mock('../notification/useNotify');
vi.mock('./useLogout');
vi.mock('../notification/useNotify');

//@ts-expect-error
useLogout.mockImplementation(() => {
const logout = () => authProvider.logout(null);
return logout;
});
const notify = jest.fn();
const notify = vi.fn();
//@ts-expect-error
useNotify.mockImplementation(() => notify);

10 changes: 5 additions & 5 deletions packages/ra-core/src/auth/usePermissions.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { waitFor, render, screen } from '@testing-library/react';
import { QueryClient } from '@tanstack/react-query';
import {
@@ -77,7 +77,7 @@ describe('usePermissions', () => {
it('should call logout when the auth.getPermissions call fails and checkError rejects', async () => {
const authProvider = {
login: () => Promise.reject('bad method'),
logout: jest.fn(() => Promise.resolve()),
logout: vi.fn(() => Promise.resolve()),
checkAuth: () => Promise.reject('bad method'),
checkError: () => Promise.reject(),
getPermissions: () => Promise.reject('not good'),
@@ -92,13 +92,13 @@ describe('usePermissions', () => {
});

it('should abort the request if the query is canceled', async () => {
const abort = jest.fn();
const abort = vi.fn();
const authProvider: AuthProvider = {
login: () => Promise.reject('bad method'),
logout: jest.fn(() => Promise.resolve()),
logout: vi.fn(() => Promise.resolve()),
checkAuth: () => Promise.reject('bad method'),
checkError: () => Promise.reject(),
getPermissions: jest.fn(
getPermissions: vi.fn(
({ signal }) =>
new Promise(() => {
signal.addEventListener('abort', () => {
6 changes: 3 additions & 3 deletions packages/ra-core/src/auth/useRequireAccess.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { waitFor, render, screen } from '@testing-library/react';
import { QueryClient } from '@tanstack/react-query';
import { Location } from 'react-router';
@@ -127,9 +127,9 @@ describe('useRequireAccess', () => {
});

it('should abort the request if the query is canceled', async () => {
const abort = jest.fn();
const abort = vi.fn();
const authProvider = {
canAccess: jest.fn(
canAccess: vi.fn(
({ signal }) =>
new Promise(() => {
signal.addEventListener('abort', () => {
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { Route, Routes } from 'react-router';
import { fireEvent, screen, render, waitFor } from '@testing-library/react';

@@ -16,7 +16,7 @@ describe('useDeleteWithConfirmController', () => {
it('should call the dataProvider.delete() function with the meta param', async () => {
let receivedMeta = null;
const dataProvider = testDataProvider({
delete: jest.fn((ressource, params) => {
delete: vi.fn((ressource, params) => {
receivedMeta = params?.meta?.key;
return Promise.resolve({ data: params?.meta?.key });
}),
@@ -52,7 +52,7 @@ describe('useDeleteWithConfirmController', () => {
it('should display success message after successful deletion', async () => {
const successMessage = 'Test Message';
const dataProvider = testDataProvider({
delete: jest.fn().mockResolvedValue({ data: {} }),
delete: vi.fn().mockResolvedValue({ data: {} }),
});

const MockComponent = () => {
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { Route, Routes } from 'react-router';
import { fireEvent, screen, render, waitFor } from '@testing-library/react';

@@ -16,7 +16,7 @@ describe('useDeleteWithUndoController', () => {
it('should call the dataProvider.delete() function with the meta param', async () => {
let receivedMeta = null;
const dataProvider = testDataProvider({
delete: jest.fn((ressource, params) => {
delete: vi.fn((ressource, params) => {
receivedMeta = params?.meta?.key;
return Promise.resolve({ data: params?.meta?.key });
}),
@@ -52,7 +52,7 @@ describe('useDeleteWithUndoController', () => {
it('should display success message after successful deletion', async () => {
const successMessage = 'Test Message';
const dataProvider = testDataProvider({
delete: jest.fn().mockResolvedValue({ data: {} }),
delete: vi.fn().mockResolvedValue({ data: {} }),
});

const MockComponent = () => {
38 changes: 19 additions & 19 deletions packages/ra-core/src/controller/create/CreateBase.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { screen, render, waitFor, fireEvent } from '@testing-library/react';

import { testDataProvider } from '../../dataProvider';
@@ -13,7 +13,7 @@ describe('CreateBase', () => {
it('should give access to the save function', async () => {
const dataProvider = testDataProvider({
// @ts-ignore
create: jest.fn((_, { data }) =>
create: vi.fn((_, { data }) =>
Promise.resolve({ data: { id: 1, ...data } })
),
});
@@ -31,11 +31,11 @@ describe('CreateBase', () => {
it('should allow to override the onSuccess function', async () => {
const dataProvider = testDataProvider({
// @ts-ignore
create: jest.fn((_, { data }) =>
create: vi.fn((_, { data }) =>
Promise.resolve({ data: { id: 1, ...data } })
),
});
const onSuccess = jest.fn();
const onSuccess = vi.fn();

render(
<NoAuthProvider
@@ -61,12 +61,12 @@ describe('CreateBase', () => {
it('should allow to override the onSuccess function at call time', async () => {
const dataProvider = testDataProvider({
// @ts-ignore
create: jest.fn((_, { data }) =>
create: vi.fn((_, { data }) =>
Promise.resolve({ data: { id: 1, ...data } })
),
});
const onSuccess = jest.fn();
const onSuccessOverride = jest.fn();
const onSuccess = vi.fn();
const onSuccessOverride = vi.fn();

const { getByText } = render(
<NoAuthProvider
@@ -92,12 +92,12 @@ describe('CreateBase', () => {
});

it('should allow to override the onError function', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
const dataProvider = testDataProvider({
// @ts-ignore
create: jest.fn(() => Promise.reject({ message: 'test' })),
create: vi.fn(() => Promise.reject({ message: 'test' })),
});
const onError = jest.fn();
const onError = vi.fn();

render(
<NoAuthProvider
@@ -120,10 +120,10 @@ describe('CreateBase', () => {
it('should allow to override the onError function at call time', async () => {
const dataProvider = testDataProvider({
// @ts-ignore
create: jest.fn(() => Promise.reject({ message: 'test' })),
create: vi.fn(() => Promise.reject({ message: 'test' })),
});
const onError = jest.fn();
const onErrorOverride = jest.fn();
const onError = vi.fn();
const onErrorOverride = vi.fn();

render(
<NoAuthProvider
@@ -148,11 +148,11 @@ describe('CreateBase', () => {
it('should allow to override the transform function', async () => {
const dataProvider = testDataProvider({
// @ts-ignore
create: jest.fn((_, { data }) =>
create: vi.fn((_, { data }) =>
Promise.resolve({ data: { id: 1, ...data } })
),
});
const transform = jest
const transform = vi
.fn()
.mockReturnValueOnce({ test: 'test transformed' });

@@ -175,12 +175,12 @@ describe('CreateBase', () => {
it('should allow to override the transform function at call time', async () => {
const dataProvider = testDataProvider({
// @ts-ignore
create: jest.fn((_, { data }) =>
create: vi.fn((_, { data }) =>
Promise.resolve({ data: { id: 1, ...data } })
),
});
const transform = jest.fn();
const transformOverride = jest
const transform = vi.fn();
const transformOverride = vi
.fn()
.mockReturnValueOnce({ test: 'test transformed' });

@@ -245,7 +245,7 @@ describe('CreateBase', () => {
new Promise<void>(resolve => {
resolveAuth = resolve;
}),
canAccess: jest.fn(
canAccess: vi.fn(
() =>
new Promise<boolean>(resolve => {
resolveCanAccess = resolve;
46 changes: 23 additions & 23 deletions packages/ra-core/src/controller/create/useCreateController.spec.tsx
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import {
screen,
waitFor,
} from '@testing-library/react';
import expect from 'expect';
import { expect } from 'vitest';
import React from 'react';
import { Route, Routes } from 'react-router-dom';

@@ -43,7 +43,7 @@ describe('useCreateController', () => {
it('should call the dataProvider.create() function on save', async () => {
const dataProvider = testDataProvider({
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
create: jest
create: vi
.fn()
.mockImplementationOnce((_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } })
@@ -111,7 +111,7 @@ describe('useCreateController', () => {
});

it('should execute default failure side effects on failure', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = testDataProvider({
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
@@ -149,7 +149,7 @@ describe('useCreateController', () => {
});

it('should use the default error message in case no message was provided', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = testDataProvider({
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
@@ -187,7 +187,7 @@ describe('useCreateController', () => {
});

it('should not trigger a notification in case of a validation error (handled by useNotifyIsFormInvalid)', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = testDataProvider({
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
@@ -227,7 +227,7 @@ describe('useCreateController', () => {
create: (_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } }),
});
const onSuccess = jest.fn();
const onSuccess = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -265,8 +265,8 @@ describe('useCreateController', () => {
create: (_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } }),
});
const onSuccess = jest.fn();
const onSuccessSave = jest.fn();
const onSuccess = vi.fn();
const onSuccessSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -305,13 +305,13 @@ describe('useCreateController', () => {
});

it('should allow mutationOptions to override the default failure side effects', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = testDataProvider({
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
create: () => Promise.reject({ message: 'not good' }),
});
const onError = jest.fn();
const onError = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -343,7 +343,7 @@ describe('useCreateController', () => {

it('should accept meta in mutationOptions', async () => {
let saveCallback;
const create = jest
const create = vi
.fn()
.mockImplementationOnce((_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } })
@@ -375,7 +375,7 @@ describe('useCreateController', () => {

it('should accept meta as a save option', async () => {
let saveCallback;
const create = jest
const create = vi
.fn()
.mockImplementationOnce((_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } })
@@ -405,14 +405,14 @@ describe('useCreateController', () => {
});

it('should allow the save onError option to override the failure side effects override', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
let saveCallback;
const dataProvider = testDataProvider({
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
create: () => Promise.reject({ message: 'not good' }),
});
const onError = jest.fn();
const onErrorSave = jest.fn();
const onError = vi.fn();
const onErrorSave = vi.fn();

let notificationsSpy;
const Notification = () => {
@@ -452,7 +452,7 @@ describe('useCreateController', () => {

it('should allow transform to transform the data before calling create', async () => {
let saveCallback;
const create = jest
const create = vi
.fn()
.mockImplementationOnce((_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } })
@@ -461,7 +461,7 @@ describe('useCreateController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
create,
});
const transform = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -484,7 +484,7 @@ describe('useCreateController', () => {

it('should allow the save transform option to override the controller transform option', async () => {
let saveCallback;
const create = jest
const create = vi
.fn()
.mockImplementationOnce((_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } })
@@ -493,8 +493,8 @@ describe('useCreateController', () => {
getOne: () => Promise.resolve({ data: { id: 12 } } as any),
create,
});
const transform = jest.fn();
const transformSave = jest.fn().mockImplementationOnce(data => ({
const transform = vi.fn();
const transformSave = vi.fn().mockImplementationOnce(data => ({
...data,
transformed: true,
}));
@@ -525,15 +525,15 @@ describe('useCreateController', () => {

it('should allow to register middlewares', async () => {
let saveCallback;
const create = jest
const create = vi
.fn()
.mockImplementationOnce((_, { data }) =>
Promise.resolve({ data: { id: 123, ...data } })
);
const dataProvider = testDataProvider({
create,
});
const middleware: Middleware<DataProvider['create']> = jest.fn(
const middleware: Middleware<DataProvider['create']> = vi.fn(
(resource, params, next) => {
return next(resource, {
...params,
@@ -588,7 +588,7 @@ describe('useCreateController', () => {
});

it('should return errors from the create call', async () => {
const create = jest.fn().mockImplementationOnce(() => {
const create = vi.fn().mockImplementationOnce(() => {
return Promise.reject({ body: { errors: { foo: 'invalid' } } });
});
const dataProvider = {
44 changes: 22 additions & 22 deletions packages/ra-core/src/controller/edit/EditBase.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import expect from 'expect';
import { expect } from 'vitest';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';

import { testDataProvider } from '../../dataProvider';
@@ -15,7 +15,7 @@ describe('EditBase', () => {
// @ts-ignore
getOne: () =>
Promise.resolve({ data: { id: 12, test: 'previous' } }),
update: jest.fn((_, { id, data, previousData }) =>
update: vi.fn((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
),
});
@@ -46,11 +46,11 @@ describe('EditBase', () => {
// @ts-ignore
getOne: () =>
Promise.resolve({ data: { id: 12, test: 'previous' } }),
update: jest.fn((_, { id, data, previousData }) =>
update: vi.fn((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
),
});
const onSuccess = jest.fn();
const onSuccess = vi.fn();

render(
<NoAuthProvider
@@ -86,12 +86,12 @@ describe('EditBase', () => {
// @ts-ignore
getOne: () =>
Promise.resolve({ data: { id: 12, test: 'previous' } }),
update: jest.fn((_, { id, data, previousData }) =>
update: vi.fn((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
),
});
const onSuccess = jest.fn();
const onSuccessOverride = jest.fn();
const onSuccess = vi.fn();
const onSuccessOverride = vi.fn();

render(
<NoAuthProvider
@@ -125,15 +125,15 @@ describe('EditBase', () => {
});

it('should allow to override the onError function', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
const dataProvider = testDataProvider({
// @ts-ignore
getOne: () =>
Promise.resolve({ data: { id: 12, test: 'previous' } }),
// @ts-ignore
update: jest.fn(() => Promise.reject({ message: 'test' })),
update: vi.fn(() => Promise.reject({ message: 'test' })),
});
const onError = jest.fn();
const onError = vi.fn();

render(
<NoAuthProvider
@@ -165,10 +165,10 @@ describe('EditBase', () => {
getOne: () =>
Promise.resolve({ data: { id: 12, test: 'previous' } }),
// @ts-ignore
update: jest.fn(() => Promise.reject({ message: 'test' })),
update: vi.fn(() => Promise.reject({ message: 'test' })),
});
const onError = jest.fn();
const onErrorOverride = jest.fn();
const onError = vi.fn();
const onErrorOverride = vi.fn();

render(
<NoAuthProvider
@@ -201,11 +201,11 @@ describe('EditBase', () => {
// @ts-ignore
getOne: () =>
Promise.resolve({ data: { id: 12, test: 'previous' } }),
update: jest.fn((_, { id, data, previousData }) =>
update: vi.fn((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
),
});
const transform = jest.fn((data, _options) => ({
const transform = vi.fn((data, _options) => ({
...data,
test: 'test transformed',
}));
@@ -241,12 +241,12 @@ describe('EditBase', () => {
// @ts-ignore
getOne: () =>
Promise.resolve({ data: { id: 12, test: 'previous' } }),
update: jest.fn((_, { id, data, previousData }) =>
update: vi.fn((_, { id, data, previousData }) =>
Promise.resolve({ data: { id, ...previousData, ...data } })
),
});
const transform = jest.fn();
const transformOverride = jest.fn((data, _options) => ({
const transform = vi.fn();
const transformOverride = vi.fn((data, _options) => ({
...data,
test: 'test transformed',
}));
@@ -284,7 +284,7 @@ describe('EditBase', () => {
it('should load data immediately if authProvider is not provided', async () => {
const dataProvider = testDataProvider({
// @ts-ignore
getOne: jest.fn(() =>
getOne: vi.fn(() =>
Promise.resolve({ data: { id: 12, test: 'Hello' } })
),
});
@@ -305,7 +305,7 @@ describe('EditBase', () => {
};
const dataProvider = testDataProvider({
// @ts-ignore
getOne: jest.fn(() =>
getOne: vi.fn(() =>
Promise.resolve({ data: { id: 12, test: 'Hello' } })
),
});
@@ -331,7 +331,7 @@ describe('EditBase', () => {
new Promise<void>(resolve => {
resolveAuth = resolve;
}),
canAccess: jest.fn(
canAccess: vi.fn(
() =>
new Promise<boolean>(resolve => {
resolveCanAccess = resolve;
@@ -340,7 +340,7 @@ describe('EditBase', () => {
};
const dataProvider = testDataProvider({
// @ts-ignore
getOne: jest.fn(() =>
getOne: vi.fn(() =>
Promise.resolve({ data: { id: 12, test: 'Hello' } })
),
});
Loading

Unchanged files with check annotations Beta

value: Store,
children,
}: StoreContextProviderProps) => {
useEffect(() => {

Check failure on line 10 in packages/ra-core/src/store/StoreContextProvider.tsx

GitHub Actions / unit-test

packages/ra-core/src/core/Resource.spec.tsx > <Resource> > renders resource routes by default

TestingLibraryElementError: Unable to find an element with the text: PostList. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. Ignored nodes: comments, script, style <body> <div> <h2> Unexpected Application Error! </h2> <h3 style="font-style: italic;" > Cannot read properties of null (reading 'useEffect') </h3> <pre style="padding: 0.5rem; background-color: rgba(200, 200, 200, 0.5);" > TypeError: Cannot read properties of null (reading 'useEffect') at useEffect (http://localhost:63315/node_modules/.vite/deps/chunk-ZMLY2J2T.js?v=2fed52ba:1078:29) at StoreContextProvider (http://localhost:63315/packages/ra-core/src/store/StoreContextProvider.tsx:8:3) at renderWithHooks (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:11414:26) at mountIndeterminateComponent (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:14792:21) at beginWork (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:15780:22) at beginWork$1 (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:19624:22) at performUnitOfWork (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:19072:20) at workLoopSync (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:19008:13) at renderRootSync (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:18987:15) at recoverFromConcurrentError (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:18604:28) </pre> <p> 💿 Hey developer 👋 </p> <p> You can provide a way better UX than this when your app throws errors by providing your own <code style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);" > ErrorBoundary </code> or <code style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);" > errorElement </code> prop on your route. </p> </div> </body> Ignored nodes: comments, script, style <body> <div> <h2> Unexpected Application Error! </h2> <h3 style="font-style: italic;" > Cannot read properties of null (reading 'useEffect') </h3> <pre style="padding: 0.5rem; background-color: rgba(200, 200, 200, 0.5);" > TypeError: Cannot read properties of null (reading 'useEffect') at useEffect (http://localhost:63315/node_modules/.vite/deps/chunk-ZMLY2J2T.js?v=2fed52ba:1078:29) at StoreContextProvider (http://localhost:63315/packages/ra-core/src/store/StoreContextProvider.tsx:8:3) at renderWithHooks (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:11414:26) at mountIndeterminateComponent (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:14792:21) at beginWork (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:15780:22) at beginWork$1 (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:19624:22) at performUnitOfWork (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:19072:20) at workLoopSync (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:19008:13) at renderRootSync (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:18987:15) at recoverFromConcurrentError (http://localhost:63315/node_modules/.vite/deps/chunk-VCHWBZ6P.js?v=ce568e40:18604:28) </pre> <p> 💿 Hey developer 👋 </p> <p> You can provide a way better UX than this when your app throws errors by providing your own <code style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);" > ErrorBoundary </code> or <code style="p
Store.setup();
return () => {
Store.teardown();
): RecordType | undefined => {
// Can't find a way to specify the RecordType when CreateContext is declared
// @ts-ignore
const context = useContext<RecordType | undefined>(RecordContext);

Check failure on line 40 in packages/ra-core/src/controller/record/useRecordContext.ts

GitHub Actions / unit-test

packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx > useGetRecordId > should return the record id it received in options

TypeError: Cannot read properties of null (reading 'useContext') ❯ useRecordContext packages/ra-core/src/controller/record/useRecordContext.ts:40:20 ❯ useGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.ts:18:26 ❯ UseGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx:9:22

Check failure on line 40 in packages/ra-core/src/controller/record/useRecordContext.ts

GitHub Actions / unit-test

packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx > useGetRecordId > should return the record id it received in options even if it is falsy

TypeError: Cannot read properties of null (reading 'useContext') ❯ useRecordContext packages/ra-core/src/controller/record/useRecordContext.ts:40:20 ❯ useGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.ts:18:26 ❯ UseGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx:9:22

Check failure on line 40 in packages/ra-core/src/controller/record/useRecordContext.ts

GitHub Actions / unit-test

packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx > useGetRecordId > should return the record id it received through the record context

TypeError: Cannot read properties of null (reading 'useContext') ❯ useRecordContext packages/ra-core/src/controller/record/useRecordContext.ts:40:20 ❯ useGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.ts:18:26 ❯ UseGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx:9:22

Check failure on line 40 in packages/ra-core/src/controller/record/useRecordContext.ts

GitHub Actions / unit-test

packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx > useGetRecordId > should return the record id it received through the record context even if it is falsy

TypeError: Cannot read properties of null (reading 'useContext') ❯ useRecordContext packages/ra-core/src/controller/record/useRecordContext.ts:40:20 ❯ useGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.ts:18:26 ❯ UseGetRecordId packages/ra-core/src/dataProvider/useGetRecordId.spec.tsx:9:22
return (props && props.record) || context;
};
React-admin requires a valid dataProvider function to work.`);
}
const finalQueryClient = useMemo(

Check failure on line 185 in packages/ra-core/src/core/CoreAdminContext.tsx

GitHub Actions / unit-test

packages/ra-core/src/dataProvider/useUpdate.spec.tsx > useUpdate > mutate > returns a callback that can be used with update arguments

TypeError: Cannot read properties of null (reading 'useMemo') ❯ CoreAdminContext packages/ra-core/src/core/CoreAdminContext.tsx:185:29

Check failure on line 185 in packages/ra-core/src/core/CoreAdminContext.tsx

GitHub Actions / unit-test

packages/ra-core/src/dataProvider/useUpdate.spec.tsx > useUpdate > mutate > returns a callback that can be used with no arguments

TypeError: Cannot read properties of null (reading 'useMemo') ❯ CoreAdminContext packages/ra-core/src/core/CoreAdminContext.tsx:185:29

Check failure on line 185 in packages/ra-core/src/core/CoreAdminContext.tsx

GitHub Actions / unit-test

packages/ra-core/src/dataProvider/useUpdate.spec.tsx > useUpdate > mutate > accepts falsy value that are not null nor undefined as the record id

TypeError: Cannot read properties of null (reading 'useMemo') ❯ CoreAdminContext packages/ra-core/src/core/CoreAdminContext.tsx:185:29
() => queryClient || new QueryClient(),
[queryClient]
);