在Jest拆卸中杀死Node.js服务器(在Jest的安装挂钩中启动)

时间:2019-03-21 18:50:32

标签: node.js child-process

我将Jest用作测试库,并在其setup hook(在我所有测试之前执行)内部,我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与外壳程序中显示的PID不同。没有在后台执行它,我得到了一个额外的过程,即外壳程序(/bin/sh)。 如何获得该过程的真实PID? 是否有消除该功能内部启动进程的最佳方法? 谢谢!

2 个答案:

答案 0 :(得分:0)

您可以在服务器上创建启动和停止方法。然后,您无需担心分支过程。

我以快递为例。

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

app.test.js

import UIKit

class ViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

            let text = "random text <a href='http://www.google.com'>http://www.google.com </a> more random text"

            let storage = NSTextStorage()
            let layout = UnderlineLayout()
            storage.addLayoutManager(layout)
            let container = NSTextContainer()
            layout.addTextContainer(container)

            let textView = UITextView(frame: CGRect(x: 30, y: 380, width: 300, height: 200), textContainer: container)
            textView.isUserInteractionEnabled = true
            textView.isEditable = false
            textView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            textView.attributedText = htmlStyleAttributeText(text: text)
            textView.backgroundColor = UIColor.white
            textView.textColor = UIColor.black

            let underLineColor: UIColor = UIColor(red: 245/255, green: 190/255, blue: 166/255, alpha: 1)


            let attributes = [NSAttributedString.Key.underlineStyle.rawValue: 0x15,
                              NSAttributedString.Key.underlineColor: underLineColor,
                              NSAttributedString.Key.font: UIFont.systemFont(ofSize: 25),
                              NSAttributedString.Key.baselineOffset:0] as! [NSAttributedString.Key : Any]

            let rg = NSRange(location: 0, length: textView.attributedText!.string.count)

            storage.addAttributes(attributes, range: rg)
            view.addSubview(textView)
        }

        public func htmlStyleAttributeText(text: String) -> NSMutableAttributedString? {

            if let htmlData = text.data(using: .utf8) {

                let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html, NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue]
                let attributedString = try? NSMutableAttributedString(data: htmlData, options: options, documentAttributes: nil)

                return attributedString
            }
            return nil
        }
}


import UIKit

class UnderlineLayout: NSLayoutManager {
    override func drawUnderline(forGlyphRange glyphRange: NSRange, underlineType underlineVal: NSUnderlineStyle, baselineOffset: CGFloat, lineFragmentRect lineRect: CGRect, lineFragmentGlyphRange lineGlyphRange: NSRange, containerOrigin: CGPoint) {
        if let container = textContainer(forGlyphAt: glyphRange.location, effectiveRange: nil) {
            let boundingRect = self.boundingRect(forGlyphRange: glyphRange, in: container)
            let offsetRect = boundingRect.offsetBy(dx: containerOrigin.x, dy: containerOrigin.y)

            let left = offsetRect.minX
            let bottom = offsetRect.maxY
            let width = offsetRect.width
            let path = UIBezierPath()
            path.lineWidth = 4
            path.move(to: CGPoint(x: left, y: bottom))
            path.addLine(to: CGPoint(x: left + width, y: bottom))
            path.stroke()
        }
    }
}

答案 1 :(得分:0)

@VtoCorleone的答案可能很好,如果您只进行了一系列与服务器相关的测试,但是如果您拥有良好的代码库,则最好在测试开始时仅启动一次服务器。我最终这样做:

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