简体   繁体   English

jest.mock 中的 Jest 'TypeError: is not a function'

[英]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-adminfirebase-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.

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