模拟节点外部模块默认使用Jest的链接方法

时间:2019-03-31 01:29:50

标签: javascript node.js jestjs

在节点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();
};

我们尝试使用笑话来测试此方法。我们有两个测试可以实现:

  • 测试是否已使用适当的对象参数调用了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”上不存在属性“开始”   import(“ / Users / Dev / cli / node_modules / ora / index”)'。

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

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

1 个答案:

答案 0 :(得分: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!
    });
  });
});