I needed to execute shell commands and keep the process alive to keep the changes made in the env variables, so I made a function that looks like this:
import { spawn } from 'child_process';
function exec(command) {
const bash = spawn('/bin/bash', {
detached: true
});
bash.stdout.setEncoding('utf-8');
bash.stderr.setEncoding('utf-8');
return new Promise(resolve => {
const result = {
stdout: '',
stderr: '',
code: 0
};
bash.stdout.on('data', data => {
// Removes the last line break (i.e \n) from the data.
result.stdout += data.substring(0, data.length - 1);
// Gets the code by getting the number before the `:` on the last line
result.code = Number(result.stdout.split('\n').pop().split(':')[0]);
resolve(result);
});
bash.stderr.on('data', err => {
result.stderr += err;
resolve(result);
});
// Writes the passed command and another to check the code of the command
bash.stdin.write(command + `; echo "$?:${ command }"\n`);
});
}
The test is simple:
it('should run a command that outputs an error', async () => {
// Notice the typo in `echoo`
const res = await exec('echoo test');
expect(res.code).toBe(127);
});
When running this test, it sometimes fails with res.code being 0 instead of 127.
When testing without jest, it works flawlessly 100% of the time.