Skip to content

Commit ae128f6

Browse files
feature(@nestjs/testing) add error logs in the testing mode (nestjs#709, nestjs#713)
1 parent cb24ca9 commit ae128f6

11 files changed

Lines changed: 789 additions & 258 deletions

File tree

packages/common/interfaces/websockets/web-socket-adapter.interface.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { Observable } from 'rxjs';
22

33
export interface WebSocketAdapter<T = any> {
44
create(port: number, options?: T);
5-
bindClientConnect(server, callback: (...args) => void);
6-
bindClientDisconnect?(client, callback: (...args) => void);
5+
bindClientConnect(server: any, callback: (...args) => void);
6+
bindClientDisconnect?(client: any, callback: (...args) => void);
77
bindMessageHandlers(
8-
client,
9-
handler: {
8+
client: any,
9+
handlers: Array<{
1010
message: any;
11-
callback: (...args) => Observable<any> | Promise<any> | any;
12-
}[],
13-
process: (data) => Observable<any>,
11+
callback: (...args: any[]) => Observable<any> | Promise<any> | any;
12+
}>,
13+
transform: (data: any) => Observable<any>,
1414
);
15-
close(server);
15+
close(server: any);
1616
}

packages/core/injector/injector.ts

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
1-
import 'reflect-metadata';
2-
import { InstanceWrapper } from './container';
3-
import { UnknownDependenciesException } from '../errors/exceptions/unknown-dependencies.exception';
4-
import { RuntimeException } from '../errors/exceptions/runtime.exception';
5-
import { Module } from './module';
6-
import { Type } from '@nestjs/common/interfaces/type.interface';
1+
import { PARAMTYPES_METADATA, SELF_DECLARED_DEPS_METADATA } from '@nestjs/common/constants';
72
import { Controller } from '@nestjs/common/interfaces/controllers/controller.interface';
83
import { Injectable } from '@nestjs/common/interfaces/injectable.interface';
4+
import { Type } from '@nestjs/common/interfaces/type.interface';
5+
import { isFunction, isNil, isUndefined } from '@nestjs/common/utils/shared.utils';
6+
import 'reflect-metadata';
7+
import { RuntimeException } from '../errors/exceptions/runtime.exception';
8+
import { UnknownDependenciesException } from '../errors/exceptions/unknown-dependencies.exception';
99
import { MiddlewareWrapper } from '../middleware/container';
10-
import {
11-
isUndefined,
12-
isNil,
13-
isFunction,
14-
} from '@nestjs/common/utils/shared.utils';
15-
import {
16-
PARAMTYPES_METADATA,
17-
SELF_DECLARED_DEPS_METADATA,
18-
} from '@nestjs/common/constants';
1910
import { UndefinedDependencyException } from './../errors/exceptions/undefined-dependency.exception';
11+
import { InstanceWrapper } from './container';
12+
import { Module } from './module';
2013

2114
export class Injector {
2215
public async loadInstanceOfMiddleware(
@@ -219,34 +212,34 @@ export class Injector {
219212
return instanceWrapper;
220213
}
221214

222-
public async lookupComponent(
215+
public async lookupComponent<T = any>(
223216
components: Map<string, any>,
224217
module: Module,
225218
{ name, index, length }: { name: any; index: number; length: number },
226-
{ metatype },
219+
wrapper: InstanceWrapper<T>,
227220
) {
228221
const scanInExports = () =>
229222
this.lookupComponentInExports(
230223
components,
231224
{ name, index, length },
232225
module,
233-
metatype,
226+
wrapper,
234227
);
235228
return components.has(name) ? components.get(name) : await scanInExports();
236229
}
237230

238-
public async lookupComponentInExports(
231+
public async lookupComponentInExports<T = any>(
239232
components: Map<string, any>,
240233
{ name, index, length }: { name: any; index: number; length: number },
241234
module: Module,
242-
metatype,
235+
wrapper: InstanceWrapper<T>,
243236
) {
244237
const instanceWrapper = await this.lookupComponentInRelatedModules(
245238
module,
246239
name,
247240
);
248241
if (isNil(instanceWrapper)) {
249-
throw new UnknownDependenciesException(metatype.name, index, length);
242+
throw new UnknownDependenciesException(wrapper.name, index, length);
250243
}
251244
return instanceWrapper;
252245
}

packages/core/middleware/routes-mapper.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
1+
import { PATH_METADATA } from '@nestjs/common/constants';
2+
import { Type } from '@nestjs/common/interfaces';
3+
import { isString, isUndefined, validatePath } from '@nestjs/common/utils/shared.utils';
14
import 'reflect-metadata';
2-
import { RouterExplorer } from '../router/router-explorer';
35
import { UnknownRequestMappingException } from '../errors/exceptions/unknown-request-mapping.exception';
4-
import { RequestMethod } from '@nestjs/common/enums/request-method.enum';
5-
import {
6-
isUndefined,
7-
validatePath,
8-
isString,
9-
} from '@nestjs/common/utils/shared.utils';
10-
import { PATH_METADATA } from '@nestjs/common/constants';
11-
import { MetadataScanner } from '../metadata-scanner';
126
import { NestContainer } from '../injector/container';
13-
import { Type } from '@nestjs/common/interfaces';
7+
import { MetadataScanner } from '../metadata-scanner';
8+
import { RouterExplorer } from '../router/router-explorer';
149

1510
export class RoutesMapper {
1611
private readonly routerExplorer: RouterExplorer;
@@ -21,7 +16,7 @@ export class RoutesMapper {
2116

2217
public mapRouteToRouteProps(route: Type<any> | any | string): string[] {
2318
if (isString(route)) {
24-
return [route];
19+
return [this.validateRoutePath(route)];
2520
}
2621
const routePath: string = Reflect.getMetadata(PATH_METADATA, route);
2722
if (isUndefined(routePath)) {

packages/core/test/injector/injector.spec.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import * as sinon from 'sinon';
1+
import * as chai from 'chai';
22
import { expect } from 'chai';
3+
import * as chaiAsPromised from 'chai-as-promised';
4+
import * as sinon from 'sinon';
5+
import { Component } from '../../../common/decorators/core/component.decorator';
36
import { InstanceWrapper, NestContainer } from '../../injector/container';
47
import { Injector } from '../../injector/injector';
5-
import { Component } from '../../../common/decorators/core/component.decorator';
6-
import { RuntimeException } from '../../errors/exceptions/runtime.exception';
78
import { Module } from '../../injector/module';
8-
import { UnknownDependenciesException } from '../../errors/exceptions/unknown-dependencies.exception';
9-
import * as chai from 'chai';
10-
import * as chaiAsPromised from 'chai-as-promised';
11-
import { UndefinedDependencyException } from '../../errors/exceptions/undefined-dependency.exception';
129
chai.use(chaiAsPromised);
1310

1411
describe('Injector', () => {
@@ -279,7 +276,12 @@ describe('Injector', () => {
279276
describe('lookupComponent', () => {
280277
let lookupComponentInRelatedModules: sinon.SinonStub;
281278
const metatype = { name: 'test', metatype: { name: 'test' } };
282-
279+
const wrapper: any = {
280+
name: 'Test',
281+
metatype,
282+
instance: null,
283+
isResolved: false,
284+
};
283285
beforeEach(() => {
284286
lookupComponentInRelatedModules = sinon.stub();
285287
(injector as any).lookupComponentInRelatedModules = lookupComponentInRelatedModules;
@@ -295,7 +297,7 @@ describe('Injector', () => {
295297
collection as any,
296298
null,
297299
{ name: metatype.name, index: 0, length: 10 },
298-
metatype,
300+
wrapper,
299301
);
300302
expect(result).to.be.equal(instance);
301303
});
@@ -309,7 +311,7 @@ describe('Injector', () => {
309311
collection as any,
310312
null,
311313
{ name: metatype.name, index: 0, length: 10 },
312-
metatype,
314+
wrapper,
313315
);
314316
expect(lookupComponentInRelatedModules.called).to.be.true;
315317
});
@@ -325,7 +327,7 @@ describe('Injector', () => {
325327
collection as any,
326328
module as any,
327329
{ name: metatype.name, index: 0, length: 10 },
328-
{ metatype },
330+
wrapper,
329331
),
330332
).to.eventually.be.rejected;
331333
});
@@ -341,7 +343,7 @@ describe('Injector', () => {
341343
collection as any,
342344
module as any,
343345
{ name: metatype.name, index: 0, length: 10 },
344-
metatype,
346+
wrapper,
345347
),
346348
).to.eventually.be.not.rejected;
347349
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Logger } from '@nestjs/common';
2+
3+
export class TestingLogger extends Logger {
4+
constructor() {
5+
super('Testing');
6+
}
7+
8+
log(message: string) {}
9+
warn(message: string) {}
10+
error(message: string, trace: string) {
11+
return Logger.error(message, trace, 'ExceptionHandler');
12+
}
13+
}

packages/testing/test.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
1-
import {
2-
NestContainer,
3-
InstanceWrapper,
4-
} from '@nestjs/core/injector/container';
51
import { ModuleMetadata } from '@nestjs/common/interfaces/modules/module-metadata.interface';
6-
import { DependenciesScanner } from '@nestjs/core/scanner';
7-
import { InstanceLoader } from '@nestjs/core/injector/instance-loader';
8-
import { Logger } from '@nestjs/common/services/logger.service';
9-
import { NestEnvironment } from '@nestjs/common/enums/nest-environment.enum';
102
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
113
import { TestingModuleBuilder } from './testing-module.builder';
124

135
export class Test {
146
private static readonly metadataScanner = new MetadataScanner();
157

168
public static createTestingModule(metadata: ModuleMetadata) {
17-
this.init();
189
return new TestingModuleBuilder(this.metadataScanner, metadata);
1910
}
20-
21-
private static init() {
22-
Logger.setMode(NestEnvironment.TEST);
23-
}
2411
}

packages/testing/testing-module.builder.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import * as deprecate from 'deprecate';
2-
import { InstanceLoader } from '@nestjs/core/injector/instance-loader';
1+
import { Logger, Module } from '@nestjs/common';
2+
import { ModuleMetadata } from '@nestjs/common/interfaces';
3+
import { ApplicationConfig } from '@nestjs/core/application-config';
34
import { NestContainer } from '@nestjs/core/injector/container';
4-
import { OverrideByFactoryOptions, OverrideBy } from './interfaces';
5-
import { Module } from '@nestjs/common';
5+
import { InstanceLoader } from '@nestjs/core/injector/instance-loader';
66
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
77
import { DependenciesScanner } from '@nestjs/core/scanner';
8-
import { ModuleMetadata } from '@nestjs/common/interfaces';
8+
import * as deprecate from 'deprecate';
9+
import { OverrideBy, OverrideByFactoryOptions } from './interfaces';
10+
import { TestingLogger } from './services/testing-logger.service';
911
import { TestingModule } from './testing-module';
10-
import { ApplicationConfig } from '@nestjs/core/application-config';
1112

1213
export class TestingModuleBuilder {
1314
private readonly applicationConfig = new ApplicationConfig();
@@ -56,6 +57,8 @@ export class TestingModuleBuilder {
5657
}
5758

5859
public async compile(): Promise<TestingModule> {
60+
this.applyLogger();
61+
5962
[...this.overloadsMap.entries()].map(([component, options]) => {
6063
this.container.replace(component, options);
6164
});
@@ -94,4 +97,8 @@ export class TestingModuleBuilder {
9497
Module(metadata)(TestModule);
9598
return TestModule;
9699
}
100+
101+
private applyLogger() {
102+
Logger.overrideLogger(new TestingLogger());
103+
}
97104
}

packages/testing/testing-module.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1-
import * as optional from 'optional';
2-
import { NestContainer } from '@nestjs/core/injector/container';
3-
import { NestApplication, NestApplicationContext } from '@nestjs/core';
4-
import { Type } from '@nestjs/common/interfaces/type.interface';
5-
import { INestApplication, INestMicroservice } from '@nestjs/common';
1+
import {
2+
HttpServer,
3+
INestApplication,
4+
INestMicroservice,
5+
Logger,
6+
} from '@nestjs/common';
67
import { MicroserviceOptions } from '@nestjs/common/interfaces/microservices/microservice-configuration.interface';
7-
import { MicroservicesPackageNotFoundException } from '@nestjs/core/errors/exceptions/microservices-package-not-found.exception';
8-
import { ApplicationConfig } from '@nestjs/core/application-config';
9-
import { HttpServer } from '@nestjs/common';
10-
import { ExpressFactory } from '@nestjs/core/adapters/express-factory';
11-
import { ExpressAdapter } from '@nestjs/core/adapters/express-adapter';
12-
import { FastifyAdapter } from '@nestjs/core/adapters/fastify-adapter';
8+
import { NestMicroserviceOptions } from '@nestjs/common/interfaces/microservices/nest-microservice-options.interface';
9+
import { NestApplicationContextOptions } from '@nestjs/common/interfaces/nest-application-context-options.interface';
1310
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
14-
import { INestFastifyApplication } from '@nestjs/common/interfaces/nest-fastify-application.interface';
1511
import { INestExpressApplication } from '@nestjs/common/interfaces/nest-express-application.interface';
12+
import { INestFastifyApplication } from '@nestjs/common/interfaces/nest-fastify-application.interface';
13+
import { Type } from '@nestjs/common/interfaces/type.interface';
14+
import { NestApplication, NestApplicationContext } from '@nestjs/core';
15+
import { ExpressAdapter } from '@nestjs/core/adapters/express-adapter';
16+
import { ExpressFactory } from '@nestjs/core/adapters/express-factory';
17+
import { FastifyAdapter } from '@nestjs/core/adapters/fastify-adapter';
18+
import { ApplicationConfig } from '@nestjs/core/application-config';
19+
import { MicroservicesPackageNotFoundException } from '@nestjs/core/errors/exceptions/microservices-package-not-found.exception';
20+
import { NestContainer } from '@nestjs/core/injector/container';
21+
import * as optional from 'optional';
1622

1723
const { NestMicroservice } =
1824
optional('@nestjs/microservices/nest-microservice') || ({} as any);
@@ -44,20 +50,25 @@ export class TestingModule extends NestApplicationContext {
4450
options?: NestApplicationOptions,
4551
): INestApplication & (INestExpressApplication | INestFastifyApplication) {
4652
httpServer = this.applyExpressAdapter(httpServer);
53+
54+
this.applyLogger(options);
4755
this.container.setApplicationRef(httpServer);
56+
4857
return new NestApplication(
4958
this.container,
5059
httpServer,
5160
this.applicationConfig,
61+
options,
5262
);
5363
}
5464

5565
public createNestMicroservice(
56-
options: MicroserviceOptions,
66+
options: NestMicroserviceOptions & MicroserviceOptions,
5767
): INestMicroservice {
5868
if (!NestMicroservice) {
5969
throw new MicroservicesPackageNotFoundException();
6070
}
71+
this.applyLogger(options);
6172
return new NestMicroservice(
6273
this.container,
6374
options,
@@ -72,4 +83,11 @@ export class TestingModule extends NestApplicationContext {
7283
}
7384
return new ExpressAdapter(httpAdapter);
7485
}
86+
87+
private applyLogger(options: NestApplicationContextOptions | undefined) {
88+
if (!options || !options.logger) {
89+
return undefined;
90+
}
91+
Logger.overrideLogger(options.logger);
92+
}
7593
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: "3"
2+
3+
services:
4+
mongodb:
5+
image: mongo:latest
6+
environment:
7+
- MONGODB_DATABASE="test"
8+
ports:
9+
- 27017:27017

0 commit comments

Comments
 (0)