diff --git a/src/__mocks__/axios.ts b/__mocks__/axios.ts
similarity index 88%
rename from src/__mocks__/axios.ts
rename to __mocks__/axios.ts
index bfbffc10..91ed4589 100644
--- a/src/__mocks__/axios.ts
+++ b/__mocks__/axios.ts
@@ -1,7 +1,7 @@
// TODO: move __mocks__ folder back to root once facebook/create-react-app#7539 is fixed
const requests = {
- get: jest.fn((path) => {
+ get: vi.fn((path) => {
if (path === '/settings.json') {
return Promise.resolve({
data: {
@@ -20,7 +20,7 @@ const requests = {
});
}
}),
- post: jest.fn(() => Promise.resolve({ data: {} })),
+ post: vi.fn(() => Promise.resolve({ data: {} })),
};
export default requests;
diff --git a/src/__mocks__/react-i18next.jsx b/__mocks__/react-i18next.jsx
similarity index 100%
rename from src/__mocks__/react-i18next.jsx
rename to __mocks__/react-i18next.jsx
diff --git a/src/App.test.tsx b/src/App.test.tsx
index b09d4924..492b9d9c 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -1,37 +1,36 @@
-import React from 'react';
+import { useMediaQuery } from '@mui/material';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import axios from 'axios';
import { createRoot } from 'react-dom/client';
import App, { AppSansHoc } from './App';
-import { act, fireEvent, render, screen } from '@testing-library/react';
import { flushPromises } from './setupTests';
-import axios from 'axios';
import { RegisterRouteType } from './state/scigateway.types';
-import { useMediaQuery } from '@mui/material';
-jest.mock('./state/actions/loadMicroFrontends', () => ({
- init: jest.fn(() => Promise.resolve()),
+vi.mock('./state/actions/loadMicroFrontends', () => ({
+ init: vi.fn(() => Promise.resolve()),
singleSpaPluginRoutes: ['/plugin1'],
}));
-jest.mock('@mui/material', () => ({
+vi.mock('@mui/material', async () => ({
__esmodule: true,
- ...jest.requireActual('@mui/material'),
- useMediaQuery: jest.fn(),
+ ...(await vi.importActual('@mui/material')),
+ useMediaQuery: vi.fn(),
}));
const testToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QifQ.hNQI_r8BATy1LyXPr6Zuo9X_V0kSED8ngcqQ6G-WV5w';
// needed for the maintenance state update test - for some reason it doesn't work when at the beginning of the test itself
-window.localStorage.__proto__.getItem = jest.fn().mockImplementation((name) => {
+window.localStorage.__proto__.getItem = vi.fn().mockImplementation((name) => {
return name === 'scigateway:token' ? testToken : null;
});
describe('App', () => {
beforeEach(() => {
- jest.mocked(useMediaQuery).mockReturnValue(true);
+ vi.mocked(useMediaQuery).mockReturnValue(true);
});
afterEach(() => {
- jest.useRealTimers();
+ vi.useRealTimers();
});
it('renders without crashing', () => {
@@ -46,27 +45,27 @@ describe('App', () => {
});
it('should show preloader when react-i18next is not ready', () => {
- render();
+ render();
expect(screen.getByText('Loading...')).toBeInTheDocument();
});
it('should dispatch loadMaintenanceState and force refresh the page when maintenance changes', async () => {
// mock so token verify succeeds
- (axios.post as jest.Mock).mockImplementation(() =>
+ (axios.post as vi.Mock).mockImplementation(() =>
Promise.resolve({
data: {},
})
);
- window.matchMedia = jest.fn().mockReturnValue({ matches: true });
+ window.matchMedia = vi.fn().mockReturnValue({ matches: true });
Object.defineProperty(window, 'location', {
configurable: true,
- value: { reload: jest.fn() },
+ value: { reload: vi.fn() },
});
- jest.useFakeTimers();
+ vi.useFakeTimers();
- render();
+ render();
const registerRouteAction = {
type: RegisterRouteType,
@@ -94,7 +93,7 @@ describe('App', () => {
expect(screen.queryByText('Maintenance')).not.toBeInTheDocument();
- (axios.get as jest.Mock).mockImplementation(() =>
+ (axios.get as vi.Mock).mockImplementation(() =>
Promise.resolve({
data: {
show: true,
@@ -104,7 +103,7 @@ describe('App', () => {
);
act(() => {
- jest.runOnlyPendingTimers();
+ vi.runOnlyPendingTimers();
});
await act(async () => {
@@ -117,7 +116,7 @@ describe('App', () => {
// should not refresh page when maintenance state changes from false to true
expect(window.location.reload).not.toHaveBeenCalled();
- (axios.get as jest.Mock).mockImplementation(() =>
+ (axios.get as vi.Mock).mockImplementation(() =>
Promise.resolve({
data: {
show: false,
@@ -126,7 +125,7 @@ describe('App', () => {
})
);
- jest.runOnlyPendingTimers();
+ vi.runOnlyPendingTimers();
await act(async () => {
await flushPromises();
diff --git a/src/authentication/githubAuthProvider.test.tsx b/src/authentication/githubAuthProvider.test.tsx
index 1a3df830..8f68a3f2 100644
--- a/src/authentication/githubAuthProvider.test.tsx
+++ b/src/authentication/githubAuthProvider.test.tsx
@@ -7,14 +7,14 @@ describe('github auth provider', () => {
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QifQ.hNQI_r8BATy1LyXPr6Zuo9X_V0kSED8ngcqQ6G-WV5w';
beforeEach(() => {
- jest.spyOn(window.localStorage.__proto__, 'getItem');
- window.localStorage.__proto__.getItem = jest
+ vi.spyOn(window.localStorage.__proto__, 'getItem');
+ window.localStorage.__proto__.getItem = vi
.fn()
.mockImplementation((name) =>
name === 'scigateway:token' ? testToken : null
);
- window.localStorage.__proto__.removeItem = jest.fn();
- window.localStorage.__proto__.setItem = jest.fn();
+ window.localStorage.__proto__.removeItem = vi.fn();
+ window.localStorage.__proto__.setItem = vi.fn();
authProvider = new GithubAuthProvider('http://localhost:8000');
});
@@ -32,7 +32,7 @@ describe('github auth provider', () => {
});
it('should call the api to verify code', async () => {
- (mockAxios.post as jest.Mock).mockImplementation(() =>
+ (mockAxios.post as vi.Mock).mockImplementation(() =>
Promise.resolve({
data: {
token: testToken,
@@ -63,7 +63,7 @@ describe('github auth provider', () => {
});
it('should log the user out if code is invalid', async () => {
- (mockAxios.post as jest.Mock).mockImplementation(() =>
+ (mockAxios.post as vi.Mock).mockImplementation(() =>
Promise.reject({
response: {
status: 401,
@@ -80,7 +80,7 @@ describe('github auth provider', () => {
});
it('should log the user out if the token has expired', async () => {
- (mockAxios.post as jest.Mock).mockImplementation(() =>
+ (mockAxios.post as vi.Mock).mockImplementation(() =>
Promise.reject({
response: {
status: 401,
@@ -97,7 +97,7 @@ describe('github auth provider', () => {
});
it('should return user information if token is valid', async () => {
- (mockAxios.post as jest.Mock).mockImplementation(() =>
+ (mockAxios.post as vi.Mock).mockImplementation(() =>
Promise.resolve({
data: {
username: 'test_user',
diff --git a/src/authentication/icatAuthProvider.test.tsx b/src/authentication/icatAuthProvider.test.tsx
index 08eeeb07..0bb6be23 100644
--- a/src/authentication/icatAuthProvider.test.tsx
+++ b/src/authentication/icatAuthProvider.test.tsx
@@ -3,7 +3,7 @@ import ICATAuthProvider from './icatAuthProvider';
import parseJwt from './parseJwt';
import { BroadcastSignOutType } from '../state/scigateway.types';
-jest.mock('./parseJwt');
+vi.mock('./parseJwt');
describe('ICAT auth provider', () => {
let icatAuthProvider: ICATAuthProvider;
@@ -22,8 +22,8 @@ describe('ICAT auth provider', () => {
return null;
}
});
- window.localStorage.__proto__.removeItem = jest.fn();
- window.localStorage.__proto__.setItem = jest.fn();
+ window.localStorage.__proto__.removeItem = vi.fn();
+ window.localStorage.__proto__.setItem = vi.fn();
icatAuthProvider = new ICATAuthProvider(
'mnemonic',
@@ -35,7 +35,7 @@ describe('ICAT auth provider', () => {
`{"sessionId": "${token}", "username": "${token} username", "userIsAdmin": true}`
);
- document.dispatchEvent = jest.fn();
+ document.dispatchEvent = vi.fn();
});
it('should set the mnemonic to empty string if none is provided (after autologin)', async () => {
@@ -160,7 +160,7 @@ describe('ICAT auth provider', () => {
);
// ensure token is null
- window.localStorage.__proto__.getItem = jest.fn().mockReturnValue(null);
+ window.localStorage.__proto__.getItem = vi.fn().mockReturnValue(null);
icatAuthProvider = new ICATAuthProvider(
undefined,
@@ -196,7 +196,7 @@ describe('ICAT auth provider', () => {
);
// ensure token is null
- window.localStorage.__proto__.getItem = jest.fn().mockReturnValue(null);
+ window.localStorage.__proto__.getItem = vi.fn().mockReturnValue(null);
icatAuthProvider = new ICATAuthProvider(
undefined,
@@ -372,7 +372,7 @@ describe('ICAT auth provider', () => {
it('should call api to set scheduled maintenance state', async () => {
const scheduledMaintenanceState = { show: true, message: 'test' };
- mockAxios.put = jest.fn().mockImplementation(() =>
+ mockAxios.put = vi.fn().mockImplementation(() =>
Promise.resolve({
data: 'test',
})
@@ -393,7 +393,7 @@ describe('ICAT auth provider', () => {
it('should log the user out if it fails to set scheduled maintenance state', async () => {
const scheduledMaintenanceState = { show: true, message: 'test' };
- mockAxios.put = jest.fn().mockImplementation(() =>
+ mockAxios.put = vi.fn().mockImplementation(() =>
Promise.reject({
response: {
status: 401,
@@ -427,7 +427,7 @@ describe('ICAT auth provider', () => {
it('should log the user out if it fails to set maintenance state', async () => {
const maintenanceState = { show: true, message: 'test' };
- mockAxios.put = jest.fn().mockImplementation(() =>
+ mockAxios.put = vi.fn().mockImplementation(() =>
Promise.reject({
response: {
status: 401,
diff --git a/src/authentication/jwtAuthProvider.test.tsx b/src/authentication/jwtAuthProvider.test.tsx
index 6b85b0dc..d596b7a1 100644
--- a/src/authentication/jwtAuthProvider.test.tsx
+++ b/src/authentication/jwtAuthProvider.test.tsx
@@ -7,14 +7,14 @@ describe('jwt auth provider', () => {
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJ1c2VySXNBZG1pbiI6ZmFsc2V9.PEuKaAD98doFTLyqcNFpsuv50AQR8ejrbDQ0pwazM7Q';
beforeEach(() => {
- jest.spyOn(window.localStorage.__proto__, 'getItem');
+ vi.spyOn(window.localStorage.__proto__, 'getItem');
window.localStorage.__proto__.getItem = jest
.fn()
.mockImplementation((name) =>
name === 'scigateway:token' ? testToken : null
);
- window.localStorage.__proto__.removeItem = jest.fn();
- window.localStorage.__proto__.setItem = jest.fn();
+ window.localStorage.__proto__.removeItem = vi.fn();
+ window.localStorage.__proto__.setItem = vi.fn();
jwtAuthProvider = new JWTAuthProvider('http://localhost:8000');
});
diff --git a/src/cookieConsent/cookieConsent.component.test.tsx b/src/cookieConsent/cookieConsent.component.test.tsx
index 18d85f36..f7092f67 100644
--- a/src/cookieConsent/cookieConsent.component.test.tsx
+++ b/src/cookieConsent/cookieConsent.component.test.tsx
@@ -76,7 +76,7 @@ describe('Cookie consent component', () => {
});
it('should set cookie to true upon user accept', async () => {
- Cookies.set = jest.fn();
+ Cookies.set = vi.fn();
const user = userEvent.setup();
render(, { wrapper: Wrapper });
@@ -91,7 +91,7 @@ describe('Cookie consent component', () => {
});
it("initalises analytics if cookie consent is true but analytics hasn't yet been initialised", () => {
- jest.spyOn(document.head, 'appendChild');
+ vi.spyOn(document.head, 'appendChild');
Cookies.get = jest
.fn()
diff --git a/src/cookieConsent/cookiesPage.component.test.tsx b/src/cookieConsent/cookiesPage.component.test.tsx
index 93151cd4..2985ec42 100644
--- a/src/cookieConsent/cookiesPage.component.test.tsx
+++ b/src/cookieConsent/cookiesPage.component.test.tsx
@@ -12,7 +12,7 @@ import { TOptionsBase } from 'i18next';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-jest.mock('react-i18next', () => ({
+vi.mock('react-i18next', () => ({
useTranslation: () => {
return {
t: (key: string, options: TOptionsBase) =>
@@ -34,8 +34,8 @@ describe('Cookies page component', () => {
};
store = mockStore(state);
- Cookies.set = jest.fn();
- Cookies.remove = jest.fn();
+ Cookies.set = vi.fn();
+ Cookies.remove = vi.fn();
});
const theme = buildTheme(false);
diff --git a/src/helpPage/helpPage.component.test.tsx b/src/helpPage/helpPage.component.test.tsx
index bc74f19c..378439cc 100644
--- a/src/helpPage/helpPage.component.test.tsx
+++ b/src/helpPage/helpPage.component.test.tsx
@@ -8,9 +8,9 @@ import { render } from '@testing-library/react';
import { ThemeProvider } from '@mui/material';
import { buildTheme } from '../theming';
-jest.mock('../hooks/useAnchor', () => ({
+vi.mock('../hooks/useAnchor', () => ({
__esModule: true,
- default: jest.fn(),
+ default: vi.fn(),
}));
describe('Help page component', () => {
diff --git a/src/homePage/homePage.component.test.tsx b/src/homePage/homePage.component.test.tsx
index e0e06fc6..7ade97b4 100644
--- a/src/homePage/homePage.component.test.tsx
+++ b/src/homePage/homePage.component.test.tsx
@@ -6,10 +6,10 @@ import { ThemeProvider } from '@mui/material';
import { buildTheme } from '../theming';
import { MemoryRouter } from 'react-router-dom';
-jest.mock('@mui/material', () => ({
+vi.mock('@mui/material', () => ({
__esmodule: true,
...jest.requireActual('@mui/material'),
- useMediaQuery: jest.fn(() => true),
+ useMediaQuery: vi.fn(() => true),
}));
describe('Home page component', () => {
diff --git a/src/hooks/useAnchor.test.tsx b/src/hooks/useAnchor.test.tsx
index ca29a761..3673e0cd 100644
--- a/src/hooks/useAnchor.test.tsx
+++ b/src/hooks/useAnchor.test.tsx
@@ -25,10 +25,10 @@ const MOCK_REACT_ROUTER_LOCATION: Partial = {
};
// mock implementation of useLocation to return the mock URL
-jest.mock('react-router', () => ({
+vi.mock('react-router', () => ({
__esModule: true,
...jest.requireActual('react-router'),
- useLocation: jest.fn(),
+ useLocation: vi.fn(),
}));
describe('useAnchor', () => {
@@ -54,12 +54,12 @@ describe('useAnchor', () => {
router: { location: createLocation('/') },
});
- const mockScrollIntoView = jest.fn();
+ const mockScrollIntoView = vi.fn();
// pretend an element is found that matches the fragment
// the weird type cast is to get around TypeScript error saying
// the object is missing a bunch of other properties
// we obviously don't care about them so there's no point in stubbing them.
- jest.spyOn(document, 'getElementById').mockReturnValueOnce({
+ vi.spyOn(document, 'getElementById').mockReturnValueOnce({
scrollIntoView: mockScrollIntoView,
} as unknown as HTMLDivElement);
@@ -83,10 +83,10 @@ describe('useAnchor', () => {
router: { location: createLocation('/') },
});
- const mockScrollIntoView = jest.fn();
+ const mockScrollIntoView = vi.fn();
// pretend no element with #fragment is found
// and pretend there is other elements with IDs != fragment
- jest.spyOn(document, 'getElementById').mockImplementation((id) =>
+ vi.spyOn(document, 'getElementById').mockImplementation((id) =>
id === 'fragment'
? null
: ({
@@ -117,12 +117,12 @@ describe('useAnchor', () => {
router: { location: createLocation('/') },
});
- const mockScrollIntoView = jest.fn();
+ const mockScrollIntoView = vi.fn();
// pretend an element is found that matches the fragment
// the weird type cast is to get around TypeScript error saying
// the object is missing a bunch of other properties
// we obviously don't care about them so there's no point in stubbing them.
- jest.spyOn(document, 'getElementById').mockReturnValueOnce({
+ vi.spyOn(document, 'getElementById').mockReturnValueOnce({
scrollIntoView: mockScrollIntoView,
} as unknown as HTMLDivElement);
diff --git a/src/loginPage/loginPage.component.test.tsx b/src/loginPage/loginPage.component.test.tsx
index f567ac27..eb3b7fc1 100644
--- a/src/loginPage/loginPage.component.test.tsx
+++ b/src/loginPage/loginPage.component.test.tsx
@@ -34,7 +34,7 @@ import {
import userEvent from '@testing-library/user-event';
import { Router } from 'react-router-dom';
-jest.mock('loglevel');
+vi.mock('loglevel');
describe('Login selector component', () => {
let props: CombinedLoginProps;
@@ -48,8 +48,8 @@ describe('Login selector component', () => {
provider: new TestAuthProvider(null),
},
res: undefined,
- verifyUsernameAndPassword: jest.fn(),
- resetAuthState: jest.fn(),
+ verifyUsernameAndPassword: vi.fn(),
+ resetAuthState: vi.fn(),
};
});
@@ -65,7 +65,7 @@ describe('Login selector component', () => {
},
];
const user = userEvent.setup();
- const testSetMnemonic = jest.fn();
+ const testSetMnemonic = vi.fn();
render(
{
},
res: undefined,
verifyUsernameAndPassword: () => Promise.resolve(),
- resetAuthState: jest.fn(),
+ resetAuthState: vi.fn(),
};
state.scigateway.authorisation = props.auth;
@@ -385,7 +385,7 @@ describe('Login page component', () => {
});
it('on submit verification method should be called with username and password arguments', async () => {
- const mockLoginfn = jest.fn(() => Promise.resolve());
+ const mockLoginfn = vi.fn(() => Promise.resolve());
const user = userEvent.setup();
props.verifyUsernameAndPassword = mockLoginfn;
@@ -447,7 +447,7 @@ describe('Login page component', () => {
history.replace('/login?token=test_token');
const promise = Promise.resolve();
- const mockLoginfn = jest.fn(() => promise);
+ const mockLoginfn = vi.fn(() => promise);
props.verifyUsernameAndPassword = mockLoginfn;
render(, { wrapper: Wrapper });
@@ -465,7 +465,7 @@ describe('Login page component', () => {
});
it('on submit verification method should be called when logs in via keyless authenticator', async () => {
- const mockLoginfn = jest.fn(() => Promise.resolve());
+ const mockLoginfn = vi.fn(() => Promise.resolve());
const user = userEvent.setup();
props.verifyUsernameAndPassword = mockLoginfn;
props.auth.provider.mnemonic = 'nokeys';
diff --git a/src/mainAppBar/mainAppBar.component.test.tsx b/src/mainAppBar/mainAppBar.component.test.tsx
index a1aefd2e..2be44e6b 100644
--- a/src/mainAppBar/mainAppBar.component.test.tsx
+++ b/src/mainAppBar/mainAppBar.component.test.tsx
@@ -21,10 +21,10 @@ import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useMediaQuery } from '@mui/material';
-jest.mock('@mui/material', () => ({
+vi.mock('@mui/material', () => ({
__esmodule: true,
...jest.requireActual('@mui/material'),
- useMediaQuery: jest.fn(),
+ useMediaQuery: vi.fn(),
}));
describe('Main app bar component', () => {
@@ -66,7 +66,7 @@ describe('Main app bar component', () => {
// I don't think MediaQuery works properly in jest
// in the implementation useMediaQuery is used to query whether the current viewport is md or larger
// here we assume it is always the case.
- jest.mocked(useMediaQuery).mockReturnValue(true);
+ vi.mocked(useMediaQuery).mockReturnValue(true);
});
const theme = buildTheme(false);
@@ -441,7 +441,7 @@ describe('Main app bar component', () => {
describe('mobile variant', () => {
beforeEach(() => {
- jest.mocked(useMediaQuery).mockReturnValue(false);
+ vi.mocked(useMediaQuery).mockReturnValue(false);
});
it('shows drawer button, logo, user avatar, notification button, and an overflow menu button', () => {
diff --git a/src/mainAppBar/mobileOverflowMenu.component.test.tsx b/src/mainAppBar/mobileOverflowMenu.component.test.tsx
index be298589..5b1de964 100644
--- a/src/mainAppBar/mobileOverflowMenu.component.test.tsx
+++ b/src/mainAppBar/mobileOverflowMenu.component.test.tsx
@@ -55,7 +55,7 @@ describe('Mobile overflow menu', () => {
});
it('combines app bar buttons and settings menu', () => {
- render(, {
+ render(, {
wrapper: Wrapper,
});
@@ -87,7 +87,7 @@ describe('Mobile overflow menu', () => {
it('redirects to Admin page when Admin button clicked (maintenance is default)', async () => {
const user = userEvent.setup();
- render(, {
+ render(, {
wrapper: Wrapper,
});
@@ -101,7 +101,7 @@ describe('Mobile overflow menu', () => {
state.scigateway.adminPageDefaultTab = 'download';
const user = userEvent.setup();
- render(, {
+ render(, {
wrapper: Wrapper,
});
@@ -114,7 +114,7 @@ describe('Mobile overflow menu', () => {
it('toggles tutorial help when tutorial menu item is clicked', async () => {
const user = userEvent.setup();
- render(, {
+ render(, {
wrapper: Wrapper,
});
@@ -129,7 +129,7 @@ describe('Mobile overflow menu', () => {
'token123'
);
- render(, {
+ render(, {
wrapper: Wrapper,
});
@@ -141,7 +141,7 @@ describe('Mobile overflow menu', () => {
it('hides help apge item when help page is disabled', () => {
state.scigateway.features.showHelpPageButton = false;
- render(, {
+ render(, {
wrapper: Wrapper,
});
diff --git a/src/navigationDrawer/navigationDrawer.component.test.tsx b/src/navigationDrawer/navigationDrawer.component.test.tsx
index 65882ffd..29d3f38e 100644
--- a/src/navigationDrawer/navigationDrawer.component.test.tsx
+++ b/src/navigationDrawer/navigationDrawer.component.test.tsx
@@ -18,10 +18,10 @@ import ScigatewayReducer, {
initialState as scigatewayInitialState,
} from '../state/reducers/scigateway.reducer';
-jest.mock('@mui/material', () => ({
+vi.mock('@mui/material', () => ({
__esmodule: true,
...jest.requireActual('@mui/material'),
- useMediaQuery: jest.fn(),
+ useMediaQuery: vi.fn(),
}));
describe('Navigation drawer component', () => {
@@ -34,7 +34,7 @@ describe('Navigation drawer component', () => {
// I don't think MediaQuery works properly in jest
// in the implementation useMediaQuery is used to query whether the current viewport is md or larger
// here we assume it is always the case.
- jest.mocked(useMediaQuery).mockReturnValue(true);
+ vi.mocked(useMediaQuery).mockReturnValue(true);
});
function Wrapper({ children }: { children: React.ReactNode }): JSX.Element {
diff --git a/src/notifications/scigatewayNotification.component.test.tsx b/src/notifications/scigatewayNotification.component.test.tsx
index 7e8a4327..b8975f6f 100644
--- a/src/notifications/scigatewayNotification.component.test.tsx
+++ b/src/notifications/scigatewayNotification.component.test.tsx
@@ -14,7 +14,7 @@ function createScigatewayNotification(
message={message}
severity={severity}
index={0}
- dismissNotification={jest.fn()}
+ dismissNotification={vi.fn()}
/>
);
}
@@ -65,7 +65,7 @@ describe('Scigateway Notification component', () => {
});
it('an action is fired when Scigateway Notification button is clicked', async () => {
- const mockDismissFn = jest.fn();
+ const mockDismissFn = vi.fn();
const user = userEvent.setup();
render(
diff --git a/src/pageContainer.test.tsx b/src/pageContainer.test.tsx
index f31320ac..0ede8e8f 100644
--- a/src/pageContainer.test.tsx
+++ b/src/pageContainer.test.tsx
@@ -16,10 +16,10 @@ import { buildTheme } from './theming';
import { toastr } from 'react-redux-toastr';
import userEvent from '@testing-library/user-event';
-jest.mock('@mui/material', () => ({
+vi.mock('@mui/material', () => ({
__esmodule: true,
...jest.requireActual('@mui/material'),
- useMediaQuery: jest.fn(() => true),
+ useMediaQuery: vi.fn(() => true),
}));
describe('PageContainer - Tests', () => {
@@ -47,7 +47,7 @@ describe('PageContainer - Tests', () => {
});
it('calls toastr.clean() when escape is clicked', async () => {
- const cleanSpy = jest.spyOn(toastr, 'clean');
+ const cleanSpy = vi.spyOn(toastr, 'clean');
render(
diff --git a/src/routing/authorisedRoute.component.test.tsx b/src/routing/authorisedRoute.component.test.tsx
index 60152922..5800ae42 100644
--- a/src/routing/authorisedRoute.component.test.tsx
+++ b/src/routing/authorisedRoute.component.test.tsx
@@ -168,7 +168,7 @@ describe('AuthorisedRoute component', () => {
it('renders non admin component when non admin user accesses it', () => {
const testAuthProvider = new TestAuthProvider('test-token');
- testAuthProvider.isAdmin = jest.fn().mockImplementationOnce(() => false);
+ testAuthProvider.isAdmin = vi.fn().mockImplementationOnce(() => false);
state.scigateway.authorisation.provider = testAuthProvider;
state.scigateway.siteLoading = false;
state.scigateway.authorisation.loading = false;
@@ -192,7 +192,7 @@ describe('AuthorisedRoute component', () => {
it('renders PageNotFound component when non admin user accesses admin component', () => {
const testAuthProvider = new TestAuthProvider('test-token');
- testAuthProvider.isAdmin = jest.fn().mockImplementationOnce(() => false);
+ testAuthProvider.isAdmin = vi.fn().mockImplementationOnce(() => false);
state.scigateway.authorisation.provider = testAuthProvider;
state.scigateway.siteLoading = false;
state.scigateway.authorisation.loading = false;
diff --git a/src/routing/routing.component.test.tsx b/src/routing/routing.component.test.tsx
index 3c74e127..86f5c67d 100644
--- a/src/routing/routing.component.test.tsx
+++ b/src/routing/routing.component.test.tsx
@@ -13,18 +13,18 @@ import { buildTheme } from '../theming';
import { act, render } from '@testing-library/react';
import { Router } from 'react-router';
-jest.mock('../adminPage/adminPage.component', () => () => 'Mocked AdminPage');
-jest.mock(
+vi.mock('../adminPage/adminPage.component', () => () => 'Mocked AdminPage');
+vi.mock(
'../maintenancePage/maintenancePage.component',
() => () => 'Mocked MaintenancePage'
);
-jest.mock('../preloader/preloader.component', () => ({
+vi.mock('../preloader/preloader.component', () => ({
Preloader: () => 'Mocked Preloader',
}));
-jest.mock('@mui/material', () => ({
+vi.mock('@mui/material', () => ({
__esmodule: true,
...jest.requireActual('@mui/material'),
- useMediaQuery: jest.fn(),
+ useMediaQuery: vi.fn(),
}));
describe('Routing component', () => {
@@ -61,7 +61,7 @@ describe('Routing component', () => {
// I don't think MediaQuery works properly in jest
// in the implementation useMediaQuery is used to query whether the current viewport is md or larger
// here we assume it is always the case.
- jest.mocked(useMediaQuery).mockReturnValue(true);
+ vi.mocked(useMediaQuery).mockReturnValue(true);
});
afterEach(() => {
@@ -172,7 +172,7 @@ describe('Routing component', () => {
it('renders a route for maintenance page when site is under maintenance and user is not admin', () => {
const testAuthProvider = new TestAuthProvider('logged in');
- testAuthProvider.isAdmin = jest.fn().mockImplementationOnce(() => false);
+ testAuthProvider.isAdmin = vi.fn().mockImplementationOnce(() => false);
state.scigateway.authorisation.provider = testAuthProvider;
state.scigateway.siteLoading = false;
state.scigateway.maintenance = { show: true, message: 'test' };
@@ -406,11 +406,11 @@ describe('Routing component', () => {
];
state.router.location = createLocation('/test_link');
- jest.spyOn(document, 'getElementById').mockImplementation(() => {
+ vi.spyOn(document, 'getElementById').mockImplementation(() => {
return document.createElement('div');
});
- const clearIntervalSpy = jest.spyOn(window, 'clearInterval');
+ const clearIntervalSpy = vi.spyOn(window, 'clearInterval');
render(, { wrapper: Wrapper });
diff --git a/src/setupTests.ts b/src/setupTests.ts
index 3bc05dc6..02ac9c7c 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -33,3 +33,7 @@ vi.mock('single-spa', () => ({
triggerAppChange: vi.fn(),
NOT_LOADED: 'NOT_LOADED',
}));
+
+// Recreate jest behaviour by mocking with __mocks__ by mocking globally here
+vi.mock('axios');
+vi.mock('react-i18next');
diff --git a/src/state/actions/scigateway.actions.test.tsx b/src/state/actions/scigateway.actions.test.tsx
index d9d10114..0cbb59bb 100644
--- a/src/state/actions/scigateway.actions.test.tsx
+++ b/src/state/actions/scigateway.actions.test.tsx
@@ -474,7 +474,7 @@ describe('scigateway actions', () => {
},
};
- document.addEventListener = jest.fn(
+ document.addEventListener = vi.fn(
(id: string, inputHandler: (event: Event) => void) => {
inputHandler(new CustomEvent('test', { detail: registerRouteAction }));
}
@@ -552,7 +552,7 @@ describe('scigateway actions', () => {
},
});
- const eventListenerSpy = jest.spyOn(document, 'addEventListener');
+ const eventListenerSpy = vi.spyOn(document, 'addEventListener');
await asyncAction(dispatch, getState);
@@ -697,7 +697,7 @@ describe('scigateway actions', () => {
})
);
- jest.spyOn(window.localStorage.__proto__, 'getItem');
+ vi.spyOn(window.localStorage.__proto__, 'getItem');
window.localStorage.__proto__.getItem = jest
.fn()
.mockImplementation((name) => (name === 'darkMode' ? 'true' : 'false'));
@@ -728,7 +728,7 @@ describe('scigateway actions', () => {
})
);
- jest.spyOn(window.localStorage.__proto__, 'getItem');
+ vi.spyOn(window.localStorage.__proto__, 'getItem');
window.localStorage.__proto__.getItem = jest
.fn()
.mockImplementation((name) =>
@@ -756,7 +756,7 @@ describe('scigateway actions', () => {
(mockAxios.get as jest.Mock).mockImplementationOnce(() =>
Promise.reject({})
);
- log.error = jest.fn();
+ log.error = vi.fn();
const asyncAction = configureSite();
const actions: Action[] = [];
@@ -777,7 +777,7 @@ describe('scigateway actions', () => {
data: 1,
})
);
- log.error = jest.fn();
+ log.error = vi.fn();
const asyncAction = configureSite();
const actions: Action[] = [];
@@ -796,7 +796,7 @@ describe('scigateway actions', () => {
(mockAxios.get as jest.Mock).mockImplementationOnce(() =>
Promise.reject({})
);
- log.error = jest.fn();
+ log.error = vi.fn();
const path = 'non/existent/path';
const asyncAction = loadStrings(path);
diff --git a/src/state/middleware/scigateway.middleware.test.tsx b/src/state/middleware/scigateway.middleware.test.tsx
index 623b09ea..0d305563 100644
--- a/src/state/middleware/scigateway.middleware.test.tsx
+++ b/src/state/middleware/scigateway.middleware.test.tsx
@@ -32,7 +32,7 @@ import { thunk } from 'redux-thunk';
import { autoLoginAuthorised } from '../actions/scigateway.actions';
import * as singleSpa from 'single-spa';
-jest.mock('single-spa');
+vi.mock('single-spa');
describe('scigateway middleware', () => {
let events: CustomEvent[] = [];
@@ -112,7 +112,7 @@ describe('scigateway middleware', () => {
return true;
};
- document.addEventListener = jest.fn(
+ document.addEventListener = vi.fn(
(id: string, inputHandler: (event: Event) => void) => {
handler = inputHandler;
}
@@ -120,13 +120,13 @@ describe('scigateway middleware', () => {
store = mockStore(getState());
- Storage.prototype.getItem = jest.fn(() => 'false');
+ Storage.prototype.getItem = vi.fn(() => 'false');
});
describe('autoLoginMiddleware', () => {
let autoLogin: jest.Mock;
beforeEach(() => {
- autoLogin = jest.fn(() => Promise.resolve());
+ autoLogin = vi.fn(() => Promise.resolve());
store = mockStore({
...getState(),
scigateway: {
@@ -173,9 +173,9 @@ describe('scigateway middleware', () => {
});
it('sends an error notification if autoLogin fails', async () => {
- log.error = jest.fn();
+ log.error = vi.fn();
- autoLogin = jest.fn(() => Promise.reject());
+ autoLogin = vi.fn(() => Promise.reject());
store = mockStore({
...getState(),
scigateway: {
@@ -374,8 +374,8 @@ describe('scigateway middleware', () => {
location: createLocation('/'),
},
});
- Storage.prototype.getItem = jest.fn().mockReturnValueOnce(undefined);
- window.matchMedia = jest.fn().mockReturnValueOnce({ matches: true });
+ Storage.prototype.getItem = vi.fn().mockReturnValueOnce(undefined);
+ window.matchMedia = vi.fn().mockReturnValueOnce({ matches: true });
const theme = buildTheme(true, false, '#654321');
const sendThemeOptionsAction = {
type: SendThemeOptionsType,
@@ -636,7 +636,7 @@ describe('scigateway middleware', () => {
});
it('should listen for notification events and create toast for error', () => {
- toastr.error = jest.fn();
+ toastr.error = vi.fn();
listenToPlugins(store.dispatch, getState);
const notificationAction = {
@@ -656,7 +656,7 @@ describe('scigateway middleware', () => {
});
it('should listen for notification events and create toast for warning', () => {
- toastr.warning = jest.fn();
+ toastr.warning = vi.fn();
listenToPlugins(store.dispatch, getState);
const notificationAction = {
@@ -675,7 +675,7 @@ describe('scigateway middleware', () => {
});
it('should listen for notification events and create toast for information', () => {
- toastr.info = jest.fn();
+ toastr.info = vi.fn();
listenToPlugins(store.dispatch, getState);
const notificationAction = {
@@ -694,7 +694,7 @@ describe('scigateway middleware', () => {
});
it('should listen for notification events and log error for invalid severity', () => {
- log.error = jest.fn();
+ log.error = vi.fn();
listenToPlugins(store.dispatch, getState);
const notificationAction = {
@@ -715,7 +715,7 @@ describe('scigateway middleware', () => {
});
it('should broadcast requestpluginrerender action but ignore it itself', () => {
- log.warn = jest.fn();
+ log.warn = vi.fn();
const mockLog = (log.warn as jest.Mock).mock;
listenToPlugins(store.dispatch, getState);
@@ -732,7 +732,7 @@ describe('scigateway middleware', () => {
});
it('should ignore BroadcastSignOut ', () => {
- log.warn = jest.fn();
+ log.warn = vi.fn();
const mockLog = (log.warn as jest.Mock).mock;
listenToPlugins(store.dispatch, getState);
@@ -743,7 +743,7 @@ describe('scigateway middleware', () => {
});
it('should listen for events and not fire unrecognised action', () => {
- log.warn = jest.fn();
+ log.warn = vi.fn();
listenToPlugins(store.dispatch, getState);
handler(new CustomEvent('test', { detail: action }));
@@ -759,7 +759,7 @@ describe('scigateway middleware', () => {
});
it('should not fire actions for events without detail', () => {
- log.error = jest.fn();
+ log.error = vi.fn();
listenToPlugins(store.dispatch, getState);
@@ -776,7 +776,7 @@ describe('scigateway middleware', () => {
});
it('should not fire actions for events without type on detail', () => {
- log.error = jest.fn();
+ log.error = vi.fn();
listenToPlugins(store.dispatch, getState);
diff --git a/src/state/reducers/scigateway.reducer.test.tsx b/src/state/reducers/scigateway.reducer.test.tsx
index 06670ced..d44a972a 100644
--- a/src/state/reducers/scigateway.reducer.test.tsx
+++ b/src/state/reducers/scigateway.reducer.test.tsx
@@ -129,7 +129,7 @@ describe('scigateway reducer', () => {
});
it('should not add steps when a duplicate target property is found', () => {
- log.error = jest.fn();
+ log.error = vi.fn();
state.helpSteps = [];
const steps = [
@@ -547,7 +547,7 @@ describe('scigateway reducer', () => {
});
it('should log error and not register plugin with duplicate route in State', () => {
- log.error = jest.fn();
+ log.error = vi.fn();
const duplicatePayload = {
...basePayload,
displayName: 'Duplicate Route',
@@ -600,7 +600,7 @@ describe('scigateway reducer', () => {
it('should log an error if an initialiseAnalytics message is sent with no analytics config', () => {
delete state.analytics;
- log.error = jest.fn();
+ log.error = vi.fn();
const updatedState = ScigatewayReducer(state, initialiseAnalytics());
expect(updatedState.analytics).toBeUndefined();
diff --git a/src/tour/tour.component.test.tsx b/src/tour/tour.component.test.tsx
index 19bd1c20..d83c87d9 100644
--- a/src/tour/tour.component.test.tsx
+++ b/src/tour/tour.component.test.tsx
@@ -13,8 +13,8 @@ import TestAuthProvider from '../authentication/testAuthProvider';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-jest.mock('popper.js', () => {
- const PopperJS = jest.requireActual('popper.js');
+vi.mock('popper.js', async () => {
+ const PopperJS = await vi.requireActual('popper.js');
return class {
public static placements = PopperJS.placements;
@@ -84,7 +84,7 @@ describe('Tour component', () => {
});
afterEach(() => {
- jest.useRealTimers();
+ vi.useRealTimers();
});
it('can navigate between tutorial steps', async () => {
@@ -145,9 +145,9 @@ describe('Tour component', () => {
content: 'Plugin link test',
},
];
- jest.useFakeTimers();
+ vi.useFakeTimers();
const user = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: vi.advanceTimersByTime,
});
render(
@@ -162,7 +162,7 @@ describe('Tour component', () => {
await user.click(screen.getByLabelText('Next'));
act(() => {
- jest.runAllTimers();
+ vi.runAllTimers();
});
expect(testStore.getActions().length).toEqual(1);
diff --git a/tsconfig.base.json b/tsconfig.base.json
new file mode 100644
index 00000000..cb41eaa8
--- /dev/null
+++ b/tsconfig.base.json
@@ -0,0 +1,32 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "esnext", "DOM", "DOM.Iterable",
+ ],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ "allowJs": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+
+ /* Bundler mode */
+ "moduleResolution": "node",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "forceConsistentCasingInFileNames": true,
+ },
+ "include": [
+ "src"
+ ]
+}
diff --git a/tsconfig.build.json b/tsconfig.build.json
new file mode 100644
index 00000000..303bffc9
--- /dev/null
+++ b/tsconfig.build.json
@@ -0,0 +1,5 @@
+{
+ "extends": "./tsconfig.base.json",
+ // Exclude test files from build
+ "exclude": ["**/?*test.*", "src/setupTests.ts"],
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 53afed36..11310aa2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,35 +1,6 @@
-{
- "compilerOptions": {
- "target": "es5",
- "lib": [
- "esnext", "DOM", "DOM.Iterable",
- ],
- "module": "ESNext",
- "skipLibCheck": true,
-
- "allowJs": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
-
- /* Bundler mode */
- "moduleResolution": "node",
- "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
- "jsx": "react-jsx",
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
- "forceConsistentCasingInFileNames": true,
- },
- "include": [
- "src"
- ],
- "exclude": [
- "**/?*test.*",
- ]
-}
+{
+ "extends": "./tsconfig.base.json",
+ "compilerOptions": {
+ "types": ["vitest/globals", "vitest/jsdom"],
+ },
+}