chai-http使用promises没有status属性

时间:2016-09-22 23:53:29

标签: typescript mocha chai

我正在尝试使用带有promises的chai-http插件(使用q)。我正在为项目使用TypeScript。

/test/users.ts:

import "mocha";
import { Collection } from "mongodb";
import { Server } from "../app";
import { IUser } from "../interfaces/user";
import { IUserModel, User } from "../schemas/user";

//use q promises
global.Promise = require("q");

//import mongoose
import mongoose = require("mongoose");

//require http server
var http = require("http");

//require chai and use should assertions
let chai = require("chai");
let expect = chai.expect;
chai.should();

//configure chai-http
chai.use(require("chai-http"));

//create http server
var port = 8080;
var app = Server.bootstrap().app;
app.set("port", port);
var server = http.createServer(app);
server.listen(port);

//parent block
describe("UserApi", function() {
  const BASE_URI: string = "/api/users";
  const COLLECTION_NAME: string = "user";
  var id: string;

  before(function(done: MochaDone) {
    //empty database
    if (collectionExists(COLLECTION_NAME)) {
      User.remove({}).catch(function(result: any) {
        done(result);
      });
    }

    //create a user
    console.log("Creating a new user.");
    var data: IUser = {
      firstName: "Brian",
      lastName: "Love",
      email: "test@test.com"
    };
    new User(data).save().then(function(user: any) {
      User.findOne(data).then(function(user: IUserModel) {
        id = user.id;
        done();
      }).catch(function(result: any) {
        done(result);
      });
    }).catch(function(result: any) {
      done(result);
    });
  });

  describe("/GET user", function() {
    it("it should get a user", function() {
      return chai
        .request(server)
        .get(`${BASE_URI}/${id}`)
        .then(function(res: any) {
          //this does not work:
          expect(res).to.have.status(200);

          //this does not work either:
          //res.should.have.status(200);
        });
    });
  });
});

function collectionExists(collectionName: string) {
  return mongoose.connection.on("open", function() {
    return mongoose.connection.db.listCollections({name: collectionName}).toArray().then(function(items: Collection[]) {
      return (items.length > 0);
    });
  });
}

快速服务器在/app.ts中创建:

//import modules
import * as bodyParser from "body-parser";
import * as cookieParser from "cookie-parser";
import * as express from "express";
import * as http from "http";
import * as logger from "morgan";
import * as path from "path";
import * as expressSession from "express-session";
import * as url from "url";
import errorHandler = require("errorhandler");
import flash = require("connect-flash");
import methodOverride = require("method-override");
import passport = require("passport");

//import mongoose
import mongoose = require("mongoose");

//import config
import { ConfigurationFactory } from "./config/factory";
import { IConfiguration } from "./config/config";


/**
 * The server.
 *
 * @class Server
 */
export class Server {

  public app: express.Application;

  /**
   * Bootstrap the application.
   *
   * @class Server
   * @method bootstrap
   * @static
   * @return {ng.auto.IInjectorService} Returns the newly created injector for this app.
   */
  public static bootstrap(): Server {
    return new Server();
  }

  /**
   * Constructor.
   *
   * @class Server
   * @constructor
   */
  constructor() {
    //create expressjs application
    this.app = express();

    //configure application
    this.config();

    //add routes
    this.routes();

    //add api
    this.api();
  }

  public api() {
    //code ommitted
  }

  /**
   * Configure application
   *
   * @class Server
   * @method config
   * @return void
   */
  public config() {
    //get configuration
    let configuration: IConfiguration = ConfigurationFactory.config();
    console.log(`[Server.config] Environment: ${configuration.toString()}`);

    //configure jade
    this.app.set("views", path.join(__dirname, "views"));
    this.app.set("view engine", "jade");

    //mount logger
    this.app.use(logger("dev"));

    //mount json form parser
    this.app.use(bodyParser.json());

    //mount query string parser
    this.app.use(bodyParser.urlencoded({
      extended: true
    }));

    //mount cookie parker
    this.app.use(cookieParser());

    //mount override
    this.app.use(methodOverride());

    //add static paths
    this.app.use(express.static(path.join(__dirname, "public")));

    //connect to mongoose
    mongoose.connect(configuration.db.mongodb).catch(error => new Error(error.message));

    //use q library for mongoose promise
    mongoose.Promise = require("q").Promise;

    // catch 404 and forward to error handler
    this.app.use(function(err: any, req: express.Request, res: express.Response, next: express.NextFunction) {
        err.status = 404;
        next(err);
    });

    //error handling
    if (configuration.isDevelopment() || configuration.isTest()) {
      this.app.use(errorHandler());
    } else if (configuration.isProduction()) {
      this.app.use(function(err: any, req: express.Request, res: express.Response, next: express.NextFunction) {
        //set status
        var status: number = err.status || 500;
        res.status(status);

        //render error
        res.render("error", {
          message: err.message,
          error: err
        });
      });
    }
  }

  /**
   * Create and return Router.
   *
   * @class Server
   * @method config
   * @return void
   */
  private routes() {
    //code ommitted
  }
}

我试图同时使用expect和should断言样式,但是我得到一个错误,表明结果没有" status"属性。检查 res 表示确实没有status属性。我能够在.then()匿名函数中设置断点。以下是显示res变量的屏幕截图:Screenshot of VS Code debug

运行mocha测试的例外是:

  1) UserApi /GET user it should get a user:                                                                                                        
     AssertionError: expected [Function] to have a property 'status'                                                                                
    at Assertion.<anonymous> (node_modules/chai-http/lib/http.js:80:38)                                                                             
    at Assertion.ctx.(anonymous function) [as status] (node_modules/chai/lib/chai/utils/addMethod.js:41:25)                                         
    at dist/test/users.js:49:37                                                                                                                     
    at _fulfilled (node_modules/q/q.js:834:54)                                                                                                      
    at self.promiseDispatch.done (node_modules/q/q.js:863:30)                                                                                       
    at Promise.promise.promiseDispatch (node_modules/q/q.js:796:13)                                                                                 
    at node_modules/q/q.js:857:14                                                                                                                   
    at runSingle (node_modules/q/q.js:137:13)                                                                                                       
    at flush (node_modules/q/q.js:125:13)  

我更愿意使用承诺方法。我检查了DefinitelyTyped定义文件,并且应该调用then()方法,第一个参数是ChaiHttp.Response类型。响应对象应该有3个属性:

interface Response {
    body: any;
    type: string;
    status: number;
}

为什么我的&#34; res&#34;参数,应该是一个ChaiHttp.Response对象,不是吗?

1 个答案:

答案 0 :(得分:1)

我想出了这个问题。我在mongoose中使用q库来承诺,我没有正确设置它。在阅读了更多文档后,我意识到您需要引用.Promise静态属性。花了很长时间才发现这一点,所以我希望这有助于拯救某人同样的问题。

以下是在mongoose中正确使用q for promises的代码:

//use q promises
global.Promise = require("q").Promise;

//import mongoose
import mongoose = require("mongoose");

//use q library for mongoose promise
mongoose.Promise = global.Promise;