我已经使用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运行我的测试。知道这可能是什么吗?
答案 0 :(得分:5)
is not a ...
”错误所以这可能不是答案,但这是我正在调试的错误的最高结果,这是调试提示。
我在运行mocha
时使用以下内容:
test/mocha.opts
--require ts-node/register
--require source-map-support/register
--watch-extensions ts
但是无论我如何导入./app
,尽管tsc
编译良好,并且node
和mocha
在编译后的{{ 1}}个文件。
.js
我将有一个import * as app from './app'
console.log({app}); // Pretty print object
和app.json
的Heroku项目。
app.ts
和mocha
的组合正在以更高的优先级加载ts-node
文件扩展名,而不是.json
文件,并且Typescript不允许我指定文件扩展名。因此,.ts
与tsc
的行为是不同的。
单元测试: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