diff --git a/integration/hello-world/e2e/router-module-middleware.spec.ts b/integration/hello-world/e2e/router-module-middleware.spec.ts new file mode 100644 index 00000000000..bc386e404df --- /dev/null +++ b/integration/hello-world/e2e/router-module-middleware.spec.ts @@ -0,0 +1,77 @@ +import { + Controller, + Get, + INestApplication, + MiddlewareConsumer, + Module, +} from '@nestjs/common'; +import { RouterModule } from '@nestjs/core'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { ApplicationModule } from '../src/app.module'; + +const RETURN_VALUE = 'test'; +const SCOPED_VALUE = 'test_scoped'; + +@Controller() +class TestController { + @Get('test') + test() { + return RETURN_VALUE; + } + + @Get('test2') + test2() { + return RETURN_VALUE; + } +} + +@Module({ + imports: [ApplicationModule], + controllers: [TestController], +}) +class TestModule { + configure(consumer: MiddlewareConsumer) { + consumer + .apply((req, res, next) => res.send(SCOPED_VALUE)) + .forRoutes(TestController); + } +} + +describe('RouterModule with Middleware functions', () => { + let app: INestApplication; + + beforeEach(async () => { + app = ( + await Test.createTestingModule({ + imports: [ + TestModule, + RouterModule.register([ + { + path: '/module-path/', + module: TestModule, + }, + ]), + ], + }).compile() + ).createNestApplication(); + + await app.init(); + }); + + it(`forRoutes(TestController) - /test`, () => { + return request(app.getHttpServer()) + .get('/module-path/test') + .expect(200, SCOPED_VALUE); + }); + + it(`forRoutes(TestController) - /test2`, () => { + return request(app.getHttpServer()) + .get('/module-path/test2') + .expect(200, SCOPED_VALUE); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/integration/hello-world/e2e/router-module.spec.ts b/integration/hello-world/e2e/router-module.spec.ts new file mode 100644 index 00000000000..cc576e261e5 --- /dev/null +++ b/integration/hello-world/e2e/router-module.spec.ts @@ -0,0 +1,99 @@ +import { Controller, Get, INestApplication, Module } from '@nestjs/common'; +import { RouterModule, Routes } from '@nestjs/core'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; + +describe('RouterModule', () => { + let app: INestApplication; + + abstract class BaseController { + @Get() + getName() { + return this.constructor.name; + } + } + + @Controller('/parent-controller') + class ParentController extends BaseController {} + @Controller('/child-controller') + class ChildController extends BaseController {} + @Controller('no-slash-controller') + class NoSlashController extends BaseController {} + + class UnknownController {} + @Module({ controllers: [ParentController] }) + class ParentModule {} + + @Module({ controllers: [ChildController] }) + class ChildModule {} + + @Module({}) + class AuthModule {} + @Module({}) + class PaymentsModule {} + + @Module({ controllers: [NoSlashController] }) + class NoSlashModule {} + + const routes1: Routes = [ + { + path: 'parent', + module: ParentModule, + children: [ + { + path: 'child', + module: ChildModule, + }, + ], + }, + ]; + const routes2: Routes = [ + { path: 'v1', children: [AuthModule, PaymentsModule, NoSlashModule] }, + ]; + + @Module({ + imports: [ParentModule, ChildModule, RouterModule.register(routes1)], + }) + class MainModule {} + + @Module({ + imports: [ + AuthModule, + PaymentsModule, + NoSlashModule, + RouterModule.register(routes2), + ], + }) + class AppModule {} + + before(async () => { + const moduleRef = await Test.createTestingModule({ + imports: [MainModule, AppModule], + }).compile(); + + app = moduleRef.createNestApplication(); + await app.init(); + }); + + it('should hit the "ParentController"', async () => { + return request(app.getHttpServer()) + .get('/parent/parent-controller') + .expect(200, 'ParentController'); + }); + + it('should hit the "ChildController"', async () => { + return request(app.getHttpServer()) + .get('/parent/child/child-controller') + .expect(200, 'ChildController'); + }); + + it('should hit the "NoSlashController"', async () => { + return request(app.getHttpServer()) + .get('/v1/no-slash-controller') + .expect(200, 'NoSlashController'); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/packages/common/test/utils/shared.utils.spec.ts b/packages/common/test/utils/shared.utils.spec.ts index 6ee8143003e..5b8110356c6 100644 --- a/packages/common/test/utils/shared.utils.spec.ts +++ b/packages/common/test/utils/shared.utils.spec.ts @@ -9,6 +9,7 @@ import { isPlainObject, isString, isUndefined, + normalizePath, } from '../../utils/shared.utils'; function Foo(a) { @@ -17,34 +18,34 @@ function Foo(a) { describe('Shared utils', () => { describe('isUndefined', () => { - it('should returns true when obj is undefined', () => { + it('should return true when obj is undefined', () => { expect(isUndefined(undefined)).to.be.true; }); - it('should returns false when object is not undefined', () => { + it('should return false when object is not undefined', () => { expect(isUndefined({})).to.be.false; }); }); describe('isFunction', () => { - it('should returns true when obj is function', () => { + it('should return true when obj is function', () => { expect(isFunction(() => ({}))).to.be.true; }); - it('should returns false when object is not function', () => { + it('should return false when object is not function', () => { expect(isFunction(null)).to.be.false; expect(isFunction(undefined)).to.be.false; }); }); describe('isObject', () => { - it('should returns true when obj is object', () => { + it('should return true when obj is object', () => { expect(isObject({})).to.be.true; }); - it('should returns false when object is not object', () => { + it('should return false when object is not object', () => { expect(isObject(3)).to.be.false; expect(isObject(null)).to.be.false; expect(isObject(undefined)).to.be.false; }); }); describe('isPlainObject', () => { - it('should returns true when obj is plain object', () => { + it('should return true when obj is plain object', () => { expect(isPlainObject({})).to.be.true; expect(isPlainObject({ prop: true })).to.be.true; expect( @@ -54,7 +55,7 @@ describe('Shared utils', () => { ).to.be.true; expect(isPlainObject(Object.create(null))).to.be.true; }); - it('should returns false when object is not object', () => { + it('should return false when object is not object', () => { expect(isPlainObject(3)).to.be.false; expect(isPlainObject(null)).to.be.false; expect(isPlainObject(undefined)).to.be.false; @@ -64,52 +65,69 @@ describe('Shared utils', () => { }); }); describe('isString', () => { - it('should returns true when obj is string', () => { + it('should return true when obj is a string', () => { expect(isString('true')).to.be.true; }); - it('should returns false when object is not string', () => { + it('should return false when object is not a string', () => { expect(isString(false)).to.be.false; expect(isString(null)).to.be.false; expect(isString(undefined)).to.be.false; }); }); describe('isConstructor', () => { - it('should returns true when string is equal constructor', () => { + it('should return true when string is equal to constructor', () => { expect(isConstructor('constructor')).to.be.true; }); - it('should returns false when string is not equal constructor', () => { + it('should return false when string is not equal to constructor', () => { expect(isConstructor('nope')).to.be.false; }); }); describe('addLeadingSlash', () => { - it('should returns validated path ("add / if not exists")', () => { + it('should return the validated path ("add / if not exists")', () => { expect(addLeadingSlash('nope')).to.be.eql('/nope'); }); - it('should returns same path', () => { + it('should return the same path', () => { expect(addLeadingSlash('/nope')).to.be.eql('/nope'); }); - it('should returns empty path', () => { + it('should return empty path', () => { expect(addLeadingSlash('')).to.be.eql(''); expect(addLeadingSlash(null)).to.be.eql(''); expect(addLeadingSlash(undefined)).to.be.eql(''); }); }); + describe('normalizePath', () => { + it('should remove all trailing slashes at the end of the path', () => { + expect(normalizePath('path/')).to.be.eql('/path'); + expect(normalizePath('path///')).to.be.eql('/path'); + expect(normalizePath('/path/path///')).to.be.eql('/path/path'); + }); + it('should replace all slashes with only one slash', () => { + expect(normalizePath('////path/')).to.be.eql('/path'); + expect(normalizePath('///')).to.be.eql('/'); + expect(normalizePath('/path////path///')).to.be.eql('/path/path'); + }); + it('should return / for empty path', () => { + expect(normalizePath('')).to.be.eql('/'); + expect(normalizePath(null)).to.be.eql('/'); + expect(normalizePath(undefined)).to.be.eql('/'); + }); + }); describe('isNil', () => { - it('should returns true when obj is undefined or null', () => { + it('should return true when obj is undefined or null', () => { expect(isNil(undefined)).to.be.true; expect(isNil(null)).to.be.true; }); - it('should returns false when object is not undefined and null', () => { + it('should return false when object is not undefined and null', () => { expect(isNil('3')).to.be.false; }); }); describe('isEmpty', () => { - it('should returns true when array is empty or not exists', () => { + it('should return true when array is empty or not exists', () => { expect(isEmpty([])).to.be.true; expect(isEmpty(null)).to.be.true; expect(isEmpty(undefined)).to.be.true; }); - it('should returns false when array is not empty', () => { + it('should return false when array is not empty', () => { expect(isEmpty([1, 2])).to.be.false; }); }); diff --git a/packages/common/utils/shared.utils.ts b/packages/common/utils/shared.utils.ts index be31a898099..c29ca218062 100644 --- a/packages/common/utils/shared.utils.ts +++ b/packages/common/utils/shared.utils.ts @@ -33,6 +33,13 @@ export const addLeadingSlash = (path?: string): string => */ export const validatePath = addLeadingSlash; +export const normalizePath = (path?: string): string => + path + ? path.startsWith('/') + ? ('/' + path.replace(/\/+$/, '')).replace(/\/+/g, '/') + : '/' + path.replace(/\/+$/, '') + : '/'; + export const isFunction = (fn: any): boolean => typeof fn === 'function'; export const isString = (fn: any): fn is string => typeof fn === 'string'; export const isConstructor = (fn: any): boolean => fn === 'constructor'; diff --git a/packages/core/injector/container.ts b/packages/core/injector/container.ts index 1ec50d4b1e6..49db5ca21f5 100644 --- a/packages/core/injector/container.ts +++ b/packages/core/injector/container.ts @@ -56,7 +56,7 @@ export class NestContainer { scope: Type[], ): Promise { // In DependenciesScanner#scanForModules we already check for undefined or invalid modules - // We sill need to catch the edge-case of `forwardRef(() => undefined)` + // We still need to catch the edge-case of `forwardRef(() => undefined)` if (!metatype) { throw new UndefinedForwardRefException(scope); } diff --git a/packages/core/injector/modules-container.ts b/packages/core/injector/modules-container.ts index 0a8ffbf2334..8f1d9dec6af 100644 --- a/packages/core/injector/modules-container.ts +++ b/packages/core/injector/modules-container.ts @@ -1,3 +1,10 @@ +import { v4 as uuid } from 'uuid'; import { Module } from './module'; -export class ModulesContainer extends Map {} +export class ModulesContainer extends Map { + private readonly _applicationId = uuid(); + + get applicationId(): string { + return this._applicationId; + } +} diff --git a/packages/core/middleware/builder.ts b/packages/core/middleware/builder.ts index 098c7443cb3..a91154da17c 100644 --- a/packages/core/middleware/builder.ts +++ b/packages/core/middleware/builder.ts @@ -9,9 +9,10 @@ import { RouteInfo, } from '@nestjs/common/interfaces/middleware'; import { MiddlewareConfiguration } from '@nestjs/common/interfaces/middleware/middleware-configuration.interface'; +import { iterate } from 'iterare'; +import { NestContainer } from '../injector'; import { RoutesMapper } from './routes-mapper'; import { filterMiddleware } from './utils'; -import { iterate } from 'iterare'; export class MiddlewareBuilder implements MiddlewareConsumer { private readonly middlewareCollection = new Set(); @@ -19,6 +20,7 @@ export class MiddlewareBuilder implements MiddlewareConsumer { constructor( private readonly routesMapper: RoutesMapper, private readonly httpAdapter: HttpServer, + private readonly container: NestContainer, ) {} public apply( diff --git a/packages/core/middleware/middleware-module.ts b/packages/core/middleware/middleware-module.ts index bbc7715d23a..f3f3ea1b91c 100644 --- a/packages/core/middleware/middleware-module.ts +++ b/packages/core/middleware/middleware-module.ts @@ -5,7 +5,6 @@ import { RouteInfo, } from '@nestjs/common/interfaces/middleware/middleware-configuration.interface'; import { NestMiddleware } from '@nestjs/common/interfaces/middleware/nest-middleware.interface'; -import { NestModule } from '@nestjs/common/interfaces/modules/nest-module.interface'; import { addLeadingSlash, isUndefined, @@ -70,28 +69,29 @@ export class MiddlewareModule { modules: Map, ) { const moduleEntries = [...modules.entries()]; - const loadMiddlewareConfiguration = async ([name, module]: [ + const loadMiddlewareConfiguration = async ([name, moduleRef]: [ string, Module, ]) => { - const instance = module.instance; - await this.loadConfiguration(middlewareContainer, instance, name); - await this.resolver.resolveInstances(module, name); + await this.loadConfiguration(middlewareContainer, moduleRef, name); + await this.resolver.resolveInstances(moduleRef, name); }; await Promise.all(moduleEntries.map(loadMiddlewareConfiguration)); } public async loadConfiguration( middlewareContainer: MiddlewareContainer, - instance: NestModule, + moduleRef: Module, moduleKey: string, ) { + const { instance } = moduleRef; if (!instance.configure) { return; } const middlewareBuilder = new MiddlewareBuilder( this.routesMapper, this.httpAdapter, + this.container, ); await instance.configure(middlewareBuilder); diff --git a/packages/core/middleware/routes-mapper.ts b/packages/core/middleware/routes-mapper.ts index 43946862818..5e9ef6e46f6 100644 --- a/packages/core/middleware/routes-mapper.ts +++ b/packages/core/middleware/routes-mapper.ts @@ -1,5 +1,5 @@ import { RequestMethod } from '@nestjs/common'; -import { PATH_METADATA } from '@nestjs/common/constants'; +import { MODULE_PATH, PATH_METADATA } from '@nestjs/common/constants'; import { RouteInfo, Type } from '@nestjs/common/interfaces'; import { addLeadingSlash, @@ -7,13 +7,15 @@ import { isUndefined, } from '@nestjs/common/utils/shared.utils'; import { NestContainer } from '../injector/container'; +import { Module } from '../injector/module'; import { MetadataScanner } from '../metadata-scanner'; import { RouterExplorer } from '../router/router-explorer'; +import { targetModulesByContainer } from '../router/router-module'; export class RoutesMapper { private readonly routerExplorer: RouterExplorer; - constructor(container: NestContainer) { + constructor(private readonly container: NestContainer) { this.routerExplorer = new RouterExplorer(new MetadataScanner(), container); } @@ -23,35 +25,41 @@ export class RoutesMapper { if (isString(route)) { return [ { - path: this.validateRoutePath(route), + path: addLeadingSlash(route), method: RequestMethod.ALL, }, ]; } - const routePath: string = Reflect.getMetadata(PATH_METADATA, route); + const routePath = this.getRoutePath(route); if (this.isRouteInfo(routePath, route)) { return [ { - path: this.validateRoutePath(route.path), + path: addLeadingSlash(route.path), method: route.method, }, ]; } - const paths = this.routerExplorer.scanForPaths( + const controllerPaths = this.routerExplorer.scanForPaths( Object.create(route), route.prototype, ); + const moduleRef = this.getHostModuleOfController(route); + const modulePath = this.getModulePath(moduleRef?.metatype); + const concatPaths = (acc: T[], currentValue: T[]) => acc.concat(currentValue); - return paths - .map( - item => - item.path && - item.path.map(p => ({ - path: - this.validateGlobalPath(routePath) + this.validateRoutePath(p), + + return controllerPaths + .map(item => + item.path?.map(p => { + let path = modulePath ?? ''; + path += this.normalizeGlobalPath(routePath) + addLeadingSlash(p); + + return { + path, method: item.requestMethod, - })), + }; + }), ) .reduce(concatPaths, []); } @@ -63,12 +71,44 @@ export class RoutesMapper { return isUndefined(path); } - private validateGlobalPath(path: string): string { + private normalizeGlobalPath(path: string): string { const prefix = addLeadingSlash(path); return prefix === '/' ? '' : prefix; } - private validateRoutePath(path: string): string { - return addLeadingSlash(path); + private getRoutePath(route: Type | RouteInfo): string | undefined { + return Reflect.getMetadata(PATH_METADATA, route); + } + + private getHostModuleOfController( + metatype: Type, + ): Module | undefined { + if (!metatype?.name) { + return; + } + const modulesContainer = this.container.getModules(); + const moduleRefsSet = targetModulesByContainer.get(modulesContainer); + if (!moduleRefsSet) { + return; + } + + const modules = Array.from(modulesContainer.values()).filter(moduleRef => + moduleRefsSet.has(moduleRef), + ); + return modules.find(({ routes }) => routes.has(metatype.name)); + } + + private getModulePath( + metatype: Type | undefined, + ): string | undefined { + if (!metatype) { + return; + } + const modulesContainer = this.container.getModules(); + const modulePath = Reflect.getMetadata( + MODULE_PATH + modulesContainer.applicationId, + metatype, + ); + return modulePath ?? Reflect.getMetadata(MODULE_PATH, metatype); } } diff --git a/packages/core/router/index.ts b/packages/core/router/index.ts index 56e4b0555f1..5e2cc66bd72 100644 --- a/packages/core/router/index.ts +++ b/packages/core/router/index.ts @@ -1 +1,3 @@ +export * from './interfaces'; export * from './request'; +export { RouterModule } from './router-module'; diff --git a/packages/core/router/interfaces/index.ts b/packages/core/router/interfaces/index.ts new file mode 100644 index 00000000000..65ccbce89db --- /dev/null +++ b/packages/core/router/interfaces/index.ts @@ -0,0 +1 @@ +export * from './routes.interface'; diff --git a/packages/core/router/interfaces/routes.interface.ts b/packages/core/router/interfaces/routes.interface.ts new file mode 100644 index 00000000000..f2547520242 --- /dev/null +++ b/packages/core/router/interfaces/routes.interface.ts @@ -0,0 +1,9 @@ +import { Type } from '@nestjs/common'; + +export interface RouteTree { + path: string; + module?: Type; + children?: Routes | Type[]; +} + +export type Routes = RouteTree[]; diff --git a/packages/core/router/router-explorer.ts b/packages/core/router/router-explorer.ts index f6738b7f17e..11bb13958e2 100644 --- a/packages/core/router/router-explorer.ts +++ b/packages/core/router/router-explorer.ts @@ -99,8 +99,7 @@ export class RouterExplorer { } else { path = [prefix + addLeadingSlash(path)]; } - - return path.map(p => addLeadingSlash(p)); + return path.map((p: string) => addLeadingSlash(p)); } public scanForPaths( @@ -135,7 +134,7 @@ export class RouterExplorer { ); const path = isString(routePath) ? [addLeadingSlash(routePath)] - : routePath.map(p => addLeadingSlash(p)); + : routePath.map((p: string) => addLeadingSlash(p)); return { path, requestMethod, diff --git a/packages/core/router/router-module.ts b/packages/core/router/router-module.ts new file mode 100644 index 00000000000..c6bf95f207e --- /dev/null +++ b/packages/core/router/router-module.ts @@ -0,0 +1,76 @@ +import { DynamicModule, Inject, Module, Type } from '@nestjs/common'; +import { MODULE_PATH } from '@nestjs/common/constants'; +import { normalizePath } from '@nestjs/common/utils/shared.utils'; +import { ModulesContainer } from '../injector'; +import { Module as ModuleClass } from '../injector/module'; +import { Routes } from './interfaces'; +import { flattenRoutePaths } from './utils'; + +export const ROUTES = Symbol('ROUTES'); + +export const targetModulesByContainer = new WeakMap< + ModulesContainer, + WeakSet +>(); + +/** + * @publicApi + */ +@Module({}) +export class RouterModule { + constructor( + private readonly modulesContainer: ModulesContainer, + @Inject(ROUTES) private readonly routes: Routes, + ) { + this.initialize(); + } + + static register(routes: Routes): DynamicModule { + return { + module: RouterModule, + providers: [ + { + provide: ROUTES, + useValue: routes, + }, + ], + }; + } + + private initialize() { + const flattenedRoutes = flattenRoutePaths(this.routes); + flattenedRoutes.forEach(route => { + const modulePath = normalizePath(route.path); + this.registerModulePathMetadata(route.module, modulePath); + this.updateTargetModulesCache(route.module); + }); + } + + private registerModulePathMetadata( + moduleCtor: Type, + modulePath: string, + ) { + Reflect.defineMetadata( + MODULE_PATH + this.modulesContainer.applicationId, + modulePath, + moduleCtor, + ); + } + + private updateTargetModulesCache(moduleCtor: Type) { + let moduleClassSet: WeakSet; + if (targetModulesByContainer.has(this.modulesContainer)) { + moduleClassSet = targetModulesByContainer.get(this.modulesContainer); + } else { + moduleClassSet = new WeakSet(); + targetModulesByContainer.set(this.modulesContainer, moduleClassSet); + } + const moduleRef = Array.from(this.modulesContainer.values()).find( + item => item?.metatype === moduleCtor, + ); + if (!moduleRef) { + return; + } + moduleClassSet.add(moduleRef); + } +} diff --git a/packages/core/router/routes-resolver.ts b/packages/core/router/routes-resolver.ts index eab93c15d3a..03881262300 100644 --- a/packages/core/router/routes-resolver.ts +++ b/packages/core/router/routes-resolver.ts @@ -127,7 +127,12 @@ export class RoutesResolver implements Resolver { } private getModulePathMetadata(metatype: Type): string | undefined { - return Reflect.getMetadata(MODULE_PATH, metatype); + const modulesContainer = this.container.getModules(); + const modulePath = Reflect.getMetadata( + MODULE_PATH + modulesContainer.applicationId, + metatype, + ); + return modulePath ?? Reflect.getMetadata(MODULE_PATH, metatype); } private getHostMetadata( diff --git a/packages/core/router/utils/flatten-route-paths.util.ts b/packages/core/router/utils/flatten-route-paths.util.ts new file mode 100644 index 00000000000..40b84340845 --- /dev/null +++ b/packages/core/router/utils/flatten-route-paths.util.ts @@ -0,0 +1,25 @@ +import { normalizePath } from '@nestjs/common/utils/shared.utils'; +import { Routes } from '../interfaces/routes.interface'; + +export function flattenRoutePaths(routes: Routes) { + const result = []; + routes.forEach(item => { + if (item.module && item.path) { + result.push({ module: item.module, path: item.path }); + } + if (item.children) { + const childrenRef = item.children as Routes; + childrenRef.forEach(child => { + if (typeof child !== 'string' && child.path) { + child.path = normalizePath( + normalizePath(item.path) + normalizePath(child.path), + ); + } else { + result.push({ path: item.path, module: child }); + } + }); + result.push(...flattenRoutePaths(childrenRef)); + } + }); + return result; +} diff --git a/packages/core/router/utils/index.ts b/packages/core/router/utils/index.ts new file mode 100644 index 00000000000..bf2f27b1d02 --- /dev/null +++ b/packages/core/router/utils/index.ts @@ -0,0 +1 @@ +export * from './flatten-route-paths.util'; diff --git a/packages/core/test/exceptions/exceptions-handler.spec.ts b/packages/core/test/exceptions/exceptions-handler.spec.ts index 928a1d95a93..15ea0a8fec9 100644 --- a/packages/core/test/exceptions/exceptions-handler.spec.ts +++ b/packages/core/test/exceptions/exceptions-handler.spec.ts @@ -107,7 +107,7 @@ describe('ExceptionsHandler', () => { }); describe('invokeCustomFilters', () => { describe('when filters array is empty', () => { - it('should returns false', () => { + it('should return false', () => { expect(handler.invokeCustomFilters(null, null)).to.be.false; }); }); @@ -134,7 +134,7 @@ describe('ExceptionsHandler', () => { handler.invokeCustomFilters(exception, res as any); expect(funcSpy.calledWith(exception, res)).to.be.true; }); - it('should returns true', () => { + it('should return true', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .true; }); @@ -144,7 +144,7 @@ describe('ExceptionsHandler', () => { handler.invokeCustomFilters(new TestException(), null); expect(funcSpy.notCalled).to.be.true; }); - it('should returns false', () => { + it('should return false', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .false; }); diff --git a/packages/core/test/exceptions/external-exception-filter-context.spec.ts b/packages/core/test/exceptions/external-exception-filter-context.spec.ts index 7e0d21472c2..755ec302165 100644 --- a/packages/core/test/exceptions/external-exception-filter-context.spec.ts +++ b/packages/core/test/exceptions/external-exception-filter-context.spec.ts @@ -30,7 +30,7 @@ describe('ExternalExceptionFilterContext', () => { beforeEach(() => { sinon.stub(exceptionFilter, 'createContext').returns([]); }); - it('should returns plain ExceptionHandler object', () => { + it('should return plain ExceptionHandler object', () => { const filter = exceptionFilter.create( new EmptyMetadata(), () => ({} as any), @@ -43,7 +43,7 @@ describe('ExternalExceptionFilterContext', () => { @UseFilters(new ExceptionFilter()) class WithMetadata {} - it('should returns ExceptionHandler object with exception filters', () => { + it('should return ExceptionHandler object with exception filters', () => { const filter = exceptionFilter.create( new WithMetadata(), () => ({} as any), @@ -54,7 +54,7 @@ describe('ExternalExceptionFilterContext', () => { }); }); describe('reflectCatchExceptions', () => { - it('should returns FILTER_CATCH_EXCEPTIONS metadata', () => { + it('should return FILTER_CATCH_EXCEPTIONS metadata', () => { expect( exceptionFilter.reflectCatchExceptions(new ExceptionFilter()), ).to.be.eql([CustomException]); @@ -64,7 +64,7 @@ describe('ExternalExceptionFilterContext', () => { class InvalidFilter {} const filters = [new ExceptionFilter(), new InvalidFilter(), 'test']; - it('should returns expected exception filters metadata', () => { + it('should return expected exception filters metadata', () => { const resolved = exceptionFilter.createConcreteContext(filters as any); expect(resolved).to.have.length(1); expect(resolved[0].exceptionMetatypes).to.be.deep.equal([ diff --git a/packages/core/test/exceptions/external-exceptions-handler.spec.ts b/packages/core/test/exceptions/external-exceptions-handler.spec.ts index 9e30b889a5e..8f39cd76f47 100644 --- a/packages/core/test/exceptions/external-exceptions-handler.spec.ts +++ b/packages/core/test/exceptions/external-exceptions-handler.spec.ts @@ -24,7 +24,7 @@ describe('ExternalExceptionsHandler', () => { beforeEach(() => { sinon.stub(handler, 'invokeCustomFilters').returns(observable$ as any); }); - it('should returns observable', () => { + it('should return observable', () => { const result = handler.next(new Error(), null); expect(result).to.be.eql(observable$); }); @@ -42,7 +42,7 @@ describe('ExternalExceptionsHandler', () => { }); describe('invokeCustomFilters', () => { describe('when filters array is empty', () => { - it('should returns identity', () => { + it('should return identity', () => { expect(handler.invokeCustomFilters(null, null)).to.be.null; }); }); @@ -67,7 +67,7 @@ describe('ExternalExceptionsHandler', () => { handler.invokeCustomFilters(exception, null); expect(funcSpy.calledWith(exception)).to.be.true; }); - it('should returns stream', () => { + it('should return stream', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .not.null; }); @@ -77,7 +77,7 @@ describe('ExternalExceptionsHandler', () => { handler.invokeCustomFilters(new TestException(), null); expect(funcSpy.notCalled).to.be.true; }); - it('should returns null', () => { + it('should return null', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .null; }); diff --git a/packages/core/test/guards/guards-consumer.spec.ts b/packages/core/test/guards/guards-consumer.spec.ts index a068b12bf7d..b62da0c2a03 100644 --- a/packages/core/test/guards/guards-consumer.spec.ts +++ b/packages/core/test/guards/guards-consumer.spec.ts @@ -1,7 +1,6 @@ -import * as sinon from 'sinon'; import { expect } from 'chai'; +import { of } from 'rxjs'; import { GuardsConsumer } from '../../guards/guards-consumer'; -import { Observable, of } from 'rxjs'; describe('GuardsConsumer', () => { let consumer: GuardsConsumer; @@ -49,7 +48,7 @@ describe('GuardsConsumer', () => { }); describe('pickResult', () => { describe('when result is Observable', () => { - it('should returns result', async () => { + it('should return result', async () => { expect(await consumer.pickResult(of(true))).to.be.true; }); }); diff --git a/packages/core/test/guards/guards-context-creator.spec.ts b/packages/core/test/guards/guards-context-creator.spec.ts index 778950182e4..af818d741fd 100644 --- a/packages/core/test/guards/guards-context-creator.spec.ts +++ b/packages/core/test/guards/guards-context-creator.spec.ts @@ -51,7 +51,7 @@ describe('GuardsContextCreator', () => { }); describe('createConcreteContext', () => { describe('when `moduleContext` is nil', () => { - it('should returns empty array', () => { + it('should return empty array', () => { const result = guardsContextCreator.createConcreteContext(guards); expect(result).to.be.empty; }); diff --git a/packages/core/test/helpers/context-utils.spec.ts b/packages/core/test/helpers/context-utils.spec.ts index 9630580fabf..54111ef6d79 100644 --- a/packages/core/test/helpers/context-utils.spec.ts +++ b/packages/core/test/helpers/context-utils.spec.ts @@ -21,7 +21,7 @@ describe('ContextUtils', () => { @CustomDecorator() custom, ) {} } - it('should returns ROUTE_ARGS_METADATA callback metadata', () => { + it('should return ROUTE_ARGS_METADATA callback metadata', () => { const instance = new TestController(); const metadata = contextUtils.reflectCallbackMetadata( instance, @@ -63,7 +63,7 @@ describe('ContextUtils', () => { }); }); describe('getArgumentsLength', () => { - it('should returns maximum index + 1 (length) placed in array', () => { + it('should return maximum index + 1 (length) placed in array', () => { const max = 4; const metadata = { [RouteParamtypes.REQUEST]: { index: 0 }, diff --git a/packages/core/test/helpers/external-context-creator.spec.ts b/packages/core/test/helpers/external-context-creator.spec.ts index 0e434d7e02f..401bb9e4262 100644 --- a/packages/core/test/helpers/external-context-creator.spec.ts +++ b/packages/core/test/helpers/external-context-creator.spec.ts @@ -243,7 +243,7 @@ describe('ExternalContextCreator', () => { describe('transformToResult', () => { describe('when resultOrDeffered', () => { describe('is Promise', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect( await contextCreator.transformToResult(Promise.resolve(value)), @@ -252,7 +252,7 @@ describe('ExternalContextCreator', () => { }); describe('is Observable', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect(await contextCreator.transformToResult(of(value))).to.be.eq( 100, @@ -261,7 +261,7 @@ describe('ExternalContextCreator', () => { }); describe('is value', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect(await contextCreator.transformToResult(value)).to.be.eq(100); }); diff --git a/packages/core/test/injector/module.spec.ts b/packages/core/test/injector/module.spec.ts index c0645dcd8c2..f1cb431cf62 100644 --- a/packages/core/test/injector/module.spec.ts +++ b/packages/core/test/injector/module.spec.ts @@ -280,7 +280,7 @@ describe('Module', () => { }); }); describe('when metatype exists in providers collection', () => { - it('should returns null', () => { + it('should return null', () => { expect(module.instance).to.be.eql(null); }); }); diff --git a/packages/core/test/interceptors/interceptors-consumer.spec.ts b/packages/core/test/interceptors/interceptors-consumer.spec.ts index fedb5997552..ae5823e1fdf 100644 --- a/packages/core/test/interceptors/interceptors-consumer.spec.ts +++ b/packages/core/test/interceptors/interceptors-consumer.spec.ts @@ -80,7 +80,7 @@ describe('InterceptorsConsumer', () => { }); }); describe('createContext', () => { - it('should returns execution context object', () => { + it('should return execution context object', () => { const instance = { constructor: {} }; const callback = () => null; const context = consumer.createContext([], instance, callback); diff --git a/packages/core/test/interceptors/interceptors-context-creator.spec.ts b/packages/core/test/interceptors/interceptors-context-creator.spec.ts index 82738a61964..093129692af 100644 --- a/packages/core/test/interceptors/interceptors-context-creator.spec.ts +++ b/packages/core/test/interceptors/interceptors-context-creator.spec.ts @@ -52,7 +52,7 @@ describe('InterceptorsContextCreator', () => { }); describe('createConcreteContext', () => { describe('when `moduleContext` is nil', () => { - it('should returns empty array', () => { + it('should return empty array', () => { const result = interceptorsContextCreator.createConcreteContext( interceptors, ); diff --git a/packages/core/test/metadata-scanner.spec.ts b/packages/core/test/metadata-scanner.spec.ts index f23e267f5a0..f0a51b6d053 100644 --- a/packages/core/test/metadata-scanner.spec.ts +++ b/packages/core/test/metadata-scanner.spec.ts @@ -29,7 +29,7 @@ describe('MetadataScanner', () => { public test2() {} } - it('should returns only methods', () => { + it('should return only methods', () => { const methods = scanner.scanFromPrototype( new Test(), Test.prototype, diff --git a/packages/core/test/middleware/builder.spec.ts b/packages/core/test/middleware/builder.spec.ts index ae73e83002e..5e8f961551f 100644 --- a/packages/core/test/middleware/builder.spec.ts +++ b/packages/core/test/middleware/builder.spec.ts @@ -10,9 +10,11 @@ describe('MiddlewareBuilder', () => { let builder: MiddlewareBuilder; beforeEach(() => { + const container = new NestContainer(); builder = new MiddlewareBuilder( - new RoutesMapper(new NestContainer()), + new RoutesMapper(container), new NoopHttpAdapter({}), + container, ); }); describe('apply', () => { diff --git a/packages/core/test/middleware/middleware-module.spec.ts b/packages/core/test/middleware/middleware-module.spec.ts index 87ecf444e4f..d12cde63482 100644 --- a/packages/core/test/middleware/middleware-module.spec.ts +++ b/packages/core/test/middleware/middleware-module.spec.ts @@ -50,16 +50,19 @@ describe('MiddlewareModule', () => { describe('loadConfiguration', () => { it('should call "configure" method if method is implemented', async () => { - const configureSpy = sinon.spy(); - const mockModule = { - configure: configureSpy, - }; - const stubContainer = new NestContainer(); stubContainer .getModules() .set('Test', new Module(class {}, stubContainer)); + const configureSpy = sinon.spy(); + const mockModule = { + instance: { + configure: configureSpy, + }, + }; + + (middlewareModule as any).container = stubContainer; await middlewareModule.loadConfiguration( new MiddlewareContainer(stubContainer), mockModule as any, @@ -72,6 +75,7 @@ describe('MiddlewareModule', () => { new MiddlewareBuilder( (middlewareModule as any).routesMapper, undefined, + stubContainer, ), ), ).to.be.true; diff --git a/packages/core/test/middleware/utils.spec.ts b/packages/core/test/middleware/utils.spec.ts index ffeb76205c7..805815f4c9d 100644 --- a/packages/core/test/middleware/utils.spec.ts +++ b/packages/core/test/middleware/utils.spec.ts @@ -22,7 +22,7 @@ describe('middleware utils', () => { beforeEach(() => { middleware = [Test, fnMiddleware, undefined, null]; }); - it('should returns filtered middleware', () => { + it('should return filtered middleware', () => { expect(filterMiddleware(middleware, [], noopAdapter)).to.have.length(2); }); }); @@ -65,12 +65,12 @@ describe('middleware utils', () => { }); describe('isClass', () => { describe('when middleware is a class', () => { - it('should returns true', () => { + it('should return true', () => { expect(isClass(Test)).to.be.true; }); }); describe('when middleware is a function', () => { - it('should returns false', () => { + it('should return false', () => { expect(isClass(fnMiddleware)).to.be.false; }); }); diff --git a/packages/core/test/pipes/params-token-factory.spec.ts b/packages/core/test/pipes/params-token-factory.spec.ts index f072d2b1ede..752f118deb2 100644 --- a/packages/core/test/pipes/params-token-factory.spec.ts +++ b/packages/core/test/pipes/params-token-factory.spec.ts @@ -10,28 +10,28 @@ describe('ParamsTokenFactory', () => { describe('exchangeEnumForString', () => { describe('when key is', () => { describe(`RouteParamtypes.BODY`, () => { - it('should returns body object', () => { + it('should return body object', () => { expect(factory.exchangeEnumForString(RouteParamtypes.BODY)).to.be.eql( 'body', ); }); }); describe(`RouteParamtypes.QUERY`, () => { - it('should returns query object', () => { + it('should return query object', () => { expect( factory.exchangeEnumForString(RouteParamtypes.QUERY), ).to.be.eql('query'); }); }); describe(`RouteParamtypes.PARAM`, () => { - it('should returns params object', () => { + it('should return params object', () => { expect( factory.exchangeEnumForString(RouteParamtypes.PARAM), ).to.be.eql('param'); }); }); describe('not available', () => { - it('should returns "custom"', () => { + it('should return "custom"', () => { expect(factory.exchangeEnumForString(-1)).to.be.eql('custom'); }); }); diff --git a/packages/core/test/pipes/pipes-consumer.spec.ts b/packages/core/test/pipes/pipes-consumer.spec.ts index 9fe77bf6ee1..d6bf927a931 100644 --- a/packages/core/test/pipes/pipes-consumer.spec.ts +++ b/packages/core/test/pipes/pipes-consumer.spec.ts @@ -34,7 +34,7 @@ describe('PipesConsumer', () => { done(); }); }); - it('should returns expected result', done => { + it('should return expected result', done => { const expectedResult = 3; consumer .apply(value, { metatype, type, data }, transforms) diff --git a/packages/core/test/pipes/pipes-context-creator.spec.ts b/packages/core/test/pipes/pipes-context-creator.spec.ts index 6230fd4aaea..3b5ea07a578 100644 --- a/packages/core/test/pipes/pipes-context-creator.spec.ts +++ b/packages/core/test/pipes/pipes-context-creator.spec.ts @@ -19,14 +19,14 @@ describe('PipesContextCreator', () => { }); describe('createConcreteContext', () => { describe('when metadata is empty or undefined', () => { - it('should returns empty array', () => { + it('should return empty array', () => { expect(creator.createConcreteContext(undefined)).to.be.deep.equal([]); expect(creator.createConcreteContext([])).to.be.deep.equal([]); }); }); describe('when metadata is not empty or undefined', () => { const metadata = [null, {}, { transform: () => ({}) }]; - it('should returns expected array', () => { + it('should return expected array', () => { const transforms = creator.createConcreteContext(metadata as any); expect(transforms).to.have.length(1); }); diff --git a/packages/core/test/router/route-params-factory.spec.ts b/packages/core/test/router/route-params-factory.spec.ts index a72fdbbe4ae..39dd2257464 100644 --- a/packages/core/test/router/route-params-factory.spec.ts +++ b/packages/core/test/router/route-params-factory.spec.ts @@ -115,7 +115,7 @@ describe('RouteParamsFactory', () => { }); }); describe(`RouteParamtypes.HOST`, () => { - it('should returns hosts object', () => { + it('should return hosts object', () => { expect( (factory as any).exchangeKeyForValue(RouteParamtypes.HOST, ...args), ).to.be.eql(req.hosts); diff --git a/packages/core/test/router/router-exception-filters.spec.ts b/packages/core/test/router/router-exception-filters.spec.ts index 3d254900a48..f506786e2fb 100644 --- a/packages/core/test/router/router-exception-filters.spec.ts +++ b/packages/core/test/router/router-exception-filters.spec.ts @@ -32,7 +32,7 @@ describe('RouterExceptionFilters', () => { beforeEach(() => { sinon.stub(exceptionFilter, 'createContext').returns([]); }); - it('should returns plain ExceptionHandler object', () => { + it('should return plain ExceptionHandler object', () => { const filter = exceptionFilter.create( new EmptyMetadata(), () => ({} as any), @@ -45,7 +45,7 @@ describe('RouterExceptionFilters', () => { @UseFilters(new ExceptionFilter()) class WithMetadata {} - it('should returns ExceptionHandler object with exception filters', () => { + it('should return ExceptionHandler object with exception filters', () => { const filter = exceptionFilter.create( new WithMetadata(), () => ({} as any), @@ -56,7 +56,7 @@ describe('RouterExceptionFilters', () => { }); }); describe('reflectCatchExceptions', () => { - it('should returns FILTER_CATCH_EXCEPTIONS metadata', () => { + it('should return FILTER_CATCH_EXCEPTIONS metadata', () => { expect( exceptionFilter.reflectCatchExceptions(new ExceptionFilter()), ).to.be.eql([CustomException]); @@ -66,7 +66,7 @@ describe('RouterExceptionFilters', () => { class InvalidFilter {} const filters = [new ExceptionFilter(), new InvalidFilter(), 'test']; - it('should returns expected exception filters metadata', () => { + it('should return expected exception filters metadata', () => { const resolved = exceptionFilter.createConcreteContext(filters as any); expect(resolved).to.have.length(1); expect(resolved[0].exceptionMetatypes).to.be.deep.equal([ diff --git a/packages/core/test/router/router-module.spec.ts b/packages/core/test/router/router-module.spec.ts new file mode 100644 index 00000000000..5b7223196a1 --- /dev/null +++ b/packages/core/test/router/router-module.spec.ts @@ -0,0 +1,50 @@ +import { expect } from 'chai'; +import { ModulesContainer, NestContainer } from '../../injector'; +import { Module } from '../../injector/module'; +import { Routes } from '../../router/interfaces'; +import { + RouterModule, + ROUTES, + targetModulesByContainer, +} from '../../router/router-module'; + +class TestModuleClass {} + +describe('RouterModule', () => { + const routes: Routes = [{ path: 'test', module: TestModuleClass }]; + + describe('register', () => { + it('should return a dynamic module with routes registered as a provider', () => { + expect(RouterModule.register(routes)).to.deep.equal({ + module: RouterModule, + providers: [ + { + provide: ROUTES, + useValue: routes, + }, + ], + }); + }); + }); + describe('when instantiated', () => { + it('should update the "targetModulesByContainer" weak map', () => { + const moduleRef = new Module(TestModuleClass, new NestContainer(null)); + const container = new ModulesContainer([ + [TestModuleClass.name, moduleRef], + ]); + + new RouterModule(container, routes); + + class NotRegisteredModuleClass {} + + new RouterModule(container, [ + { + path: 'random', + module: NotRegisteredModuleClass, + }, + ]); + + expect(targetModulesByContainer.get(container).has(moduleRef)).to.be.true; + }); + }); +}); diff --git a/packages/core/test/router/router-response-controller.spec.ts b/packages/core/test/router/router-response-controller.spec.ts index d664ff85963..7a084739c77 100644 --- a/packages/core/test/router/router-response-controller.spec.ts +++ b/packages/core/test/router/router-response-controller.spec.ts @@ -71,7 +71,7 @@ describe('RouterResponseController', () => { describe('transformToResult', () => { describe('when resultOrDeffered', () => { describe('is Promise', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect( await routerResponseController.transformToResult( @@ -82,7 +82,7 @@ describe('RouterResponseController', () => { }); describe('is Observable', () => { - it('should returns toPromise', async () => { + it('should return toPromise', async () => { const lastValue = 100; expect( await routerResponseController.transformToResult( @@ -93,7 +93,7 @@ describe('RouterResponseController', () => { }); describe('is value', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect( await routerResponseController.transformToResult(value), @@ -105,14 +105,14 @@ describe('RouterResponseController', () => { describe('getStatusByMethod', () => { describe('when RequestMethod is POST', () => { - it('should returns 201', () => { + it('should return 201', () => { expect( routerResponseController.getStatusByMethod(RequestMethod.POST), ).to.be.eql(201); }); }); describe('when RequestMethod is not POST', () => { - it('should returns 200', () => { + it('should return 200', () => { expect( routerResponseController.getStatusByMethod(RequestMethod.GET), ).to.be.eql(200); diff --git a/packages/core/test/router/utils/flat-routes.spec.ts b/packages/core/test/router/utils/flat-routes.spec.ts new file mode 100644 index 00000000000..2cd739b0727 --- /dev/null +++ b/packages/core/test/router/utils/flat-routes.spec.ts @@ -0,0 +1,88 @@ +import { Module } from '@nestjs/common'; +import { expect } from 'chai'; +import { flattenRoutePaths } from '../../../router/utils'; + +describe('flattenRoutePaths', () => { + it('should flatten all route paths', () => { + @Module({}) + class ParentModule {} + @Module({}) + class ChildModule {} + @Module({}) + class ChildChildModule {} + @Module({}) + class ChildModule2 {} + @Module({}) + class ParentChildModule {} + @Module({}) + class ChildChildModule2 {} + @Module({}) + class AuthModule {} + @Module({}) + class CatsModule {} + @Module({}) + class DogsModule {} + + @Module({}) + class AuthModule2 {} + @Module({}) + class CatsModule2 {} + @Module({}) + class CatsModule3 {} + @Module({}) + class AuthModule3 {} + const routes = [ + { + path: '/parent', + module: ParentModule, + children: [ + { + path: '/child', + module: ChildModule, + children: [ + { path: '/child2', module: ChildModule2 }, + { + path: '/parentchild', + module: ParentChildModule, + children: [ + { + path: '/childchild', + module: ChildChildModule, + children: [ + { path: '/child2child', module: ChildChildModule2 }, + ], + }, + ], + }, + ], + }, + ], + }, + { path: '/v1', children: [AuthModule, CatsModule, DogsModule] }, + { path: '/v2', children: [AuthModule2, CatsModule2] }, + { path: '/v3', children: [AuthModule3, CatsModule3] }, + ]; + const expectedRoutes = [ + { path: '/parent', module: ParentModule }, + { path: '/parent/child', module: ChildModule }, + { path: '/parent/child/child2', module: ChildModule2 }, + { path: '/parent/child/parentchild', module: ParentChildModule }, + { + path: '/parent/child/parentchild/childchild', + module: ChildChildModule, + }, + { + path: '/parent/child/parentchild/childchild/child2child', + module: ChildChildModule2, + }, + { path: '/v1', module: AuthModule }, + { path: '/v1', module: CatsModule }, + { path: '/v1', module: DogsModule }, + { path: '/v2', module: AuthModule2 }, + { path: '/v2', module: CatsModule2 }, + { path: '/v3', module: AuthModule3 }, + { path: '/v3', module: CatsModule3 }, + ]; + expect(flattenRoutePaths(routes)).to.be.eql(expectedRoutes); + }); +}); diff --git a/packages/microservices/test/container.spec.ts b/packages/microservices/test/container.spec.ts index 12799229d54..402d8813258 100644 --- a/packages/microservices/test/container.spec.ts +++ b/packages/microservices/test/container.spec.ts @@ -7,7 +7,7 @@ describe('ClientsContainer', () => { instance = new ClientsContainer(); }); describe('getAllClients', () => { - it('should returns array of clients', () => { + it('should return array of clients', () => { const clients = [1, 2, 3]; (instance as any).clients = clients; expect(instance.getAllClients()).to.be.eql(clients); diff --git a/packages/microservices/test/context/exception-filters-context.spec.ts b/packages/microservices/test/context/exception-filters-context.spec.ts index 756d15faa18..0fdec779891 100644 --- a/packages/microservices/test/context/exception-filters-context.spec.ts +++ b/packages/microservices/test/context/exception-filters-context.spec.ts @@ -30,7 +30,7 @@ describe('ExceptionFiltersContext', () => { beforeEach(() => { sinon.stub(exceptionFilter, 'createContext').returns([]); }); - it('should returns plain ExceptionHandler object', () => { + it('should return plain ExceptionHandler object', () => { const filter = exceptionFilter.create( new EmptyMetadata(), () => ({} as any), @@ -43,7 +43,7 @@ describe('ExceptionFiltersContext', () => { @UseFilters(new ExceptionFilter()) class WithMetadata {} - it('should returns ExceptionHandler object with exception filters', () => { + it('should return ExceptionHandler object with exception filters', () => { const filter = exceptionFilter.create( new WithMetadata(), () => ({} as any), diff --git a/packages/microservices/test/context/rpc-context-creator.spec.ts b/packages/microservices/test/context/rpc-context-creator.spec.ts index ff08f6377a5..6de5a5ca4c4 100644 --- a/packages/microservices/test/context/rpc-context-creator.spec.ts +++ b/packages/microservices/test/context/rpc-context-creator.spec.ts @@ -138,7 +138,7 @@ describe('RpcContextCreator', () => { }); describe('reflectCallbackParamtypes', () => { - it('should returns paramtypes array', () => { + it('should return paramtypes array', () => { const paramtypes = contextCreator.reflectCallbackParamtypes( instance, instance.test, diff --git a/packages/microservices/test/exceptions/rpc-exceptions-handler.spec.ts b/packages/microservices/test/exceptions/rpc-exceptions-handler.spec.ts index dd146952db9..9c40ca85878 100644 --- a/packages/microservices/test/exceptions/rpc-exceptions-handler.spec.ts +++ b/packages/microservices/test/exceptions/rpc-exceptions-handler.spec.ts @@ -64,7 +64,7 @@ describe('RpcExceptionsHandler', () => { beforeEach(() => { sinon.stub(handler, 'invokeCustomFilters').returns(observable$); }); - it('should returns observable', () => { + it('should return observable', () => { const result = handler.handle(new RpcException(''), null); expect(result).to.be.eql(observable$); }); @@ -82,7 +82,7 @@ describe('RpcExceptionsHandler', () => { }); describe('invokeCustomFilters', () => { describe('when filters array is empty', () => { - it('should returns identity', () => { + it('should return identity', () => { expect(handler.invokeCustomFilters(null, null)).to.be.null; }); }); @@ -107,7 +107,7 @@ describe('RpcExceptionsHandler', () => { handler.invokeCustomFilters(exception, null); expect(funcSpy.calledWith(exception)).to.be.true; }); - it('should returns stream', () => { + it('should return stream', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .not.null; }); @@ -117,7 +117,7 @@ describe('RpcExceptionsHandler', () => { handler.invokeCustomFilters(new TestException(), null); expect(funcSpy.notCalled).to.be.true; }); - it('should returns null', () => { + it('should return null', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .null; }); diff --git a/packages/microservices/test/listeners-metadata-explorer.spec.ts b/packages/microservices/test/listeners-metadata-explorer.spec.ts index c91c8b24dd3..01b63413ad5 100644 --- a/packages/microservices/test/listeners-metadata-explorer.spec.ts +++ b/packages/microservices/test/listeners-metadata-explorer.spec.ts @@ -82,7 +82,7 @@ describe('ListenerMetadataExplorer', () => { }); }); describe('scanForClientHooks', () => { - it(`should returns properties with @Client decorator`, () => { + it(`should return properties with @Client decorator`, () => { const obj = new Test(); const hooks = [...instance.scanForClientHooks(obj)]; diff --git a/packages/microservices/test/server/server.spec.ts b/packages/microservices/test/server/server.spec.ts index e515cc5fd9e..3c4b402a228 100644 --- a/packages/microservices/test/server/server.spec.ts +++ b/packages/microservices/test/server/server.spec.ts @@ -125,7 +125,7 @@ describe('Server', () => { describe('transformToObservable', () => { describe('when resultOrDeferred', () => { describe('is Promise', () => { - it('should returns Observable', async () => { + it('should return Observable', async () => { const value = 100; expect( await server @@ -135,7 +135,7 @@ describe('Server', () => { }); }); describe('is Observable', () => { - it('should returns Observable', async () => { + it('should return Observable', async () => { const value = 100; expect( await server.transformToObservable(of(value)).toPromise(), @@ -143,7 +143,7 @@ describe('Server', () => { }); }); describe('is value', () => { - it('should returns Observable', async () => { + it('should return Observable', async () => { const value = 100; expect( await server.transformToObservable(value).toPromise(), diff --git a/packages/websockets/socket-server-provider.ts b/packages/websockets/socket-server-provider.ts index c050bf8fc24..207b76061a0 100644 --- a/packages/websockets/socket-server-provider.ts +++ b/packages/websockets/socket-server-provider.ts @@ -1,6 +1,5 @@ -import { addLeadingSlash } from '@nestjs/common/utils/shared.utils'; +import { addLeadingSlash, isString } from '@nestjs/common/utils/shared.utils'; import { ApplicationConfig } from '@nestjs/core/application-config'; -import { isString } from 'util'; import { GatewayMetadata } from './interfaces/gateway-metadata.interface'; import { SocketEventsHost } from './interfaces/socket-events-host.interface'; import { SocketEventsHostFactory } from './socket-events-host-factory'; diff --git a/packages/websockets/test/context/exception-filters.context.spec.ts b/packages/websockets/test/context/exception-filters.context.spec.ts index 70e999d4cf8..ddc6ac8e402 100644 --- a/packages/websockets/test/context/exception-filters.context.spec.ts +++ b/packages/websockets/test/context/exception-filters.context.spec.ts @@ -1,9 +1,9 @@ -import * as sinon from 'sinon'; import { expect } from 'chai'; -import { UseFilters } from '../../../common/decorators/core/exception-filters.decorator'; +import * as sinon from 'sinon'; import { Catch } from '../../../common/decorators/core/catch.decorator'; -import { ExceptionFiltersContext } from '../../context/exception-filters-context'; +import { UseFilters } from '../../../common/decorators/core/exception-filters.decorator'; import { NestContainer } from '../../../core/injector/container'; +import { ExceptionFiltersContext } from '../../context/exception-filters-context'; describe('ExceptionFiltersContext', () => { let moduleName: string; @@ -25,7 +25,7 @@ describe('ExceptionFiltersContext', () => { beforeEach(() => { sinon.stub(exceptionFilter, 'createContext').returns([]); }); - it('should returns plain ExceptionHandler object', () => { + it('should return plain ExceptionHandler object', () => { const filter = exceptionFilter.create( new EmptyMetadata(), () => ({} as any), @@ -38,7 +38,7 @@ describe('ExceptionFiltersContext', () => { @UseFilters(new ExceptionFilter()) class WithMetadata {} - it('should returns ExceptionHandler object with exception filters', () => { + it('should return ExceptionHandler object with exception filters', () => { const filter = exceptionFilter.create( new WithMetadata(), () => ({} as any), diff --git a/packages/websockets/test/context/ws-context-creator.spec.ts b/packages/websockets/test/context/ws-context-creator.spec.ts index 7825f28ef14..b51a489879d 100644 --- a/packages/websockets/test/context/ws-context-creator.spec.ts +++ b/packages/websockets/test/context/ws-context-creator.spec.ts @@ -133,7 +133,7 @@ describe('WsContextCreator', () => { }); describe('reflectCallbackParamtypes', () => { - it('should returns paramtypes array', () => { + it('should return paramtypes array', () => { const paramtypes = contextCreator.reflectCallbackParamtypes( instance, instance.test, diff --git a/packages/websockets/test/exceptions/ws-exceptions-handler.spec.ts b/packages/websockets/test/exceptions/ws-exceptions-handler.spec.ts index 60af15734eb..199b092e3c5 100644 --- a/packages/websockets/test/exceptions/ws-exceptions-handler.spec.ts +++ b/packages/websockets/test/exceptions/ws-exceptions-handler.spec.ts @@ -72,7 +72,7 @@ describe('WsExceptionsHandler', () => { }); describe('invokeCustomFilters', () => { describe('when filters array is empty', () => { - it('should returns false', () => { + it('should return false', () => { expect(handler.invokeCustomFilters(null, null)).to.be.false; }); }); @@ -99,7 +99,7 @@ describe('WsExceptionsHandler', () => { handler.invokeCustomFilters(exception, res as any); expect(funcSpy.calledWith(exception, res)).to.be.true; }); - it('should returns true', () => { + it('should return true', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .true; }); @@ -109,7 +109,7 @@ describe('WsExceptionsHandler', () => { handler.invokeCustomFilters(new TestException(), null); expect(funcSpy.notCalled).to.be.true; }); - it('should returns false', () => { + it('should return false', () => { expect(handler.invokeCustomFilters(new TestException(), null)).to.be .false; }); diff --git a/packages/websockets/test/gateway-metadata-explorer.spec.ts b/packages/websockets/test/gateway-metadata-explorer.spec.ts index d869a1b3440..b495fea5f38 100644 --- a/packages/websockets/test/gateway-metadata-explorer.spec.ts +++ b/packages/websockets/test/gateway-metadata-explorer.spec.ts @@ -67,7 +67,7 @@ describe('GatewayMetadataExplorer', () => { }); }); describe('scanForServerHooks', () => { - it(`should returns properties with @Client decorator`, () => { + it(`should return properties with @Client decorator`, () => { const obj = new Test(); const servers = [...instance.scanForServerHooks(obj as any)]; diff --git a/packages/websockets/test/socket-server-provider.spec.ts b/packages/websockets/test/socket-server-provider.spec.ts index 57118c0fd0e..b3f7ffc056a 100644 --- a/packages/websockets/test/socket-server-provider.spec.ts +++ b/packages/websockets/test/socket-server-provider.spec.ts @@ -1,9 +1,9 @@ import { ApplicationConfig } from '@nestjs/core/application-config'; import { expect } from 'chai'; import * as sinon from 'sinon'; +import { AbstractWsAdapter } from '../adapters/ws-adapter'; import { SocketServerProvider } from '../socket-server-provider'; import { SocketsContainer } from '../sockets-container'; -import { AbstractWsAdapter } from '../adapters/ws-adapter'; class NoopAdapter extends AbstractWsAdapter { public create(port: number, options?: any) {} @@ -33,7 +33,7 @@ describe('SocketServerProvider', () => { afterEach(() => { mockContainer.restore(); }); - it(`should returns stored server`, () => { + it(`should return stored server`, () => { const server = { test: 'test' }; mockContainer.expects('getSocketEventsHostByPort').returns(server); diff --git a/packages/websockets/test/web-sockets-controller.spec.ts b/packages/websockets/test/web-sockets-controller.spec.ts index cda2fb08c7b..de93cacd8f9 100644 --- a/packages/websockets/test/web-sockets-controller.spec.ts +++ b/packages/websockets/test/web-sockets-controller.spec.ts @@ -245,7 +245,7 @@ describe('WebSocketsController', () => { fn(client); }); - it('should returns function', () => { + it('should return function', () => { expect( instance.getConnectionHandler(null, null, null, null, null), ).to.be.a('function'); @@ -337,7 +337,7 @@ describe('WebSocketsController', () => { describe('pickResult', () => { describe('when defferedResult contains value which', () => { describe('is a Promise', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect( await ( @@ -348,7 +348,7 @@ describe('WebSocketsController', () => { }); describe('is an Observable', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect( await ( @@ -359,7 +359,7 @@ describe('WebSocketsController', () => { }); describe('is a value', () => { - it('should returns Promise', async () => { + it('should return Promise', async () => { const value = 100; expect( await (