Chris Huang
Chris Huang

Reputation: 66

How to test react components wrapped by ThemeProvider/withStyle?

I want to test a component wrapped by withStyle, but it looks like theme object does not go through the component. I'm curious if there is any good practice to do that.

I wanted to try using createShallow() and dive() to get access of

//GameBoard.test.js
import React from 'react';
import { createShallow } from '@material-ui/core/test-utils'
import GameBoard from './GameBoard';
import { ThemeProvider} from '@material-ui/styles';
import { createMuiTheme } from '@material-ui/core'

describe('GameBoard', () => {

  const theme = createMuiTheme({
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    typography: {
      htmlFontSize: 18
    }
  });

  let shallow

  const MockTheme = ({ children }) => {
    return (
      <ThemeProvider theme={theme}>
        {children}
      </ThemeProvider>
    );
  }

  beforeAll(() => {
    shallow = createShallow()
  })



  it('renders without crashing', () => {
    const board = shallow(<MockTheme><GameBoard/></MockTheme>)
  })

  it('random answer is between 0 and 100', () => {
    const board = shallow(<MockTheme><GameBoard/></MockTheme>)
    board.find(GameBoard).dive()
    //this is what I really want to try, to access its component method:
    board.find(GameBoard).dive().instance().setConfig(0, 100)
    //expect(board.state('answer')).toBeGreaterThanOrEqual(0)
    //expect(board.state('answer')).toBeLessThanOrEqual(100)
  })
})

And my GameBoard component is exported with

export default withStyles(styles)(GameBoard)

App.js, its parent component


const theme = createMuiTheme({
  background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
  typography: {
    htmlFontSize: 18
  }
});

const App = () => {
  return (
    <ThemeProvider theme={theme}>
      <GameBoard/>
    </ThemeProvider>
  );
}

export default App;

styles

const styles = theme => createStyles({
  root: {
    flexGrow: 1,
    marginBottom: theme.spacing(3),
  },

})

Test Result

FAIL  src/GameBoard.test.js
  ● Console

    console.error node_modules/warning/warning.js:34
      Warning: 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.

  ● GameBoard › random answer is between 0 and 100

    TypeError: theme.spacing is not a function

      4 |   root: {
      5 |     flexGrow: 1,
    > 6 |     marginBottom: theme.spacing(3),
        |                         ^
      7 |   },
      8 |   paper: {
      9 |     height: "100%",

Upvotes: 2

Views: 2787

Answers (1)

Chris Huang
Chris Huang

Reputation: 66

Just found a way of using mount and find its child component, I think this solves the problem.

describe('GameBoard', () => {

  const theme = createMuiTheme({
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    typography: {
      htmlFontSize: 18
    }
  });

  let mount

  const MockTheme = ({ children }) => {
    return (
      <ThemeProvider theme={theme}>
        {children}
      </ThemeProvider>
    );
  }

  beforeAll(() => {
    mount = createMount()
  })



  it('renders without crashing', () => {
    const board = mount(<MockTheme><GameBoard/></MockTheme>)
  })

  it('random answer is between 0 and 100', () => {
    const boardWrapper = mount(<MockTheme><GameBoard/></MockTheme>)
    const board = boardWrapper.find("GameBoard").at(0)
    board.instance().setNewConfig(0, 100)
    expect(board.state('answer')).toBeGreaterThanOrEqual(0)
    expect(board.state('answer')).toBeLessThanOrEqual(100)
  })
})

Upvotes: 2

Related Questions