I'm trying to write a test for this piece of code:
const util = require('node:util')
const exec = util.promisify(require('node:child_process').exec)
class Command {
async execute(command) {
try {
const { stdout, stderr } = await exec(command)
return { code: 0, stdout, stderr }
} catch (error) {
return {
code: error.code,
stdout: error.stdout,
stderr: error.stderr
}
}
}
}
I've looked at How to mock a promisified and bound function? and How do I use Jest to mock a promisified function? but I cannot figure out how exactly mock exec
or whether I should mock promisify
.
I tried this one:
const { Command } = require('../src/utils')
jest.mock('node:child_process', () => ({
exec: jest.fn()
}))
describe('Command', () => {
it('executes a command', async () => {
const command = new Command()
const cmd = 'la -la'
const expected = {
code: 0,
stdout: cmd,
stderr: ''
}
require('node:child_process').exec.mockReturnValueOnce({
stdout: cmd,
stderr: ''
})
const result = await command.execute(cmd)
expected(result).toEqual(expected)
})
})
but I get thrown: "Exceeded timeout of 5000 ms for a test.
.
What should I mock, and how?
I've looked at comments from @jonrsharpe and other similar answers. Also found this answer which provides some clue how to mock exec. Finally made some progress and it works now.
The reasons why I failed before were:
command
, options
, callback
) but if my code do not define options, I should not define it in mock.error
, stdout
, stderr
). I was thinking that I should call the callback like callback(null, 'stdout', 'stderr')
or maybe callback({error: null, stdout: 'stdout', stderr: 'stderr'})
but based on other answers it should actually be callback(null, {stdout: 'stdout', stderr: 'stderr'})
for some reason.Anyways I finally was able to make it work with this:
const { Command } = require('../src/utils')
jest.mock('node:child_process', () => ({
exec: jest
.fn()
.mockImplementation((command, callback) =>
callback(null, { stdout: command, stderr: '' })
)
}))
describe('Command', () => {
it('executes a command', async () => {
const command = new Command()
const cmd = 'la -la'
const expected = {
code: 0,
stdout: cmd,
stderr: ''
}
const result = await command.execute(cmd)
expect(result).toEqual(expected)
})
})