带有 supertest 的 nodejs,为不同的测试用例调用端点两次得到一个 Did you forget to wait for something async in your test?

nodejs with supertest, calling an endpoint twice for different test cases getting a Did you forget to wait for something async in your test?

我有一个端点,我在 2 个不同的描述上调用了两次以测试不同的响应

const express = require("express");
const router = express.Router();
const fs = require("fs");
const multer = require("multer");
const upload = multer({ dest: "files/" });
const csv = require("fast-csv");

let response = { message: "success" }
router.post("/post_file", upload.single("my_file"), (req, res) => {
    let output = get_output(req.file.path);
    fs.unlinkSync(req.file.path);

    if(output.errors.length > 0) response.message = "errors found";

    res.send(JSON.stringify(response))
})


const get_output = (path) => {

  let errors = []
  let fs_stream = fs.createReadStream(path);
  let csv_stream = csv.parse().on("data", obj => {
                   if(!is_valid(obj)) errors.push(obj);
            });
  

  fs_stream.pipe(csv_stream);

  return {errors};
}

const is_valid = (row) => {
   console.log("validate row")
   
   // i validate here and return a bool
}

我的单元测试

const app = require("../server");
const supertest = require("supertest");
const req = supertest(app);

describe("parent describe", () => {

  describe("first call", () => {   
      const file = "my path to file"

      // this call succeeds
    it("should succeed", async (done) => {
      let res = await req
        .post("/post_file")
        .attach("my_file", file);
     
      expect(JSON.parse(res.text).message).toBe("success")
      done();
     });
   })

    describe("second call", () => {   
      const file = "a different file"

    // this is where the error starts
    it("should succeed", async (done) => {
      let res = await req
        .post("/post_file")
        .attach("my_file", file);
     
      expect(JSON.parse(res.text).message).toBe("errors found")
      done();
     });
   })
})

// csv file is this

NAME,ADDRESS,EMAIL
Steve Smith,35 Pollock St,ssmith@emailtest.com

我得到以下内容

测试完成后无法登录。你忘了在你的测试中等待一些异步的东西吗? 试图记录“验证行”。

问题是被测试的路由没有正确实现,它异步工作但不等待 get_output 结束并同步响应错误响应。测试仅显示 console.log 在测试结束后被异步调用。

一致使用承诺是保证正确执行顺序的可靠方法。流需要被 promified 链接:

router.post("/post_file", upload.single("my_file"), async (req, res, next) => {
  try {
    let output = await get_output(req.file.path);
    ...
    res.send(JSON.stringify(response))
  } catch (err) {
    next(err)
  }
})    

const get_output = (path) => {
  let errors = []
  let fs_stream = fs.createReadStream(path);
  return new Promise((resolve, reject) => {
    let csv_stream = csv.parse()
    .on("data", obj => {...})
    .on("error", reject)
    .on("end", () => resolve({errors}))
  });
}

asyncdone 不应在测试中混用,因为它们服务于相同的目标,如果 done 无法访问,这可能会导致测试超时:

it("should succeed", async () => {
  let res = await req
    .post("/post_file")
    .attach("my_file", file);
 
  expect(JSON.parse(res.text).message).toBe("success")
});