Интеграционное тестирование Nodejs / Express / Mongoose с Jest / Supertest Одна модель Mongoose экономит, одна модель Mongoose - нет - PullRequest
0 голосов
/ 25 июня 2019

Я использую Postman и пользовательский интерфейс ReactJS для вызова этой регистрации, и она работает, как я ожидаю. По иронии судьбы интеграционные тесты Jest и Supertest не дают ожидаемых результатов. При интеграционном тестировании Профиль создается, а Пользователь - нет.

Архитектура довольно проста. MongoDB в контейнере Docker и Node, использующий nodemon в VSCode.

Я должен делать что-то не так, я просто не могу определить, что это такое.


// 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;
}

Когда я вызываю этот код с помощью пользовательского интерфейса, почтальона или скручивания, создается пользователь и профиль, как и ожидалось.

Когда я запускаю интеграционный тест, запускается npm-тест: интеграция или npm-тест, Только профиль создан.

мои сценарии package.json: «тест»: «шутка», "тест: интеграция": "jest --testPathPattern интеграции.test",

Наконец, нигде не сообщается об ошибках. Пользователь просто не создан.

1 Ответ

0 голосов
/ 25 июня 2019

После нескольких часов работы и тестирования этой проблемы я обнаружил, что событие afterAll () вызывалось случайным образом.Иногда после всех тестов во внутреннем описании () выполнялся, а иногда нет.Конечно, когда afterAll () запускает всех пользователей, которые были удалены из хранилища данных.

Если перемещены beforeAll () и AfterAll () во внутреннюю описание ().Это работало очень хорошо, пока я не включил другие интеграционные тесты, такие как авторизация, например, которые также использовали таблицу User.Я заметил, что тестовые наборы не выполняются синхронно.Поскольку один набор тестов вытеснял данные из другого набора тестов, в то время как выполнялся другой набор тестов.

Теперь я настроил базу данных для набора тестов.Я знаю, неуклюжий, вонючий, хакерский и неправильный, но мне нужно двигаться дальше.Кто-нибудь знает, можете ли вы контролировать синхронное и / или асинхронное поведение Jest?Пожалуйста, не предлагайте мокко и / или чай.

...