我正在尝试对Express的身份验证中间件进行单元测试。中间件非常简单,可以在下面完整查看:
const admin = require('./../config/firebase/firebase');
// Models - User
const User = require('./../models/user');
const auth = async (req, res, next) => {
try {
// The Authorization Bearer Token sent in the header of the request needs to be decoded.
const token = req.header('Authorization').replace('Bearer ', '');
const decoded = await admin.auth().verifyIdToken(token);
// Finding that user in the database by their Firebase UID.
const user = await User.findOne({ _id: decoded.uid });
// If that user does not exist, we'll throw an error.
if (!user) {
throw new Error();
}
// Making the user accessible to the endpoint.
req.user = user;
// Proceed
next();
} catch (e) {
// HTTP 404 Unauthorized Response Status
res.status(401).send({ error: 'Please authenticate.' });
}
}
module.exports = auth;
由于Firebase Admin SDK返回一个包含用户UID作为属性的对象,出于测试目的,我创建了一个“伪令牌”,它只是一个具有UID属性的对象。然后,我对Admin SDK进行了模拟,以便它返回传入的内容,如下所示:
module.exports = {
auth() {
return this;
},
verifyIdToken(token) {
return JSON.parse(token);
},
initializeApp(app) {
},
credential: {
cert() {
}
}
}
由于auth中间件希望在测试数据库中找到用户,因此我必须在beforeAll
钩子中将其配置为Jest Setup:
const userOneToken = JSON.stringify({ uid: 'example UID' });
const userOne = {
_id: 'example UID',
// ...
};
beforeAll(async () => {
await User.deleteMany();
await User.save(userOne);
app.use(auth).get('/', (req, res) => res.send());
});
这意味着中间件将始终能够获得UID作为回报,该UID可用于在测试数据库中查找测试用户。
导入我的Express Application之后,测试套件本身非常简单,只需进行三个测试:
const auth = require('./../../src/middleware/auth');
describe('Express Auth Middleware', () => {
test('Should return 401 with an invalid token', async () => {
await request(app)
.get('/')
.set('Authorization', 'Bearer 123')
.send()
.expect(401);
});
test('Should return 401 without an Authorization Header', async () => {
await request(app)
.get('/')
.send()
.expect(401);
});
test('Should return 200 with a valid token', async () => {
await request(app)
.get('/')
.set('Authorization', `Bearer ${userOneToken}`)
.send()
.expect(200);
});
});
但是,似乎测试正在泄漏内存(显然是通过使用--detectLeaks
标志进行调用)。此外,看来Jest还在寻找上次测试遗留下来的打开手柄。使用--detectOpenHandles
标志运行套件会在上次测试的TCPSERVERWRAP
请求中返回get
错误。
提出了可能的解决方案in this GitHub issue,但没有一个对我有用。
任何帮助解决此问题的方法将不胜感激,因为我的所有测试套件都依赖于Supertest来泄漏内存。谢谢。