React testing library and styled components - cannot read properties of undefined

Viewed 2144

Am trying to use react testing library on my project, but it isn't happy about the theme being passed to styled components in props, and I am getting this error:"TypeError: Cannot read properties of undefined". The full error message can be seen below.

error message

This is the component I am testing (a very simple one as I was trying to check testing library was working):

import React from "react";
import styled from "styled-components/macro";
import { rem } from "polished";
import DoneIcon from "@mui/icons-material/Done";

const Flag = styled.div`
  background-color: ${(props) => props.theme.colors.primary};
  font-size: ${rem("14px")};
  display: inline-flex;
  align-items: center;
  height: 32px;
  border-radius: 16px;
  padding: 0 12px 0 8px;
  margin-bottom: ${rem("16px")};
  color: #ffffff;
`;

const StyledDoneIcon = styled(DoneIcon)`
  margin-right: 4px;
`;

const CompletionFlag = (props) => {
  console.log("props: ", props);
  return (
    <Flag>
      <StyledDoneIcon />
      <span>Complete</span>
    </Flag>
  );
};

export default CompletionFlag;

And this is the test that is failing (I am yet to write the full test as the render throws the error):

import { render } from "../../../test-utils/testing-library-utils";
import CompletionFlag from "../CompletionFlag";

test("check text in completion flag", () => {
  render(<CompletionFlag />);
});

And here is my custom render taken from the testing library docs:

import React from "react";
import { render } from "@testing-library/react";
import { ThemeProvider } from "@mui/material/styles";
import { theme } from "../global-styles/global";

const AllTheProviders = ({ children }) => {
  console.log("theme: ", theme);
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
};

const customRender = (ui, options) =>
  render(ui, { wrapper: AllTheProviders, ...options });

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

export { customRender as render };

Probably not necessary, but for reference this is how we are actually using the theme in our app component:

import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { StyledEngineProvider } from "@mui/material/styles";
import { ThemeProvider } from "@mui/material/styles";

import { GlobalStyle, theme } from "./global-styles/global";
import Login from "./components/pages/Login";
import Home from "./components/pages/Home";
import PageNotFound from "./components/pages/PageNotFound";
import { PrivateRoute } from "./components/organisms/PrivateRoute";

function App() {
  return (
    <StyledEngineProvider injectFirst>
      <ThemeProvider theme={theme}>
        <GlobalStyle />
        <BrowserRouter
          basename={
            process.env.REACT_APP_ENVIRONMENT === "development"
              ? "/"
              : process.env.PUBLIC_URL
          }
        >
          <Routes>
            <Route path="/login" element={<Login />} />
            <Route path="/" element={<PrivateRoute />}>
              <Route path="/:collectionId/home" element={<Home />} />
              <Route path="/*" element={<PageNotFound />} />
              <Route path="*" element={<PageNotFound />} />
            </Route>
          </Routes>
        </BrowserRouter>
      </ThemeProvider>
    </StyledEngineProvider>
  );
}

export default App;

Any help would be appreciated as my googling hasn't helped so far.

2 Answers

You should try to wrap the CompletionFlag component in your unit test into ThemeProvider and provide the theme to it

import { render } from "../../../test-utils/testing-library-utils";
import CompletionFlag from "../CompletionFlag";
import { ThemeProvider } from "@mui/material/styles";
import { theme } from "../global-styles/global";

test("check text in completion flag", () => {
  render(
    <ThemeProvider theme={theme}>
      <CompletionFlag />
    </ThemeProvider>
    );
});

I think the colors property is missing from the themes object. Have you checked the themes object if colors is there. To just get rid of this error you can do a conditional check like this.

background-color: ${(props) => props.theme.colors?.primary};
Related