Класс TypeScript Express Api не является конструктором при тестировании с помощью ts-node
Я настроил экспресс-приложение с использованием классов машинописи и столкнулся со странной проблемой. Все тесты прошли, и сегодня, когда я пошел обновлять некоторые маршруты, мои тесты больше не выполнялись. Когда я запускаю свой тестовый скрипт, я получаю это сообщение об ошибке в консоли:
$ 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
файлы для мокко для запуска моих тестов. Есть идеи, что это может быть?
1 ответ
Отладка " is not a ...
"ошибки
Таким образом, это, вероятно, НЕ будет ответом, но этот вопрос был главным результатом ошибки, которую я отлаживал, и вот подсказка отладки.
я бегал mocha
со следующим:
test/mocha.opts
--require ts-node/register
--require source-map-support/register
--watch-extensions ts
Но как бы я ни импортировал ./app
Я не мог заставить классы или функции работать, несмотря на tsc
составление штрафа и node
а также mocha
работает нормально на скомпилированном .js
файлы.
import * as app from './app'
console.log({app}); // Pretty print object
Как это случилось бы, у меня был проект Heroku с app.json
а также app.ts
,
Сочетание mocha
а также ts-node
загружали .json
расширение файла в качестве более высокого приоритета вместо .ts
file и Typescript не позволяют мне указывать расширение файла. Так что это поведение отличается в 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
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"target":"es2017",
"esModuleInterop":true,
// "strict": true,
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"types":["node"],
"rootDirs":[
"src"
]
},
"include": [
"src/**/*",
"test/**/*"
],
"exclude":[
"**/node_modules/**"
]
}