Search code examples
reactjsunit-testingjestjsenzyme

Spying on React functional component method with jest and enzyme; Cannot spyOn on a primitive value


I am trying to test a React component and make sure that when its button gets clicked, the correct method gets invoked. However, when I try to run my test and try to spy on that method, I get the following message:

Error: Cannot spyOn on a primitive value; undefined given

How do I test that when a button is clicked the correct method is invoked? Thanks!

sampleComponent.jsx:

import * as React from 'react';

const SampleComponent = () => {
  const sampleMethod = () => {
    console.log('hello world');
  };

  return <button onClick={sampleMethod} type="button">Click Me</button>;
};

export default SampleComponent;

sampleComponent.test.jsx:

import * as React from 'react';
import { shallow } from 'enzyme';
import SampleComponent from './sample';

test('testing spy', () => {
  const spy = jest.spyOn(SampleComponent.prototype, 'sampleMethod');
  const wrapper = shallow(<SampleComponent />);
  wrapper.find('button').simulate('click');
  expect(spy).toHaveBeenCalled();
});

Solution

  • The error means, the function sampleMethod you defined inside the functional component SampleComponent is not defined in SampleComponent.prototype. So SampleComponent.prototype.sampleMethod is undefined, jest can't spy on a undefined value.

    So the correct way to test sampleMethod event handler is like this:

    index.spec.tsx:

    import React from 'react';
    import SampleComponent from './';
    import { shallow } from 'enzyme';
    
    describe('SampleComponent', () => {
      test('should handle click correctly', () => {
        const logSpy = jest.spyOn(console, 'log');
        const wrapper = shallow(<SampleComponent></SampleComponent>);
        const button = wrapper.find('button');
        expect(button.text()).toBe('Click Me');
        button.simulate('click');
        expect(logSpy).toBeCalledWith('hello world');
      });
    });
    

    We can spy on console.log, to assert it is to be called or not.

    Unit test result with 100% coverage:

     PASS  src/react-enzyme-examples/02-react-hooks/index.spec.tsx
      SampleComponent
        ✓ should handle click correctly (19ms)
    
      console.log node_modules/jest-mock/build/index.js:860
        hello world
    
    -----------|----------|----------|----------|----------|-------------------|
    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:        5.036s
    

    Dependencies version:

    "react": "^16.11.0",
    "enzyme": "^3.10.0",
    "enzyme-adapter-react-16": "^1.15.1",
    "jest": "^24.9.0",
    "jest-environment-enzyme": "^7.1.1",
    "jest-enzyme": "^7.1.1",