在 jest 拆解中杀死 node.js 服务器(在 jest 的设置挂钩中启动)

Killing a node.js server (launched in jest's setup hook) in jest teardown

我正在使用 Jest as a testing library and inside its setup hook (which is executed before all my tests), I spawn 一个在特定端口上启动测试服务器的子进程。 设置代码基本上执行一个 NPM 命令:

"run-server-test": "NODE_ENV=test SERVER_PORT=3001 node src/index.js &",
"test": "NODE_ENV=test SERVER_PORT=3001 jest --detectOpenHandles --forceExit",

这是设置函数:

const { spawn } = require("child_process")

module.exports = async function setup() {
  return new Promise((resolve, reject) => {
    const testServerProcess = spawn("npm", ["run", "run-server-test"])

    testServerProcess.on("error", err => {
      console.log("Failed to start subprocess.", err)
      reject(err)
    })

    testServerProcess.stdout.on("data", data => {
      if (data.toString().startsWith("Apollo Server")) {
        console.log(`\nTest server running with PID ${testServerProcess.pid}`)
        resolve(true)
      }
    })

    testServerProcess.stderr.on("data", data => {
      console.error(`stderr: ${data}`)
      reject(new Error(data.toString()))
    })
  })
}

请注意,我使用 & 在后台执行命令。当 Jest 完成它的工作时,我注意到 ps 它的 PID 与 shell 中显示的不同。如果不在后台执行它,我会得到一个额外的进程,shell 的进程 (/bin/sh)。 我怎样才能获得该进程的真实 PID? 有没有最好的方法来终止在该函数内启动的进程? 谢谢!

您可以在服务器上创建启动和停止方法。这样你就不用担心分叉你的进程了。

我以快递为例。

app.js

const start = async (callback => { 
  await database.connect();
  server.listen(config.port, config.ip, () => {
    callback();
  });
};

const stop = (callback => {
  server.close(async () => {
    await database.disconnect();
    callback();
  });
};

app.test.js

const server = require('./path/to/server');

beforeAll(async () => {
  try {
    await server.start();
  } catch (error) {
    // if the server doesn't start up or the seeding fails, just
    // exit the process ASAP
    process.exit(1);  
  }
});

afterAll(done => {
  server.stop(done);
});

我目前的做法如下:

  • 将 Express bootstrap 进程包装在一个函数中,returns httpServer 实例用于使服务器侦听请求。这是 beforeAll 钩子的一个很好的例子。
  • afterAll.
  • 中使用之前的参考关闭服务器

另一种选择(有点棘手)可能是在所有测试开始时启动服务器一次并在结束时关闭它:

  • 直接生成节点进程而不是通过 npm
  • 将进程 ID 存储在临时 mongo 的集合中(但可以是任何东西)
  • 在拆解中,我检索了 PID,然后我就做 process.kill(PID, "SIGTERM")