How can I check the change handler for entering file type in React using Jest / Enzyme?

I want to check if my React component can use FileReader to import the contents of a user selected file from the <input type="file"/> element. My code below shows a working component with a broken test.

In my test, I try to use blob as a replacement for the file, because blobs can also be "read" with FileReader . Is this the right approach? I also suspect that part of the problem is that reader.onload is asynchronous and that my test should take this into account. Do I need some promise? Alternatively, maybe I need to make fun of FileReader with jest.fn() ?

I would rather use the standard React stack. In particular, I want to use Jest and Enzyme and not use, say, Jasmine or Sinon, etc. However, if you know that something cannot be done with Jest / Enzyme, but can be done in a different way, this can also be useful.

MyComponent.js:

 import React from 'react'; class MyComponent extends React.Component { constructor(props) { super(props); this.state = {fileContents: ''}; this.changeHandler = this.changeHandler.bind(this); } changeHandler(evt) { const reader = new FileReader(); reader.onload = () => { this.setState({fileContents: reader.result}); console.log('file contents:', this.state.fileContents); }; reader.readAsText(evt.target.files[0]); } render() { return <input type="file" onChange={this.changeHandler}/>; } } export default MyComponent; 

MyComponent.test.js:

 import React from 'react'; import {shallow} from 'enzyme'; import MyComponent from './MyComponent'; it('should test handler', () => { const blob = new Blob(['foo'], {type : 'text/plain'}); shallow(<MyComponent/>).find('input') .simulate('change', { target: { files: [ blob ] } }); expect(this.state('fileContents')).toBe('foo'); }); 
+6
source share
1 answer

This answer shows how to access all the different parts of the code using jest. However, this does not necessarily mean that you need to test all of these parts in this way.

The test code is essentially the same as in the question, except that I replaced addEventListener('load', ... with onload = ... , and I deleted the console.log line:

MyComponent.js

 import React from 'react'; class MyComponent extends React.Component { constructor(props) { super(props); this.state = {fileContents: ''}; this.changeHandler = this.changeHandler.bind(this); } changeHandler(evt) { const reader = new FileReader(); reader.addEventListener('load', () => { this.setState({fileContents: reader.result}); }); reader.readAsText(evt.target.files[0]); } render() { return <input type="file" onChange={this.changeHandler}/>; } } export default MyComponent; 

I believe that I was able to test almost everything in the code test (with one exception noted in the comments and discussed below) with the following:

MyComponent.test.js

 import React from 'react'; import {mount} from 'enzyme'; import MyComponent from './temp01'; it('should test handler', () => { const componentWrapper = mount(<MyComponent/>); const component = componentWrapper.get(0); // should the line above use `componentWrapper.instance()` instead? const fileContents = 'file contents'; const expectedFinalState = {fileContents: fileContents}; const file = new Blob([fileContents], {type : 'text/plain'}); const readAsText = jest.fn(); const addEventListener = jest.fn((_, evtHandler) => { evtHandler(); }); const dummyFileReader = {addEventListener, readAsText, result: fileContents}; window.FileReader = jest.fn(() => dummyFileReader); spyOn(component, 'setState').and.callThrough(); // spyOn(component, 'changeHandler').and.callThrough(); // not yet working componentWrapper.find('input').simulate('change', {target: {files: [file]}}); expect(FileReader ).toHaveBeenCalled ( ); expect(addEventListener ).toHaveBeenCalledWith('load', jasmine.any(Function)); expect(readAsText ).toHaveBeenCalledWith(file ); expect(component.setState).toHaveBeenCalledWith(expectedFinalState ); expect(component.state ).toEqual (expectedFinalState ); // expect(component.changeHandler).toHaveBeenCalled(); // not yet working }); 

The only thing I have not yet verified explicitly is whether or not changeHandler is changeHandler . It seems to be easy, but for some reason it still eludes me. This was clearly caused because it was confirmed that the other mocking functions inside it were called, but I still could not check whether it was called by itself, either using jest.fn() , or even Jasmine spyOn . I asked this other question on SO to try to solve this remaining problem.

+9
source

Source: https://habr.com/ru/post/1014159/


All Articles