David
David

Reputation: 4847

How do I mock the implementation of material-ui withStyles?

How do I mock the implementation of withStyles in material-ui/core/styles.js?

Here is the test:

import React from 'react'
import { shallow } from 'enzyme'
import { withStyles } from '@material-ui/core/styles'

import TempComponent from './TempComponent'

jest.mock('@material-ui/core')

it('renders correctly', () => {
  const withStylesFake = styles =>
    component => (
      component
    )

  withStyles.mockImplementation(withStylesFake)

  const wrapper = shallow(<TempComponent />)
  expect(wrapper).toMatchSnapshot()
})

Here is the code:

import React from 'react'
import { withStyles } from '@material-ui/core/styles'

const TempComponent = () => (
  <button>Click Me!</button>
)

export default withStyles({})(TempComponent)

Here is the error:

TypeError: _styles.withStyles.mockImplementation is not a function

  at Object.<anonymous>.it (src/TempComponent.snapshot.test.js:15:22)
      at new Promise (<anonymous>)
  at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
      at <anonymous>
  at process._tickCallback (internal/process/next_tick.js:188:7)

This would work:

// ./__mocks__/@material-ui/core/styles
export const withStyles = styles => (
  component => (
    component
  )
) 

but this is not local to the test.

Upvotes: 2

Views: 8814

Answers (3)

stone
stone

Reputation: 8652

Because the TempComponent import is evaluated before your test code, you'll need to mock withStyles earlier in the process. Calling mockImplementation occurs too late in the process.

There are two ways to do that: pass a factory into jest.mock, or use a manual mock. The manual mock is working for you, but you say you want something local to the test, so you'll want to use the factory parameter. Here's how.

Mock the styles import instead of the core import. Use the second arg to jest.mock, the "module factory parameter," to pass in a module factory function: a function that returns an object that replaces the styles import. For your purposes, that means the object needs to have a withStyles function:

jest.mock('@material-ui/core/styles', () => ({
  withStyles: styles => component => component
}));

No need to import withStyles into your test or call mockImplementation; you can delete those lines.

Upvotes: 5

user2600410
user2600410

Reputation: 15

This is a way I used to define component style with material UI.

import { withStyles } from '@material-ui/core/styles';

const styles = theme => ({
  root: {
    ...theme.mixins.gutters(),
    paddingTop: theme.spacing.unit * 2,
    paddingBottom: theme.spacing.unit * 2,
    marginBottom: theme.spacing.unit * 3,
    maxWidth: theme.spacing.unit * 120,
    overflowX: 'auto',
  },
});

function PaperSheet() {
    return (
        <Paper className={classes.root} elevation={1} />
    );
}

export default withStyles(styles)(PaperSheet);

Upvotes: -3

David
David

Reputation: 4847

The way I found around this was to export the component as follows. No mocks necessary.

Test:

import React from 'react'
import { shallow } from 'enzyme'

import { TempComponent } from './TempComponent'

it('renders correctly', () => {
  const wrapper = shallow(<TempComponent />)
  expect(wrapper).toMatchSnapshot()
})

Implementation:

import React from 'react'
import { withStyles } from '@material-ui/core/styles'

export const TempComponent = () => (
  <button>Click Me!</button>
)

export default withStyles({})(TempComponent)

Upvotes: 6

Related Questions