Testing is an essential part of the development process, especially when working with modern frameworks such as React. In this blog post, we will delve into a common issue that developers face while testing React functional components with Jest and Enzyme: spying on methods and dealing with the error “Cannot spyOn on a primitive value; undefined given.”
Understanding the Issue
Suppose we have a simple functional component that displays a button. When the button is clicked, it calls the sampleMethod
function:
import * as React from 'react'; const SampleComponent = () => { const sampleMethod = () => { console.log('hello world'); }; return Click Me; }; export default SampleComponent;
When testing this component, you may attempt to spy on the sampleMethod
function using Jest’s spyOn
method:
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(); wrapper.find('button').simulate('click'); expect(spy).toHaveBeenCalled(); });
Unfortunately, this approach will result in the error “Cannot spyOn on a primitive value; undefined given.” This error occurs because the sampleMethod
function is not defined on the SampleComponent.prototype
, so Jest cannot spy on it.
Alternative Approach: Spying on Dependencies
Instead of trying to spy on the method itself, you can spyOn the dependencies that the method uses. For instance, since our sampleMethod
function calls console.log
, we can spy on this function:
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(); const button = wrapper.find('button'); expect(button.text()).toBe('Click Me'); button.simulate('click'); expect(logSpy).toBeCalledWith('hello world'); }); });
In this case, spying on console.log
allows us to assert that the sampleMethod
function is being called when the button is clicked.
Considerations for Production
- Keep in mind that this approach is just a workaround for testing purposes. You should not leave
console.log
statements in your production code. - If the function you are testing relies on other dependencies, you should spy on those dependencies instead of
console.log
.
Conclusion
Although spying on methods within React functional components can be challenging, there are workarounds available to ensure your components are properly tested. By spying on the dependencies used within your methods, you can verify that they are being called as expected when events are triggered. Remember to keep your test code clean and avoid using hacks that may impact the functionality of your production code.