7

My React component has to respond to resize event, for which I am using jQuery, ie:

//...
componentDidMount: function() {
  $(window).on("resize", function);
}
//..

However, this causes issues with my Jest test, specifically:

- TypeError: Cannot read property 'on' of undefined
    at RadiumEnhancer.React.createClass.componentDidMount (bundles/Opportunities/OpportunityPartial.jsx:21:14)

When stepping through the test it looks like window is defined in a jest test, but $(window) doesn't appear to return anything.

I was under the impression that Jest would examine the required module (jQuery)'s API to construct its mock, but if I'm understanding the problem correctly it seems like this isn't happening?

I can get around this by not mocking jQuery, but obviously that isn't totally preferable.

1
  • 1
    I'm not sure whether this is correct or not, but I had success with beforeAll ( () => { window.jQuery = require( 'jquery' ); });. Or window.$ in your case. Commented Oct 11, 2017 at 23:41

1 Answer 1

1

Here is the unit test solution using jestjs and enzyme:

index.tsx:

import React, { Component } from 'react';
import $ from 'jquery';

class SomeComponent extends Component {
  componentDidMount() {
    $(window).on('resize', this.resizeEventHandler);
  }

  resizeEventHandler() {
    console.log('resize event handler');
  }

  render() {
    return <div>some component</div>;
  }
}

export default SomeComponent;

index.spec.tsx:

import React from 'react';
import SomeComponent from './';
import { shallow } from 'enzyme';
import $ from 'jquery';

jest.mock('jquery', () => {
  const m$ = {
    on: jest.fn(),
  };
  return jest.fn(() => m$);
});

describe('36082197', () => {
  afterEach(() => {
    jest.restoreAllMocks();
    jest.resetAllMocks();
  });
  it('should pass', () => {
    const logSpy = jest.spyOn(console, 'log');
    const eventHandlerMap = {};
    ($().on as jest.MockedFunction<any>).mockImplementation((event, handler) => {
      eventHandlerMap[event] = handler;
    });
    const wrapper = shallow(<SomeComponent></SomeComponent>);
    const instance = wrapper.instance();
    expect(wrapper.text()).toBe('some component');
    expect($).toBeCalledWith(window);
    // tslint:disable-next-line: no-string-literal
    expect($(window).on).toBeCalledWith('resize', instance['resizeEventHandler']);
    eventHandlerMap['resize']();
    expect(logSpy).toBeCalledWith('resize event handler');
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/36082197/index.spec.tsx (12.045s)
  36082197
    ✓ should pass (18ms)

  console.log node_modules/jest-mock/build/index.js:860
    resize event handler

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |      100 |      100 |      100 |      100 |                   |
 index.tsx |      100 |      100 |      100 |      100 |                   |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        14.267s, estimated 15s

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.