javascript - 如何使用 Jest/Enzyme 测试 React 中文件类型输入的更改处理程序?

标签 javascript reactjs filereader jestjs enzyme

我想测试我的React组件是否可以使用FileReader<input type="file"/> 导入用户选择的文件的内容元素。我下面的代码显示了一个工作组件,但测试已损坏。

在我的测试中,我尝试使用 blob 作为文件的替代品,因为 blob 也可以被 FileReader “读取” 。这是一个有效的方法吗?我还怀疑问题的一部分是 reader.onload是异步的,我的测试需要考虑到这一点。我需要在某个地方做出 promise 吗?或者,我是否需要模拟 FileReader使用jest.fn()

我真的更愿意只使用标准的 React 堆栈。特别是,我想使用 Jest 和 Enzyme,而不是必须使用 Jasmine 或 Sinon 等。但是,如果您知道某些事情不能用 Jest/Enzyme 完成,但可以 以另一种方式完成,这可能也会有帮助。

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');
});

最佳答案

此答案展示了如何使用 jest 访问代码的所有不同部分。然而,这并不一定意味着应该以这种方式测试所有这些部分。

测试中的代码本质上与问题中的相同,只是我用 addEventListener('load', ... 替换 onload = ... >,并且我删除了 console.log 行:

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;

我相信我已经成功地测试了被测代码中的几乎所有内容(除了注释中指出的一个异常(exception),并在下面进一步讨论),如下所示:

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(); });
        // WARNING: But read the comment by Drenai for a potentially serious
        // problem with the above test of `addEventListener`.
    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
});

我还没有明确测试的一件事是 changeHandler 是否被调用。这看起来应该很容易,但无论出于何种原因,它仍然让我困惑。它显然已经被调用,因为它内的其他模拟函数已被确认已被调用,但我还无法检查它本身是否被调用,或者使用jest.fn() 甚至 Jasmine 的 spyOn。我问过this other question所以尝试解决这个剩余的问题。

关于javascript - 如何使用 Jest/Enzyme 测试 React 中文件类型输入的更改处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41702911/

相关文章:

javascript - 使用 HTML5 在 Canvas 上绘制图像

java - 在Java中读取mp3文件的元数据 - 文件未找到异常

javascript - "Search and destroy"迭代没有一次删除所有项目

javascript - PanResponder React原生参数

c# - VS2017 中的 ASP.Net Core : Setting up React. js + webpack + babel

reactjs - Redux - reducer 没有被调用

java - 读取 .txt 文件并返回单词列表及其在文件中的频率

javascript - 有没有办法在 JavaScript 中使用 FileReader 获取文件的特定部分?

javascript - Mouseenter 和 mouseleave 同时触发

javascript - 停止生成器时,Break 如何在 for-of 循​​环中工作?