0
votes

I want to test that a class method is called on 'mousedown' event. Please take a look on the code below.

This is my component:

import React, { Component } from 'react';
import styled from 'styled-components';

import MyChildClass from './MyChildClass';


export default class MyClass extends Component {

constructor(props) {
    super(props);

    // Init state
    this.state = {
      balls: []
    };

    this.onMouseUpHandler = this.onMouseUpHandler.bind(this, this.state.balls);
  }

onMouseDownHandler = (balls, e) => {
    ...
  };

render() {

    return (
      <StyledEnvironment className='wrapper'>
        <div
          onMouseDown={this.onMouseDownHandler}
          onMouseUp={this.onMouseUpHandler}
        >
          {balls}
        </div>
      </StyledEnvironment>
    );
  }

And this is my test:

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

import MyClass from '../MyClass';

it('should call onMouseDownHandler on mouse down', () => {
    //...arrange
    const instance = component.instance();
    const wrapper = component.find('.wrapper').at(0);
    instance.setMousePosition = jest.fn();
    instance.onMouseDownHandler = jest.fn();
    instance.forceUpdate();
    component.update();
    //...act
    wrapper.simulate('mouseDown');
    //...assert
    expect(instance.onMouseDownHandler).toHaveBeenCalled();
  });

So, I eventually expect the test to pass, but still the runner returns fail, with message

Expected mock function to have been called, but it was not called.

I've gone through many examples on Google, and found out that this is proper pattern of testing events.

1
Guys, I actually when gone through the code with clear head, I saw that the wrapper class 'wrapper' should have been added to the div element in the jsx, and not to the StyledEnvironment component... the rest of the test is OK, and actually is a standard pattern for this. ThanksViktor Dojcinovski

1 Answers

1
votes

Use arrow function as the method of class is not easy to test. Because it will be used as property of class, not instance method of class. So I suggest you refactor the method.

After refactoring, you can use jest.spyOn(object, methodName) to spy on the onMouseDownHandler method.

For example,

index.tsx:

import React, { Component } from 'react';

const StyledEnvironment = ({ children, className }) => <div className={className}>{children}</div>;

export default class MyClass extends Component<any, any> {
  constructor(props) {
    super(props);
    this.state = {
      balls: []
    };
  }

  onMouseDownHandler(balls, e) {
    // TBD
  }
  onMouseUpHandler(balls, e) {
    // TBD
  }

  render() {
    return (
      <StyledEnvironment className="wrapper">
        <div
          onMouseDown={e => this.onMouseDownHandler(this.state.balls, e)}
          onMouseUp={e => this.onMouseUpHandler(this.state.balls, e)}>
          {this.state.balls}
        </div>
      </StyledEnvironment>
    );
  }
}

index.spec.tsx:

import React from 'react';
import { shallow } from 'enzyme';
import MyClass from './';

describe('MyClass', () => {
  test('should handle mousedown event', () => {
    const wrapper = shallow(<MyClass></MyClass>);
    const onMouseDownHandlerSpy = jest.spyOn(MyClass.prototype, 'onMouseDownHandler');
    wrapper.find('div').simulate('mouseDown');
    expect(onMouseDownHandlerSpy).toBeCalled();
  });
});

Unit test result with coverage report:

 PASS  src/stackoverflow/58652312/index.spec.tsx
  MyClass
    ✓ should handle mousedown event (12ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |    76.47 |      100 |     62.5 |    91.67 |                   |
 index.tsx |    76.47 |      100 |     62.5 |    91.67 |                25 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.951s, estimated 9s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58652312