Превышен тайм-аут бросков Мокко, но Mongoose сохраняет данные в БД в цепочке Promise? - PullRequest
0 голосов
/ 29 августа 2018

Я использую Mocha, Mongoose и MongoDB.

Моя цель - просто запустить тест по созданию учетной записи. У меня есть следующий код:

require( "./../../config/config" );
var mongoose = require( "mongoose" );
mongoose.connect( process.env.MONGODB_URI );

const expect = require( "expect" );
var { Account } = require( "./../../models/account" );

describe( "Account Creation", () =>
{
    it( "should successfully create an account", ( done ) =>
    {
        var data =
        {
            username: "PrestonJ",
            email: "someEmail@mail.com",
            password: "somePassword123!"
        };

        var account = new Account( data );
        account.save().then( ( result ) =>
        {
            console.log( "(temporary log)  account saved" );
            done();
        }).catch( ( e ) => done( e ) );
    });
});

Цепочка обещаний Mongoose выполняет и сохраняет новую учетную запись в базе данных, но done() никогда не достигается (даже если она записана, и вызов консоли над ней работает).

Это приводит к сбою теста Mocha, давая мне: Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

Я пытался просто return цепочка Обещаний, но это тоже не работает. Я также попытался удалить done вместе с возвратом цепи, но безрезультатно.

Прошло несколько часов, и я не смог найти правильные практики / исправления.

Edit: Я пытался увеличить время ожидания для мокко. Ошибка как-то проглочена? Это что-то в моем файле модели?

Редактировать 2: Вот источник для модели аккаунта:

var mongoose = require( "mongoose" );

const _ = require( "lodash" );
const validator = require( "validator" );
const jwt = require( "jsonwebtoken" );
const bcrypt = require( "bcryptjs" );

let Account_CollectionName = "accounts";
var Account_Schema = new mongoose.Schema(
{
    username:
    {
        type: String,
        minLength: 3,
        trim: true,
        required: true,
        unique: true
    },
    email:
    {
        type: String,
        minlength: 1,
        trim: true,
        required: false,
        unique: true,
        sparse: true,
        validate: validator.isEmail,
        message: "{VALUE} is not a valid email"
    },
    password:
    {
        type: String,
        required: true,
        minLength: 5
    },
    tokens:
    [{
        access:
        {
            type: String,
            required: true
        },
        token:
        {
            type: String,
            required: true
        }
    }],
},
{
    collection: Account_CollectionName
});

Account_Schema.pre( "save", function( next )
{
    var account = this;

    if( account.isModified( "password" ) )
    {
        bcrypt.genSalt( 10, ( err, salt ) =>
        {
            bcrypt.hash( account.password, salt, ( err, hash ) =>
            {
                account.password = hash;
                next();
            });
        });
    }
    else
        next();
});

Account_Schema.methods.toJSON = function()
{
    var account = this;
    var accountObject = account.toObject();

    return _.pick( accountObject,
        [
            "_id", "username", "email"
        ] );
};

Account_Schema.methods.generateAuthToken = function()
{
    var account = this;
    var access = "auth";
    var token = jwt.sign( { _id: account._id.toHexString(), access }, process.env.JWT_SECRET ).toString();

    account.tokens = account.tokens.concat( [{ access, token }] );

    return account.save().then( () =>
    {
        return token;
    });
};

Account_Schema.statics.findByToken = function( token )
{
    var Account = this;
    var decoded;

    try {
        decoded = jwt.verify( token, process.env.JWT_SECRET );
    }
    catch( e )
    {
        return Promise.reject();
    }

    return Account.findOne(
    {
        "_id" : decoded._id,
        "tokens.token": token,
        "tokens.access": "auth"
    });
};

Account_Schema.statics.findByCredentials = function( username, password )
{
    var Account = this;

    return Account.findOne( { username } ).then( ( account ) =>
    {
        if( ! account )
            return Promise.reject();

        return new Promise( ( resolve, reject ) =>
        {
            bcrypt.compare( password, account.password, ( err, res ) =>
            {
                if( res )
                    resolve( account );
                else
                    reject();
            });
        });
    });
};

Account_Schema.methods.removeToken = function( token )
{
    var account = this;

    return account.update(
    {
        $pull:
        {
            tokens: { token }
        }
    });
};

var Account = mongoose.model( Account_CollectionName, Account_Schema );

module.exports = { Account };

Ответы [ 2 ]

0 голосов
/ 30 августа 2018

Я понял это. Ряд вещей должен был быть сделан; Вот фиксированный источник для блока it:

it( "should successfully create an account", () =>
{
    var data =
    {
        username: "PrestonJ",
        email: "someEmail@mail.com",
        password: "somePassword123!"
    };

    let account = new Account( data );
    return account.save().then( ( result ) =>
    {
        if( result )
        {
            console.log( "Successful!" );
            return Promise.resolve();
        }
        else
            return Promise.reject( "cannot save" );
    }).catch( ( e ) =>
    {
        return Promise.reject( e );
    });
});
  1. Удалить все следы done / done()
  2. return account.save().then(...)...
  3. В then() используйте return Promise.resolve() вместо done()
  4. В catch() используйте return Promise.reject(e) вместо done(e)
0 голосов
/ 29 августа 2018

Вы получаете эту ошибку, потому что mocha ждал период времени 200 мс до завершения действия сохранения, а поскольку это действие заняло более 200 мс, ваш тест не пройден.

Лучший способ справиться с такой проблемой - узнать максимальное количество времени, которое ваше приложение потратит на ответ, и установить это время как тайм-аут.

Вы можете установить время ожидания для тестов мокко, просто добавив флаг timeout

Вы можете указать это в файле mocha.opts как

    --timeout 50000

Это заставит ваши тестовые случаи подождать 50 секунд, прежде чем истечет время ожидания для любой операции.

...