Earlier everything worked, but i already have no idea what is wrong. Other tests pass correctly. Problem is only with method parameter decorators. Package dependencies fresh enough.
The error: "TypeError: Cannot read properties of undefined (reading 'prototype')";
Here is controller to test (simplified, but fails):
import {
Controller, Post, Body,
} from '@nestjs/common';
@Controller('mytest')
export class MyTestController {
@Post()
async testMethod(@Body() b: any): Promise<void> {
return undefined;
}
}
With @Res and @Req decorators from '@nestjs/common' got the same error. Tried to use custom @required decorator from Typescript docs: The same error.
The test:
import { MyTestController } from './mytest-controller';
test('...', async () => {
const a = new MyTestController();
expect(true).toBeTruthy();
});
Test fails during MyTestController is importing after test command was run. So the test is not even reached.
If i remove all parameter decorators, test will pass.
reflect-metadata is imported in jest global setup file. But tried to import directly in the test file: no difference.
I tried:
Package dependencies:
"dependencies": {
"@nestjs/common": "^8.2.6",
"@nestjs/core": "^8.2.6",
"@nestjs/schematics": "^8.0.5",
"@types/express": "^4.17.12",
"@types/jsonwebtoken": "^8.5.1",
"@types/supertest": "^2.0.11",
"argon2": "^0.28.3",
"dotenv": "^14.3.2",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.5.2",
"ts-node": "^10.7.0",
"typeorm": "^0.2.41",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/cli": "^7.16.8",
"@babel/core": "^7.16.12",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-decorators": "^7.16.7",
"@babel/plugin-proposal-export-default-from": "^7.16.7",
"@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.16.7",
"@nestjs/testing": "8.2.6",
"@types/jest": "^27.4.1",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.10.1",
"babel-jest": "^27.5.1",
"babel-plugin-parameter-decorator": "^1.0.16",
"eslint": "^8.7.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^26.0.0",
"jest": "^27.5.1",
"supertest": "^6.2.2",
"testcontainers": "^8.6.1",
"ts-jest": "^27.1.4",
"typescript": "^4.5.5"
}
Any ideas?
Tried to unite controller and it's test in one file: got error.
Tried to use decorator without controller (just class) as below, no erorrs.
import 'reflect-metadata';
const requiredMetadataKey = Symbol('required');
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
const existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}
class A {
do(@required par: any): void {
return undefined;
}
}
test('...', async () => {
const a = new A();
a.do({});
expect(true).toBeTruthy();
});
So something is wrong with bundle of nestjs controller and any method parameter decorator.
Removal @Controller() and @Post() decorators from MyTestController, but with @Body() decorator: no errors.
I can suppose there is problem with babel-jest, which transforms ts to old js style. My babel config:
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
"node": "current"
}
}
],
"@babel/preset-typescript"
],
plugins: [
["@babel/plugin-proposal-decorators", {"legacy": true}],
["@babel/plugin-proposal-class-properties"],
"@babel/plugin-proposal-export-default-from",
"babel-plugin-parameter-decorator",
],
}
But, in my opinion, babel is configured properly
So, i couldn't find a mistake in babel. So i found another transformer named 'ts-jest' and replaced babel-jest with in in the jest config file:
transform: {
"\\.ts$": 'ts-jest',
},
But after that there were errors in jest-setup-after-end, global-setup and global-teardown files about import (like: you cannot use 'import' statement outside the module). I had to convert this files from .js to .ts, add them to tsconfig.json in "include" section and everything became right.