Testing with Jest & Enzyme

When should we write tests?

- Unit Test as a bug Report

- Unit Test as a feature documentation

- Code design

- Developer understanding

Test Component

What should we test?

What should we test?

  • The real DOM (Given props and state does it render the right thing?)
  • Events (Are the events fired?)
  • State changes (Are the state transitions correct?)

Testing DOM

class Button extends Component {

  render(){
      returns(
        <button>{ this.props.text }</button>
      );
    }
}

Test

import Button from './Button';

describe('<Button />', () => {
  it('should render a button with the right text', () => {
    const wrapper = mount(<Button text='mycs' />);
    expect(wrapper.find('button').text()).toBe('mycs');
  });
}

Component

Testing Events

class Button extends Component {

  onClickHandler(e){
     this.props.onClick(e);
  }

  render(){
      returns(
        <button onClick={ e => this.onClickHandler(e) }>
          { this.props.text }
        </button>
      );
    }
}

Test

  it('should call the passed onClick callback', () => {
    const onButtonClick = jest.fn();
    const wrapper = mount(
      <Button onClick={onButtonClick} />
    );
    wrapper.find('button').simulate('click');
    expect(onClickCallback).toHaveBeenCalled();
  });

Component

Testing State Transitions

class Button extends Component {

   ...

  onClickHandler(e){
     this.setState({ angularSucks: true });
  }

  render(){
      returns(
        <button onClick={ e => this.onClickHandler(e) }>
          { this.props.text }
        </button>
      );
    }
}

Test

  it('should call the passed onClick callback', () => {
    const onButtonClick = jest.fn();
    const wrapper = mount(
      <Button onClick={onButtonClick} />
    );
    wrapper.find('button').simulate('click');
    expect(wrapper.state().angularSucks).toBeTruthy();
  });

Component

Mock Functions / Classes

// Function

const func = jest.fn();
const func2 = jest.fn().mockImplementation(() => 42);

// Reset mocks

func.mockReset(); // To avoid affecting another test


// Class
SomeClass.mockImplementation(() => {
  return {
    m: mMock
  }
})

const some = new SomeClass()
some.m('a', 'b')
console.log('Calls to m: ', mMock.mock.calls)

Component

Mock Modules

__mocks__/AuthService.js

Folder structure

SaveDesign.jest.jsx

Automatic mocks

Mock Modules

SaveDesign.jest.jsx

Automatic mocks

Test function without instantiating Component

// Component
class MyComponent extends Component{
   ...

   calculateBboxes(mappingStructure){
     ...
   }

   ...

}

// Test
import MyComponent from './MyComponent';

it('should calculate BBoxes', () => {
    const boxes = MyComponent.prototype.calculateBboxes(mockMappingStructure);
    expect(boxes).toEqual(expectedResult);
});

Update props, mock instance function

  it('should re-initialize the canvas when props are updating', () => {
    const wrapper = mount(<BboxOverlay mappingStructure={mappingStructure} );
    wrapper.instance().initCanvas = jest.fn();
    wrapper.setProps({something: 5});
    expect(wrapper.instance().initCanvas).toHaveBeenCalled();
  });

Component

Test scripts

- npm run jest // spawns parallel test runs

- npm run jest:notify // notify when test run finish

- npm run jest:ci // run test in sequense


- npm run jest filename.js // run single test file

Code coverage

Everytime you run jest a coverage folder is generated, open index.html to see your code coverage

100% Code coverage doesnt mean that your test is meaningfull 

const func(){
  return 10;
}


it('should return 10', () => {
    func(); // Istanbul will report 100% code coverage
    expect(true).toBe(true);
});

Review your tests
Review others' tests in PR reviews

Include your code coverage in your PR

Maybe a tool would help?

Thanks

Testing with Jest & Enzyme

By Avraam Mavridis

Testing with Jest & Enzyme

  • 1,012