'此插座已关闭'当在Mocha测试中听到stdout时

时间:2018-06-17 05:49:28

标签: node.js mocha

此测试

posts/comments [GET]

抛出错误:

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);
})

其中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) 是这些摩卡线:

node_modules\mocha\lib\reporters\spec.js:80:13

它应该测试使用 runner.on('fail', function(test) { console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); }); 输出到process.stdout的代码,但我无法进入此部分; spawn电话会立即抛出错误。

问题仍然存在于最新的Mocha(5.2.0)和默认配置中,使用中的报告者不会影响结果。

发生了什么以及如何监听process.stdout.on('data', ...)?如果这是不可能的,那么如何在Mocha中测试产生过程的stdout呢?

1 个答案:

答案 0 :(得分:3)

我无法重现错误:process.stdout.on('data', callback); // error is thrown at this line。很难说为什么它对您不利。无论如何,process.stdout是可写的流,因此不支持data事件。另一方面,childProcess.stdout从父级角度来看是可读的流。

拦截子进程的标准输出的最简单方法是:

const ch = spawn(...)
ch.stdout.on('data', d => ...) // 'd' is a buffer

如果要对任意生成程序的stdout进行测试,恐怕在生成进程时需要传递自定义可写流作为子进程的stdout。流必须基于文件描述符,因此不幸的是,简单的Duplex不会起作用。

以下是可能的设置:

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)

并不是说这是最好的方法:可以将其抽象化以实现可重用性,并且可以删除tail依赖性。