When trying to run component tests in cypress I get this error:
The following error originated from your test code, not from Cypress. > Cannot access 'api' before initialization When Cypress detects uncaught errors originating from your test code it will automatically fail the current test. Cypress could not associate this error to any specific test. We dynamically generated a new test to display this failure.
it comes from my redux store config file store/index.ts
:
import { configureStore } from '@reduxjs/toolkit';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import { api } from './api/api';
import { sendErrorToSentryMiddleware } from './middlewares/sentry';
import { unauthenticateMiddleware } from './middlewares/unauthenticate';
import { debugReducer } from './reducers/debug';
import { loginPageErrorsReducer } from './reducers/errorMessages/loginPageErrors';
import { securityPageErrorsReducer } from './reducers/errorMessages/securityPageErrors';
import { profileReducer } from './reducers/profile';
import { reauthReducer } from './reducers/reauth/reauth';
import { shareReservationReducer } from './reducers/sharereservation';
const store = configureStore({
reducer: {
profile: profileReducer,
securityPageErrors: securityPageErrorsReducer,
loginPageErrors: loginPageErrorsReducer,
reauth: reauthReducer,
shareReservation: shareReservationReducer,
debug: debugReducer,
[api.reducerPath]: api.reducer, // line that triggers the error
},
preloadedState: {},
middleware: getDefaultMiddleware =>
getDefaultMiddleware().concat([
api.middleware,
unauthenticateMiddleware,
sendErrorToSentryMiddleware,
]),
enhancers: getDefaultEnhancers => {
return getDefaultEnhancers().concat(sentryReduxEnhancer);
},
});
So it seems Cypress just copy the whole project codebase to run its tests, however I don't need the redux store to run any of the component tests, is there a way to fix this?
I have tried to add the Redux store to the component test file to fix it but it didn't work:
import { configureStore } from '@reduxjs/toolkit';
import { mount } from 'cypress/react';
import React from 'react';
import { Provider } from 'react-redux';
import SellCalculator from '../../src/components/pages/funds/SellCalculator';
import { ModalContext } from '../../src/context/modalContext';
import { api } from '../../src/store/api/api';
describe('SellCalculator', () => {
const defaultProps = {
sharePrice: 100,
totalShares: 15,
onChange: cy.stub().as('onChangeSpy'),
};
const store = configureStore({
reducer: {
[api.reducerPath]: api.reducer,
},
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
const mountWithContext = (props = defaultProps) => {
const setModal = cy.stub().as('setModalSpy');
mount(
<Provider store={store}>
<ModalContext.Provider
value={{
setModal,
Modal: null,
loading: false,
setLoading: () => {},
}}
>
<SellCalculator {...props} />
</ModalContext.Provider>
</Provider>
);
};
it('renders with initial values', () => {
mountWithContext();
cy.contains('Share price (USD)').should('be.visible');
cy.contains('$100').should('be.visible');
cy.contains('Sell price (USD)').should('be.visible');
cy.contains('$100').should('be.visible'); // Initial value is 1 share
});
});
Is there a way to fix this? Ideally I would like cypress to only use the files relevant for the components being tested
You say so it seems Cypress just copy the whole project codebase to run its tests, but that is not the case.
To include react-redux
in the component test, you must explicitly add the <Provider>
for the store - which you have done.
mount(
<Provider store={store}>
...
But then you say however I don't need the redux store to run any of the component tests, so the obvious thing to try is removing that <Provider store={store}>
wrapper from the mount function.
You haven't given us the <SellCalculator>
code, so we don't know for sure if the store can be removed, but looking at the store's reducers the only thing I see that might be tightly coupled is shareReservationReducer
.
If this is the case, you will need to mock the store, similar to the modal mock
const setModal = cy.stub().as('setModalSpy');
const mockStore = {
shareReservation: cy.stub().callsFake(() => {...})
}
mount(
<Provider store={mockStore}>
<ModalContext.Provider
...