testHelpers.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import React, { PropsWithChildren, ReactElement } from 'react';
  2. import {
  3. MemoryRouter,
  4. MemoryRouterProps,
  5. Route,
  6. Routes,
  7. } from 'react-router-dom';
  8. import { Provider } from 'react-redux';
  9. import { ThemeProvider } from 'styled-components';
  10. import theme from 'theme/theme';
  11. import { render, RenderOptions, screen } from '@testing-library/react';
  12. import { AnyAction, Store } from 'redux';
  13. import { RootState } from 'redux/interfaces';
  14. import { configureStore } from '@reduxjs/toolkit';
  15. import rootReducer from 'redux/reducers';
  16. import mockStoreCreator from 'redux/store/configureStore/mockStoreCreator';
  17. import { QueryClient, QueryClientProvider } from 'react-query';
  18. interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
  19. preloadedState?: Partial<RootState>;
  20. store?: Store<Partial<RootState>, AnyAction>;
  21. initialEntries?: MemoryRouterProps['initialEntries'];
  22. }
  23. export function getByTextContent(textMatch: string | RegExp): HTMLElement {
  24. return screen.getByText((content, node) => {
  25. const hasText = (nod: Element) => nod.textContent === textMatch;
  26. const nodeHasText = hasText(node as Element);
  27. const childrenDontHaveText = Array.from(node?.children || []).every(
  28. (child) => !hasText(child)
  29. );
  30. return nodeHasText && childrenDontHaveText;
  31. });
  32. }
  33. interface WithRouterProps {
  34. children: React.ReactNode;
  35. path: string;
  36. }
  37. export const WithRoute: React.FC<WithRouterProps> = ({ children, path }) => {
  38. return (
  39. <Routes>
  40. <Route path={path} element={children} />
  41. </Routes>
  42. );
  43. };
  44. const customRender = (
  45. ui: ReactElement,
  46. {
  47. preloadedState,
  48. store = configureStore<RootState>({
  49. reducer: rootReducer,
  50. preloadedState,
  51. }),
  52. initialEntries,
  53. ...renderOptions
  54. }: CustomRenderOptions = {}
  55. ) => {
  56. // use new QueryClient instance for each test run to avoid issues with cache
  57. const queryClient = new QueryClient({
  58. defaultOptions: { queries: { retry: false } },
  59. });
  60. // overrides @testing-library/react render.
  61. const AllTheProviders: React.FC<PropsWithChildren<unknown>> = ({
  62. children,
  63. }) => {
  64. return (
  65. <ThemeProvider theme={theme}>
  66. <Provider store={store}>
  67. <QueryClientProvider client={queryClient}>
  68. <MemoryRouter initialEntries={initialEntries}>
  69. {children}
  70. </MemoryRouter>
  71. </QueryClientProvider>
  72. </Provider>
  73. </ThemeProvider>
  74. );
  75. };
  76. return render(ui, { wrapper: AllTheProviders, ...renderOptions });
  77. };
  78. export { customRender as render };
  79. export class EventSourceMock {
  80. url: string;
  81. close: () => void;
  82. open: () => void;
  83. error: () => void;
  84. onmessage: () => void;
  85. constructor(url: string) {
  86. this.url = url;
  87. this.open = jest.fn();
  88. this.error = jest.fn();
  89. this.onmessage = jest.fn();
  90. this.close = jest.fn();
  91. }
  92. }
  93. export const getTypeAndPayload = (store: typeof mockStoreCreator) => {
  94. return store.getActions().map(({ type, payload }) => ({ type, payload }));
  95. };
  96. export const getAlertActions = (mockStore: typeof mockStoreCreator) =>
  97. getTypeAndPayload(mockStore).filter((currentAction: AnyAction) =>
  98. currentAction.type.startsWith('alerts')
  99. );