This test
it.only('should not throw', () => {
var output = '';
function callback(data) {
output += data.toString();
}
process.stdout.on('data', callback); // error is thrown at this line
// ...
process.stdout.removeListener('data', callback);
})
throws an error:
Error: This socket is closed
at WriteStream.Socket._writeGeneric (net.js:679:19)
at WriteStream.Socket._write (net.js:730:8)
at doWrite (_stream_writable.js:331:12)
at writeOrBuffer (_stream_writable.js:317:5)
at WriteStream.Writable.write (_stream_writable.js:243:11)
at WriteStream.Socket.write (net.js:657:40)
at Console.log (console.js:43:16)
at Runner.<anonymous> (node_modules\mocha\lib\reporters\spec.js:80:13)
at emitTwo (events.js:111:20)
at Runner.emit (events.js:191:7)
at Runner.fail (node_modules\mocha\lib\runner.js:251:8)
at Runner.uncaught (node_modules\mocha\lib\runner.js:757:8)
at process.uncaught (node_modules\mocha\lib\runner.js:839:10)
at emitOne (events.js:96:13)
at process.emit (events.js:188:7)
at process._fatalException (bootstrap_node.js:297:26)
Where node_modules\mocha\lib\reporters\spec.js:80:13
are these Mocha lines:
runner.on('fail', function(test) {
console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
});
It's supposed to test code that outputs to process.stdout
with spawn
, but I wasn't able to get to this part; the error is thrown instantly on process.stdout.on('data', ...)
call.
The problem persists with latest Mocha (5.2.0) and default configuration, a reporter in use doesn't affect the result.
What is going on and how can process.stdout
be listened? If this is impossible, how can stdout from spawned process be tested in Mocha otherwise?
I was not able to reproduce the error: process.stdout.on('data', callback); // error is thrown at this line
. So hard to say why it breaks for you. Anyway process.stdout
is a writeable stream, so data
event is not supported. On the other hand childProcess.stdout
is a readable stream from parent perspective.
The easiest way to intercept stdout of a child process is to:
const ch = spawn(...)
ch.stdout.on('data', d => ...) // 'd' is a buffer
If you want to test against stdout of an arbitrary spawn process I am afraid you need to pass a custom writeable stream as subprocess's stdout, when spawning the process. The stream needs to be based on a file descriptor, so simple Duplex
will not work unfortunately.
Here is a possible setup:
process.js
const { spawn } = require('child_process')
module.exports = (outStream) => {
console.log('PARENT')
const s = spawn('node', [`${__dirname}/child.js`], { stdio: ['ignore', outStream] })
return () => {
console.log('PARENT-DISPOSE')
s.kill()
}
}
child.js
process.stdout.write('FROM CHILD')
setTimeout(() => process.stdout.write('FROM CHILD END'), 100)
process.spec.js
const { spawn } = require('child_process')
const fs = require('fs')
const process = require('./process.js')
// path to temporary file
const commF = `${__dirname}/comm`
it('test spawn', (done) => {
const w = fs.createWriteStream(commF)
let dispose
w.on('open', () => {
dispose = process(w)
})
// unfortunately I was not able to make fs.createReadStram to read data in real-time
// so here we use another subprocess just for that
let readProcess = spawn('tail', ['-f', commF])
readProcess.stdout.on('data', x => {
const d = x && x.toString()
console.log('TEST', d) // only logs from child are present here
if (d.startsWith('FROM CHILD END')) {
w.close()
fs.unlinkSync(commF)
dispose()
readProcess.kill()
done()
}
})
}).timeout(500)
Not saying that this is the best way to do it: it could be abstracted away for re-usability and the tail
dependency may be removed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With