5

Currently I am trying to unit test my application that is built with Create-React-App with typescript, and it is styled with chakraui. Chakrui includes a component ThemeProvider that must wrap the entire application as such.

This is my index.tsx file

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { ThemeProvider, CSSReset } from "@chakra-ui/core/dist";
import { theme } from "@chakra-ui/core/dist";

ReactDOM.render(
  <React.StrictMode>
    <ThemeProvider theme={theme}>
      <CSSReset />
      <App />
    </ThemeProvider>
  </React.StrictMode>,
  document.getElementById("root")

For every unit test that I write, I am having to wrap the component with ThemeProvider for the test to pass:

import React from "react";
import { render } from "@testing-library/react";
import { ThemeProvider } from "@chakra-ui/core/dist";

import App from "./App";

describe("<App />", () => {
  test("smoke test", () => {
    render(
      <ThemeProvider>
        <App />
      </ThemeProvider>
    );
  });
});

But this is very verbose, and must be done for every test that I write. Is there a way to do this just once in each .test.tsx file?

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Red Sky Harbor
  • 108
  • 2
  • 7

2 Answers2

4

You could create your own theme wrapper function

import React from "react";
import { ThemeProvider } from "@chakra-ui/core/dist";

export const ThemeWrapper = ({ children }) => (
  <ThemeProvider>{children}</ThemeProvider>
);

And then specify the wrapper in the test

import React from "react";
import { render } from "@testing-library/react";
import { ThemeWrapper } from "../testUtils";

import App from "./App";

describe("<App />", () => {
  test("smoke test", () => {
    render(<App />, { wrapper: ThemeWrapper });
  });
});

This marginally reduces the code for testing. You may be able to also go the route of creating a custom render function (following the steps for redux).

It could look something like

import React from "react";
import { render } from "@testing-library/react";
import { ThemeProvider } from "@chakra-ui/core/dist";

export const renderWithTheme = ui => {
  const Wrapper = ({ children }) => (
    <ThemeProvider>{children}</ThemeProvider>
  );

  return render(ui, { wrapper: Wrapper });
};

Basically the same as the wrapper above, but more integrated into a test render function. You can adjust the function signature a bit as well if you need to pass in a theme object, or other render options, this is just a simple example.

Now the test looks like

import React from "react";
import { renderWithTheme } from "../testUtils";

import App from "./App";

describe("<App />", () => {
  test("smoke test", () => {
    renderWithTheme(<App />);
});
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
0

It might be the case that Jest might be mocking your imports from @chakra-ui/core/dist (depending on your jest configuration) which might be resulting your imported chakra-ui components to be undefined.

Importing the Theme Provider and wrapping it everytime with your renders might be one way to do it. The problem might arise when you have multiple components in your index.tsx. So, you might not want to import each and every component.

In that case, you will want to import the actual components from @chakra-ui/core.

The best way (according to me) to do so in Jest is:

jest.mock("@chakra-ui/core", () => {
    const ui = jest.requireActual("@chakra-ui/core");
    return {
        ...ui,
        customKey: 'customValue',
    };
})

This way you can even add custom function and key-values to the imported module.

uinstinct
  • 630
  • 1
  • 7
  • 14