node mongoose mocha:如何在我的测试中处理 Promise.reject

Posted

技术标签:

【中文标题】node mongoose mocha:如何在我的测试中处理 Promise.reject【英文标题】:node mongoose mocha : how to handle a Promise.reject in my test 【发布时间】:2017-10-28 18:03:45 【问题描述】:

目前我的身份验证如下:

function login(req, res, next) 
  // fetch user from the db
  User.findOne(req.body)
    .exec()   // make query a Promise
    .then((user) => 
      const token = jwt.sign( username: user.username , config.jwtSecret);
      return res.json( token, username: user.username );
    )
    .catch(() => 
      const err = new APIError('Authentication error', httpStatus.UNAUTHORIZED, true);
      return Promise.reject(err);
    );

我正在尝试使用通用 APIError 类来标准化我的错误

import httpStatus from 'http-status';

/**
 * @extends Error
 */
class ExtendableError extends Error 
  constructor(message, status, isPublic) 
    super(message);
    this.name = this.constructor.name;
    this.message = message;
    this.status = status;
    this.isPublic = isPublic;
    this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
    Error.captureStackTrace(this, this.constructor.name);
  


/**
 * Class representing an API error.
 * @extends ExtendableError
 */
class APIError extends ExtendableError 
  /**
   * Creates an API error.
   * @param string message - Error message.
   * @param number status - HTTP status code of error.
   * @param boolean isPublic - Whether the message should be visible to user or not.
   */
  constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) 
    super(message, status, isPublic);
  


export default APIError;

如何在我的测试中测试 Promise.reject ?

describe('# POST /api/v1/auth/login', () => 
it('should return Authentication error', () => 
  return request(app)
    .post('/api/v1/auth/login')
    .send(invalidUserCredentials)
     // following lines are not valid anymore with Promise.reject ..
    .expect(httpStatus.UNAUTHORIZED)
    .then((res) => 
      expect(res.body.message).to.equal('Authentication error');
    );
);

【问题讨论】:

【参考方案1】:

您根本没有处理错误/拒绝。您需要将错误发送回。我建议在你的路由末尾添加一个错误处理中间件,然后使用next(err) 传递给它。

// at the end of your routes
app.use(function(err, req, res, next) 
  // do whatever you want, but at least send status and message:
    res.status(err.status).json(
        message: err.message,
    );
);

现在通过以下方式处理您的路线中的错误:

.catch(() => 
  const err = new APIError('Authentication error', httpStatus.UNAUTHORIZED, true);
  return next(err);
);

【讨论】:

非常感谢 Johannes 的反馈 .. 你让我走上正轨 .. 事实上,我在我的 express.js 文件中处理了错误.. 但是我发现 APIError 设置不是对 ... const err = new APIError('Authentication error', httpStatus.UNAUTHORIZED, true); console.log('CTLR err instanceof APIError ?: ', (err instanceof APIError));返回下一个(错误); err 未设置为 APIError 类实例...将检查原因... 现在已经解决了...感谢 Johannes.. 我现在在我的 express.js error_handler 中正确处理了错误.. 需要检查使用了错误包!应该是 es6-error,否则 Babel 没有正确处理 instanceOf()【参考方案2】:

现在运行良好,我在 express.js 错误处理中遇到了问题。因为 APIError 类型检查总是错误的...扩展 es6-error 包而不是 Error 解决了这个 Babel 问题...

APIError.js

import ExtendableError from 'es6-error';  // solve Babel issue w isInstanceOf()
import httpStatus from 'http-status'

class MyExtendableError extends ExtendableError 
  constructor(message, status, isPublic) 
    super(message);
    this.name = this.constructor.name;
    this.message = message;
    this.status = status;
    this.isPublic = isPublic;
    this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
    Error.captureStackTrace(this, this.constructor.name);
  


/**
 * Class representing an API error.
 * @extends MyExtendableError
 */
class APIError extends MyExtendableError 
  constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) 
    super(message, status, isPublic);
  


export default APIError;

Express.js

// catch 404 and forward to error handler
/* istanbul ignore next  */
app.use((req, res, next) => 
  const err = new APIError('API not found', httpStatus.NOT_FOUND);
  return next(err);
);

// if error is not an instance Of APIError, convert it.
app.use((err, req, res, next) => 
  if (err instanceof expressValidation.ValidationError) 
    // validation error contains errors which is an array of error each containing message[]
    const unifiedErrorMessage = err.errors.map((error) => 
      return error.messages.join('. ');
    ).join(' and ');
    const error = new APIError(unifiedErrorMessage, err.status, true);
    res.status(error.status).json(
      message: err.isPublic ? err.message : httpStatus[err.status],
      stack: (config.env === 'test' || config.env === 'development' ) ? err.stack : 
    );
   else if (!(err instanceof APIError)) 
    const apiError = new APIError(err.message, err.status, err.isPublic);
    res.status(apiError.status).json(
      message: err.isPublic ? err.message : httpStatus[err.status],
      stack: (config.env === 'test' || config.env === 'development' ) ? err.stack : 
    );
  else 
    res.status(err.status).json(
    message: err.isPublic ? err.message : httpStatus[err.status],
    stack: (config.env === 'test' || config.env === 'development' ) ? err.stack : 
   );
  
);

auth.route.js

import express from 'express';
import validate from 'express-validation';
import expressJwt from 'express-jwt';
import paramValidation from '../../../config/param-validation';
import authCtrl from '../controllers/auth.controller';
import config from '../../../config/config';

const router = express.Router();

/** POST /api/auth/login - Returns token if correct username and password is provided */
router.route('/login')
  .post(validate(paramValidation.login), authCtrl.login);

auth.controller.js

function login(req, res, next) 
  // fetch user from the db
  User.findOne(req.body)
    .exec()   // make query a Promise
    .then((user) => 
      const token = jwt.sign( username: user.username , config.jwtSecret);
      return res.json( token, username: user.username );
    )
    .catch(() => 
      const err = new APIError('Authentication error', httpStatus.UNAUTHORIZED, true);
      return next(err);
    );

auth.test.js

..
    it('should return Authentication error', () => 
      return request(app)
        .post('/api/v1/auth/login')
        .send(invalidUserCredentials)
        .expect(httpStatus.UNAUTHORIZED)
        .then((res) => 
          expect(res.body.message).to.equal('Authentication error');
        );
    );
...

【讨论】:

以上是关于node mongoose mocha:如何在我的测试中处理 Promise.reject的主要内容,如果未能解决你的问题,请参考以下文章

在我的 node.js 应用程序中使用 mongodb 和 mongoose 在 Mocha 和 Chai 上运行测试后无法清除数据库

如何使用 Node、Mocha 获取代码覆盖率信息

如何在 mocha 单元测试中使用猫鼬?

为 Mongoose 运行多个 Mocha 测试文件已损坏

如何使用 mongoose、mocha 和 chai 编写用于向 mongodb 插入和检索对象的单元测试?

“未检测到侦听器”验证错误 Mongoose 和 Mocha