0
votes

I'm having a problem testing my components that are wrapped in HOCs. I have a class component that's wrapped by 2 HOC's(Redux Form and Connect). I don't want to test the connected components. I want to test the methods inside of the class.

I read on the Redux docs that you can test the class component separately by exporting it from the component file and importing the named component in the test file. I've done that and am still unable to test class methods. I also tried to use the enzyme dive() method to bypass the HOCs which then gave me an error:

Invariant Violation: Could not find "store" in either the context or props of "Connect(Form(MyComponent))"

Component file:

export class MyComponent extends Component {
  getThing() {
    return thing;
  }
  render() {
    <Form >
      ...
    </Form>
  }
}

MyComponent = reduxForm({
  ...
})(MyComponent)

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent);

Test file:

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

import { MyComponent } from '../MyComponent';

let wrapper;

describe('MyComponent tests', () => {
  beforeEach(() => {
    wrapper = shallow(<MyComponent />).dive().dive()

  it('has a getThing method', () => {
    const instance = wrapper.instance();
    expect(instance.getThing).toBeDefined();
  }); //Invariant Violation: Could not find "store" in either the context or props of "Connect(Form(MyComponent))"
});

I expect the method to be defined but I'm still getting the Invariant Violation error. I also tried not using dive() and expected the method to be defined but received undefined. Any insight on what I'm doing wrong?

2

2 Answers

0
votes

Try exporting MyComponent without reassigning its value and store the reduxForm-wrapped component in a new variable.

export class MyComponent extends Component {
  getThing() {
    return thing;
  }
  render() {
    <Form >
      ...
    </Form>
  }
}

const MyComponentReduxForm = reduxForm({
  ...
})(MyComponent)

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponentReduxForm);

Or eliminate the variable all together and wrap it directly within the connect:

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(reduxForm({
  ...
})(MyComponent));

0
votes

I copied and pasted your code in my own test and there were a few errors in your code but after fixing them everything ran cleanly. I've noted some things I fixed regarding your example code.

// Class code
export class MyComponent extends Component {
  getThing() {
    // FIXED: Don't forget to define thing... and you probably mean this.thing
    return thing;
  }
  render() {
    // FIXED: You weren't returning the HTML element here
    return <Form />;
  }
}


// Test code
let wrapper;

describe("MyComponent tests", () => {
  beforeEach(() => {
    // FIXED: You don't need the .dive.dive here
    wrapper = shallow(<MyComponent />);
  // FIXED: Missing closing bracket around the beforeEach
  });

  it("has a getThing method", () => {
    const instance = wrapper.instance();
    expect(instance.getThing).toBeDefined();
  }); //Invariant Violation: Could not find "store" in either the context or props of "Connect(Form(MyComponent))"
});

As for your error, when you import the component code don't forget that

MyComponent = reduxForm({
  ...
})(MyComponent)

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent);

Actually runs which means the connect function is running as well. It maybe better to split your container and your component code into two different files to make it easier to test the component separately than the container.

As far as unit testing the container, a Google search for "testing redux containers" should come up with some answers of how to setup the mocks required for connect to run successfully in unit tests.