Since exec executes asynchronously, you'll need to change the now function a bit in order to test it. As it's written, you don't have a way for the caller to know when now is finished. The simplest ways to change this are:
- Make it return a Promise that resolves when it's done
- Make it take a callback that is called when it's done
Promise
function now(script) {
return new Promise((resolve, reject) => {
let execute = exec(script)
execute.stdout.on('data', (data) => {
if (data.charAt(data.length - 1) === '\n') {
console.log(data.toString().slice(0, -1))
} else {
console.log(data.toString())
}
})
// Resolve the Promise when the shell exits
execute.on('exit', resolve);
// Error handling omitted for brevity, you can call reject() on failure
});
}
Here's the test. There are various ways to check that console.log is called. This one uses a spy but you could also inject a log function and default it to console.log.
it('logs from shell command', async () => {
jest.spyOn(console, "log");
await greet('echo "foo"');
expect(console.log).toBeCalledWith('foo');
});
Callback
function now(script, callback) {
let execute = exec(script)
execute.stdout.on('data', (data) => {
if (data.charAt(data.length - 1) === '\n') {
console.log(data.toString().slice(0, -1))
} else {
console.log(data.toString())
}
})
// Resolve the Promise when the shell exits
execute.on('exit', callback);
// Error handling omitted for brevity, you can pass an error to the callback on failure
}
The expect needs to be in the callback so the test waits until the shell has exited. Note that you need to call done for the test to finish. Promises are generally more ergonomic, but callbacks have their uses as well so I included them both.
it('logs from shell command', (done) => {
jest.spyOn(console, "log");
greet('echo "foo"', () => {
expect(console.log).toBeCalledWith('foo');
done()
});
});