模拟节点外部模块默认使用Jest的链接方法 [英] Mock node external module default with chained method using 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屋!