【问题标题】:Mock node external module default with chained method using jest使用 jest 使用链式方法模拟节点外部模块默认值
【发布时间】:2019-08-21 13:21:14
【问题描述】:

在我们的节点 CLI 中,我们有一个简单的方法:

'use strict';

const ora = require('ora');

module.exports = function startSpinner({ textOnStart, color, spinnerType }) {
  const spinner = ora({
    text: textOnStart,
    color: color || 'cyan',
    spinner: spinnerType || ''
  }).start();
};

我们尝试用 jest 来测试这个方法。我们有两个测试要实现:

  • 测试是否使用正确的对象参数调用了 ora
  • 测试start()方法是否被调用

话虽如此,我们无法正确模拟 ora 模块。

ora是第三方,基本构造如下:

class Ora {
    constructor(options){}
    start(){ }
}

const oraFactory = function (opts) {
    return new Ora(opts);
};

module.exports = oraFactory;
module.exports.default = oraFactory;

我们正在寻找一种模拟 ora 的方法。

我们尝试使用自动模拟:

const ora = require('ora');

jest.mock('ora');

const startSpinner = require('./startSpinner');

describe('startSpinner', () => {
  beforeEach(() => {
    startSpinner({});
  });

  describe('ora', () => {
    it('should call ora', () => {
      expect(ora).toHaveBeenCalled();
    });

    it('should call ora start', () => {
      expect(ora.start).toHaveBeenCalled();
    });
  });
});

但两个测试分别失败:

匹配器错误:接收到的值必须是模拟或间谍函数

Received has type:  function
Received has value: [Function oraFactory]

匹配器错误:接收到的值必须是模拟或间谍函数

Received has value: undefined

我们尝试使用自定义模拟:

const ora = require('ora');

jest.mock('ora', () => {
  return jest.fn().mockImplementation(() => {
    return { start: jest.fn() };
  });
});

最终得到完全相同的结果。

我们甚至尝试将我们的测试转换为打字稿,然后使用:

import * as ora from 'ora';

const startMock = jest.fn();
jest.mock('ora', () => {
  return jest.fn().mockImplementation(() => {
    return { start: startMock };
  });
});

然后我们能够成功测试 ora 被调用。但我们最终得到了expect(ora.start).toHaveBeenCalled(); 甚至expect((ora as any).start).toHaveBeenCalled(); 的错误:

错误 TS2339:类型“typeof”上不存在属性“start” import("/Users/Dev/cli/node_modules/ora/index")'.

肯定是导入的ora的类型定义是export default function ora(options?: Options | string): Ora;造成的

如何在 jest 的节点测试环境中模拟像 ora 这样的第三方?

【问题讨论】:

    标签: javascript node.js jestjs


    【解决方案1】:

    你有几个选择:


    你可以像这样模拟ora

    jest.mock('ora', () => {
      const start = jest.fn();
      const result = { start };
      return jest.fn(() => result);
    });
    

    ...然后调用ora获取它返回的对象(因为它总是返回相同的对象)并使用该对象访问start

    it('should call ora start', () => {
      const result = ora();
      expect(result.start).toHaveBeenCalled();  // Success!
    });
    

    或者,如果您愿意,可以将 start 模拟作为属性附加到 ora 模拟,以便在测试期间轻松访问它,如下所示:

    const ora = require('ora');
    
    jest.mock('ora', () => {
      const start = jest.fn();
      const result = { start };
      const ora = jest.fn(() => result);
      ora.start = start;  // attach the start mock to ora
      return ora;
    });
    
    const startSpinner = require('./startSpinner');
    
    describe('startSpinner', () => {
      beforeEach(() => {
        startSpinner({});
      });
    
      describe('ora', () => {
        it('should call ora', () => {
          expect(ora).toHaveBeenCalled();  // Success!
        });
    
        it('should call ora start', () => {
          expect(ora.start).toHaveBeenCalled();  // Success!
        });
      });
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-22
      • 2018-07-14
      • 2019-12-02
      • 2022-01-03
      • 2023-03-11
      • 2018-01-18
      • 1970-01-01
      相关资源
      最近更新 更多