最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React how to test function called in FileReader onload function - Stack Overflow

programmeradmin2浏览0评论

I have the below code in a ponent. I want to test that onSubmit of the form, it calls the this.props.onUpload method in reader. How can I test that? My expect test is not working, I'm guessing it's because the this.props.onUpload is inside reader.onload function?

UploadForm.js

handleSubmit(e) {
    e.preventDefault();

    var inputData = '';
    var file = this.state.file;
    if (file) {
        var reader = new FileReader();
        reader.onload = (function(file) {
            return function(e) {
                inputData = e.target.result;
                this.props.onUpload(inputData);
            };
        })(file).bind(this);
        reader.readAsText(file);            
    }

}

render() {
    return(
        <form onSubmit={this.handleSubmit}>
            <label> Enter File: <br/>
                <input type="file" id="fileinput" onChange={this.handleChange}/>    
            </label>
            <input type="submit" value="Submit" className="btn-upload" />
        </form>
    );
}

UploadForm.test.js

const mockOnUpload = jest.fn();
const file = new File([""], "filename");
const form = shallow(<UploadForm onUpload={mockOnUpload}/>);
const event = {
          preventDefault: jest.fn(),
          target: {files : [file]}
        };

describe('when clicking `upload-file` button', () => {
    beforeEach(() => {
      form.find('#fileinput').simulate('change', event);
      form.find('form').simulate('submit', event);
    });

    it('calls the handleSubmit CallBack', () => {
      expect(mockOnUpload).toHaveBeenCalledWith(input);
    });

});

I have the below code in a ponent. I want to test that onSubmit of the form, it calls the this.props.onUpload method in reader. How can I test that? My expect test is not working, I'm guessing it's because the this.props.onUpload is inside reader.onload function?

UploadForm.js

handleSubmit(e) {
    e.preventDefault();

    var inputData = '';
    var file = this.state.file;
    if (file) {
        var reader = new FileReader();
        reader.onload = (function(file) {
            return function(e) {
                inputData = e.target.result;
                this.props.onUpload(inputData);
            };
        })(file).bind(this);
        reader.readAsText(file);            
    }

}

render() {
    return(
        <form onSubmit={this.handleSubmit}>
            <label> Enter File: <br/>
                <input type="file" id="fileinput" onChange={this.handleChange}/>    
            </label>
            <input type="submit" value="Submit" className="btn-upload" />
        </form>
    );
}

UploadForm.test.js

const mockOnUpload = jest.fn();
const file = new File([""], "filename");
const form = shallow(<UploadForm onUpload={mockOnUpload}/>);
const event = {
          preventDefault: jest.fn(),
          target: {files : [file]}
        };

describe('when clicking `upload-file` button', () => {
    beforeEach(() => {
      form.find('#fileinput').simulate('change', event);
      form.find('form').simulate('submit', event);
    });

    it('calls the handleSubmit CallBack', () => {
      expect(mockOnUpload).toHaveBeenCalledWith(input);
    });

});
Share Improve this question asked Dec 24, 2017 at 18:29 MerCMerC 3231 gold badge5 silver badges19 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

Super great start with the mock upload being passed in as a prop and creating a fake event!

I always like running into testing issues like these in my own work because it tells me I have a code smell: if it's not easy to test, it likely means it is harder to predict, harder to debug, harder to explain, &c.

I remend breaking out your functions to more singled responsibility. As it stands, your handleSubmit is doing a bit more than just handling submit. It also adds an onload function to an instance of FileReader and calls readAsText on that instance.

Your IIFE:

function(file) {
  return function(e) {
    inputData = e.target.result;
    this.props.onUpload(inputData);
  };
})(file).bind(this);

could be pulled out to an arrow function (taking care of bind) on the ponent:

readerOnLoad = file => (e) => {
  this.props.onUpload(e.target.result);
}

(Also, is file needed as an argument here? Doesn't appear to be used.)

Then handleSubmit can interact withreaderOnLoad` like;

reader.onload = this.readOnLoad(file);

At this point, you can test that:

  1. handleSubmit calls readerOnLoad with a file argument if it exists on state.
  2. readerOnLoad, called with a file argument and then an event argument, calls this.props.onLoad with the event target result value.

If both of these tests pass, you can be confident that your code will work with real events, files, and FileReader instances.

It looks like you already understand how to pass in duck-type arguments (like events) that match native/browser objects, so just put those together and enjoy the peace of mind of your nicely collaborating functions!

发布评论

评论列表(0)

  1. 暂无评论