模拟节点外部模块默认使用Jest的链接方法 [英] Mock node external module default with chained method using jest

查看:179
本文介绍了模拟节点外部模块默认使用Jest的链接方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In our node CLI we have a simple method:

'use strict';

const ora = require('ora');

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

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

We try to use jest to test this method. We have two tests to achieve:

  • 测试是否已使用适当的对象参数调用了ora
  • 测试方法start()之后是否被调用
  • Testing that ora has been called with proper object argument
  • Testing that the method start() was called afterward

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

That being said we cannot achieve to mock ora module properly.

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

ora is a third party that is basically constructed as follow:

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

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

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

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

We are looking for a way to mock ora.

我们尝试使用自动模拟:

We tried to use auto mock:

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

但是两个测试分别失败:

But both tests fail with respectively:

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

Matcher error: received value must be a mock or spy function

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

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

Matcher error: received value must be a mock or spy function

Received has value: undefined

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

We tried to use a custom mock:

const ora = require('ora');

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

并且最终得到相同的准确结果.

and it ends up with the same exact result.

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

We even tried to convert our test to typescript and then use:

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();的错误:

Then we were able to test successfuly that ora was called. But we ended up with an error for expect(ora.start).toHaveBeenCalled(); or even expect((ora as any).start).toHaveBeenCalled();:

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

error TS2339: Property 'start' does not exist on type 'typeof import("/Users/Dev/cli/node_modules/ora/index")'.

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

Surely caused by the fact the type definition of imported ora is export default function ora(options?: Options | string): Ora;

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

How to then mock a third party like ora in jest's node test environnement?

推荐答案

您有几个选择:

您可以像这样模拟ora:

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

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

...and then call ora to get the object it returns (since it always returns the same object) and use that object to access start:

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


或者,如果您愿意,可以将start模拟作为属性附加到ora模拟,作为在测试期间访问它的一种简便方法:


Or if you want you can attach the start mock as a property to the ora mock as an easy way to access it during your tests like this:

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

这篇关于模拟节点外部模块默认使用Jest的链接方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆