37

I am trying to use mount from Enzyme to test my component in which a several Material UI component are nested. I get this error when running the test:

TypeError: Cannot read property 'prepareStyles' of undefined

After some digging, I did found that a theme needs to be passed down in a context. I am doing that in the test but still get this error.

My test:

import expect from  'expect';
import React, {PropTypes} from 'react';
import {mount} from 'enzyme';
import SearchBar from './SearchBar';
import getMuiTheme from 'material-ui/styles/getMuiTheme';

function setup() {
  const muiTheme = getMuiTheme();

  const props = {
    closeSearchBar: () => {},
    fetchSearchData: () => {},
    data: [],
    searching: false
  };

  return mount(<SearchBar {...props} />, {context: {muiTheme}});
}

describe('SearchBar Component', ()=> {

  it('Renders search toolbar properly', () => {
    const wrapper = setup();
    expect(wrapper.find('.toolbar').length).toBe(1);
    expect(wrapper.find('button').length).toBe(1);
  });
});

My searchbar component is a stateless component, so I am not pulling in any context. But even when I am, I still get the same error.

What am I doing wrong?

Rubens Mariuzzo
  • 28,358
  • 27
  • 121
  • 148
Erika
  • 905
  • 1
  • 8
  • 15

2 Answers2

56

Try adding childContextTypes in the mount options:

return mount(
  <SearchBar {...props} />, {
    context: {muiTheme},
    childContextTypes: {muiTheme: React.PropTypes.object}
  }
);

By doing it you set the Enzyme wrapper to make the muiTheme available to it's children through the context.

Rubens Mariuzzo
  • 28,358
  • 27
  • 121
  • 148
Nícolas Iensen
  • 3,899
  • 4
  • 22
  • 26
  • Yes, that was exactly what it was missing. I guess I'm gonna have to look up the React context a little bit more as was trying to pass `contextTypes: {muiTheme: React.PropTypes.object}`, but not `childContextTypes`. Thanks Nicolas! – Erika Jul 11 '16 at 12:49
  • 3
    same works with `shallow`, just replace mount by shallow. – nils petersohn Aug 15 '16 at 08:01
  • 1
    Thanks a ton for this! I can't believe it was that simple. I was already accepting that I would need to always wrap my tested components in the redux store provider. – gustavohenke Oct 16 '16 at 16:02
  • shallow works for only one level, that's the point of it. Jordan Harband from enzyme pointed this. You can check this [issue](https://github.com/airbnb/enzyme/issues/664) and this [issue](https://github.com/airbnb/enzyme/issues/770) on github. – vladblindu Jan 21 '17 at 05:38
2

this is my handy method to test Material UI with shallow and mount

...
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import getMuiTheme from 'material-ui/styles/getMuiTheme';

const muiTheme = getMuiTheme();
const shallowWithContext = (node) => shallow(node, {context: {muiTheme}, childContextTypes: {muiTheme: PropTypes.object}});

const mountWithContext = (node) => mount(
  node, {context: {muiTheme}, childContextTypes: {muiTheme: PropTypes.object}}
);


// now you can do
const wrapper = shallowWithContext(<Login auth={auth} onChange={() => 'test'} />);
STEEL
  • 8,955
  • 9
  • 67
  • 89