Ryan Tang
Ryan Tang

Reputation: 74

How to test method calls in the same class using Jest?

I'm trying to test function calls inside the class to make sure they're called, but I can't seem to figure out how to do that with Jest.

Automatic mocks don't work, and neither does calling jest.mock with the module factory param.

This is the class in question, and I want to test that calling play() calls playSoundFile().

class SoundPlayer {
  constructor() {
    this.foo = 'bar';
  }

  playSoundFile(fileName) {
    console.log('Playing sound file ' + fileName);
  }

  play() {
    this.playSoundFile('song.mp3');
  }
}

module.exports = SoundPlayer;

This is the test file:

const SoundPlayer = require('../sound-player');
jest.mock('../sound-player');

it('test', () => {
  const soundPlayerConsumer = new SoundPlayer();

  const coolSoundFileName = 'song.mp3';
  soundPlayerConsumer.play();

  const mockPlaySoundFile = SoundPlayer.mock.instances[0].playSoundFile;
  expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName);
});

mockPlaySoundFile.mock.calls is empty, and it errors out because of that.

Upvotes: 2

Views: 5191

Answers (2)

skyboyer
skyboyer

Reputation: 23685

I propose you don't mock any internal method. Instead you can mock any external dependency and call methods supposed to be public. Then you run assertions against what public(supposed to be called outside) methods return and also check mocks(mocked external dependencies) for being/not being called.

In this particular example there is just console.log:

console.log = jest.fn();
const soundPlayerConsumer = new SoundPlayer();
soundPlayerConsumer.play();
expect(console.log).toHaveBeenCalledTimes(1);
expect(console.log).toHaveBeenCalledWith('Playing sound file song.mp3');

In more real-world scenario it may need you to mock document or even use jsdom to mock <audio /> HTML element. But approach would be the same.

Upvotes: 2

Ryan Tang
Ryan Tang

Reputation: 74

If I don't mock the entire class and just spy on the function, it works. However this doesn't get around testing intensive functions, e.g. calls to the database.

const SoundPlayer = require('../sound-player');

it('test', () => {
  const soundPlayerConsumer = new SoundPlayer();
  const playSpy = jest.fn();
  soundPlayerConsumer.playSoundFile = fileName => playSpy(fileName);

  soundPlayerConsumer.play();

  expect(playSpy).toHaveBeenCalledWith('song.mp3');
});

Upvotes: 2

Related Questions