Run component tests with a real store and use renderWithContext everywhere (#25217)
* Change renderWithFullContext to not mock Redux store * Remove renderWithIntl and renderWithIntlAndStore * Rename renderWithFullContext to renderWithContext * Use renderWithContext for WS context
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ab349946db
Коммит
be34a5d2df
@@ -22,50 +22,42 @@ import type {GlobalState} from 'types/store';
|
||||
export * from '@testing-library/react';
|
||||
export {userEvent};
|
||||
|
||||
export const renderWithIntl = (component: React.ReactNode | React.ReactNodeArray, locale = 'en') => {
|
||||
return render(<IntlProvider locale={locale}>{component}</IntlProvider>);
|
||||
};
|
||||
export type FullContextOptions = {
|
||||
locale?: string;
|
||||
useMockedStore?: boolean;
|
||||
}
|
||||
|
||||
export const renderWithIntlAndStore = (component: React.ReactNode | React.ReactNodeArray, initialState: DeepPartial<GlobalState> = {}, locale = 'en', divContainer?: HTMLDivElement) => {
|
||||
// We use a redux-mock-store store for testing, but we set up a real store to ensure the initial state is complete
|
||||
const realStore = configureStore(initialState);
|
||||
export const renderWithContext = (
|
||||
component: React.ReactElement,
|
||||
initialState: DeepPartial<GlobalState> = {},
|
||||
partialOptions?: FullContextOptions,
|
||||
) => {
|
||||
const options = {
|
||||
locale: partialOptions?.locale ?? 'en',
|
||||
useMockedStore: partialOptions?.useMockedStore ?? false,
|
||||
};
|
||||
|
||||
const store = mockStore(realStore.getState());
|
||||
|
||||
return render(
|
||||
<IntlProvider locale={locale}>
|
||||
<Provider store={store}>
|
||||
{component}
|
||||
</Provider>
|
||||
</IntlProvider>,
|
||||
{container: divContainer},
|
||||
);
|
||||
};
|
||||
|
||||
export const renderWithFullContext = (component: React.ReactNode | React.ReactNodeArray, initialState: DeepPartial<GlobalState> = {}, locale = 'en') => {
|
||||
// We use a redux-mock-store store for testing, but we set up a real store to ensure the initial state is complete
|
||||
const testState = configureStore(initialState).getState();
|
||||
const testStore = configureOrMockStore(initialState, options.useMockedStore);
|
||||
|
||||
// Store these in an object so that they can be maintained through rerenders
|
||||
const renderState = {
|
||||
component,
|
||||
history: createBrowserHistory(),
|
||||
locale,
|
||||
state: testState,
|
||||
store: mockStore(testState),
|
||||
options,
|
||||
store: testStore,
|
||||
};
|
||||
|
||||
// This should wrap the component in roughly the same providers used in App and RootProvider
|
||||
function wrapComponent() {
|
||||
function WrapComponent(props: {children: React.ReactElement}) {
|
||||
// Every time this is called, these values should be updated from `renderState`
|
||||
return (
|
||||
<Provider store={renderState.store}>
|
||||
<Router history={renderState.history}>
|
||||
<IntlProvider
|
||||
locale={renderState.locale}
|
||||
locale={renderState.options.locale}
|
||||
>
|
||||
<WebSocketContext.Provider value={WebSocketClient}>
|
||||
{renderState.component}
|
||||
{props.children}
|
||||
</WebSocketContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
@@ -73,36 +65,41 @@ export const renderWithFullContext = (component: React.ReactNode | React.ReactNo
|
||||
);
|
||||
}
|
||||
|
||||
const results = render(wrapComponent());
|
||||
const results = render(component, {wrapper: WrapComponent});
|
||||
|
||||
return {
|
||||
...results,
|
||||
rerender: (newComponent: React.ReactNode | React.ReactNodeArray) => {
|
||||
rerender: (newComponent: React.ReactElement) => {
|
||||
renderState.component = newComponent;
|
||||
|
||||
results.rerender(wrapComponent());
|
||||
results.rerender(renderState.component);
|
||||
},
|
||||
|
||||
/**
|
||||
* Rerenders the component after replacing the entire store state with the provided one.
|
||||
*/
|
||||
replaceStoreState: (newInitialState: DeepPartial<GlobalState>) => {
|
||||
const newTestState = configureStore(newInitialState).getState();
|
||||
renderState.state = newTestState;
|
||||
renderState.store = mockStore(newTestState);
|
||||
renderState.store = configureOrMockStore(newInitialState, renderState.options.useMockedStore);
|
||||
|
||||
results.rerender(wrapComponent());
|
||||
results.rerender(renderState.component);
|
||||
},
|
||||
|
||||
/**
|
||||
* Rerenders the component after merging the current store state with the provided one.
|
||||
*/
|
||||
updateStoreState: (stateDiff: DeepPartial<GlobalState>) => {
|
||||
const newTestState = mergeObjects(renderState.state, stateDiff);
|
||||
renderState.state = newTestState;
|
||||
renderState.store = mockStore(newTestState);
|
||||
const newInitialState = mergeObjects(renderState.store.getState(), stateDiff);
|
||||
renderState.store = configureOrMockStore(newInitialState, renderState.options.useMockedStore);
|
||||
|
||||
results.rerender(wrapComponent());
|
||||
results.rerender(renderState.component);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
function configureOrMockStore<T>(initialState: DeepPartial<T>, useMockedStore: boolean) {
|
||||
let testStore = configureStore(initialState);
|
||||
if (useMockedStore) {
|
||||
testStore = mockStore(testStore.getState());
|
||||
}
|
||||
return testStore;
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user