[英]Jest 'TypeError: is not a function' in jest.mock
I'm writing a Jest mock, but I seem to have a problem when defining a mocked function outside of the mock itself.我正在编写一个 Jest 模拟,但是在模拟本身之外定义模拟函数时我似乎遇到了问题。
I have a class:我有一堂课:
myClass.js
class MyClass {
constructor(name) {
this.name = name;
}
methodOne(val) {
return val + 1;
}
methodTwo() {
return 2;
}
}
export default MyClass;
And a file using it:和一个使用它的文件:
testSubject.js
import MyClass from './myClass';
const classInstance = new MyClass('Fido');
const testSubject = () => classInstance.methodOne(1) + classInstance.name;
export default testSubject;
And the test:和测试:
testSubject.test.js
import testSubject from './testSubject';
const mockFunction = jest.fn(() => 2)
jest.mock('./myClass', () => () => ({
name: 'Name',
methodOne: mockFunction,
methodTwo: jest.fn(),
}))
describe('MyClass tests', () => {
it('test one', () => {
const result = testSubject()
expect(result).toEqual('2Name')
})
})
However, I get the following error:但是,我收到以下错误:
TypeError: classInstance.methodOne is not a function
类型错误:classInstance.methodOne 不是函数
If I instead write:如果我改为写:
...
methodOne: jest.fn(() => 2)
Then the test passes no problem.然后测试通过没有问题。
Is there a way of defining this outside of the mock itself?有没有办法在模拟本身之外定义它?
In my case, I had to mock a Node.js module.就我而言,我必须模拟一个 Node.js 模块。 I'm using React and Redux in ES6, with Jest and Enzyme for unit tests.
我在 ES6 中使用 React 和Redux ,并使用 Jest 和 Enzyme 进行单元测试。
In the file I'm using, and writing a test for, I'm importing the node modules as default:在我正在使用并为其编写测试的文件中,我将默认导入节点模块:
import nodeModulePackage from 'nodeModulePackage';
So I needed to mock it as a default since I kept getting the error (0, _blah.default) is not a function.
所以我需要将它模拟为默认值,因为我不断收到错误
(0, _blah.default) is not a function.
. .
My solution was to do:我的解决方案是这样做:
jest.mock('nodeModulePackage', () => jest.fn(() => {}));
In my case, I just needed to override the function and make it return an empty object.就我而言,我只需要覆盖该函数并使其返回一个空对象。
If you need to call a function on that node module, you'll do the following:如果您需要在该节点模块上调用函数,您将执行以下操作:
jest.mock('nodeModulePackage', () => ({ doSomething: jest.fn(() => 'foo') }));
I figured this out.我想通了。 It is to do with hoisting, see: Jest mocking reference error
与提升有关,参见: Jest mocking 参考错误
The reason it had worked in a previous test, where I had done it, was because the testSubject was itself a class.它在我之前做过的测试中起作用的原因是因为 testSubject 本身就是一个类。 This meant that when the testSubject was instantiated, it was after the variable declaration in the test file, so the mock had access to use it.
这意味着当 testSubject 被实例化时,它是在测试文件中的变量声明之后,所以模拟可以使用它。
So in the above case it was never going to work.因此,在上述情况下,它永远不会起作用。
In my case, it was the importing, as described at Getting `TypeError: jest.fn is not a function` (posting here because my problem showed in jest.mock
, so I looked here first).在我的情况下,它是导入,如获取`TypeError:jest.fn 不是函数`中所述(发布在这里是因为我的问题显示在
jest.mock
,所以我jest.mock
这里)。
The basic problem was that someone had put in基本问题是有人投入了
const jest = require('jest');
But that is wrong (should be jest-mock instead of jest).但那是错误的(应该是玩笑而不是玩笑)。 This had worked in Node.js 10 with the line as originally put.
这在 Node.js 10 中与最初放置的行一起工作。 It did not work in Node.js 14. I'm guessing that they used different versions of Jest, perhaps indirectly (other packages needed updated for 14).
它在 Node.js 14 中不起作用。我猜他们使用了不同版本的 Jest,可能是间接的(其他包需要为 14 更新)。
const jest = require('jest-mock');
Also, in a test file, it will probably already be done for you, so you don't need to require anything.此外,在测试文件中,它可能已经为您完成,因此您不需要任何东西。 The file will run properly without that line.
如果没有该行,该文件将正常运行。
Linting may give an error with that line omitted, but that can be fixed with Linting 可能会在省略该行的情况下给出错误,但这可以通过
/* global jest */
or if you're already doing that with expect
,或者如果你已经用
expect
做到了,
/* global expect, jest */
The linter seemed happy when that line appeared either after or before jest
was first used.当第一次使用
jest
之后或之前出现该行时,linter 似乎很高兴。 You may choose order based on readability rather than by functional requirement if your linter works the same way.如果您的 linter 工作方式相同,您可以根据可读性而不是功能要求来选择顺序。
In my case it was from the module.exports
.就我而言,它来自
module.exports
。
Instead of writing而不是写作
module.exports = {sum: sum};
Write写
module.exports = sum;
Note : sum is a function that adds 2 numbers注意:sum 是一个将 2 个数字相加的函数
In case anyone is still facing a similar issue, to resolve the failing tests I had to return a mocked function like so:如果有人仍然面临类似的问题,为了解决失败的测试,我必须返回一个模拟函数,如下所示:
const tea = TeamMaker.makeTea();
tea(); // TypeError: tea is not a function
jest.mock('url/to/TeamMaker', () => ({ makeTea: jest.fn(() => jest.fn) })); // tests passed
Defining mockOne
as an unassigned let
and then initialising the variable inside the mocking function worked for me:将
mockOne
定义为未分配的let
然后初始化mockOne
函数内的变量对我有用:
let mockFunction
jest.mock('./myClass', () => () => {
mockFunction = jest.fn(() => 2)
return {
name: 'Name',
methodOne: mockFunction,
methodTwo: jest.fn(),
}
}))
In my case, it was the way i was exporting the files that was the issue.就我而言,这是我导出问题的方式。
The file i was trying to mock was being exported like: export const fn = () => {};
我试图模拟的文件被导出如下:
export const fn = () => {};
The mocked file i wrote was being exported like:我写的模拟文件被导出如下:
const fn = () => {};
export default fn;
Once i made sure that the mocked file was also being exported like the file to be mocked, i didn't have this issue一旦我确定模拟文件也像要模拟的文件一样被导出,我就没有这个问题
following is the answer which worked for me以下是对我有用的答案
import {testSubject} from '../testsubject';
describe('sometest',(){
it('some test scenario',()=>{
testSubject.mockReturnValue(()=>jest.fn);
})
})
I am writing my version in case it helps someone.我正在编写我的版本,以防它对某人有所帮助。
I was facing error while mocking firebase-admin
.我在
firebase-admin
时firebase-admin
错误。 I jest-mocked firebase-admin
like below:我像下面这样开玩笑地嘲笑
firebase-admin
:
jest.mock('firebase-admin');
But I started getting following error:但我开始收到以下错误:
firebase_admin_1.default.messaging is not a function
It was coming because in the app code, I had used firebase-admin
like this:这是因为在应用程序代码中,我像这样使用了
firebase-admin
:
await admin.messaging().send(message)
(message is an instance of TokenMessage ) (消息是TokenMessage 的一个实例)
The problem was that I was not mocking the member variables and member methods.问题是我没有嘲笑成员变量和成员方法。 Here it was the member method
messaging
and a nested member method within messaging
called send
.这是部件方法
messaging
和内嵌套成员方法messaging
调用send
。 (See that messaging
method is called on admin
and then send
is called on the value of admin.messaging()
). (请参见
messaging
方法被称为上admin
然后send
被称为上的值admin.messaging()
All that was needed was to mock these like below:所需要的只是模拟这些,如下所示:
jest.mock('firebase-admin', () => ({
credential: {
cert: jest.fn(),
},
initializeApp: jest.fn(),
messaging: jest.fn().mockImplementation(() => {
return {
send: jest
.fn()
.mockReturnValue('projects/name_of_project/messages/message_id'),
};
}),
}));
(Note that I have also mocked other member variables/methods as per my original requirement. You would probably need these mocks as well) (请注意,我还根据最初的要求模拟了其他成员变量/方法。您可能也需要这些模拟)
For me, it was the jest config.对我来说,这是开玩笑的配置。
Because my project was initially in .js
and was upgrade to .ts
.因为我的项目最初是在
.js
,然后升级到.ts
。
So the class I tested was in .ts
but my jest.config.js
was config for .js
file.所以我测试的类在
.ts
但我的jest.config.js
是.js
文件的配置。
See below my new config :请参阅下面我的新配置:
module.exports = {
...
collectCoverageFrom: ['src/**/*.{ts,js,jsx,mjs}'],
...
testMatch: [
'<rootDir>/src/**/__tests__/**/*.{ts,js,jsx,mjs}',
'<rootDir>/src/**/?(*.)(spec|test).{ts,js,jsx,mjs}',
]
};
For the other Jest newbies out there, if you mock multiple functions from the same package or module like this:对于其他 Jest 新手,如果您模拟来自同一个包或模块的多个函数,如下所示:
jest.mock(
'pathToModule',
() => ({
functionA: jest.fn(() => {
return 'contentA';
}),
})
);
jest.mock(
'pathToModule',
() => ({
functionB: jest.fn(() => {
return 'contentB';
}),
})
);
The second mock will override the first, and you'll end up with functionA
is not a function.第二个模拟将覆盖第一个,您最终会发现
functionA
不是一个函数。
Just combine them if they're both coming from the same module.如果它们都来自同一个模块,只需将它们组合起来。
jest.mock(
'samePathToModule',
() => ({
functionA: jest.fn(() => {
return 'contentA';
}),
functionB: jest.fn(() => {
return 'contentB';
}),
})
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.