带有 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}))
});
}
async
和 done
不应在测试中混用,因为它们服务于相同的目标,如果 done
无法访问,这可能会导致测试超时:
it("should succeed", async () => {
let res = await req
.post("/post_file")
.attach("my_file", file);
expect(JSON.parse(res.text).message).toBe("success")
});
我有一个端点,我在 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}))
});
}
async
和 done
不应在测试中混用,因为它们服务于相同的目标,如果 done
无法访问,这可能会导致测试超时:
it("should succeed", async () => {
let res = await req
.post("/post_file")
.attach("my_file", file);
expect(JSON.parse(res.text).message).toBe("success")
});