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();
});
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",
import * as React from 'react';
export let util = {sampleMethod: null };
const SampleComponent = () => {
util.sampleMethod = () => {
console.log('hello world');
};
return <button onClick={sampleMethod} type="button">Click Me</button>;
};
export default SampleComponent;
import { shallow } from 'enzyme';
import SampleComponent, {util} from './sample';
test('testing spy', () => {
const spy = jest.spyOn( util, 'sampleMethod' );
const wrapper = shallow(<SampleComponent />);
wrapper.find('button').simulate('click');
expect(spy).toHaveBeenCalled(1);
});
I know I'm late to answer but I think this would help some other developers also
Also searching for a way on spying on a function inside a functional component, it seems just not possible to be done nicley (booo!). I didn't want to spy on a console log, the 2nd suggestion using an object defined outside the fc I was not able to get it working.
I came up with a solution which is also not nice, but simple and may help others with this problem. It is NOT spying on the function, which was asked for, but the outcome is may be close enough for some scenarios.
MyFC.tsx
const MyFC = ({callback}: {callback?:()=>void}) => {
const handleMyClick =
callback // this is the mock fn
|| ()=> console.log("do stuff") // this would be the regular implementation
return <button onClick={handleMyClick}>Click Me</button>
}
MyFC.test.tsx
it('should be triggered', () => {
const mockFn = jest.fn();
const wrapper = mount(<MyFC callback={mockFn}/>);
wrapper.find('button').simulate('click')
expect(mockFn).toBeCalled()
}
with this approach you can at least test if it's called, with what arguments etc If somebody finds a way to do this properly, I would be glad to hear...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With