繁体   English   中英

使用 jest 使用链式方法默认模拟节点外部模块

[英]Mock node external module default with chained method using jest

在我们的节点 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.start).toHaveBeenCalled(); 甚至expect((ora as any).start).toHaveBeenCalled();

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

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

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

你有几个选择:


你可以像这样模拟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 mock 作为属性附加到ora mock 作为在测试期间访问它的一种简单方法,如下所示:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM