【发布时间】:2020-05-17 13:35:17
【问题描述】:
我正在使用 Node.js 和 express 构建一个 Restfull API,并决定使用 Jest 和 Supertest 测试我的应用程序,在我的 App 类中,我需要一些 i18n 配置(i18n 是用于翻译的库)。
当运行常规快递服务器并使用 Insomnia 或 Postman 手动测试我的路线时,一切正常。但是当我尝试为 /login 路由创建测试时,测试运行良好并且我得到了预期的结果,但 Jest 从未完成运行,它显示 Jest has detected the following 1 open handle potentially keeping Jest from exiting。从它所指出的来看,似乎是对 i18n.configure(... 的调用留下了一个打开的句柄,这很有趣,我检查了 configure 方法,它不是异步的。
这是我的 App.js 文件:
require("dotenv").config({
path: process.env.NODE_ENV === "test" ? ".env.test" : ".env"
});
const express = require("express");
const cookieParser = require("cookie-parser");
class AppController {
constructor() {
this.express = express();
this.configure();
this.middlewares();
this.routes();
}
async configure() {
this.i18n = require("./config/i18n");
}
middlewares() {
this.express.use(express.json());
this.express.use(cookieParser());
this.express.use(this.i18n.init);
}
routes() {
this.express.use(require("./routes"));
}
}
module.exports = new AppController().express;
i18n 配置文件:
const i18n = require("i18n");
i18n.configure({
locales: ["pt-br", "en-us"],
defaultLocale: "pt-br",
cookie: "locale",
directory: "./locales",
autoReload: true
});
i18n.setLocale("pt-br");
module.exports = i18n;
测试本身:
const request = require("supertest");
const app = require("../../src/app.js");
describe("Authentication", () => {
it("should not authenticate when user does not exist", async () => {
const response = await request(app)
.post("/login")
.send({
username: "john",
password: "123123"
});
expect(response.status).toBe(401);
});
});
/login 路由(它在登录文件夹中,这就是为什么我可以只为路由声明“/”):
const routes = require("express").Router();
const LoginController = require("../app/controllers/LoginController");
routes.post("/", LoginController.index);
module.exports = routes;
具有索引功能的LoginController:
const passport = require("../../app/middlewares/passport");
const jwt = require("jsonwebtoken");
class LoginController {
async index(req, res) {
passport.authenticate("local", { session: false }, (error, user) => {
if (error || !user) {
res.status(401).send(res.__(error));
} else {
const payload = {
username: user.username,
expires: Date.now() + parseInt(process.env.JWT_EXPIRATION_MS)
};
req.login(payload, { session: false }, error => {
if (error) {
res.status(400).send({ error });
}
const token = jwt.sign(
JSON.stringify(payload),
process.env.APP_SECRET
);
res.cookie("jwt", token, { httpOnly: true, secure: true });
res.status(200).send({ username: user.username });
});
}
})(req, res);
}
}
module.exports = new LoginController();
以防万一,这里是护照策略:
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const passportJWT = require("passport-jwt");
const JWTStrategy = passportJWT.Strategy;
const { User } = require("../models");
passport.use(
new LocalStrategy(async (username, password, done) => {
try {
const user = await User.findOne({ where: { username } });
let passwordsMatch = false;
if (user) {
passwordsMatch = await user.checkPassword(password);
}
if (passwordsMatch) {
return done(null, user);
} else {
return done("Incorrect username and/or password");
}
} catch (error) {
done(error);
}
})
);
passport.use(
new JWTStrategy(
{
jwtFromRequest: req => req.headers.authorization.split(" ")[1],
secretOrKey: process.env.APP_SECRET
},
(jwtPayload, done) => {
if (Date.now() > jwtPayload.expires) {
return done("jwt expired");
}
return done(null, jwtPayload);
}
)
);
module.exports = passport;
【问题讨论】:
标签: node.js express jestjs supertest