bigbuffet-rw/app/soapbox/jest/test-helpers.tsx

130 lines
3.5 KiB
TypeScript
Raw Normal View History

2022-07-06 11:56:55 -07:00
import { configureMockStore } from '@jedmao/redux-mock-store';
2022-08-08 12:53:21 -07:00
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render, RenderOptions } from '@testing-library/react';
2022-08-09 09:00:44 -07:00
import { renderHook, RenderHookOptions } from '@testing-library/react-hooks';
2022-07-06 15:02:44 -07:00
import { merge } from 'immutable';
import React, { FC, ReactElement } from 'react';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { Action, applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import '@testing-library/jest-dom';
import NotificationsContainer from '../features/ui/containers/notifications_container';
import { default as rootReducer } from '../reducers';
2022-07-06 11:56:55 -07:00
import type { AnyAction } from 'redux';
import type { AppDispatch } from 'soapbox/store';
2022-07-06 11:12:35 -07:00
// Mock Redux
// https://redux.js.org/recipes/writing-tests/
2022-07-06 15:02:44 -07:00
const rootState = rootReducer(undefined, {} as Action);
2022-07-06 11:56:55 -07:00
const mockStore = configureMockStore<typeof rootState, AnyAction, AppDispatch>([thunk]);
2022-05-13 13:08:38 -07:00
/** Apply actions to the state, one at a time. */
const applyActions = (state: any, actions: any, reducer: any) => {
return actions.reduce((state: any, action: any) => reducer(state, action), state);
};
2022-08-09 09:00:44 -07:00
/** React Query client for tests. */
2022-08-08 12:53:21 -07:00
const queryClient = new QueryClient({
logger: {
// eslint-disable-next-line no-console
log: console.log,
warn: console.warn,
error: () => { },
},
defaultOptions: {
queries: {
staleTime: 0,
cacheTime: Infinity,
2022-08-08 12:53:21 -07:00
retry: false,
},
},
});
const createTestStore = (initialState: any) => createStore(rootReducer, initialState, applyMiddleware(thunk));
const TestApp: FC<any> = ({ children, storeProps, routerProps = {} }) => {
2022-07-06 15:02:44 -07:00
let store: ReturnType<typeof createTestStore>;
2022-07-06 13:25:07 -07:00
let appState = rootState;
if (storeProps) {
2022-07-06 13:25:07 -07:00
appState = merge(rootState, storeProps);
store = createTestStore(appState);
} else {
2022-07-06 13:25:07 -07:00
store = createTestStore(appState);
}
const props = {
locale: 'en',
store,
};
return (
<Provider store={props.store}>
<QueryClientProvider client={queryClient}>
<IntlProvider locale={props.locale}>
<MemoryRouter {...routerProps}>
{children}
<NotificationsContainer />
</MemoryRouter>
</IntlProvider>
</QueryClientProvider>
</Provider>
);
};
const customRender = (
ui: ReactElement,
options?: Omit<RenderOptions, 'wrapper'>,
store?: any,
routerProps?: any,
) => render(ui, {
wrapper: () => <TestApp children={ui} storeProps={store} routerProps={routerProps} />,
...options,
});
2022-08-09 09:00:44 -07:00
/** Like renderHook, but with access to the Redux store. */
const customRenderHook = <T extends {}>(
callback: (props?: any) => any,
options?: Omit<RenderHookOptions<T>, 'wrapper'>,
store?: any,
) => {
return renderHook(callback, {
wrapper: ({ children }) => <TestApp children={children} storeProps={store} />,
...options,
});
};
2022-08-08 12:53:21 -07:00
2022-04-12 06:51:28 -07:00
const mockWindowProperty = (property: any, value: any) => {
const { [property]: originalProperty } = window;
delete window[property];
beforeAll(() => {
Object.defineProperty(window, property, {
configurable: true,
writable: true,
value,
});
});
afterAll(() => {
window[property] = originalProperty;
});
};
export * from '@testing-library/react';
export {
customRender as render,
2022-08-09 09:00:44 -07:00
customRenderHook as renderHook,
mockStore,
applyActions,
rootState,
rootReducer,
2022-04-12 06:51:28 -07:00
mockWindowProperty,
2022-04-16 17:03:33 -07:00
createTestStore,
queryClient,
};