¿Alguien ha podido borrar Redux entre pruebas? ¿Qué hiciste?
Tengo una aplicación React Native Expo que usa Redux.
Tengo una prueba que funciona de forma aislada, pero cuando ejecuto todas las pruebas, falla porque quedan cambios de estado en redux de otras pruebas.
¿Cómo 'vacío' la tienda redux entre pruebas?
Probé el paquete mock-redux-store, pero cuando le pasé un combineReducers(), no devolvió nada.
Podría reconstruir los segmentos de estado allí manualmente y pasarlos a la tienda simulada, pero eso sería difícil de mantener.
testing-library-utils.js :
//This file adds a Redux Provider to a component's context when running Jest tests from test files. //This first import enables jest native, which enables some state-centric matchers import '@testing-library/jest-native/extend-expect'; import React from 'react'; import { render } from '@testing-library/react-native'; import { Provider, combineReducers, applyMiddleware, compose } from 'redux'; import ReduxThunk from 'redux-thunk'; import { createMockStore } from 'redux-test-utils'; // import { store } from '../App'; import logBooksReducer from '../store/reducers/logBooks-reducer'; import authReducer from '../store/reducers/auth-reducer'; const composedMiddleWare = compose(applyMiddleware(ReduxThunk)); const rootReducer = combineReducers({ logBooks: logBooksReducer, auth: authReducer, }); const store = createMockStore(rootReducer, composedMiddleWare); console.log('STORE ', JSON.stringify(store.getState())); const AllTheProviders = ({ children }) => { console.log('Store.getState() from UTILS ', store.getState()); return <Provider store={store}>{children}</Provider>; }; const customRender = (ui, options) => render(ui, { wrapper: AllTheProviders, ...options }); // re-export everything export * from '@testing-library/react-native'; // override render method export { customRender as render };Redux es un objeto que define el estado actual de la aplicación. Entonces, a menos que sepas el orden correcto de las bromas, no funcionará. Por cierto, Jest no ejecuta las pruebas en el mismo orden cada vez. A veces almacena los que fallaron y los ejecuta primero la próxima vez.
Lo que se recomienda es que intensifique la tienda Redux para cada prueba/archivo de prueba.
Esta es mi test/utils/mocks/redux/index.js
import configureStore from 'redux-mock-store'; import createMockBluetooth from '../bt'; import createMockApi from '../api'; import createMockState from './state'; ... const createMockStore = ({ state = createMockState(), api = createMockApi(), ble = createMockBluetooth(), ..., middlewares = [], } = {}) => { const thunkMiddleware = ({ dispatch, getState }) => (next) => (action) => ( typeof action !== 'function' ? next(action) : action(dispatch, getState, { api, bt, ... }) ); return configureStore([thunkMiddleware, ...middlewares])(state); }; export default createMockStore;De esta manera me permite definir una tienda diferente para cada prueba:
addressList.test.js
const defaultProps = { navigation: { state: { params: {} }, dispatch: jest.fn(), ... pop: jest.fn(), popToTop: jest.fn(), isFocused: jest.fn(), }, }; const getStoreWithMockAddresses = (mockData) => createMockStore({ state: createMockState({ listOfAddresses: mockData, }, { customMerge: preferOverride('listOfAddresses'), }), }); .... test('random test', () => { const mockAddresses = { fullList: [ { name: 'address-1', number: 69 }, ], }; const mockStore = getStoreWithMockAddresses(mockAddresses); const { getByTestId } = render(<YourComponent navigation={ defaultProps.navigation } />, { wrapper: { store: mockStore } }); }Necesito configurar para cada prueba. Tiene sentido ya que estoy probando que los componentes funcionarán en un estado específico.
Tenga en cuenta que la sintaxis del método de render es un poco porque estoy usando una implementación personalizada del renderizado original.
EDITAR:
import merge from 'deepmerge'; const createMockState = (overrides = {}, options = []) => merge({ ... listOfAddresses: { fullList: [] }, }, overrides, options); export default createMockState;¡Finalmente lo tengo!
Esta es mi versión modificada de lo que está en Redux Testing Docs
//This file adds a Redux Provider to a component's context when running Jest tests from test files. //This first import enables jest native, which enables some state-centric matchers import '@testing-library/jest-native/extend-expect'; import React from 'react'; import { render as rtlRender } from '@testing-library/react-native'; // This line is important import { Provider } from 'react-redux'; import { rootReducer } from '../App'; //Importing my same Root Reducer, so maintaining is easier import { NavigationContainer } from '@react-navigation/native'; import { configureStore } from '@reduxjs/toolkit'; //Need to install @reduxjs/toolkit const render = ( ui, { preloadedState, store = configureStore({ reducer: rootReducer, preloadedState, middleware: getDefaultMiddleware => getDefaultMiddleware({ serializableCheck: false, }), }), ...renderOptions } = {} ) => { const Wrapper = ({ children }) => { return ( <Provider store={store}> <NavigationContainer>{children}</NavigationContainer> //Adding nav container here </Provider> ); }; return rtlRender(ui, { wrapper: Wrapper, ...renderOptions }); }; // re-export everything export * from '@testing-library/react-native'; // override render method export { render };Luego, por prueba, pasa el estado precargado a la función de representación de la prueba. De esta manera, cada prueba puede tener un entorno de prueba redux separado.
it('Displays the locaiton', async () => { const preloadedState = { entries: { allEntries: myPreloadedStateForThisTest } }; // Make sure to match the data structure of your real state. const { findByText } = render(<EntriesScreen />, { preloadedState }); // Expect: await findByText(/West Virginia/i); });Gracias @markerikson por el código de ejemplo.