【问题标题】:How to properly mock the file reader using Jest?如何使用 Jest 正确模拟文件阅读器?
【发布时间】:2021-04-07 10:25:54
【问题描述】:

我正在尝试模拟文件阅读器,并且我有一个接受回调的函数,但是在测试期间,调用回调的行没有被覆盖。怎么解决?

功能:

const testFunction = (uint8arr, callback) => {
  const bb = new Blob([uint8arr]);
  const f = new FileReader();
  f.onload = function (e) {
    callback(e.target.result);
  };

  f.readAsText(bb);
};

module.exports = { testFunction };

测试:

const { testFunction } = require("./index");

class FileReaderMock {
  DONE = FileReader.DONE;
  EMPTY = FileReader.EMPTY;
  LOADING = FileReader.LOADING;
  readyState = 0;
  error = null;
  result = null;
  abort = jest.fn();
  addEventListener = jest.fn();
  dispatchEvent = jest.fn();
  onabort = jest.fn();
  onerror = jest.fn();
  onload = jest.fn();
  onloadend = jest.fn();
  onloadprogress = jest.fn();
  onloadstart = jest.fn();
  onprogress = jest.fn();
  readAsArrayBuffer = jest.fn();
  readAsBinaryString = jest.fn();
  readAsDataURL = jest.fn();
  readAsText = jest.fn();
  removeEventListener = jest.fn();
}

const mockCallback = jest.fn();

describe("testFunction", () => {
  const fileReader = new FileReaderMock();

  jest.spyOn(window, "FileReader").mockImplementation(() => fileReader);

  it("should be called mockCallback and readAsText with the blob value", () => {
    const uintArray = new Uint8Array();
    testFunction(uintArray, mockCallback);

    // expect(mockCallback).toHaveBeenCalled();
    // expect(fileReader.readAsText).toHaveBeenCalledWith(new Blob([uintArray]));
  });
});

代码沙盒:https://codesandbox.io/s/jest-test-forked-ecejb?file=/index.test.js

【问题讨论】:

    标签: javascript node.js unit-testing jestjs mocking


    【解决方案1】:

    可以使用Object.defineProperty()方法的getter和setter来拦截onload函数的赋值操作,这样就可以像往常一样获取onload函数测试了。

    例如

    index.js:

    const testFunction = (uint8arr, callback) => {
      const bb = new Blob([uint8arr]);
      const f = new FileReader();
      f.onload = function (e) {
        callback(e.target.result);
      };
    
      f.readAsText(bb);
    };
    
    module.exports = { testFunction };
    

    index.test.js:

    const { testFunction } = require('./index');
    
    describe('testFunction', () => {
      it('should be called mockCallback and readAsText with the blob value', () => {
        const mockCallback = jest.fn();
        const fileReader = {
          readAsText: jest.fn(),
        };
        let onloadRef;
        Object.defineProperty(fileReader, 'onload', {
          get() {
            return this._onload;
          },
          set(onload) {
            onloadRef = onload;
            this._onload = onload;
          },
        });
        jest.spyOn(window, 'FileReader').mockImplementation(() => fileReader);
        const uintArray = new Uint8Array();
        testFunction(uintArray, mockCallback);
    
        // onload test
        const event = { target: { result: 'teresa teng' } };
        onloadRef(event);
        expect(mockCallback).toBeCalledWith('teresa teng');
        expect(fileReader.readAsText).toBeCalledWith(new Blob([uintArray]));
      });
    });
    

    单元测试结果:

     PASS  examples/66964346/index.test.js (7.479 s)
      testFunction
        ✓ should be called mockCallback and readAsText with the blob value (4 ms)
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |     100 |      100 |     100 |     100 |                   
     index.js |     100 |      100 |     100 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        8.575 s, estimated 9 s
    

    【讨论】:

      猜你喜欢
      • 2019-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-03
      • 2021-09-05
      相关资源
      最近更新 更多