- Why does monkey-patching only work for commonJS?
- Or maybe broader what is an ES module situation?
- What’s the difference between commonJS and ES Module JS?
- What is their relation to ES versions?
How can you create different mock implementations of the same Module within the same test file?
For example, we want to test the thumbWar
implementation for the case that player1 wins but
also for the case that player2 wins. So we need two mock implementations. With monkey patching,
this is not a problem. But how we do it in an ES Modules situation?
Here is the code for thumbWar and getWinner for reference
//thumb-war.js
function thumbWar(player1, player2) {
const numberToWin = 2
let player1Wins = 0
let player2Wins = 0
while (player1Wins < numberToWin && player2Wins < numberToWin) {
const winner = utils.getWinner(player1, player2)
if (winner === player1) {
player1Wins++
} else if (winner === player2) {
player2Wins++
}
}
return player1Wins > player2Wins ? player1 : player2
}
//utils.js
// returns the winning player or null for a tie
function getWinner(player1, player2) {
const winningNumber = Math.random()
return winningNumber < 1 / 3
? player1
: winningNumber < 2 / 3
? player2
: null
}
A solution I found is to change the mock by useing the mockImplemetation
property e.g:
utils.getWinner.mockImplementation((p1, p2) => p2)
But I have also read that the shortcut for the above is
utils.getWinner = jest.fn((p1, p2) => p2)
which in the end for me looks an awful lot again like monkey patching. Can you lift my confusion?
Here is the test code for reference:
const thumbWar = require('../thumb-war')
const utilsMock = require('../utils')
jest.mock('../utils', () => {
return {
getWinner: jest.fn((p1, p2) => p1)
}
})
test('returns first winner', () => {
const winner = thumbWar('Kent C. Dodds', 'Ken Wheeler')
expect(winner).toBe('Kent C. Dodds')
expect(utilsMock.getWinner.mock.calls).toEqual([
['Kent C. Dodds', 'Ken Wheeler'],
['Kent C. Dodds', 'Ken Wheeler']
])
// cleanup
utilsMock.getWinner.mockReset()
})
test('returns second winner', () => {
// How to change the mock implementation without monkey patching?
// Contradictionary to the mention "monkey patching does not work
// in an ES Module situation", in this test monkey patching is working,
// but I assume that is only because we are using commonJS modules.
utilsMock.getWinner = jest.fn((p1, p2) => p2)
const winner = thumbWar('Kent C. Dodds', 'Ken Wheeler')
expect(winner).toBe('Ken Wheeler')
expect(utilsMock.getWinner.mock.calls).toEqual([
['Kent C. Dodds', 'Ken Wheeler'],
['Kent C. Dodds', 'Ken Wheeler']
])
// cleanup
utilsMock.getWinner.mockReset()
})