Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
546 views
in Technique[技术] by (71.8m points)

javascript - 如何使用Jest / Enzyme在React中测试文件类型输入的更改处理程序?(How can I test a change handler for a file-type input in React using Jest/Enzyme?)

I want to test whether my React component can use FileReader to import the contents of a user-selected file from an <input type="file"/> element.

(我想测试我的React组件是否可以使用FileReader<input type="file"/>元素中导入用户选择的文件的内容。)

My code below shows a working component with a broken test.

(我的以下代码显示了测试失败的有效组件。)

In my test I'm attempting to use a blob as a substitute for the file because blobs can also be "read" by FileReader .

(在我的测试中,我尝试使用Blob代替文件,因为FileReader也可以“读取” Blob。)

Is that a valid approach?

(那是有效的方法吗?)

I also suspect that part of the issue is that reader.onload is asynchronous and that my test needs to take this into consideration.

(我还怀疑部分问题是reader.onload是异步的,并且我的测试需要考虑到这一点。)

Do I need a promise somewhere?

(我需要在某个地方许下诺言吗?)

Alternatively, do I perhaps need to mock FileReader using jest.fn() ?

(或者,是否可能需要使用jest.fn()模拟FileReader ?)

I would really prefer to only use the standard React stack.

(我真的更喜欢只使用标准的React堆栈。)

In particular I want to use Jest and Enzyme and not have to use, say, Jasmine or Sinon, etc. However if you know something can't be done with Jest/Enzyme but can be done another way, that might also be helpful.

(特别是我想使用Jest和Enzyme,而不必使用Jasmine或Sinon等。但是,如果您知道Jest / Enzyme 无法完成某些工作,而又可以通过其他方式完成,那也可能会有所帮助。)

MyComponent.js:

(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:

(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');
});
  ask by Andrew Willems translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This answers shows how to access all of the different parts of the code using jest.

(此答案显示了如何使用jest访问代码的所有不同部分。)

However, it doesn't necessarily mean that one should test all of these parts this way.

(但是,这并不一定意味着应该以这种方式测试所有这些部分。)

The code-under-test is essentially the same as in the question except that I have substituted addEventListener('load', ... for onload = ... , and I have removed the console.log line:

(被测代码与问题中的代码基本相同,除了我用addEventListener('load', ...代替onload = ... ,并且删除了console.log行:)

MyComponent.js :

(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 I've managed to test just about everything in the code-under-test (with the one exception noted in the comments and discussed further below) with the following:

(我相信我已经设法通过以下测试了被测代码中的所有内容(注释中指出了一个例外,下面对此进行了进一步讨论):)

MyComponent.test.js :

(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 one thing I haven't explicitly tested yet is whether or not changeHandler was called.

(我尚未明确测试的一件事是是否调用了changeHandler 。)

This seems like it should be easy but for whatever reason it is still eluding me.

(这似乎很容易,但无论出于何种原因,它仍然使我难以理解。)

It clearly has been called, as other mocked functions within it are confirmed to have been called but I haven't yet been able to check whether it itself was called, either using jest.fn() or even Jasmine's spyOn .

(它清楚地调用,因为它的其他功能嘲笑被证实已被调用但我还没能检查自己是否被调用,或者使用jest.fn()甚至茉莉花的spyOn 。)

I have asked this other question on SO to try to address this remaining problem.

(我在SO上问了另一个问题 ,以尝试解决这个剩余的问题。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...