5

I have a small application that uses redux-dynamic-modules as a store, react-router for routing and all the compenents are function components with hooks like useState,useHistory,useLocation, useSelector, useDispatch etc.

I want to set up react-testing-library to test out the components and as said in documentation I need to set up a custom render().

So here's my index.tsx

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "./redux/store";


ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

Here's my App.tsx

import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { SearchPage } from "./pages/search/search-page";
import { LayoutComponent as Layout } from "./components/shared/layout/layout";
import { DynamicModuleLoader } from "redux-dynamic-modules";
import { reduxSearch } from "./redux/search";
import { store } from "./redux/store";
import { paths } from "./lib/constants/paths";


const App = () => {
  return (
    <>
      <Router>
        <DynamicModuleLoader
          modules={[reduxSearch()]}
          createStore={() => store}
        >
        <Layout>
          <Route exact path={paths.search}>
            <SearchPage />
          </Route>
        </Layout>
        </DynamicModuleLoader>
      </Router>
    </>
  );
};

export default App;

And finally the test-utils.tsx I've created for the cusom renderer:

import React, { ReactElement, ReactNode } from "react";
import { render as rtlRender, RenderOptions } from "@testing-library/react";
import { DynamicModuleLoader } from "redux-dynamic-modules";
import { Provider } from "react-redux";
import { reduxSearch } from "../redux/search";
import { store, history } from "../redux/store";
import { Router } from "react-router-dom";

export interface WrapperProps {
  children: ReactElement;
}

const render = (ui: ReactElement, renderOptions?: RenderOptions) => {
  const Wrapper = ({ children }: WrapperProps): ReactElement => {
    return (
      <Provider store={store}>
        <Router history={history}>
          <DynamicModuleLoader
            modules={[reduxSearch()]}
            createStore={() => store}
          >
            {children}
          </DynamicModuleLoader>
        </Router>
      </Provider>
    );
  };
  return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
};

// re-export everything
export * from "@testing-library/react";

// override render method
export { render };
):

I seem to follow the documnetation and examples provided, but I'm getting this error in my TSLint console on this line return rtlRender(ui, { wrapper: Wrapper, ...renderOptions }); (wrapper is underlined)

  Overload 1 of 2, '(ui: ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>, options?: Pick<...> | undefined): RenderResult<...>', gave the following error.
    Type '({ children }: WrapperProps) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | ... | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<...>)>' is not assignable to type 'ComponentClass<{}, any> | FunctionComponent<{}> | undefined'.
      Type '({ children }: WrapperProps) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | ... | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<...>)>' is not assignable to type 'FunctionComponent<{}>'.
        Types of parameters '__0' and 'props' are incompatible.
          Type '{ children?: ReactNode; }' is not assignable to type 'WrapperProps'.
            Types of property 'children' are incompatible.
              Type 'ReactNode' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>'.
                Type 'undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>'.
  Overload 2 of 2, '(ui: ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>, options: RenderOptions<...>): RenderResult<...>', gave the following error.
    Type '({ children }: WrapperProps) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | ... | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<...>)>' is not assignable to type 'ComponentClass<{}, any> | FunctionComponent<{}> | undefined'.
      Type '({ children }: WrapperProps) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | ... | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<...>)>' is not assignable to type 'FunctionComponent<{}>'.```

What is the right way to set this up, to test the connected components?

Sergei Klinov
  • 730
  • 2
  • 12
  • 25

1 Answers1

5

You are getting that error because you props are not compatible to those expected for the wrapper property. You can fix it easily by adding React's functional component type which includes a definition of children within it:

import React, { ReactElement, ReactNode } from "react";
import { render as rtlRender, RenderOptions } from "@testing-library/react";
import { DynamicModuleLoader } from "redux-dynamic-modules";
import { Provider } from "react-redux";
import { reduxSearch } from "../redux/search";
import { store, history } from "../redux/store";
import { Router } from "react-router-dom";


const render = (ui: ReactElement, renderOptions?: RenderOptions) => {
  const Wrapper : React.FC = ({ children }) => {
    return (
      <Provider store={store}>
        <Router history={history}>
          <DynamicModuleLoader
            modules={[reduxSearch()]}
            createStore={() => store}
          >
            {children}
          </DynamicModuleLoader>
        </Router>
      </Provider>
    );
  };
  return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
};

// re-export everything
export * from "@testing-library/react";

// override render method
export { render };

Jose Felix
  • 970
  • 5
  • 7
  • Thanks! Now I'm getting a different error on test: `TypeError: window.matchMedia is not a function` - on `rtlRender()` - but that's a different case – Sergei Klinov Apr 27 '20 at 06:11
  • Create a question on it and link me, I have a solution for that too :) – Jose Felix Apr 27 '20 at 17:57
  • Thanks, it would be a duplicate for [this](https://stackoverflow.com/questions/39830580/jest-test-fails-typeerror-window-matchmedia-is-not-a-function) – Sergei Klinov Apr 28 '20 at 03:18