2

I'm testing for state within a Create-React-App with Enzyme. How can I pass this test?

When my App component is rendered in my test it is wrapped in

<BrowserRouter>

(attempting to mount it otherwise yields a

 Invariant failed: You should not use <Route> outside a <Router>

error in the test).

Shallow wrapping yields

 TypeError: Cannot read property 'state' of null

as does mounting and wrapping with

<BrowserRouter>.

I have tried this

Result: Question unanswered

this

Result: Question unanswered

this

Result: Uninstalling react-test-renderer made no difference

and this

Result: I checked the state in my component and it is defined. console.log(wrapper.instance().state) yields the same error: 'null'

App.js:

class App extends Component {
  //#region Constructor
  constructor(props) {
    super(props);
    this.state = {
    //... other correctly formatted state variables
      specificRankingOptionBtns: false
    }

app.test.js:

import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import App  from '../../App'
import renderer from 'react-test-renderer'
import { shallow, mount } from 'enzyme';

describe('App', () => {
fit('renders App.js state correctly', () => {
  const wrapper = mount(<BrowserRouter><App /></BrowserRouter>);
  //console.log(wrapper.instance().state);
  //const wrapper = shallow(<App />);
  //const wrapper = mount(<App />);
  console.log(wrapper.instance().state);
  //const wrapper = mount(shallow(<BrowserRouter><App /> 
  //</BrowserRouter>).get(0));
  expect(wrapper.state('specificRankingOptionBtns')).toEqual(false);
});
}

Expect: test to pass

Actual: "TypeError: ReactWrapper::state("specificRankingOptionBtns") requires that state not be null or undefined"

dotnetspec
  • 91
  • 1
  • 5

1 Answers1

2

I had the same issue. This worked for me.

import { MemoryRouter as Router } from 'react-router-dom';

it('should find MaskedTextInput in LoginPage', () => {
    const mountWithRouter = node => mount(<Router>{node}</Router>);
    const wrapper = mountWithRouter(<LoginPage {...mockedProps} />);
    const maskedInput = wrapper.find('MaskedTextInput');

    const componentInstance = wrapper
        .childAt(0)
        .childAt(0) 
        .instance(); // could also be instance

    const mountedState = componentInstance.state.passwordInputType;
    expect(mountedState).toEqual('password');
});
wriozumi
  • 569
  • 6
  • 6
  • Thanks. I did the Import and changed the test to this: ` const mountWithRouter = node => mount({node}); const wrapper = mountWithRouter(); const componentInstance = wrapper .childAt(0) .childAt(0) // could also be .find(Foo) .instance(); const mountedState = componentInstance.state.specificRankingOptionBtns; expect(mountedState).toEqual(false); ` But I got `TypeError: Cannot read property 'state' of null`. Following react test library principles I'm now not sure I should be testing internal state anyway [?] – dotnetspec Jun 13 '19 at 04:24
  • Try to console.log your instance, then you can see where is your state. – wriozumi Jun 14 '19 at 10:44
  • console.log gives `state: null }` at the end of a long output containing references to 'FiberNode' about which Dan Abramov says 'The only way to get there was via child._owner which is considered internal. So yes, deep quality check like this is a bad idea.' Unless anyone disagrees I think I shouldn't be testing this implementation detail and re-think my test approach [?]. Thanks for your comments ... – dotnetspec Jun 15 '19 at 08:57