How to mock es6 class using Jest

前端 未结 2 466
暖寄归人
暖寄归人 2020-12-15 17:29

I am attempting to mock a class Mailer using jest and I can\'t figure out how to do it. The docs don\'t give many examples of how this works. The process is the

相关标签:
2条回答
  • 2020-12-15 17:45

    Just for Googlers and future visitors, here's how I've setup jest mocking for ES6 classes. I also have a working example at github, with babel-jest for transpiling the ES module syntax so that jest can mock them properly.

    __mocks__/MockedClass.js

    const stub = {
      someMethod: jest.fn(),
      someAttribute: true
    }
    
    module.exports = () => stub;
    

    Your code can call this with new, and in your tests you can call the function and overwrite any default implementation.

    example.spec.js

    const mockedClass = require("path/to/MockedClass")(); 
    const AnotherClass = require("path/to/AnotherClass");
    let anotherClass;
    
    jest.mock("path/to/MockedClass");
    
    describe("AnotherClass", () => {
      beforeEach(() => {
        mockedClass.someMethod.mockImplementation(() => {
          return { "foo": "bar" };
        });
    
        anotherClass = new AnotherClass();
      });
    
      describe("on init", () => {
        beforeEach(() => { 
          anotherClass.init(); 
        });
    
        it("uses a mock", () => {
          expect(mockedClass.someMethod.toHaveBeenCalled();
          expect(anotherClass.settings)
            .toEqual(expect.objectContaining({ "foo": "bar" }));
        });
      });
    
    });
    
    0 讨论(0)
  • 2020-12-15 17:56

    You don't have to mock your mailer class but the mailgun-js module. So mailgun is a function that returns the function messages that return the function send. So the mock will look like this.

    for the happy path

    const happyPath = () => ({
      messages: () => ({
        send: (args, callback) => callback()
      })
    })
    

    for the error case

    const errorCase = () => ({
      messages: () => ({
        send: (args, callback) => callback('someError')
      })
    })
    

    as you have this 2 cases it make sense to mock the module inside your test. First you have to mock it with a simple spy where we later can set the implementation for our cases and then we have to import the module.

    jest.mock('mailgun-js', jest.fn())
    import mailgun from 'mailgun-js'
    import Mailer from '../../../../server/services/emails/mailer'
    

    As your module uses promises we have 2 options either return the promise from the test or use async/await. I use the later one for more info have a look here.

    test('test the happy path', async() => {
     //mock the mailgun so it returns our happy path mock
      mailgun.mockImplementation(() => happyPath)
      //we need to use async/awit here to let jest recognize the promise
      const send = await Mailer.send();
      expect(send).toBe('The email was sent successfully!')
    });
    

    If you would like to test that the mailgun send method was called with the correct parameter you need to adapt the mock like this:

    const send = jest.fn((args, callback) => callback())
    const happyPath = () => ({
      messages: () => ({
        send: send
      })
    })
    

    Now you could check that the first parameter for send was correct:

    expect(send.mock.calls[0][0]).toMatchSnapshot()
    
    0 讨论(0)
提交回复
热议问题