I'm trying to spy on a method of an ES6 class which I have manually mocked.
I'm following the official Jest documentation, which targets only JavaScript.
Here's my code:
// sound-player.ts
export default class SoundPlayer {
foo: string
constructor() {
this.foo = 'bar'
}
playFile(fileName: string) {
console.log(`Playing sound file: ${fileName}`)
}
}
// __mocks__/sound-player.ts
export const mockPlayFile = jest.fn()
const mock = jest.fn().mockImplementation(() => {
return { playFile: mockPlayFile }
})
export default mock
// sound-player-consumer.ts
import SoundPlayer from './sound-player'
export default class SoundPlayerConsumer {
soundPlayer: SoundPlayer
constructor(soundPlayer: SoundPlayer) {
this.soundPlayer = soundPlayer
}
playSomethingCool() {
this.soundPlayer.playFile('something-cool.mp3')
}
}
// sound-player-consumer.test.ts
// @ts-ignore
import SoundPlayer, { mockPlayFile } from './sound-player'
import SoundPlayerConsumer from './sound-player-consumer'
jest.mock('./sound-player')
const MockedSoundPlayer = SoundPlayer as jest.Mock<SoundPlayer>
beforeEach(() => {
MockedSoundPlayer.mockClear()
mockPlayFile.mockClear()
})
it('We can check if the consumer called the class constructor', () => {
const soundPlayer = new MockedSoundPlayer()
const soundPlayerConsumer = new SoundPlayerConsumer(soundPlayer)
expect(SoundPlayer).toHaveBeenCalledTimes(1)
})
it('We can check if the consumer called a method on the class instance', () => {
const soundPlayer = new MockedSoundPlayer()
const soundPlayerConsumer = new SoundPlayerConsumer(soundPlayer)
soundPlayerConsumer.playSomethingCool()
expect(mockPlayFile).toHaveBeenCalledWith('something-cool.mp3')
})
These tests pass, because I used a trick.
Please pay attention to the first line of sound-player-consumer.test.ts. Without that, the TypeScript compiler would complain about mockPlayFile not being exported by sound-player.ts.
To me, this means that from Jest's perspective everything is fine.
However, I would like to fix everything from TypeScript's perspective and remove the @ts-ignore comment.