2
votes

Given the following example with a basic test, I'd expect bar to be returned when sendMessage.message is mocked with Jest. Instead, when called, it returns the original value of "Hello World".

serviceBus.js

export const message = () => {
  return "Hello world";
};

export const foo = () => {
  return message();
};

mockDemo.test.js

import * as sendMessage from "../src/services/serviceBus";

describe("sendMessage", () => {
  sendMessage.message = jest.fn(() => {
    return "bar";
  });

  it(`message should return bar`, async () => {
    expect(sendMessage.message()).toBe("bar");
    expect(sendMessage.foo()).toBe("bar");
  });
});

And the results as follows:

$ ./node_modules/.bin/jest ./__tests__/mockDemo.test.js
 FAIL  __tests__/mockDemo.test.js
  MessageReceiver Router
    ✕ message should return bar (9ms)

  ● MessageReceiver Router › message should return bar

    expect(received).toBe(expected) // Object.is equality

    Expected: "bar"
    Received: "Hello world"

       9 |   it(`message should return bar`, async () => {
      10 |     expect(sendMessage.message()).toBe("bar");
    > 11 |     expect(sendMessage.foo()).toBe("bar");
         |                               ^
      12 |   });
      13 | });
      14 |

      at Object.<anonymous> (__tests__/mockDemo.test.js:11:31)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total

It looks as if sendMessage.foo is calling the bound function once imported of message, which by default returns Hello World.

How would one mock message in this context?

Update

Using jest.fn().mockImplementation(() => "bar"); results in the same behaviour:

describe("MessageReceiver Router", () => {
  //   sendMessage.message.mockImplementation = jest.fn(() => {
  //     return "bar";
  //   });

  sendMessage.message = jest.fn().mockImplementation(() => "bar");

  it(`message should return bar`, async () => {
    expect(sendMessage.message()).toBe("bar");
    expect(sendMessage.foo()).toBe("bar");
  });
});

Results:

$ ./node_modules/.bin/jest ./__tests__/mockDemo.test.js
 FAIL  __tests__/mockDemo.test.js
  MessageReceiver Router
    ✕ message should return bar (10ms)

  ● MessageReceiver Router › message should return bar

    expect(received).toBe(expected) // Object.is equality

    Expected: "bar"
    Received: "Hello world"

      11 |   it(`message should return bar`, async () => {
      12 |     expect(sendMessage.message()).toBe("bar");
    > 13 |     expect(sendMessage.foo()).toBe("bar");
         |                               ^
      14 |   });
      15 | });
      16 |

      at Object.<anonymous> (__tests__/mockDemo.test.js:13:31)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.175s
2
sendMessage.message.mockImplementation?evolutionxbox
Doesn't work unfortunately :/steadweb
Ah. It has been closed over. So you may not be able to.evolutionxbox

2 Answers

1
votes

So internal functions called cannot be mocked or spyed on. To fix this, you need to create an object of services, and export that instead.

serviceBus.js

const message = () => {
  return "Hello world";
};

const foo = () => {
  return services.message();
};

const services = {
  message,
  foo
};

export default services;

mockDemo.test.js

import sendMessage from "../src/services/serviceBus";

describe("MessageReceiver Router", () => {
  sendMessage.message = jest.fn(() => {
    return "bar";
  });

  it(`message should return bar`, async () => {
    expect(sendMessage.message()).toBe("bar");
    expect(sendMessage.foo()).toBe("bar");
  });
});
0
votes

You should use spyOn method to mock the sendMessage.message method.

import * as sendMessage from "../src/services/serviceBus";

describe("sendMessage", () => {
   jest.spyOn(sendMessage, 'message').mockReturnValue("bar")

  it(`message should return bar`, async () => {
    expect(sendMessage.message()).toBe("bar");
    expect(sendMessage.foo()).toBe("bar");
  });
});