使用ts-node进行测试时,TypeScript Express Api类不是构造函数

时间:2017-11-08 00:16:06

标签: node.js typescript express mocha ts-node

我已经使用typescript类设置了一个快速应用程序,并遇到了一个奇怪的问题。所有的测试都已经过去了,今天当我去更新一些路线时,我的测试不再运行了。当我运行我的测试脚本时,我在控制台中收到此错误消息:

$ mocha -c --reporter spec --compilers ts:ts-node/register ./test/*.test.ts --
timeout 20000

/Users/christiantodd/Development/projects/bby-react-api/src/index.ts:8
const app: Api = new Api();
             ^
TypeError: Api_1.default is not a constructor
at Object.<anonymous> (/Users/christiantodd/Development/projects/bby-react-api/src/index.ts:8:18)
at Module._compile (module.js:635:30)
at Module.m._compile (/Users/christiantodd/Development/projects/bby-react-api/node_modules/ts-node/src/index.ts:392:23)
at Module._extensions..js (module.js:646:10)
at Object.require.extensions.(anonymous function) [as .ts] (/Users/christiantodd/Development/projects/bby-react-api/node_modules/ts-node/src/index.ts:395:12)

我的Api.ts文件如下所示:

import * as bodyParser from 'body-parser';
import * as express from 'express';
import * as expressValidator from 'express-validator';
import * as helmet from 'helmet';
import * as morgan from 'morgan';
import * as passport from 'passport';
import * as compression from 'compression';

/* import all routers */
import BestBuyRouter from './routes/BestBuyRouter';
import UserRouter from './routes/UserRouter';

export default class Api {
  /* reference to the express instance */
  public express: express.Application;

  /* create the express instance and attach app level middleware and routes */
  constructor() {
    this.express = express();
    this.middleware();
    this.routes();
  }

  /* get current environment */
  public currentEnv(): string {
    return this.express.get('env');
  }

  /* apply middleware */
  private middleware(): void {
    this.express.use((req, res, next) => {
      /* Don't allow caching. Needed for IE support :/ */
      res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
      res.header('Pragma', 'no-cache');
      res.header('Access-Control-Allow-Origin', '*');
      res.header(
        'Access-Control-Allow-Methods',
        'PUT, GET, POST, DELETE, OPTIONS'
      );
      res.header(
        'Access-Control-Allow-Headers',
        'Origin, X-Requested-With, Content-Type, Accept, Authorization, Access-Control-Allow-Credentials'
      );
      res.header('Access-Control-Allow-Credentials', 'true');
      next();
    });
    this.express.use(compression());
    this.express.use(helmet());
    this.express.use(morgan('dev'));
    this.express.use(bodyParser.json());
    this.express.use(bodyParser.urlencoded({ extended: false }));
    this.express.use(passport.initialize());
    this.express.use(expressValidator());
    this.express.use((err, req, res, next) => {
      console.error(err);
      res.status(err.status || 500).json({
        message: err.message,
        error: err
      });
    });
  }

  /* connect resource routers */
  private routes(): void {
    /* create an instance of the each of our routers */
    const userRouter = new UserRouter();
    const bestBuyRouter = new BestBuyRouter();

    /* attach all routers to our express app */
    this.express.use(userRouter.path, userRouter.router);
    this.express.use(bestBuyRouter.path, bestBuyRouter.router);
  }
}

和我的index.ts

import Api from './Api';
require('dotenv').config();
const mongoose = require('mongoose');
/* Set mongoose promise to native ES6 promise */
mongoose.Promise = global.Promise;

/* Instantiate our app instance */
const app: Api = new Api();

const connectOptions = {
  useMongoClient: true,
  keepAlive: true,
  reconnectTries: Number.MAX_VALUE
};

/* Get current environment */
export const ENV = app.currentEnv();

let DATABASE_URL;
let PORT;

/* set environment variables */
if (ENV === 'production') {
  DATABASE_URL = process.env.MONGODB_URI;
  PORT = parseInt(process.env.PORT, 10);
} else {
  DATABASE_URL = process.env.TEST_DATABASE_URL;
  PORT = 3000;
}

let server;

export const runServer = async (
  dbURL: string = DATABASE_URL,
  port: number = PORT
) => {
  try {
    await mongoose.connect(dbURL, connectOptions);
    await new Promise((resolve, reject) => {
      server = app.express
        .listen(port, () => {
          console.info(`The ${ENV} server is listening on port ${port} `);
          resolve();
        })
        .on('error', err => {
          mongoose.disconnect();
          reject(err);
        });
    });
  } catch (err) {
    console.error(err);
  }
};

export const closeServer = async () => {
  try {
    await mongoose.disconnect();
    await new Promise((resolve, reject) => {
      console.info(`Closing server. Goodbye old friend.`);
      server.close(err => (err ? reject(err) : resolve()));
    });
  } catch (err) {
    console.error(err);
  }
};

require.main === module && runServer().catch(err => console.error(err));

最后,我的tsconfig.json

{
  "compilerOptions": {
    "lib": ["dom", "es7"],
    "allowJs": true,
    "watch": true,
    "noImplicitAny": false,
    "removeComments": true,
    "sourceMap": false,
    "target": "es6",
    "module": "commonjs",
    "outDir": "./lib",
    "types": [
      "body-parser",
      "mongodb",
      "mongoose",
      "passport",
      "node",
      "nodemailer",
      "mocha",
      "chai",
      "express",
      "express-validator",
      "chai-http"
    ],
    "typeRoots": ["./node_modules/@types"]
  },
  "compileOnSave": true,
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "**/*.test.ts"]
}

对我而言,当这个配置在过去对我有用时,突然得到这种行为真的很奇怪。我仍然可以很好地启动我的服务器,但由于某种原因,ts-node不想编译我的*test.ts文件以供mocha运行我的测试。知道这可能是什么吗?

1 个答案:

答案 0 :(得分:5)

调试“ is not a ...”错误

所以这可能不是答案,但这是我正在调试的错误的最高结果,这是调试提示。

我在运行mocha时使用以下内容:

test/mocha.opts

--require ts-node/register
--require source-map-support/register
--watch-extensions ts

但是无论我如何导入./app,尽管tsc编译良好,并且nodemocha在编译后的{{ 1}}个文件。

.js

我将有一个import * as app from './app' console.log({app}); // Pretty print object app.json的Heroku项目。

app.tsmocha的组合正在以更高的优先级加载ts-node文件扩展名,而不是.json文件,并且Typescript不允许我指定文件扩展名。因此,.tstsc的行为是不同的。

奖励积分-打字稿代码覆盖率

单元测试:mocha + ts-node

集成测试:nyc mocha src/**/*-test.ts

nyc mocha test/**/*.ts

package.json

{ "nyc": { "extension": [ ".ts" ], "include": [ "src/**/*.ts" ], "exclude": [ "src/**/*-test.ts", "test/**/*.ts" ], "require": [ "ts-node/register" ], "reporter": [ "text-summary" ], "sourceMap": true, "instrument": true, "all": true } }

tsconfig.json