【问题标题】:Integration Testing Nodejs/Express/Mongoose with Jest/Supertest One Mongoose Model Saves, One Mongoose Model Doesn't集成测试 Nodejs/Express/Mongoose 与 Jest/Supertest 一个 Mongoose 模型保存,一个 Mongoose 模型不保存
【发布时间】:2021-07-21 04:39:05
【问题描述】:

我使用 Postman 和 ReactJS UI 来调用这个注册执行,它按我的预期工作。具有讽刺意味的是,Jest 和 Supertest 集成测试并没有产生预期的结果。集成测试时,会创建 Profile 而不会创建 User。

架构非常简单。 Docker 容器中的 MongoDB,以及 VSCode 中使用 nodemon 的 Node。

我一定是做错了什么,我就是看不出是什么。


// The Integration Test __test__/users/../user.test.js

const app = require('../../app');
const uuidv4 = require('uuid/v4');
const User = require('../../src/models/User');
const Profile = require('../../src/models/Profile');
const bcrypt = require('bcryptjs');
const mongoose = require('mongoose');
const request = require("supertest");

const {
    MONGO_URI,
    TEST_DB_NAME
} = process.env;
let DB_URI = MONGO_URI + TEST_DB_NAME;
let NAME = TEST_DB_NAME;

mongoose.connect(DB_URI, {
    useNewUrlParser: true,
    useCreateIndex: true,
    dbName: NAME
});

describe('User Integration Test', () => {
    // make sure app is imported without issues
    it('Has App Defined', () => {
        expect(app).toBeDefined();
    });

    let server;

    beforeAll(async () => {
        // Clear Test Data
        await User.deleteMany({});
        await Profile.deleteMany({});
        server = await app.listen(3001);
    });

    afterAll(async (done) => {
        // Clear Test Data
        await User.deleteMany({});
        await Profile.deleteMany({});
        // Close server
        await server.close(done);
    });

    describe('User route tests', () => {

        it('Can Register a User', async () => {
            const body = {
                "username": "User21",
                "email": "user21@user.com",
                "password": "123456",
                "avatar": "image.jpg"
            }
            await request(server)
                .post('/api/v1/users')
                .send(body)
                .set('Accept', 'application/json')
                .set('Content-Type', 'application/json')
                .expect(200)
        });

});

// THE EXPRESS ROUTE in api/v1/users.js

const express = require('express');
const auth = require('../../middleware/auth');
const router = express.Router();
const { UserService } = require('../../services');
const {
    check,
    validationResult
} = require('express-validator/check');

// @route   POST api/users
// @desc    Register User
// @access  Public
// @return  status message
router.post('/', [
    check('email', 'Please provide a valid email address').isEmail(),
    check('password', 'Please enter a password with 6 or more characters').isLength({ min: 6 }),
    check('username', 'Username is Required.').not().isEmpty()
], async (req, res, next) => {
    try {
        //--Validate
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
            return res.status(400).json({
                errors: errors.array()
            });
        }

        const message = await UserService.register(req.body);
        return res.status(200).json(message)

    } catch (err) {
        next(err);
    }
});

// THE register METHOD found in ../../services/UserService.js

const register = async (data) => {
    try {

        // Destructure the data
        const {
            username,
            email,
            password,
            avatar
        } = data;

        // remove spaces from username and lcase it
        let user_name = username.replace(/\s/g, '').toLowerCase();
        // Check if the username or email already exists
        await doesUserExist(user_name, email);
        // Create a new user 
        const token = uuidv4();
        user = new User({
            email: email.toLowerCase(),
            username: user_name,
            avatar: avatar,
            verifyEmailToken: token
        });

        // encrypt the password
        const salt = await bcrypt.genSalt(10);
        user.password = await bcrypt.hash(password, salt);
        // Save the user
        // (Works Unless Running Jest Integration Tests)
        await user.save(); 

        // Create and save an empty Profile for the new user
        profile = new Profile();
        profile.user = user;
        // (Always Works)
        await profile.save();

        // Send verification email
        await send(user, 'Verify Your Email', token, 'verify-email.html');

        return { message: 'User was registered successfully.' };


    } catch (err) {
        throw err;
    }
}

// Does user exist method found in ./UserService.js
const doesUserExist = async (username, email) => {

    // Check if user exists by email
    let message = await checkEmail(email);
    if (!message.email_available) {
        throw new Error('Email already exists');
    }
    // Check if user exists by username
    message = await checkUserName(username.toLowerCase())
    if (!message.username_available) {
        throw new Error('Username already exists');
    }
    return false;
}

当我通过 UI、Postman 或 curl 调用此代码时,用户和配置文件都会按预期创建。

当我运行集成测试时,npm run test:integration 或 npm test, 仅创建配置文件。

我的 package.json 脚本: “测试”:“开玩笑”, "test:integration": "jest --testPathPattern integration.test",

最后,任何地方都没有报告错误。根本没有创建用户。

【问题讨论】:

    标签: mongodb express jestjs mongoose-schema supertest


    【解决方案1】:

    经过几个小时的工作和测试这个问题,我发现 afterAll() 事件是随机引发的。有时在内部 describe() 中的所有测试运行之后,有时没有。当然,当 afterAll() 运行从数据存储中删除的所有用户时。

    如果将 beforeAll() 和 AfterAll() 移动到内部 describe()。这工作得很好,直到我包含其他集成测试,例如授权,例如也使用 User 表。我注意到测试套件没有同步执行。当另一个测试套件正在执行时,一个测试套件正在破坏另一个测试套件中的数据。

    我现在为每个测试套件设置一个数据库。我知道笨重、不可靠、笨拙和错误,但我必须继续前进。有谁知道您是否可以控制 Jest 的同步和/或异步行为?请不要推荐 Mocha 和/或 Chai。

    【讨论】:

      【解决方案2】:

      我遇到了类似的问题,在播种文档和检索文档之间似乎存在间歇性竞争条件。

      我通过使用 --runInBand 标志运行 jest 来修复它。

      【讨论】:

        猜你喜欢
        • 2018-08-07
        • 2018-05-31
        • 2020-01-31
        • 2015-11-13
        • 2019-06-23
        • 2015-09-29
        • 1970-01-01
        • 2018-10-25
        • 1970-01-01
        相关资源
        最近更新 更多