Jest 内存泄漏测试 Express 中间件

5 unit-testing node.js express supertest jestjs

我正在尝试对 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;
Run Code Online (Sandbox Code Playgroud)

由于 Firebase Admin SDK 返回一个包含用户 UID 作为属性的对象,因此为了我的测试目的,我创建了一个“假令牌”,它只是一个具有 UID 属性的对象。然后我模拟 Admin SDK,使其返回传入的任何内容,如下所示:

module.exports = {
    auth() {
        return this;
    },
    verifyIdToken(token) {
        return JSON.parse(token);
    },
    initializeApp(app) {
    },
    credential: {
        cert() {

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

由于 auth 中间件希望在 test 数据库中找到一个用户,我必须在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());
});
Run Code Online (Sandbox Code Playgroud)

这意味着中间件总是能够得到一个 UID 作为回报,它可以用来在测试数据库中找到一个测试用户。

导入我的 Express 应用程序后,测试套件本身非常简单,只有三个测试:

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);   
    });
});
Run Code Online (Sandbox Code Playgroud)

然而,似乎测试正在泄漏内存(显然通过使用--detectLeaks标志调用)。此外,似乎 Jest 还发现了上次测试留下的开放句柄。运行带有--detectOpenHandles标志的套件会根据上次测试TCPSERVERWRAPget请求返回错误。

在这个 GitHub 问题中提出潜在的解决方案,但没有一个对我有用。

任何解决此问题的帮助将不胜感激,因为我所有的测试套件都在泄漏内存,因为它们依赖于 Supertest。谢谢你。