mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
update(@nestjs) increase test coverage, update package dependencies
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@ npm-debug.log
|
||||
# example
|
||||
/quick-start
|
||||
/example_dist
|
||||
/example
|
||||
|
||||
# tests
|
||||
/test
|
||||
|
||||
@@ -8,5 +8,4 @@ before_script:
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
script:
|
||||
- npm test
|
||||
- npm run build
|
||||
after_success: npm run coverage
|
||||
@@ -3,6 +3,6 @@ import { Guard, CanActivate } from '@nestjs/common';
|
||||
@Guard()
|
||||
export class RolesGuard implements CanActivate {
|
||||
public async canActivate() {
|
||||
return await Promise.resolve(false);
|
||||
return await Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nestjs",
|
||||
"version": "3.0.0",
|
||||
"version": "4.0.0",
|
||||
"description": "Modern, fast, powerful node.js web framework",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -48,6 +48,7 @@
|
||||
"@nestjs/testing": "*",
|
||||
"@nestjs/websockets": "*",
|
||||
"cli-color": "^1.1.0",
|
||||
"engine.io-client": "^3.1.1",
|
||||
"express": "^4.14.0",
|
||||
"iterare": "0.0.8",
|
||||
"json-socket": "^0.2.1",
|
||||
@@ -55,11 +56,12 @@
|
||||
"redis": "^2.7.1",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"rxjs": "^5.4.2",
|
||||
"socket.io": "^1.7.2",
|
||||
"socket.io": "^1.7.4",
|
||||
"typescript": "^2.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^3.4.34",
|
||||
"@types/chai": "^3.5.2",
|
||||
"@types/chai-as-promised": "0.0.31",
|
||||
"@types/express": "^4.0.35",
|
||||
"@types/mocha": "^2.2.38",
|
||||
"@types/node": "^7.0.5",
|
||||
@@ -70,6 +72,7 @@
|
||||
"awesome-typescript-loader": "^3.0.0-beta.18",
|
||||
"body-parser": "^1.17.2",
|
||||
"chai": "^3.5.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"concurrently": "^3.4.0",
|
||||
"core-js": "^2.4.1",
|
||||
"coveralls": "^2.11.16",
|
||||
|
||||
@@ -3,8 +3,8 @@ import { INestMicroservice, ExceptionFilter, PipeTransform } from './index';
|
||||
import { WebSocketAdapter } from './web-socket-adapter.interface';
|
||||
|
||||
export interface INestApplication {
|
||||
init(): void;
|
||||
listen(port: number, callback?: () => void);
|
||||
init(): Promise<void>;
|
||||
listen(port: number, callback?: () => void): Promise<any>;
|
||||
setGlobalPrefix(prefix: string): void;
|
||||
useWebSocketAdapter(adapter: WebSocketAdapter): void;
|
||||
connectMicroservice(config: MicroserviceConfiguration): INestMicroservice;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/common",
|
||||
"version": "2.0.3",
|
||||
"version": "4.0.0",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
|
||||
26
src/common/test/utils/use-guards.decorator.spec.ts
Normal file
26
src/common/test/utils/use-guards.decorator.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'reflect-metadata';
|
||||
import { expect } from 'chai';
|
||||
import { UseGuards } from '../../utils/decorators/use-guards.decorator';
|
||||
import { GUARDS_METADATA } from './../../constants';
|
||||
|
||||
describe('@UseGuards', () => {
|
||||
const guards = [ 'guard1', 'guard2' ];
|
||||
|
||||
@UseGuards(...guards as any) class Test {}
|
||||
|
||||
class TestWithMethod {
|
||||
@UseGuards(...guards as any)
|
||||
public static test() {}
|
||||
}
|
||||
|
||||
it('should enhance class with expected guards array', () => {
|
||||
const metadata = Reflect.getMetadata(GUARDS_METADATA, Test);
|
||||
expect(metadata).to.be.eql(guards);
|
||||
});
|
||||
|
||||
it('should enhance method with expected guards array', () => {
|
||||
const metadata = Reflect.getMetadata(GUARDS_METADATA, TestWithMethod.test);
|
||||
expect(metadata).to.be.eql(guards);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -4,17 +4,12 @@ import { isUndefined, isFunction, isNil, isEmpty } from '@nestjs/common/utils/sh
|
||||
import { Controller } from '@nestjs/common/interfaces';
|
||||
import { CanActivate, HttpStatus } from '@nestjs/common';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/toPromise';
|
||||
import { HttpException } from '../index';
|
||||
import { FORBIDDEN_MESSAGE } from './constants';
|
||||
import 'rxjs/add/operator/toPromise';
|
||||
|
||||
export class GuardsConsumer {
|
||||
public async tryActivate(
|
||||
guards: CanActivate[],
|
||||
data: any,
|
||||
instance: Controller,
|
||||
callback: (...args) => any): Promise<boolean> {
|
||||
|
||||
public async tryActivate(guards: CanActivate[], data, instance: Controller, callback: (...args) => any): Promise<boolean> {
|
||||
if (!guards || isEmpty(guards)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ export class Injector {
|
||||
|
||||
const instances = await Promise.all(args.map(async (param) => {
|
||||
const paramWrapper = await this.resolveSingleParam<T>(wrapper, param, module, context);
|
||||
if (paramWrapper.isExported && !paramWrapper.isResolved) {
|
||||
if (!paramWrapper.isResolved) {
|
||||
isResolved = false;
|
||||
}
|
||||
return paramWrapper.instance;
|
||||
@@ -142,7 +142,7 @@ export class Injector {
|
||||
const components = module.components;
|
||||
const instanceWrapper = await this.scanForComponent(components, name, module, wrapper, context);
|
||||
|
||||
if (!instanceWrapper.isResolved && !instanceWrapper.isExported) {
|
||||
if (!instanceWrapper.isResolved) {
|
||||
await this.loadInstanceOfComponent(instanceWrapper, module);
|
||||
}
|
||||
if (instanceWrapper.async) {
|
||||
@@ -162,18 +162,10 @@ export class Injector {
|
||||
|
||||
public async scanForComponentInExports(components: Map<string, any>, name: any, module: Module, metatype, context: Module[] = []) {
|
||||
const instanceWrapper = await this.scanForComponentInRelatedModules(module, name, context);
|
||||
if (!isNil(instanceWrapper)) {
|
||||
return instanceWrapper;
|
||||
}
|
||||
const { exports } = module;
|
||||
if (!exports.has(metatype.name)) {
|
||||
if (isNil(instanceWrapper)) {
|
||||
throw new UnknownDependenciesException(metatype.name);
|
||||
}
|
||||
return {
|
||||
instance: null,
|
||||
isResolved: false,
|
||||
isExported: true,
|
||||
};
|
||||
return instanceWrapper;
|
||||
}
|
||||
|
||||
public async scanForComponentInScopes(context: Module[], name: any, metatype) {
|
||||
|
||||
@@ -19,8 +19,10 @@ export class ModuleTokenFactory {
|
||||
public getScopeStack(scope: NestModuleMetatype[]): string[] {
|
||||
const reversedScope = scope.reverse();
|
||||
const firstGlobalIndex = reversedScope.findIndex((s) => this.reflectScope(s) === 'global');
|
||||
const scopeStack = scope.reverse().slice(scope.length - firstGlobalIndex - 1);
|
||||
return scopeStack.map((module) => module.name);
|
||||
scope.reverse();
|
||||
const stack = firstGlobalIndex >= 0 ?
|
||||
scope.slice(scope.length - firstGlobalIndex - 1) : scope;
|
||||
return stack.map((module) => module.name);
|
||||
}
|
||||
|
||||
private reflectScope(metatype: NestModuleMetatype) {
|
||||
|
||||
@@ -88,6 +88,10 @@ export class Module {
|
||||
}
|
||||
|
||||
public addInjectable(injectable: Metatype<Injectable>) {
|
||||
if (this.isCustomProvider(injectable)) {
|
||||
this.addCustomProvider(injectable, this._injectables);
|
||||
return;
|
||||
}
|
||||
this._injectables.set(injectable.name, {
|
||||
name: injectable.name,
|
||||
metatype: injectable,
|
||||
@@ -97,8 +101,8 @@ export class Module {
|
||||
}
|
||||
|
||||
public addComponent(component: ComponentMetatype) {
|
||||
if (this.isCustomComponent(component)) {
|
||||
this.addCustomComponent(component);
|
||||
if (this.isCustomProvider(component)) {
|
||||
this.addCustomProvider(component, this._components);
|
||||
return;
|
||||
}
|
||||
this._components.set((component as Metatype<Injectable>).name, {
|
||||
@@ -109,11 +113,11 @@ export class Module {
|
||||
});
|
||||
}
|
||||
|
||||
public isCustomComponent(component: ComponentMetatype): component is CustomClass | CustomFactory | CustomValue {
|
||||
public isCustomProvider(component: ComponentMetatype): component is CustomClass | CustomFactory | CustomValue {
|
||||
return !isNil((component as CustomComponent).provide);
|
||||
}
|
||||
|
||||
public addCustomComponent(component: CustomFactory | CustomValue | CustomClass) {
|
||||
public addCustomProvider(component: CustomFactory | CustomValue | CustomClass, collection: Map<string, any>) {
|
||||
const { provide } = component;
|
||||
const name = isFunction(provide) ? provide.name : provide;
|
||||
const comp = {
|
||||
@@ -121,9 +125,9 @@ export class Module {
|
||||
name,
|
||||
};
|
||||
|
||||
if (this.isCustomClass(comp)) this.addCustomClass(comp);
|
||||
else if (this.isCustomValue(comp)) this.addCustomValue(comp);
|
||||
else if (this.isCustomFactory(comp)) this.addCustomFactory(comp);
|
||||
if (this.isCustomClass(comp)) this.addCustomClass(comp, collection);
|
||||
else if (this.isCustomValue(comp)) this.addCustomValue(comp, collection);
|
||||
else if (this.isCustomFactory(comp)) this.addCustomFactory(comp, collection);
|
||||
}
|
||||
|
||||
public isCustomClass(component): component is CustomClass {
|
||||
@@ -138,9 +142,9 @@ export class Module {
|
||||
return !isUndefined((component as CustomFactory).useFactory);
|
||||
}
|
||||
|
||||
public addCustomClass(component: CustomClass) {
|
||||
public addCustomClass(component: CustomClass, collection: Map<string, any>) {
|
||||
const { provide, name, useClass } = component;
|
||||
this._components.set(name, {
|
||||
collection.set(name, {
|
||||
name,
|
||||
metatype: useClass,
|
||||
instance: null,
|
||||
@@ -148,9 +152,9 @@ export class Module {
|
||||
});
|
||||
}
|
||||
|
||||
public addCustomValue(component: CustomValue) {
|
||||
public addCustomValue(component: CustomValue, collection: Map<string, any>) {
|
||||
const { provide, name, useValue: value } = component;
|
||||
this._components.set(name, {
|
||||
collection.set(name, {
|
||||
name,
|
||||
metatype: null,
|
||||
instance: value,
|
||||
@@ -160,9 +164,9 @@ export class Module {
|
||||
});
|
||||
}
|
||||
|
||||
public addCustomFactory(component: CustomFactory) {
|
||||
public addCustomFactory(component: CustomFactory, collection: Map<string, any>) {
|
||||
const { provide, name, useFactory: factory, inject } = component;
|
||||
this._components.set(name, {
|
||||
collection.set(name, {
|
||||
name,
|
||||
metatype: factory as any,
|
||||
instance: null,
|
||||
@@ -173,7 +177,7 @@ export class Module {
|
||||
}
|
||||
|
||||
public addExportedComponent(exportedComponent: ComponentMetatype) {
|
||||
if (this.isCustomComponent(exportedComponent)) {
|
||||
if (this.isCustomProvider(exportedComponent)) {
|
||||
this.addCustomExportedComponent(exportedComponent);
|
||||
return;
|
||||
}
|
||||
@@ -201,7 +205,10 @@ export class Module {
|
||||
}
|
||||
|
||||
public replace(toReplace, options) {
|
||||
this.addComponent({
|
||||
if (options.isComponent) {
|
||||
return this.addComponent({ provide: toReplace, ...options });
|
||||
}
|
||||
this.addInjectable({
|
||||
provide: toReplace,
|
||||
...options,
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Metatype, MiddlewaresConsumer } from '@nestjs/common/interfaces';
|
||||
import { MiddlewareConfigProxy } from '@nestjs/common/interfaces/middlewares';
|
||||
import { RoutesMapper } from './routes-mapper';
|
||||
import { NestMiddleware } from '@nestjs/common';
|
||||
import { filterMiddlewares } from './utils';
|
||||
|
||||
export class MiddlewareBuilder implements MiddlewaresConsumer {
|
||||
private readonly middlewaresCollection = new Set<MiddlewareConfiguration>();
|
||||
@@ -54,10 +55,10 @@ export class MiddlewareBuilder implements MiddlewaresConsumer {
|
||||
private readonly builder: MiddlewareBuilder,
|
||||
middlewares,
|
||||
) {
|
||||
this.includedRoutes = this.filterMiddlewares(middlewares);
|
||||
this.includedRoutes = filterMiddlewares(middlewares);
|
||||
}
|
||||
|
||||
public with(...args): this {
|
||||
public with(...args): MiddlewareConfigProxy {
|
||||
this.contextArgs = args;
|
||||
return this;
|
||||
}
|
||||
@@ -81,28 +82,5 @@ export class MiddlewareBuilder implements MiddlewaresConsumer {
|
||||
private mapRoutesToFlatList(forRoutes) {
|
||||
return forRoutes.reduce((a, b) => a.concat(b));
|
||||
}
|
||||
|
||||
private filterMiddlewares(middlewares) {
|
||||
return [].concat(middlewares)
|
||||
.filter(isFunction)
|
||||
.map((middleware) => {
|
||||
if (this.isClass(middleware)) {
|
||||
return middleware;
|
||||
}
|
||||
return AssignToken(class {
|
||||
public resolve = (...args) => (req, res, next) => middleware(req, res, next);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private isClass(middleware) {
|
||||
return middleware.toString().substring(0, 5) === 'class';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const AssignToken = (metatype): Metatype<any> => {
|
||||
this.id = this.id || 1;
|
||||
Object.defineProperty(metatype, 'name', { value: ++this.id });
|
||||
return metatype;
|
||||
};
|
||||
}
|
||||
27
src/core/middlewares/utils.ts
Normal file
27
src/core/middlewares/utils.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import { Metatype } from '@nestjs/common/interfaces';
|
||||
|
||||
export const filterMiddlewares = (middlewares) => {
|
||||
return [].concat(middlewares)
|
||||
.filter(isFunction)
|
||||
.map((middleware) => mapToClass(middleware));
|
||||
};
|
||||
|
||||
export const mapToClass = (middleware) => {
|
||||
if (this.isClass(middleware)) {
|
||||
return middleware;
|
||||
}
|
||||
return assignToken(class {
|
||||
public resolve = (...args) => (req, res, next) => middleware(req, res, next);
|
||||
});
|
||||
};
|
||||
|
||||
export const isClass = (middleware) => {
|
||||
return middleware.toString().substring(0, 5) === 'class';
|
||||
};
|
||||
|
||||
export const assignToken = (metatype): Metatype<any> => {
|
||||
this.id = this.id || 1;
|
||||
Object.defineProperty(metatype, 'name', { value: ++this.id });
|
||||
return metatype;
|
||||
};
|
||||
@@ -43,11 +43,16 @@ export class NestFactory {
|
||||
}
|
||||
|
||||
private static async initialize(module) {
|
||||
this.logger.log(messages.APPLICATION_START);
|
||||
await ExceptionsZone.asyncRun(async () => {
|
||||
this.dependenciesScanner.scan(module);
|
||||
await this.instanceLoader.createInstancesOfDependencies();
|
||||
});
|
||||
try {
|
||||
this.logger.log(messages.APPLICATION_START);
|
||||
await ExceptionsZone.asyncRun(async () => {
|
||||
this.dependenciesScanner.scan(module);
|
||||
await this.instanceLoader.createInstancesOfDependencies();
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
process.abort();
|
||||
}
|
||||
}
|
||||
|
||||
private static createProxy(target) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/core",
|
||||
"version": "2.0.5",
|
||||
"version": "4.0.0",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@core)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -12,10 +12,10 @@
|
||||
"iterare": "0.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "~2.*",
|
||||
"@nestjs/websockets": "~2.*",
|
||||
"@nestjs/microservices": "~2.*",
|
||||
"@nestjs/common": "~4.*",
|
||||
"@nestjs/websockets": "~4.*",
|
||||
"@nestjs/microservices": "~4.*",
|
||||
"reflect-metadata": "0.1.10",
|
||||
"rxjs": "^5.0.3"
|
||||
"rxjs": "^5.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,28 @@ describe('ApplicationConfig', () => {
|
||||
expect(appConfig.getGlobalPrefix()).to.be.eql('');
|
||||
});
|
||||
});
|
||||
describe('IOAdapter', () => {
|
||||
it('should set io adapter', () => {
|
||||
const ioAdapter = { test: 0 };
|
||||
appConfig.setIoAdapter(ioAdapter as any);
|
||||
|
||||
expect(appConfig.getIoAdapter()).to.be.eql(ioAdapter);
|
||||
});
|
||||
});
|
||||
describe('Pipes', () => {
|
||||
it('should set global pipes', () => {
|
||||
const pipes = ['test', 'test2'];
|
||||
appConfig.useGlobalPipes(...pipes as any);
|
||||
|
||||
expect(appConfig.getGlobalPipes()).to.be.eql(pipes);
|
||||
});
|
||||
});
|
||||
describe('Filters', () => {
|
||||
it('should set global filters', () => {
|
||||
const filters = ['test', 'test2'];
|
||||
appConfig.useGlobalFilters(...filters as any);
|
||||
|
||||
expect(appConfig.getGlobalFilters()).to.be.eql(filters);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -32,7 +32,7 @@ describe('ExceptionsHandler', () => {
|
||||
handler.next(new Error(), response);
|
||||
|
||||
expect(statusStub.calledWith(500)).to.be.true;
|
||||
expect(jsonStub.calledWith({ message: 'Unknown exception' })).to.be.true;
|
||||
expect(jsonStub.calledWith({ statusCode: 500, message: 'Unknown exception' })).to.be.true;
|
||||
});
|
||||
describe('when exception is instance of HttpException', () => {
|
||||
it('should method send expected response status code and json object', () => {
|
||||
@@ -52,7 +52,7 @@ describe('ExceptionsHandler', () => {
|
||||
handler.next(new HttpException(message, status), response);
|
||||
|
||||
expect(statusStub.calledWith(status)).to.be.true;
|
||||
expect(jsonStub.calledWith({ message })).to.be.true;
|
||||
expect(jsonStub.calledWith({ message, statusCode: status })).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when "invokeCustomFilters" returns true', () => {
|
||||
|
||||
51
src/core/test/guards/guards-consumer.spec.ts
Normal file
51
src/core/test/guards/guards-consumer.spec.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { GuardsConsumer } from './../../guards/guards-consumer';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
describe('GuardsConsumer', () => {
|
||||
let consumer: GuardsConsumer;
|
||||
let guards: any[];
|
||||
beforeEach(() => {
|
||||
consumer = new GuardsConsumer();
|
||||
guards = [{ canActivate: () => true }, { canActivate: () => true }];
|
||||
});
|
||||
describe('tryActivate', () => {
|
||||
describe('when guards array is empty', () => {
|
||||
it('should return true', async () => {
|
||||
const canActivate = await consumer.tryActivate([], {}, null, null);
|
||||
expect(canActivate).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when guards array is not empty', () => {
|
||||
describe('when at least on guard returns false', () => {
|
||||
it('should return false', async () => {
|
||||
const canActivate = await consumer.tryActivate([
|
||||
...guards,
|
||||
{ canActivate: () => false },
|
||||
], {}, null, null);
|
||||
expect(canActivate).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('when each guard returns true', () => {
|
||||
it('should return true', async () => {
|
||||
const canActivate = await consumer.tryActivate(guards, {}, null, null);
|
||||
expect(canActivate).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('pickResult', () => {
|
||||
describe('when result is Observable', () => {
|
||||
it('should returns promise', () => {
|
||||
expect(consumer.pickResult(Observable.of(true))).to.eventually.instanceOf(Promise);
|
||||
});
|
||||
});
|
||||
describe('when result is Promise', () => {
|
||||
it('should await promise', async () => {
|
||||
expect(await consumer.pickResult(Promise.resolve(true))).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
61
src/core/test/guards/guards-context-creator.spec.ts
Normal file
61
src/core/test/guards/guards-context-creator.spec.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { GuardsContextCreator } from '../../guards/guards-context-creator';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
describe('GuardsContextCreator', () => {
|
||||
let guardsContextCreator: GuardsContextCreator;
|
||||
let guards: any[];
|
||||
let container;
|
||||
let getSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
guards = [
|
||||
{
|
||||
name: 'test',
|
||||
instance: {
|
||||
canActivate: () => true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
instance: {
|
||||
canActivate: () => true,
|
||||
},
|
||||
},
|
||||
{},
|
||||
undefined,
|
||||
];
|
||||
getSpy = sinon.stub().returns({
|
||||
injectables: new Map([
|
||||
['test', guards[0]],
|
||||
['test2', guards[1]],
|
||||
]),
|
||||
});
|
||||
container = {
|
||||
getModules: () => ({
|
||||
get: getSpy,
|
||||
}),
|
||||
};
|
||||
guardsContextCreator = new GuardsContextCreator(container as any);
|
||||
});
|
||||
describe('createConcreteContext', () => {
|
||||
describe('when `moduleContext` is nil', () => {
|
||||
it('should returns empty array', () => {
|
||||
const result = guardsContextCreator.createConcreteContext(guards);
|
||||
expect(result).to.be.empty;
|
||||
});
|
||||
});
|
||||
describe('when `moduleContext` is defined', () => {
|
||||
beforeEach(() => {
|
||||
// tslint:disable-next-line:no-string-literal
|
||||
guardsContextCreator['moduleContext'] = 'test';
|
||||
});
|
||||
it('should filter metatypes', () => {
|
||||
expect(
|
||||
guardsContextCreator.createConcreteContext(guards),
|
||||
).to.have.length(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -37,4 +37,16 @@ describe('NestContainer', () => {
|
||||
expect(() => container.addExportedComponent(null, 'TestModule')).throw(UnknownModuleException);
|
||||
});
|
||||
|
||||
it('should "addInjectable" throw "UnknownModuleException" when module is not stored in collection', () => {
|
||||
expect(() => container.addInjectable(null, 'TestModule')).throw(UnknownModuleException);
|
||||
});
|
||||
|
||||
describe('clear', () => {
|
||||
it('should call `clear` on modules collection', () => {
|
||||
const clearSpy = sinon.spy((container as any).modules, 'clear');
|
||||
container.clear();
|
||||
expect(clearSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -6,6 +6,9 @@ import { Component } from '../../../common/utils/decorators/component.decorator'
|
||||
import { RuntimeException } from '../../errors/exceptions/runtime.exception';
|
||||
import { Module } from '../../injector/module';
|
||||
import { UnknownDependenciesException } from '../../errors/exceptions/unknown-dependencies.exception';
|
||||
import * as chai from 'chai';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
describe('Injector', () => {
|
||||
let injector: Injector;
|
||||
@@ -57,25 +60,25 @@ describe('Injector', () => {
|
||||
moduleDeps.components.set('DependencyTwo', depTwo);
|
||||
});
|
||||
|
||||
it('should create an instance of component with proper dependencies', () => {
|
||||
injector.loadInstance(mainTest, moduleDeps.components, moduleDeps);
|
||||
it('should create an instance of component with proper dependencies', async () => {
|
||||
await injector.loadInstance(mainTest, moduleDeps.components, moduleDeps);
|
||||
const { instance } = moduleDeps.components.get('MainTest') as InstanceWrapper<MainTest>;
|
||||
|
||||
expect(instance.depOne instanceof DependencyOne).to.be.true;
|
||||
expect(instance.depTwo instanceof DependencyOne).to.be.true;
|
||||
expect(instance instanceof MainTest).to.be.true;
|
||||
expect(instance.depOne).instanceof(DependencyOne);
|
||||
expect(instance.depTwo).instanceof(DependencyOne);
|
||||
expect(instance).instanceof(MainTest);
|
||||
});
|
||||
|
||||
it('should set "isResolved" property to true after instance initialization', () => {
|
||||
injector.loadInstance(mainTest, moduleDeps.components, moduleDeps);
|
||||
it('should set "isResolved" property to true after instance initialization', async () => {
|
||||
await injector.loadInstance(mainTest, moduleDeps.components, moduleDeps);
|
||||
const { isResolved } = moduleDeps.components.get('MainTest') as InstanceWrapper<MainTest>;
|
||||
expect(isResolved).to.be.true;
|
||||
});
|
||||
|
||||
it('should throw RuntimeException when type is not stored in collection', () => {
|
||||
expect(
|
||||
injector.loadInstance.bind(injector, 'Test', moduleDeps.components, moduleDeps),
|
||||
).to.throw(RuntimeException);
|
||||
return expect(
|
||||
injector.loadInstance({} as any, moduleDeps.components, moduleDeps),
|
||||
).to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
});
|
||||
@@ -112,8 +115,10 @@ describe('Injector', () => {
|
||||
});
|
||||
|
||||
describe('resolveSingleParam', () => {
|
||||
it('should throw "RuntimeException" when param is undefined', () => {
|
||||
expect(() => injector.resolveSingleParam(null, undefined, null, [])).throws(RuntimeException);
|
||||
it('should throw "RuntimeException" when param is undefined', async () => {
|
||||
return expect(
|
||||
injector.resolveSingleParam(null, undefined, null, []),
|
||||
).to.eventually.be.rejected;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -159,22 +164,22 @@ describe('Injector', () => {
|
||||
(injector as any).scanForComponentInRelatedModules = scanForComponentInRelatedModules;
|
||||
});
|
||||
|
||||
it('should return object from collection if exists', () => {
|
||||
it('should return object from collection if exists', async () => {
|
||||
const instance = { test: 3 };
|
||||
const collection = {
|
||||
has: () => true,
|
||||
get: () => instance,
|
||||
};
|
||||
const result = injector.scanForComponent(collection as any, metatype.name, null, metatype);
|
||||
const result = await injector.scanForComponent(collection as any, metatype.name, null, metatype);
|
||||
expect(result).to.be.equal(instance);
|
||||
});
|
||||
|
||||
it('should call "scanForComponentInRelatedModules" when object is not in collection', () => {
|
||||
it('should call "scanForComponentInRelatedModules" when object is not in collection', async () => {
|
||||
scanForComponentInRelatedModules.returns({});
|
||||
const collection = {
|
||||
has: () => false,
|
||||
};
|
||||
injector.scanForComponent(collection as any, metatype.name, null, metatype);
|
||||
await injector.scanForComponent(collection as any, metatype.name, null, metatype);
|
||||
expect(scanForComponentInRelatedModules.called).to.be.true;
|
||||
});
|
||||
|
||||
@@ -185,8 +190,8 @@ describe('Injector', () => {
|
||||
};
|
||||
const module = { exports: collection };
|
||||
expect(
|
||||
() => injector.scanForComponent(collection as any, metatype.name, module as any, { metatype }),
|
||||
).throws(UnknownDependenciesException);
|
||||
injector.scanForComponent(collection as any, metatype.name, module as any, { metatype }),
|
||||
).to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
it('should not throw "UnknownDependenciesException" instanceWrapper is not null', () => {
|
||||
@@ -196,8 +201,8 @@ describe('Injector', () => {
|
||||
};
|
||||
const module = { exports: collection };
|
||||
expect(
|
||||
() => injector.scanForComponent(collection as any, metatype.name, module as any, metatype),
|
||||
).not.throws(UnknownDependenciesException);
|
||||
injector.scanForComponent(collection as any, metatype.name, module as any, metatype),
|
||||
).to.eventually.be.not.rejected;
|
||||
});
|
||||
|
||||
});
|
||||
@@ -206,7 +211,7 @@ describe('Injector', () => {
|
||||
let loadInstanceOfComponent: sinon.SinonSpy;
|
||||
const metatype = { name: 'test' };
|
||||
const module = {
|
||||
relatedModules: [],
|
||||
relatedModules: new Map(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -214,40 +219,44 @@ describe('Injector', () => {
|
||||
(injector as any).loadInstanceOfComponent = loadInstanceOfComponent;
|
||||
});
|
||||
|
||||
it('should return null when there is no related modules', () => {
|
||||
const result = injector.scanForComponentInRelatedModules(module as any, null, []);
|
||||
it('should return null when there is no related modules', async () => {
|
||||
const result = await injector.scanForComponentInRelatedModules(module as any, null, []);
|
||||
expect(result).to.be.eq(null);
|
||||
});
|
||||
|
||||
it('should return null when related modules do not have appropriate component', () => {
|
||||
let module = {
|
||||
relatedModules: [{
|
||||
relatedModules: new Map([['key', {
|
||||
components: {
|
||||
has: () => false,
|
||||
},
|
||||
exports: {
|
||||
has: () => true,
|
||||
},
|
||||
}],
|
||||
}]] as any),
|
||||
};
|
||||
expect(injector.scanForComponentInRelatedModules(module as any, metatype as any, [])).to.be.eq(null);
|
||||
expect(
|
||||
injector.scanForComponentInRelatedModules(module as any, metatype as any, []),
|
||||
).to.be.eventually.eq(null);
|
||||
|
||||
module = {
|
||||
relatedModules: [{
|
||||
relatedModules: new Map([['key', {
|
||||
components: {
|
||||
has: () => true,
|
||||
},
|
||||
exports: {
|
||||
has: () => false,
|
||||
},
|
||||
}],
|
||||
}]] as any),
|
||||
};
|
||||
expect(injector.scanForComponentInRelatedModules(module as any, metatype as any, [])).to.be.eq(null);
|
||||
expect(
|
||||
injector.scanForComponentInRelatedModules(module as any, metatype as any, []),
|
||||
).to.eventually.be.eq(null);
|
||||
});
|
||||
|
||||
it('should call "loadInstanceOfComponent" when component is not resolved', () => {
|
||||
it('should call "loadInstanceOfComponent" when component is not resolved', async () => {
|
||||
let module = {
|
||||
relatedModules: [{
|
||||
relatedModules: new Map([['key', {
|
||||
components: {
|
||||
has: () => true,
|
||||
get: () => ({
|
||||
@@ -257,15 +266,15 @@ describe('Injector', () => {
|
||||
exports: {
|
||||
has: () => true,
|
||||
},
|
||||
}],
|
||||
}]] as any),
|
||||
};
|
||||
injector.scanForComponentInRelatedModules(module as any, metatype as any, []);
|
||||
await injector.scanForComponentInRelatedModules(module as any, metatype as any, []);
|
||||
expect(loadInstanceOfComponent.called).to.be.true;
|
||||
});
|
||||
|
||||
it('should not call "loadInstanceOfComponent" when component is resolved', () => {
|
||||
it('should not call "loadInstanceOfComponent" when component is resolved', async () => {
|
||||
let module = {
|
||||
relatedModules: [{
|
||||
relatedModules: new Map([['key', {
|
||||
components: {
|
||||
has: () => true,
|
||||
get: () => ({
|
||||
@@ -275,9 +284,9 @@ describe('Injector', () => {
|
||||
exports: {
|
||||
has: () => true,
|
||||
},
|
||||
}],
|
||||
}]] as any),
|
||||
};
|
||||
injector.scanForComponentInRelatedModules(module as any, metatype as any, []);
|
||||
await injector.scanForComponentInRelatedModules(module as any, metatype as any, []);
|
||||
expect(loadInstanceOfComponent.called).to.be.false;
|
||||
});
|
||||
|
||||
@@ -285,19 +294,19 @@ describe('Injector', () => {
|
||||
|
||||
describe('scanForComponentInScopes', () => {
|
||||
it('should returns null when component is not available in any scope', () => {
|
||||
expect(injector.scanForComponentInScopes([], '', {})).to.be.null;
|
||||
expect(injector.scanForComponentInScopes([], '', {})).to.eventually.be.null;
|
||||
});
|
||||
it('should returns wrapper when component is available in any scope', () => {
|
||||
const component = 'test';
|
||||
sinon.stub(injector, 'scanForComponentInScope').returns(component);
|
||||
expect(injector.scanForComponentInScopes([{}] as any, '', {})).to.be.eql(component);
|
||||
expect(injector.scanForComponentInScopes([{}] as any, '', {})).to.eventually.be.eql(component);
|
||||
});
|
||||
});
|
||||
|
||||
describe('scanForComponentInScope', () => {
|
||||
it('should returns null when scope throws exception', () => {
|
||||
sinon.stub(injector, 'scanForComponent').throws('exception');
|
||||
expect(injector.scanForComponentInScope({} as any, '', {})).to.be.null;
|
||||
expect(injector.scanForComponentInScope({} as any, '', {})).to.eventually.be.null;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -27,13 +27,14 @@ describe('InstanceLoader', () => {
|
||||
mockContainer = sinon.mock(container);
|
||||
});
|
||||
|
||||
it('should call "loadPrototypeOfInstance" for each component and route in each module', () => {
|
||||
it('should call "loadPrototypeOfInstance" for each component and route in each module', async () => {
|
||||
const injector = new Injector();
|
||||
(loader as any).injector = injector;
|
||||
|
||||
const module = {
|
||||
components: new Map(),
|
||||
routes: new Map(),
|
||||
injectables: new Map(),
|
||||
metatype: { name: 'test' },
|
||||
};
|
||||
const componentWrapper = { instance: null, metatype: TestComponent };
|
||||
@@ -51,18 +52,19 @@ describe('InstanceLoader', () => {
|
||||
sinon.stub(injector, 'loadInstanceOfRoute');
|
||||
sinon.stub(injector, 'loadInstanceOfComponent');
|
||||
|
||||
loader.createInstancesOfDependencies();
|
||||
await loader.createInstancesOfDependencies();
|
||||
expect(loadComponentPrototypeStub.calledWith(componentWrapper, module.components)).to.be.true;
|
||||
expect(loadComponentPrototypeStub.calledWith(routeWrapper, module.components)).to.be.true;
|
||||
});
|
||||
|
||||
it('should call "loadInstanceOfComponent" for each component in each module', () => {
|
||||
it('should call "loadInstanceOfComponent" for each component in each module', async () => {
|
||||
const injector = new Injector();
|
||||
(loader as any).injector = injector;
|
||||
|
||||
const module = {
|
||||
components: new Map(),
|
||||
routes: new Map(),
|
||||
injectables: new Map(),
|
||||
metatype: { name: 'test' },
|
||||
};
|
||||
const testComp = { instance: null, metatype: TestComponent, name: 'TestComponent' };
|
||||
@@ -76,17 +78,18 @@ describe('InstanceLoader', () => {
|
||||
const loadComponentStub = sinon.stub(injector, 'loadInstanceOfComponent');
|
||||
sinon.stub(injector, 'loadInstanceOfRoute');
|
||||
|
||||
loader.createInstancesOfDependencies();
|
||||
await loader.createInstancesOfDependencies();
|
||||
expect(loadComponentStub.calledWith(module.components.get('TestComponent'), module)).to.be.true;
|
||||
});
|
||||
|
||||
it('should call "loadInstanceOfRoute" for each route in each module', () => {
|
||||
it('should call "loadInstanceOfRoute" for each route in each module', async () => {
|
||||
const injector = new Injector();
|
||||
(loader as any).injector = injector;
|
||||
|
||||
const module = {
|
||||
components: new Map(),
|
||||
routes: new Map(),
|
||||
injectables: new Map(),
|
||||
metatype: { name: 'test' },
|
||||
};
|
||||
const wrapper = { name: 'TestRoute', instance: null, metatype: TestRoute };
|
||||
@@ -99,7 +102,7 @@ describe('InstanceLoader', () => {
|
||||
sinon.stub(injector, 'loadInstanceOfComponent');
|
||||
const loadRoutesStub = sinon.stub(injector, 'loadInstanceOfRoute');
|
||||
|
||||
loader.createInstancesOfDependencies();
|
||||
await loader.createInstancesOfDependencies();
|
||||
expect(loadRoutesStub.calledWith(module.routes.get('TestRoute'), module)).to.be.true;
|
||||
});
|
||||
|
||||
|
||||
@@ -37,6 +37,29 @@ describe('Module', () => {
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should add injectable', () => {
|
||||
const collection = new Map();
|
||||
const setSpy = sinon.spy(collection, 'set');
|
||||
(module as any)._injectables = collection;
|
||||
|
||||
module.addInjectable(TestComponent);
|
||||
expect(setSpy.getCall(0).args).to.deep.equal([ 'TestComponent', {
|
||||
name: 'TestComponent',
|
||||
metatype: TestComponent,
|
||||
instance: null,
|
||||
isResolved: false,
|
||||
}]);
|
||||
});
|
||||
|
||||
describe('when injectable is custom provided', () => {
|
||||
it('should call `addCustomProvider`', () => {
|
||||
const addCustomProviderSpy = sinon.spy(module, 'addCustomProvider');
|
||||
|
||||
module.addInjectable({ provide: 'test' } as any);
|
||||
expect(addCustomProviderSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
it('should add component', () => {
|
||||
const collection = new Map();
|
||||
const setSpy = sinon.spy(collection, 'set');
|
||||
@@ -51,14 +74,14 @@ describe('Module', () => {
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should call "addCustomComponent" when "provide" property exists', () => {
|
||||
const addCustomComponent = sinon.spy();
|
||||
module.addCustomComponent = addCustomComponent;
|
||||
it('should call "addCustomProvider" when "provide" property exists', () => {
|
||||
const addCustomProvider = sinon.spy();
|
||||
module.addCustomProvider = addCustomProvider;
|
||||
|
||||
const provider = { provide: 'test', useValue: 'test' };
|
||||
|
||||
module.addComponent(provider as any);
|
||||
expect((addCustomComponent as sinon.SinonSpy).called).to.be.true;
|
||||
expect((addCustomProvider as sinon.SinonSpy).called).to.be.true;
|
||||
});
|
||||
|
||||
it('should call "addCustomClass" when "useClass" property exists', () => {
|
||||
@@ -67,7 +90,7 @@ describe('Module', () => {
|
||||
|
||||
const provider = { provide: 'test', useClass: () => null };
|
||||
|
||||
module.addCustomComponent(provider as any);
|
||||
module.addCustomProvider(provider as any, new Map());
|
||||
expect((addCustomClass as sinon.SinonSpy).called).to.be.true;
|
||||
});
|
||||
|
||||
@@ -77,7 +100,7 @@ describe('Module', () => {
|
||||
|
||||
const provider = { provide: 'test', useValue: () => null };
|
||||
|
||||
module.addCustomComponent(provider as any);
|
||||
module.addCustomProvider(provider as any, new Map());
|
||||
expect((addCustomValue as sinon.SinonSpy).called).to.be.true;
|
||||
});
|
||||
|
||||
@@ -87,7 +110,7 @@ describe('Module', () => {
|
||||
|
||||
const provider = { provide: 'test', useFactory: () => null };
|
||||
|
||||
module.addCustomComponent(provider as any);
|
||||
module.addCustomProvider(provider as any, new Map());
|
||||
expect((addCustomFactory as sinon.SinonSpy).called).to.be.true;
|
||||
});
|
||||
|
||||
@@ -101,7 +124,7 @@ describe('Module', () => {
|
||||
(module as any)._components = collection;
|
||||
});
|
||||
it('should store component', () => {
|
||||
module.addCustomClass(component as any);
|
||||
module.addCustomClass(component as any, (module as any)._components);
|
||||
expect(setSpy.calledWith(component.name, {
|
||||
name: component.name,
|
||||
metatype: type,
|
||||
@@ -124,13 +147,14 @@ describe('Module', () => {
|
||||
});
|
||||
|
||||
it('should store component', () => {
|
||||
module.addCustomValue(component as any);
|
||||
module.addCustomValue(component as any, (module as any)._components);
|
||||
expect(setSpy.calledWith(name, {
|
||||
name,
|
||||
metatype: null,
|
||||
instance: value,
|
||||
isResolved: true,
|
||||
isNotMetatype: true,
|
||||
async: false,
|
||||
})).to.be.true;
|
||||
});
|
||||
});
|
||||
@@ -147,7 +171,7 @@ describe('Module', () => {
|
||||
(module as any)._components = collection;
|
||||
});
|
||||
it('should store component', () => {
|
||||
module.addCustomFactory(component as any);
|
||||
module.addCustomFactory(component as any, (module as any)._components);
|
||||
expect(setSpy.getCall(0).args).to.deep.equal([component.name, {
|
||||
name: component.name,
|
||||
metatype: type,
|
||||
@@ -175,4 +199,30 @@ describe('Module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when exported component is custom provided', () => {
|
||||
it('should call `addCustomExportedComponent`', () => {
|
||||
const addCustomExportedComponentSpy = sinon.spy(module, 'addCustomExportedComponent');
|
||||
|
||||
module.addExportedComponent({ provide: 'test' } as any);
|
||||
expect(addCustomExportedComponentSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('replace', () => {
|
||||
describe('when component', () => {
|
||||
it('should call `addComponent`', () => {
|
||||
const addComponentSpy = sinon.spy(module, 'addComponent');
|
||||
module.replace(null, { isComponent: true });
|
||||
expect(addComponentSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when guard', () => {
|
||||
it('should call `addInjectable`', () => {
|
||||
const addInjectableSpy = sinon.spy(module, 'addInjectable');
|
||||
module.replace(null, {});
|
||||
expect(addInjectableSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -61,15 +61,15 @@ describe('MiddlewaresModule', () => {
|
||||
const route = { path: 'Test' };
|
||||
const configuration = {
|
||||
middlewares: [ TestMiddleware ],
|
||||
forRoutes: [ TestRoute ]
|
||||
forRoutes: [ TestRoute ],
|
||||
};
|
||||
|
||||
const useSpy = sinon.spy();
|
||||
const app = { use: useSpy };
|
||||
|
||||
expect(MiddlewaresModule.setupRouteMiddleware.bind(
|
||||
MiddlewaresModule, route, configuration, 'Test' as any, app as any,
|
||||
)).throws(RuntimeException);
|
||||
expect(
|
||||
MiddlewaresModule.setupRouteMiddleware(route as any, configuration, 'Test' as any, app as any),
|
||||
).to.eventually.be.rejectedWith(RuntimeException);
|
||||
});
|
||||
|
||||
it('should throw "InvalidMiddlewareException" exception when middlewares does not have "resolve" method', () => {
|
||||
@@ -95,9 +95,9 @@ describe('MiddlewaresModule', () => {
|
||||
instance,
|
||||
} as any);
|
||||
|
||||
expect(MiddlewaresModule.setupRouteMiddleware.bind(
|
||||
MiddlewaresModule, route, configuration, moduleKey, app as any,
|
||||
)).throws(InvalidMiddlewareException);
|
||||
expect(
|
||||
MiddlewaresModule.setupRouteMiddleware(route as any, configuration, moduleKey, app as any),
|
||||
).to.be.rejectedWith(InvalidMiddlewareException);
|
||||
});
|
||||
|
||||
it('should store middlewares when middleware is stored in container', () => {
|
||||
|
||||
63
src/core/test/middlewares/utils.spec.ts
Normal file
63
src/core/test/middlewares/utils.spec.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { filterMiddlewares, mapToClass, isClass, assignToken } from '../../middlewares/utils';
|
||||
|
||||
describe('middleware utils', () => {
|
||||
class Test {}
|
||||
function fnMiddleware(req, res, next) {}
|
||||
|
||||
describe('filterMiddlewares', () => {
|
||||
let middlewares: any[];
|
||||
beforeEach(() => {
|
||||
middlewares = [Test, fnMiddleware, undefined, null];
|
||||
});
|
||||
it('should returns filtered middlewares', () => {
|
||||
expect(
|
||||
filterMiddlewares(middlewares),
|
||||
).to.have.length(2);
|
||||
});
|
||||
});
|
||||
describe('mapToClass', () => {
|
||||
describe('when middleware is a class', () => {
|
||||
it('should returns identity', () => {
|
||||
const type = mapToClass(Test);
|
||||
expect(type).to.eql(Test);
|
||||
});
|
||||
});
|
||||
describe('when middleware is a function', () => {
|
||||
it('should returns metatype', () => {
|
||||
const metatype = mapToClass(fnMiddleware);
|
||||
expect(metatype).to.not.eql(fnMiddleware);
|
||||
});
|
||||
it('should define `resolve` method', () => {
|
||||
const metatype = mapToClass(fnMiddleware);
|
||||
expect(new metatype().resolve).to.exist;
|
||||
});
|
||||
it('should encapsulate function', () => {
|
||||
const spy = sinon.spy();
|
||||
const metatype = mapToClass(spy);
|
||||
new metatype().resolve()();
|
||||
expect(spy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('isClass', () => {
|
||||
describe('when middleware is a class', () => {
|
||||
it('should returns true', () => {
|
||||
expect(isClass(Test)).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when middleware is a function', () => {
|
||||
it('should returns false', () => {
|
||||
expect(isClass(fnMiddleware)).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('assignToken', () => {
|
||||
describe('should define `name` property on metatype', () => {
|
||||
const anonymousType = class {};
|
||||
assignToken(anonymousType);
|
||||
expect(anonymousType.name).to.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -41,16 +41,6 @@ describe('RouterExceptionFilters', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
/*describe('reflectExceptionFilters', () => {
|
||||
const filters = [ ExceptionFilter ];
|
||||
@ExceptionFilters(...filters as any)
|
||||
class WithMetadata {}
|
||||
it('should returns EXCEPTION_FILTERS_METADATA metadata', () => {
|
||||
expect(
|
||||
exceptionFilter.reflectExceptionFilters(new WithMetadata()),
|
||||
).to.be.eql(filters);
|
||||
});
|
||||
});*/
|
||||
describe('reflectCatchExceptions', () => {
|
||||
it('should returns FILTER_CATCH_EXCEPTIONS metadata', () => {
|
||||
expect(
|
||||
|
||||
@@ -7,6 +7,9 @@ import { RouteParamsFactory } from '../../router/route-params-factory';
|
||||
import { PipesContextCreator } from '../../pipes/pipes-context-creator';
|
||||
import { PipesConsumer } from '../../pipes/pipes-consumer';
|
||||
import { ApplicationConfig } from '../../application-config';
|
||||
import { GuardsConsumer } from '../../guards/guards-consumer';
|
||||
import { GuardsContextCreator } from '../../guards/guards-context-creator';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
|
||||
describe('RouterExecutionContext', () => {
|
||||
let contextCreator: RouterExecutionContext;
|
||||
@@ -29,13 +32,14 @@ describe('RouterExecutionContext', () => {
|
||||
|
||||
contextCreator = new RouterExecutionContext(
|
||||
factory, new PipesContextCreator(new ApplicationConfig()), consumer,
|
||||
new GuardsContextCreator(new NestContainer()), new GuardsConsumer(),
|
||||
);
|
||||
});
|
||||
describe('create', () => {
|
||||
describe('when callback metadata is undefined', () => {
|
||||
it('should only bind instance as an context', () => {
|
||||
const instance = {};
|
||||
contextCreator.create(instance, callback as any);
|
||||
contextCreator.create(instance, callback as any, '');
|
||||
expect(bindSpy.calledWith(instance)).to.be.true;
|
||||
});
|
||||
});
|
||||
@@ -58,7 +62,7 @@ describe('RouterExecutionContext', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
instance = { foo: 'bar' };
|
||||
proxyContext = contextCreator.create(instance, callback as any);
|
||||
proxyContext = contextCreator.create(instance, callback as any, '');
|
||||
});
|
||||
it('should be a function', () => {
|
||||
expect(proxyContext).to.be.a('function');
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('RouterExplorer', () => {
|
||||
{ path: 'test', requestMethod: RequestMethod.GET },
|
||||
];
|
||||
|
||||
routerBuilder.applyPathsToRouterProxy(null, paths as any, null);
|
||||
routerBuilder.applyPathsToRouterProxy(null, paths as any, null, '');
|
||||
|
||||
expect(bindStub.calledWith(null, paths[0], null)).to.be.true;
|
||||
expect(bindStub.callCount).to.be.eql(paths.length);
|
||||
|
||||
@@ -45,4 +45,35 @@ describe('RouterProxy', () => {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('createExceptionLayerProxy', () => {
|
||||
|
||||
it('should method return thunk', () => {
|
||||
const proxy = routerProxy.createExceptionLayerProxy(() => {}, handler);
|
||||
expect(typeof proxy === 'function').to.be.true;
|
||||
});
|
||||
|
||||
it('should method encapsulate callback passed as argument', () => {
|
||||
const expectation = handlerMock.expects('next').once();
|
||||
const proxy = routerProxy.createExceptionLayerProxy((err, req, res, next) => {
|
||||
throw new HttpException('test', 500);
|
||||
}, handler);
|
||||
proxy(null, null, null, null);
|
||||
expectation.verify();
|
||||
});
|
||||
|
||||
it('should method encapsulate async callback passed as argument', (done) => {
|
||||
const expectation = handlerMock.expects('next').once();
|
||||
const proxy = routerProxy.createExceptionLayerProxy(async (err, req, res, next) => {
|
||||
throw new HttpException('test', 500);
|
||||
}, handler);
|
||||
proxy(null, null, null, null);
|
||||
|
||||
setTimeout(() => {
|
||||
expectation.verify();
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -33,7 +33,7 @@ describe('RoutesResolver', () => {
|
||||
});
|
||||
|
||||
describe('setupRouters', () => {
|
||||
it('should method setup controllers to express application instance', () => {
|
||||
it('should method setup controllers to router instance', () => {
|
||||
const routes = new Map();
|
||||
routes.set('TestRoute', {
|
||||
instance: new TestRoute(),
|
||||
@@ -41,10 +41,7 @@ describe('RoutesResolver', () => {
|
||||
});
|
||||
|
||||
const use = sinon.spy();
|
||||
const applicationMock = { use };
|
||||
|
||||
routesResolver.setupRouters(routes, '', applicationMock as any);
|
||||
expect(use.calledOnce).to.be.true;
|
||||
routesResolver.setupRouters(routes, '', { use } as any);
|
||||
expect(use.calledWith('/global', router)).to.be.true;
|
||||
});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Module } from '../../common/utils/decorators/module.decorator';
|
||||
import { NestModule } from '../../common/interfaces/modules/nest-module.interface';
|
||||
import { Component } from '../../common/utils/decorators/component.decorator';
|
||||
import { Controller } from '../../common/utils/decorators/controller.decorator';
|
||||
import { MetadataScanner } from '../metadata-scanner';
|
||||
|
||||
describe('DependenciesScanner', () => {
|
||||
|
||||
@@ -35,7 +36,7 @@ describe('DependenciesScanner', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
scanner = new DependenciesScanner(container);
|
||||
scanner = new DependenciesScanner(container, new MetadataScanner());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -28,8 +28,8 @@ export class RpcContextCreator {
|
||||
const exceptionHandler = this.exceptionFiltersContext.create(instance, callback);
|
||||
const pipes = this.pipesCreator.create(instance, callback);
|
||||
const guards = this.guardsContextCreator.create(instance, callback, module);
|
||||
|
||||
const metatype = this.getDataMetatype(instance, callback);
|
||||
|
||||
return this.rpcProxy.create(async (data) => {
|
||||
const canActivate = await this.guardsConsumer.tryActivate(guards, data, instance, callback);
|
||||
if (!canActivate) {
|
||||
|
||||
@@ -16,10 +16,8 @@ export class RpcExceptionsHandler {
|
||||
}
|
||||
const status = 'error';
|
||||
if (!(exception instanceof RpcException)) {
|
||||
return Observable.throw({
|
||||
status,
|
||||
message: messages.UNKNOWN_EXCEPTION_MESSAGE,
|
||||
});
|
||||
const message = messages.UNKNOWN_EXCEPTION_MESSAGE;
|
||||
return Observable.throw({ status, message });
|
||||
}
|
||||
const res = exception.getError();
|
||||
const message = isObject(res) ? res : ({ status, message: res });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/microservices",
|
||||
"version": "2.0.5",
|
||||
"version": "4.0.0",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@microservices)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -10,12 +10,12 @@
|
||||
"dependencies": {
|
||||
"json-socket": "^0.2.1",
|
||||
"iterare": "0.0.8",
|
||||
"redis": "^2.6.5"
|
||||
"redis": "^2.7.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "~2.*",
|
||||
"@nestjs/core": "~2.*",
|
||||
"@nestjs/common": "~4.*",
|
||||
"@nestjs/core": "~4.*",
|
||||
"reflect-metadata": "0.1.10",
|
||||
"rxjs": "^5.0.3"
|
||||
"rxjs": "^5.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Subscription } from 'rxjs/Subscription';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import 'rxjs/add/operator/finally';
|
||||
import 'rxjs/add/observable/empty';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
export abstract class Server {
|
||||
protected readonly messageHandlers: MessageHandlers = {};
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { ExceptionFilters } from '../../../common/utils/decorators/exception-filters.decorator';
|
||||
import { Catch } from '../../../common/utils/decorators/catch.decorator';
|
||||
import { ExceptionFiltersContext } from './../../context/exception-filters-context';
|
||||
|
||||
describe('ExceptionFiltersContext', () => {
|
||||
let moduleName: string;
|
||||
let exceptionFilter: ExceptionFiltersContext;
|
||||
|
||||
class CustomException {}
|
||||
@Catch(CustomException)
|
||||
class ExceptionFilter {
|
||||
public catch(exc, res) {}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
moduleName = 'Test';
|
||||
exceptionFilter = new ExceptionFiltersContext();
|
||||
});
|
||||
describe('create', () => {
|
||||
describe('when filters metadata is empty', () => {
|
||||
class EmptyMetadata {}
|
||||
beforeEach(() => {
|
||||
sinon.stub(exceptionFilter, 'createContext').returns([]);
|
||||
});
|
||||
it('should returns plain ExceptionHandler object', () => {
|
||||
const filter = exceptionFilter.create(new EmptyMetadata(), () => ({}) as any);
|
||||
expect((filter as any).filters).to.be.empty;
|
||||
});
|
||||
});
|
||||
describe('when filters metadata is not empty', () => {
|
||||
@ExceptionFilters(new ExceptionFilter())
|
||||
class WithMetadata {}
|
||||
|
||||
it('should returns ExceptionHandler object with exception filters', () => {
|
||||
const filter = exceptionFilter.create(new WithMetadata(), () => ({}) as any);
|
||||
expect((filter as any).filters).to.not.be.empty;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
131
src/microservices/test/context/rpc-context-creator.spec.ts
Normal file
131
src/microservices/test/context/rpc-context-creator.spec.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { Guard, Pipe, UseGuards, Component, UsePipes } from './../../../common';
|
||||
import { RpcProxy } from './../../context/rpc-proxy';
|
||||
import { RpcContextCreator } from './../../context/rpc-context-creator';
|
||||
import { RpcExceptionsHandler } from '../../exceptions/rpc-exceptions-handler';
|
||||
import { ExceptionFiltersContext } from './../../context/exception-filters-context';
|
||||
import { PipesContextCreator } from '../../../core/pipes/pipes-context-creator';
|
||||
import { PipesConsumer } from '../../../core/pipes/pipes-consumer';
|
||||
import { PARAMTYPES_METADATA } from '../../../common/constants';
|
||||
import { GuardsContextCreator } from '../../../core/guards/guards-context-creator';
|
||||
import { GuardsConsumer } from '../../../core/guards/guards-consumer';
|
||||
import { NestContainer } from '../../../core/injector/container';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
import { RpcException } from '../../index';
|
||||
|
||||
@Guard()
|
||||
class TestGuard { canActivate: () => true; }
|
||||
|
||||
@Pipe()
|
||||
class TestPipe {
|
||||
transform(val) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
describe('RpcContextCreator', () => {
|
||||
let contextCreator: RpcContextCreator;
|
||||
let rpcProxy: RpcProxy;
|
||||
let exceptionFiltersContext: ExceptionFiltersContext;
|
||||
let pipesCreator: PipesContextCreator;
|
||||
let pipesConsumer: PipesConsumer;
|
||||
let guardsContextCreator: GuardsContextCreator;
|
||||
let guardsConsumer: GuardsConsumer;
|
||||
let instance: Test;
|
||||
let module: string;
|
||||
|
||||
@UseGuards(TestGuard)
|
||||
@Component()
|
||||
class Test {
|
||||
@UsePipes(new TestPipe())
|
||||
test(data: string) {
|
||||
return Observable.of(false);
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
rpcProxy = new RpcProxy();
|
||||
exceptionFiltersContext = new ExceptionFiltersContext();
|
||||
pipesCreator = new PipesContextCreator();
|
||||
pipesConsumer = new PipesConsumer();
|
||||
guardsContextCreator = new GuardsContextCreator(new NestContainer());
|
||||
guardsConsumer = new GuardsConsumer();
|
||||
contextCreator = new RpcContextCreator(
|
||||
rpcProxy, exceptionFiltersContext, pipesCreator as any,
|
||||
pipesConsumer as any, guardsContextCreator as any, guardsConsumer as any,
|
||||
);
|
||||
|
||||
instance = new Test();
|
||||
module = 'test';
|
||||
});
|
||||
describe('create', () => {
|
||||
it('should create exception handler', () => {
|
||||
const handlerCreateSpy = sinon.spy(exceptionFiltersContext, 'create');
|
||||
contextCreator.create(instance, instance.test, module);
|
||||
expect(handlerCreateSpy.calledWith(instance, instance.test)).to.be.true;
|
||||
});
|
||||
it('should create pipes context', () => {
|
||||
const pipesCreateSpy = sinon.spy(pipesCreator, 'create');
|
||||
contextCreator.create(instance, instance.test, module);
|
||||
expect(pipesCreateSpy.calledWith(instance, instance.test)).to.be.true;
|
||||
});
|
||||
it('should create guards context', () => {
|
||||
const guardsCreateSpy = sinon.spy(guardsContextCreator, 'create');
|
||||
contextCreator.create(instance, instance.test, module);
|
||||
expect(guardsCreateSpy.calledWith(instance, instance.test, module)).to.be.true;
|
||||
});
|
||||
describe('when proxy called', () => {
|
||||
it('should call guards consumer `tryActivate`', async () => {
|
||||
const tryActivateSpy = sinon.spy(guardsConsumer, 'tryActivate');
|
||||
const proxy = await contextCreator.create(instance, instance.test, module);
|
||||
const data = 'test';
|
||||
await proxy(data);
|
||||
|
||||
expect(tryActivateSpy.called).to.be.true;
|
||||
});
|
||||
describe('when can activate', () => {
|
||||
it('should call pipes consumer `applyPipes`', async () => {
|
||||
const applyPipesSpy = sinon.spy(pipesConsumer, 'applyPipes');
|
||||
const proxy = await contextCreator.create(instance, instance.test, module);
|
||||
const data = 'test';
|
||||
await proxy(data);
|
||||
|
||||
expect(applyPipesSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when can not activate', () => {
|
||||
it('should throws forbidden exception', async () => {
|
||||
const tryActivateStub = sinon.stub(guardsConsumer, 'tryActivate').returns(false);
|
||||
const proxy = await contextCreator.create(instance, instance.test, module);
|
||||
const data = 'test';
|
||||
|
||||
expect(proxy(data)).to.eventually.rejectedWith(RpcException);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reflectCallbackParamtypes', () => {
|
||||
it('should returns paramtypes array', () => {
|
||||
const paramtypes = contextCreator.reflectCallbackParamtypes(instance, instance.test);
|
||||
expect(paramtypes).to.be.eql([String]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDataMetatype', () => {
|
||||
describe('when paramtypes are reflected', () => {
|
||||
it('should returns data paramtype', () => {
|
||||
const type = contextCreator.getDataMetatype(instance, instance.test);
|
||||
expect(type).to.be.eql(String);
|
||||
});
|
||||
});
|
||||
describe('when paramtypes are not reflected', () => {
|
||||
it('should returns null', () => {
|
||||
const type = contextCreator.getDataMetatype(instance, () => ({}));
|
||||
expect(type).to.be.null;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
37
src/microservices/test/context/rpc-proxy.spec.ts
Normal file
37
src/microservices/test/context/rpc-proxy.spec.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { RpcProxy } from './../../context/rpc-proxy';
|
||||
import { RpcExceptionsHandler } from './../../exceptions/rpc-exceptions-handler';
|
||||
import { RpcException } from '../../exceptions/rpc-exception';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
describe('RpcProxy', () => {
|
||||
let routerProxy: RpcProxy;
|
||||
let handlerMock: sinon.SinonMock;
|
||||
let handler: RpcExceptionsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
handler = new RpcExceptionsHandler();
|
||||
handlerMock = sinon.mock(handler);
|
||||
routerProxy = new RpcProxy();
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
|
||||
it('should method return thunk', async () => {
|
||||
const proxy = await routerProxy.create(async (data) => Observable.of(true), handler);
|
||||
expect(typeof proxy === 'function').to.be.true;
|
||||
});
|
||||
|
||||
it('should method encapsulate callback passed as argument', async () => {
|
||||
const expectation = handlerMock.expects('handle').once();
|
||||
const proxy = routerProxy.create(async (data) => {
|
||||
throw new RpcException('test');
|
||||
}, handler);
|
||||
await proxy(null);
|
||||
expectation.verify();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
14
src/microservices/test/exceptions/rpc-exception.spec.ts
Normal file
14
src/microservices/test/exceptions/rpc-exception.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { RpcException } from '../../exceptions/rpc-exception';
|
||||
|
||||
describe('RpcException', () => {
|
||||
let instance: RpcException;
|
||||
const error = 'test';
|
||||
beforeEach(() => {
|
||||
instance = new RpcException(error);
|
||||
});
|
||||
it('should returns error message or object', () => {
|
||||
expect(instance.getError()).to.be.eql(error);
|
||||
});
|
||||
});
|
||||
115
src/microservices/test/exceptions/rpc-exceptions-handler.spec.ts
Normal file
115
src/microservices/test/exceptions/rpc-exceptions-handler.spec.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { RpcExceptionsHandler } from './../../exceptions/rpc-exceptions-handler';
|
||||
import { RpcException } from './../../exceptions/rpc-exception';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
import 'rxjs/add/observable/empty';
|
||||
|
||||
describe('RpcExceptionsHandler', () => {
|
||||
let handler: RpcExceptionsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
handler = new RpcExceptionsHandler();
|
||||
});
|
||||
|
||||
describe('handle', () => {
|
||||
it('should method returns expected stream with message when exception is unknown', (done) => {
|
||||
const stream$ = handler.handle(new Error());
|
||||
stream$.catch((err) => {
|
||||
expect(err).to.be.eql({ status: 'error', message: 'Unknown exception' });
|
||||
done();
|
||||
return Observable.empty();
|
||||
}).subscribe(() => ({}));
|
||||
});
|
||||
describe('when exception is instance of WsException', () => {
|
||||
it('should method emit expected status and json object', (done) => {
|
||||
const message = {
|
||||
custom: 'Unauthorized',
|
||||
};
|
||||
const stream$ = handler.handle(new RpcException(message));
|
||||
stream$.catch((err) => {
|
||||
expect(err).to.be.eql(message);
|
||||
done();
|
||||
return Observable.empty();
|
||||
}).subscribe(() => ({}));
|
||||
});
|
||||
it('should method emit expected status and transform message to json', (done) => {
|
||||
const message = 'Unauthorized';
|
||||
|
||||
const stream$ = handler.handle(new RpcException(message));
|
||||
stream$.catch((err) => {
|
||||
expect(err).to.be.eql({ message, status: 'error' });
|
||||
done();
|
||||
return Observable.empty();
|
||||
}).subscribe(() => ({}));
|
||||
});
|
||||
});
|
||||
describe('when "invokeCustomFilters" returns observable', () => {
|
||||
const observable$ = Observable.of(true);
|
||||
beforeEach(() => {
|
||||
sinon.stub(handler, 'invokeCustomFilters').returns(observable$);
|
||||
});
|
||||
it('should returns observable', () => {
|
||||
const result = handler.handle(new RpcException(''));
|
||||
expect(result).to.be.eql(observable$);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('setCustomFilters', () => {
|
||||
const filters = [ 'test', 'test2' ];
|
||||
it('should set custom filters', () => {
|
||||
handler.setCustomFilters(filters as any);
|
||||
expect((handler as any).filters).to.be.eql(filters);
|
||||
});
|
||||
it('should throws exception when passed argument is not an array', () => {
|
||||
expect(
|
||||
() => handler.setCustomFilters(null),
|
||||
).to.throw;
|
||||
});
|
||||
});
|
||||
describe('invokeCustomFilters', () => {
|
||||
describe('when filters array is empty', () => {
|
||||
it('should returns identity', () => {
|
||||
expect(handler.invokeCustomFilters(null)).to.be.null;
|
||||
});
|
||||
});
|
||||
describe('when filters array is not empty', () => {
|
||||
let filters, funcSpy;
|
||||
class TestException {}
|
||||
|
||||
beforeEach(() => {
|
||||
funcSpy = sinon.spy();
|
||||
});
|
||||
describe('when filter exists in filters array', () => {
|
||||
beforeEach(() => {
|
||||
filters = [
|
||||
{ exceptionMetatypes: [ TestException ], func: funcSpy },
|
||||
];
|
||||
(handler as any).filters = filters;
|
||||
});
|
||||
it('should call funcSpy', () => {
|
||||
handler.invokeCustomFilters(new TestException());
|
||||
expect(funcSpy.notCalled).to.be.false;
|
||||
});
|
||||
it('should call funcSpy with exception and response passed as an arguments', () => {
|
||||
const exception = new TestException();
|
||||
handler.invokeCustomFilters(exception);
|
||||
expect(funcSpy.calledWith(exception)).to.be.true;
|
||||
});
|
||||
it('should returns stream', () => {
|
||||
expect(handler.invokeCustomFilters(new TestException())).to.be.not.null;
|
||||
});
|
||||
});
|
||||
describe('when filter does not exists in filters array', () => {
|
||||
it('should not call funcSpy', () => {
|
||||
handler.invokeCustomFilters(new TestException());
|
||||
expect(funcSpy.notCalled).to.be.true;
|
||||
});
|
||||
it('should returns null', () => {
|
||||
expect(handler.invokeCustomFilters(new TestException())).to.be.null;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import { ListenersController } from '../listeners-controller';
|
||||
import { ListenerMetadataExplorer } from '../listener-metadata-explorer';
|
||||
import { MetadataScanner } from '../../core/metadata-scanner';
|
||||
import { ClientsContainer } from '../container';
|
||||
import { RpcContextCreator } from '../context/rpc-context-creator';
|
||||
|
||||
describe('ListenersController', () => {
|
||||
let instance: ListenersController,
|
||||
@@ -17,7 +18,7 @@ describe('ListenersController', () => {
|
||||
explorer = sinon.mock(metadataExplorer);
|
||||
});
|
||||
beforeEach(() => {
|
||||
instance = new ListenersController(new ClientsContainer());
|
||||
instance = new ListenersController(new ClientsContainer(), sinon.createStubInstance(RpcContextCreator) as any);
|
||||
(instance as any).metadataExplorer = metadataExplorer;
|
||||
addSpy = sinon.spy();
|
||||
server = {
|
||||
@@ -31,11 +32,8 @@ describe('ListenersController', () => {
|
||||
{ pattern: 'test2', targetCallback: '2' },
|
||||
];
|
||||
explorer.expects('explore').returns(handlers);
|
||||
instance.bindPatternHandlers(null, server);
|
||||
|
||||
instance.bindPatternHandlers(null, server, '');
|
||||
expect(addSpy.calledTwice).to.be.true;
|
||||
expect(addSpy.calledWith(handlers[0].pattern, handlers[0].targetCallback)).to.be.true;
|
||||
expect(addSpy.calledWith(handlers[1].pattern, handlers[1].targetCallback)).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -95,7 +95,7 @@ describe('ServerRedis', () => {
|
||||
});
|
||||
it(`should publish NO_PATTERN_MESSAGE if pattern not exists in messageHandlers object`, () => {
|
||||
server.handleMessage(channel, {}, null);
|
||||
expect(getPublisherSpy.calledWith({ err: NO_PATTERN_MESSAGE })).to.be.true;
|
||||
expect(getPublisherSpy.calledWith({ status: 'error', error: NO_PATTERN_MESSAGE })).to.be.true;
|
||||
});
|
||||
it(`should call handler with expected arguments`, () => {
|
||||
const handler = sinon.spy();
|
||||
|
||||
@@ -54,7 +54,7 @@ describe('ServerTCP', () => {
|
||||
});
|
||||
it('should send NO_PATTERN_MESSAGE error if key is not exists in handlers object', () => {
|
||||
server.handleMessage(socket, msg);
|
||||
expect(socket.sendMessage.calledWith({ err: NO_PATTERN_MESSAGE })).to.be.true;
|
||||
expect(socket.sendMessage.calledWith({ status: 'error', error: NO_PATTERN_MESSAGE })).to.be.true;
|
||||
});
|
||||
it('should call handler if exists in handlers object', () => {
|
||||
const handler = sinon.spy();
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Client } from './../../utils/client.decorator';
|
||||
describe('@Client', () => {
|
||||
const pattern = { role: 'test' };
|
||||
class TestComponent {
|
||||
@Client(pattern)
|
||||
@Client(pattern as any)
|
||||
public static instance;
|
||||
}
|
||||
it(`should enhance property with metadata`, () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/testing",
|
||||
"version": "2.0.3",
|
||||
"version": "4.0.0",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@testing)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -8,7 +8,8 @@
|
||||
"compile": "tsc -p tsconfig.json"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "~2.*",
|
||||
"@nestjs/core": "~2.*"
|
||||
"@nestjs/common": "~4.*",
|
||||
"@nestjs/core": "~4.*",
|
||||
"@nestjs/microservices": "~4.*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,12 @@ export class TestingModuleBuilder {
|
||||
this.scanner.scan(this.module);
|
||||
}
|
||||
|
||||
public overrideGuard(typeOrToken): OverrideBy {
|
||||
return this.override(typeOrToken, false);
|
||||
}
|
||||
|
||||
public overrideComponent(typeOrToken): OverrideBy {
|
||||
const addOverload = (options) => {
|
||||
this.overloadsMap.set(typeOrToken, {
|
||||
...options,
|
||||
});
|
||||
return this;
|
||||
};
|
||||
return this.createOverrideByBuilder(addOverload);
|
||||
return this.override(typeOrToken, true);
|
||||
}
|
||||
|
||||
public async compile(): Promise<TestingModule> {
|
||||
@@ -47,6 +45,17 @@ export class TestingModuleBuilder {
|
||||
return new TestingModule(this.container, [], root);
|
||||
}
|
||||
|
||||
private override(typeOrToken, isComponent: boolean): OverrideBy {
|
||||
const addOverload = (options) => {
|
||||
this.overloadsMap.set(typeOrToken, {
|
||||
...options,
|
||||
isComponent,
|
||||
});
|
||||
return this;
|
||||
};
|
||||
return this.createOverrideByBuilder(addOverload);
|
||||
}
|
||||
|
||||
private createOverrideByBuilder(add: (provider) => TestingModuleBuilder): OverrideBy {
|
||||
return {
|
||||
useValue: (value) => add({ useValue: value }),
|
||||
|
||||
@@ -6,6 +6,9 @@ import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import { ModuleTokenFactory } from '@nestjs/core/injector/module-token-factory';
|
||||
import { NestModuleMetatype } from '@nestjs/common/interfaces/modules/module-metatype.interface';
|
||||
import { UnknownModuleException } from './errors/unknown-module.exception';
|
||||
import { NestApplication, NestMicroservice } from '@nestjs/core';
|
||||
import { INestApplication, INestMicroservice } from '@nestjs/common';
|
||||
import { MicroserviceConfiguration } from '@nestjs/microservices';
|
||||
|
||||
export class TestingModule {
|
||||
private readonly moduleTokenFactory = new ModuleTokenFactory();
|
||||
@@ -15,6 +18,14 @@ export class TestingModule {
|
||||
private readonly scope: NestModuleMetatype[],
|
||||
private readonly contextModule) {}
|
||||
|
||||
public createNestApplication(express?): INestApplication {
|
||||
return new NestApplication(this.container, express);
|
||||
}
|
||||
|
||||
public createNestMicroservice(config: MicroserviceConfiguration): INestMicroservice {
|
||||
return new NestMicroservice(this.container, config);
|
||||
}
|
||||
|
||||
public select<T>(module: Metatype<T>): TestingModule {
|
||||
const modules = this.container.getModules();
|
||||
const moduleMetatype = this.contextModule.metatype;
|
||||
|
||||
@@ -13,18 +13,15 @@ export class WsExceptionsHandler {
|
||||
|
||||
const status = 'error';
|
||||
if (!(exception instanceof WsException)) {
|
||||
client.emit('exception', {
|
||||
status,
|
||||
message: messages.UNKNOWN_EXCEPTION_MESSAGE,
|
||||
});
|
||||
return;
|
||||
const message = messages.UNKNOWN_EXCEPTION_MESSAGE;
|
||||
return client.emit('exception', { status, message });
|
||||
}
|
||||
const res = exception.getError();
|
||||
const message = isObject(res) ? res : ({
|
||||
const result = exception.getError();
|
||||
const message = isObject(result) ? result : ({
|
||||
status,
|
||||
message: res,
|
||||
message: result,
|
||||
});
|
||||
client.emit('exception', { status, message });
|
||||
client.emit('exception', message);
|
||||
}
|
||||
|
||||
public setCustomFilters(filters: ExceptionFilterMetadata[]) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/websockets",
|
||||
"version": "2.0.3",
|
||||
"version": "4.0.0",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@websockets)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -12,9 +12,9 @@
|
||||
"socket.io": "^1.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "~2.*",
|
||||
"@nestjs/core": "~2.*",
|
||||
"@nestjs/common": "~4.*",
|
||||
"@nestjs/core": "~4.*",
|
||||
"reflect-metadata": "0.1.10",
|
||||
"rxjs": "^5.0.3"
|
||||
"rxjs": "^5.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { ExceptionFilters } from '../../../common/utils/decorators/exception-filters.decorator';
|
||||
import { Catch } from '../../../common/utils/decorators/catch.decorator';
|
||||
import { ExceptionFiltersContext } from './../../context/exception-filters-context';
|
||||
|
||||
describe('ExceptionFiltersContext', () => {
|
||||
let moduleName: string;
|
||||
let exceptionFilter: ExceptionFiltersContext;
|
||||
|
||||
class CustomException {}
|
||||
@Catch(CustomException)
|
||||
class ExceptionFilter {
|
||||
public catch(exc, res) {}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
moduleName = 'Test';
|
||||
exceptionFilter = new ExceptionFiltersContext();
|
||||
});
|
||||
describe('create', () => {
|
||||
describe('when filters metadata is empty', () => {
|
||||
class EmptyMetadata {}
|
||||
beforeEach(() => {
|
||||
sinon.stub(exceptionFilter, 'createContext').returns([]);
|
||||
});
|
||||
it('should returns plain ExceptionHandler object', () => {
|
||||
const filter = exceptionFilter.create(new EmptyMetadata(), () => ({}) as any);
|
||||
expect((filter as any).filters).to.be.empty;
|
||||
});
|
||||
});
|
||||
describe('when filters metadata is not empty', () => {
|
||||
@ExceptionFilters(new ExceptionFilter())
|
||||
class WithMetadata {}
|
||||
|
||||
it('should returns ExceptionHandler object with exception filters', () => {
|
||||
const filter = exceptionFilter.create(new WithMetadata(), () => ({}) as any);
|
||||
expect((filter as any).filters).to.not.be.empty;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
131
src/websockets/test/context/ws-context-creator.spec.ts
Normal file
131
src/websockets/test/context/ws-context-creator.spec.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { Guard, Pipe, UseGuards, Component, UsePipes } from './../../../common';
|
||||
import { WsProxy } from './../../context/ws-proxy';
|
||||
import { WsContextCreator } from './../../context/ws-context-creator';
|
||||
import { WsExceptionsHandler } from '../../exceptions/ws-exceptions-handler';
|
||||
import { ExceptionFiltersContext } from './../../context/exception-filters-context';
|
||||
import { PipesContextCreator } from '../../../core/pipes/pipes-context-creator';
|
||||
import { PipesConsumer } from '../../../core/pipes/pipes-consumer';
|
||||
import { PARAMTYPES_METADATA } from '../../../common/constants';
|
||||
import { GuardsContextCreator } from '../../../core/guards/guards-context-creator';
|
||||
import { GuardsConsumer } from '../../../core/guards/guards-consumer';
|
||||
import { NestContainer } from '../../../core/injector/container';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
import { WsException } from '../../index';
|
||||
|
||||
@Guard()
|
||||
class TestGuard { canActivate: () => true; }
|
||||
|
||||
@Pipe()
|
||||
class TestPipe {
|
||||
transform(val) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
describe('WsContextCreator', () => {
|
||||
let contextCreator: WsContextCreator;
|
||||
let wsProxy: WsProxy;
|
||||
let exceptionFiltersContext: ExceptionFiltersContext;
|
||||
let pipesCreator: PipesContextCreator;
|
||||
let pipesConsumer: PipesConsumer;
|
||||
let guardsContextCreator: GuardsContextCreator;
|
||||
let guardsConsumer: GuardsConsumer;
|
||||
let instance: Test;
|
||||
let module: string;
|
||||
|
||||
@UseGuards(TestGuard)
|
||||
@Component()
|
||||
class Test {
|
||||
@UsePipes(new TestPipe())
|
||||
test(client: string, data: number) {
|
||||
return Observable.of(false);
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
wsProxy = new WsProxy();
|
||||
exceptionFiltersContext = new ExceptionFiltersContext();
|
||||
pipesCreator = new PipesContextCreator();
|
||||
pipesConsumer = new PipesConsumer();
|
||||
guardsContextCreator = new GuardsContextCreator(new NestContainer());
|
||||
guardsConsumer = new GuardsConsumer();
|
||||
contextCreator = new WsContextCreator(
|
||||
wsProxy, exceptionFiltersContext, pipesCreator as any,
|
||||
pipesConsumer as any, guardsContextCreator as any, guardsConsumer as any,
|
||||
);
|
||||
|
||||
instance = new Test();
|
||||
module = 'test';
|
||||
});
|
||||
describe('create', () => {
|
||||
it('should create exception handler', () => {
|
||||
const handlerCreateSpy = sinon.spy(exceptionFiltersContext, 'create');
|
||||
contextCreator.create(instance, instance.test, module);
|
||||
expect(handlerCreateSpy.calledWith(instance, instance.test)).to.be.true;
|
||||
});
|
||||
it('should create pipes context', () => {
|
||||
const pipesCreateSpy = sinon.spy(pipesCreator, 'create');
|
||||
contextCreator.create(instance, instance.test, module);
|
||||
expect(pipesCreateSpy.calledWith(instance, instance.test)).to.be.true;
|
||||
});
|
||||
it('should create guards context', () => {
|
||||
const guardsCreateSpy = sinon.spy(guardsContextCreator, 'create');
|
||||
contextCreator.create(instance, instance.test, module);
|
||||
expect(guardsCreateSpy.calledWith(instance, instance.test, module)).to.be.true;
|
||||
});
|
||||
describe('when proxy called', () => {
|
||||
it('should call guards consumer `tryActivate`', async () => {
|
||||
const tryActivateSpy = sinon.spy(guardsConsumer, 'tryActivate');
|
||||
const proxy = await contextCreator.create(instance, instance.test, module);
|
||||
const data = 'test';
|
||||
await proxy(null, data);
|
||||
|
||||
expect(tryActivateSpy.called).to.be.true;
|
||||
});
|
||||
describe('when can activate', () => {
|
||||
it('should call pipes consumer `applyPipes`', async () => {
|
||||
const applyPipesSpy = sinon.spy(pipesConsumer, 'applyPipes');
|
||||
const proxy = await contextCreator.create(instance, instance.test, module);
|
||||
const data = 'test';
|
||||
await proxy(null, data);
|
||||
|
||||
expect(applyPipesSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when can not activate', () => {
|
||||
it('should throws forbidden exception', async () => {
|
||||
const tryActivateStub = sinon.stub(guardsConsumer, 'tryActivate').returns(false);
|
||||
const proxy = await contextCreator.create(instance, instance.test, module);
|
||||
const data = 'test';
|
||||
|
||||
expect(proxy(null, data)).to.eventually.rejectedWith(WsException);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reflectCallbackParamtypes', () => {
|
||||
it('should returns paramtypes array', () => {
|
||||
const paramtypes = contextCreator.reflectCallbackParamtypes(instance, instance.test);
|
||||
expect(paramtypes).to.be.eql([String, Number]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDataMetatype', () => {
|
||||
describe('when paramtypes are reflected', () => {
|
||||
it('should returns data paramtype', () => {
|
||||
const type = contextCreator.getDataMetatype(instance, instance.test);
|
||||
expect(type).to.be.eql(Number);
|
||||
});
|
||||
});
|
||||
describe('when paramtypes are not reflected', () => {
|
||||
it('should returns null', () => {
|
||||
const type = contextCreator.getDataMetatype(instance, () => ({}));
|
||||
expect(type).to.be.null;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
35
src/websockets/test/context/ws-proxy.spec.ts
Normal file
35
src/websockets/test/context/ws-proxy.spec.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { WsProxy} from './../../context/ws-proxy';
|
||||
import { WsExceptionsHandler } from '../../exceptions/ws-exceptions-handler';
|
||||
import { WsException } from '../../exceptions/ws-exception';
|
||||
|
||||
describe('WsProxy', () => {
|
||||
let routerProxy: WsProxy;
|
||||
let handlerMock: sinon.SinonMock;
|
||||
let handler: WsExceptionsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
handler = new WsExceptionsHandler();
|
||||
handlerMock = sinon.mock(handler);
|
||||
routerProxy = new WsProxy();
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
|
||||
it('should method return thunk', async () => {
|
||||
const proxy = await routerProxy.create(async (client, data) => {}, handler);
|
||||
expect(typeof proxy === 'function').to.be.true;
|
||||
});
|
||||
|
||||
it('should method encapsulate callback passed as argument', async () => {
|
||||
const expectation = handlerMock.expects('handle').once();
|
||||
const proxy = routerProxy.create(async (client, data) => {
|
||||
throw new WsException('test');
|
||||
}, handler);
|
||||
await proxy(null, null);
|
||||
expectation.verify();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
14
src/websockets/test/exceptions/ws-exception.spec.ts
Normal file
14
src/websockets/test/exceptions/ws-exception.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { WsException } from '../../exceptions/ws-exception';
|
||||
|
||||
describe('WsException', () => {
|
||||
let instance: WsException;
|
||||
const error = 'test';
|
||||
beforeEach(() => {
|
||||
instance = new WsException(error);
|
||||
});
|
||||
it('should returns error message or object', () => {
|
||||
expect(instance.getError()).to.be.eql(error);
|
||||
});
|
||||
});
|
||||
111
src/websockets/test/exceptions/ws-exceptions-handler.spec.ts
Normal file
111
src/websockets/test/exceptions/ws-exceptions-handler.spec.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { WsExceptionsHandler } from './../../exceptions/ws-exceptions-handler';
|
||||
import { WsException } from './../../exceptions/ws-exception';
|
||||
|
||||
describe('WsExceptionsHandler', () => {
|
||||
let handler: WsExceptionsHandler;
|
||||
let emitStub: sinon.SinonStub;
|
||||
let client;
|
||||
|
||||
beforeEach(() => {
|
||||
handler = new WsExceptionsHandler();
|
||||
emitStub = sinon.stub();
|
||||
client = {
|
||||
emit: emitStub,
|
||||
};
|
||||
client.emit.returns(client);
|
||||
});
|
||||
|
||||
describe('handle', () => {
|
||||
it('should method emit expected status code message when exception is unknown', () => {
|
||||
handler.handle(new Error(), client);
|
||||
expect(emitStub.calledWith(
|
||||
'exception',
|
||||
{ status: 'error', message: 'Unknown exception' },
|
||||
)).to.be.true;
|
||||
});
|
||||
describe('when exception is instance of WsException', () => {
|
||||
it('should method emit expected status and json object', () => {
|
||||
const message = {
|
||||
custom: 'Unauthorized',
|
||||
};
|
||||
handler.handle(new WsException(message), client);
|
||||
expect(emitStub.calledWith('exception', message)).to.be.true;
|
||||
});
|
||||
it('should method emit expected status and transform message to json', () => {
|
||||
const message = 'Unauthorized';
|
||||
|
||||
handler.handle(new WsException(message), client);
|
||||
expect(emitStub.calledWith('exception', { message, status: 'error' })).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when "invokeCustomFilters" returns true', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(handler, 'invokeCustomFilters').returns(true);
|
||||
});
|
||||
it('should not call `emit`', () => {
|
||||
handler.handle(new WsException(''), client);
|
||||
expect(emitStub.notCalled).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('setCustomFilters', () => {
|
||||
const filters = [ 'test', 'test2' ];
|
||||
it('should set custom filters', () => {
|
||||
handler.setCustomFilters(filters as any);
|
||||
expect((handler as any).filters).to.be.eql(filters);
|
||||
});
|
||||
it('should throws exception when passed argument is not an array', () => {
|
||||
expect(
|
||||
() => handler.setCustomFilters(null),
|
||||
).to.throw;
|
||||
});
|
||||
});
|
||||
describe('invokeCustomFilters', () => {
|
||||
describe('when filters array is empty', () => {
|
||||
it('should returns false', () => {
|
||||
expect(handler.invokeCustomFilters(null, null)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('when filters array is not empty', () => {
|
||||
let filters, funcSpy;
|
||||
class TestException {}
|
||||
|
||||
beforeEach(() => {
|
||||
funcSpy = sinon.spy();
|
||||
});
|
||||
describe('when filter exists in filters array', () => {
|
||||
beforeEach(() => {
|
||||
filters = [
|
||||
{ exceptionMetatypes: [ TestException ], func: funcSpy },
|
||||
];
|
||||
(handler as any).filters = filters;
|
||||
});
|
||||
it('should call funcSpy', () => {
|
||||
handler.invokeCustomFilters(new TestException(), null);
|
||||
expect(funcSpy.notCalled).to.be.false;
|
||||
});
|
||||
it('should call funcSpy with exception and response passed as an arguments', () => {
|
||||
const exception = new TestException();
|
||||
const res = { foo: 'bar' };
|
||||
|
||||
handler.invokeCustomFilters(exception, res);
|
||||
expect(funcSpy.calledWith(exception, res)).to.be.true;
|
||||
});
|
||||
it('should returns true', () => {
|
||||
expect(handler.invokeCustomFilters(new TestException(), null)).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when filter does not exists in filters array', () => {
|
||||
it('should not call funcSpy', () => {
|
||||
handler.invokeCustomFilters(new TestException(), null);
|
||||
expect(funcSpy.notCalled).to.be.true;
|
||||
});
|
||||
it('should returns false', () => {
|
||||
expect(handler.invokeCustomFilters(new TestException(), null)).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -55,11 +55,11 @@ describe('GatewayMetadataExplorer', () => {
|
||||
test = new Test();
|
||||
});
|
||||
it(`should return null when "isMessageMapping" metadata is undefined`, () => {
|
||||
const metadata = instance.exploreMethodMetadata(test, Object.getPrototypeOf(test), 'noMessage');
|
||||
const metadata = instance.exploreMethodMetadata(test, 'noMessage');
|
||||
expect(metadata).to.eq(null);
|
||||
});
|
||||
it(`should return message mapping properties when "isMessageMapping" metadata is not undefined`, () => {
|
||||
const metadata = instance.exploreMethodMetadata(test, Object.getPrototypeOf(test), 'test');
|
||||
const metadata = instance.exploreMethodMetadata(test, 'test');
|
||||
expect(metadata).to.have.keys([ 'callback', 'message' ]);
|
||||
expect(metadata.message).to.eql(message);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import { InvalidSocketPortException } from '../exceptions/invalid-socket-port.ex
|
||||
import { GatewayMetadataExplorer } from '../gateway-metadata-explorer';
|
||||
import { MetadataScanner } from '../../core/metadata-scanner';
|
||||
import { ApplicationConfig } from '@nestjs/core/application-config';
|
||||
import { WsContextCreator } from '../context/ws-context-creator';
|
||||
|
||||
describe('WebSocketsController', () => {
|
||||
let instance: WebSocketsController;
|
||||
@@ -24,7 +25,7 @@ describe('WebSocketsController', () => {
|
||||
config = new ApplicationConfig();
|
||||
provider = new SocketServerProvider(null, config);
|
||||
mockProvider = sinon.mock(provider);
|
||||
instance = new WebSocketsController(provider, null, config);
|
||||
instance = new WebSocketsController(provider, null, config, sinon.createStubInstance(WsContextCreator));
|
||||
});
|
||||
describe('hookGatewayIntoServer', () => {
|
||||
let subscribeObservableServer: sinon.SinonSpy;
|
||||
|
||||
Reference in New Issue
Block a user