Testing styled components with react-testing-library
Asked Answered
J

2

5

I'm currently trying to test a styled component with a Mocked Provider as follows:

import React from "react";
import TestResults from "./TestResults";
import {
  render,
  cleanup,
  findByTestId,
  findByText,
  waitForElement,
} from "@testing-library/react";
import { MockedProvider } from "@apollo/react-testing";




describe("TestResultsComponent", () => {
  describe("Overall", () => {
    it("should render successfully - base", async () => {
      const { getByText } = render(
        <MockedProvider>
          <TestResults />
        </MockedProvider>
      );
      expect(getByText("Preview")).toBeInTheDocument();
    });
  });
});

I'm using the makeStyles hook in the TestResults file

When I run my tests, I receive the following error:

TypeError: theme.spacing is not a function
 Material-UI: the `styles` argument provided is invalid.
      You are providing a function without a theme in the context.
      One of the parent elements needs to use a ThemeProvider.

I'm not sure if I should mock out the implementation of makeStyles. This is the my first time seeing an error like this, I have been testing other components that use the same hook and it has not been an issue.
Judaica answered 9/6, 2020 at 20:12 Comment(0)
V
13

@material-ui/styles styling solution is standalone, it doesn't know anything about Material-UI components. You need to use the ThemeProvider from the style-components package with the const theme = createMuiTheme() function from the core package and render this with your test. Best case would be that you have defined your theme already somewhere in your application and simply can import it.

so your test should become:

import React from "react";
import {ThemeProvider} from 'styled-components';
import { createMuiTheme } from '@material-ui/core/styles';
import TestResults from "./TestResults";
import {
  render,
  cleanup,
  findByTestId,
  findByText,
  waitForElement,
} from "@testing-library/react";
import { MockedProvider } from "@apollo/react-testing";

describe("TestResultsComponent", () => {
  describe("Overall", () => {
    it("should render successfully - base", async () => {
      const theme = createMuiTheme()
      const { getByText } = render(
        <ThemeProvider theme={muiTheme}>
          <MockedProvider>
            <TestResults />
          </MockedProvider>
        </ThemeProvider>
      );
      expect(getByText("Preview")).toBeInTheDocument();
    });
  });
})

If this boilerplate for wrapping your components becomes to much you can also write a Wrapper-Component which sets up your needed components and pass this component as second argument to the render-Options

See the docs for the wrapper here

Vmail answered 11/6, 2020 at 7:50 Comment(1)
thank you for insight @takethefake. Is there any difference importing the ThemeProvider from "@material-ui/styles" as opposed to 'styled-components? Also to your point about a custom theme, I have already defined it in my app so I will pass it through as the theme props to the provider. Ex. <ThemeProvider theme={customTheme}>Judaica
P
1

Thank to @takethefake answer, in my case we didn't use MaterialUi but it was quite similar:

import React from 'react';
import { render, screen } from '@testing-library/react';
import { ThemeProvider } from 'styled-components';
import { STRING } from '../constants';
import Theme from '../styles/theme';
import { PreOnboarding } from './PreOnboarding';

test('la valeur `trigger.cta` est utilisée comme fallback du titre', () => {
  const trigger = { cta: 'fallback title', text: STRING.empty };
  const theme = Theme({ color1: 'red', color2: 'blue' });

  render(
    <ThemeProvider theme={theme}>
      <PreOnboarding trigger={trigger} />
    </ThemeProvider>
  );
  const button = screen.getByRole('label', { name: /fallback title/i });
  expect(button).toBeVisible();
});
Preciado answered 15/2, 2021 at 11:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.