26
loading...
This website collects cookies to deliver better user experience
<Provider>
. That Provider ensures all components rendered in that tree use the same redux store. When you're building an app, you usually just add <Provider>
at the top level and don't have to worry about it. When testing redux apps though it becomes a major pain. Each test for a redux-connected component has to be individually wrapped in its own provider. connect()
ed component and a basic (non-redux) version of the same component in the same file. They then just don't test the redux-connected version at all. Please don't do this.connect()
doesn't support this pattern. It's unlikely that you'll be able to continue to separate your component that way as you move into the future.renderWithContext
, getStoreWithState
, and getStateWithItems
. These utilities help me work with state and context without cluttering my tests with complex setup code. getStoreWithState
:import { configureStore } from "@reduxjs/toolkit";
const reducer = { /* ... */ }
export const store = configureStore({ reducer });
export function getStoreWithState(preloadedState) {
return configureStore({ reducer, preloadedState });
}
import { render } from "@testing-library/react";
export function renderWithContext(element, state) {
const store = getStoreWithState(state);
const utils = render(
<Provider store={store}>
{element}
</Provider>
);
return { store, ...utils };
mountWithStore
function inside of them, but I think you get a ton of benefit moving this into an app-wide utility file. It makes it a lot easier to pre-populate state consistently and provide any additional context that might be needed for your tests.import { renderWithContext } from "../test-utils";
test("error banner should appear", () => {
renderWithContext(<Header />, { errors: [{ /* ... */ } ] })
expect(screen.getByRole("alert")).toHaveTextContent("Could not load data");
});
export function getStateWithErrors(errors) {
const state = {
products: { /* ... */ },
cart: { checkoutState: "READY", items: {} },
errors
};
return state;
}
import {
renderWithContext,
getStateWithErrors
} from "../test-utils";
test("error banner should appear", () => {
const state = getStateWithErrors([{ /* ... */ }]);
renderWithContext(<Header />, state);
expect(screen.getByRole("alert")).toHaveTextContent("Could not load data");
});
test("error banner should not appear", () => {
const state = getStateWithErrors([]);
renderWithContext(<Header />, state);
expect((screen.queryByRole("alert"))).toBeNull();
});