mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
feat(core): repl
This commit is contained in:
106
integration/repl/e2e/repl.spec.ts
Normal file
106
integration/repl/e2e/repl.spec.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { clc } from '@nestjs/common/utils/cli-colors.util';
|
||||
import { repl } from '@nestjs/core';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { UsersModule } from '../src/users/users.module';
|
||||
|
||||
const prompt = '\u001b[1G\u001b[0J\u001b[32m>\u001b[0m \u001b[3G';
|
||||
|
||||
describe('REPL', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(clc, 'yellow').callsFake(text => text);
|
||||
sinon.stub(clc, 'green').callsFake(text => text);
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
delete globalThis[AppModule.name];
|
||||
delete globalThis[UsersModule.name];
|
||||
});
|
||||
|
||||
it('get()', async () => {
|
||||
const server = await repl(AppModule);
|
||||
|
||||
let outputText = '';
|
||||
sinon.stub(process.stdout, 'write').callsFake(text => {
|
||||
outputText += text;
|
||||
return true;
|
||||
});
|
||||
server.emit('line', 'get(UsersService)');
|
||||
|
||||
expect(outputText).to.equal(
|
||||
`UsersService { usersRepository: UsersRepository {} }
|
||||
${prompt}`,
|
||||
);
|
||||
|
||||
outputText = '';
|
||||
server.emit('line', 'get(UsersService).findAll()');
|
||||
|
||||
expect(outputText).to
|
||||
.equal(`\u001b[32m'This action returns all users'\u001b[39m
|
||||
${prompt}`);
|
||||
|
||||
outputText = '';
|
||||
server.emit('line', 'get(UsersRepository)');
|
||||
|
||||
expect(outputText).to.equal(`UsersRepository {}
|
||||
${prompt}`);
|
||||
});
|
||||
|
||||
it('debug()', async () => {
|
||||
const server = await repl(AppModule);
|
||||
|
||||
let outputText = '';
|
||||
sinon.stub(process.stdout, 'write').callsFake(text => {
|
||||
outputText += text;
|
||||
return true;
|
||||
});
|
||||
server.emit('line', 'debug(UsersModule)');
|
||||
|
||||
expect(outputText).to.equal(
|
||||
`
|
||||
UsersModule:
|
||||
- controllers:
|
||||
◻ UsersController
|
||||
- providers:
|
||||
◻ UsersService
|
||||
◻ UsersRepository
|
||||
|
||||
${prompt}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('methods()', async () => {
|
||||
const server = await repl(AppModule);
|
||||
|
||||
let outputText = '';
|
||||
sinon.stub(process.stdout, 'write').callsFake(text => {
|
||||
outputText += text;
|
||||
return true;
|
||||
});
|
||||
server.emit('line', 'methods(UsersRepository)');
|
||||
|
||||
expect(outputText).to.equal(
|
||||
`
|
||||
Methods:
|
||||
◻ find
|
||||
|
||||
${prompt}`,
|
||||
);
|
||||
|
||||
outputText = '';
|
||||
server.emit('line', 'methods(UsersService)');
|
||||
|
||||
expect(outputText).to.equal(
|
||||
`
|
||||
Methods:
|
||||
◻ create
|
||||
◻ findAll
|
||||
◻ findOne
|
||||
◻ update
|
||||
◻ remove
|
||||
|
||||
${prompt}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
7
integration/repl/src/app.module.ts
Normal file
7
integration/repl/src/app.module.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UsersModule } from './users/users.module';
|
||||
|
||||
@Module({
|
||||
imports: [UsersModule],
|
||||
})
|
||||
export class AppModule {}
|
||||
1
integration/repl/src/users/dto/create-user.dto.ts
Normal file
1
integration/repl/src/users/dto/create-user.dto.ts
Normal file
@@ -0,0 +1 @@
|
||||
export class CreateUserDto {}
|
||||
4
integration/repl/src/users/dto/update-user.dto.ts
Normal file
4
integration/repl/src/users/dto/update-user.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateUserDto } from './create-user.dto';
|
||||
|
||||
export class UpdateUserDto extends PartialType(CreateUserDto) {}
|
||||
1
integration/repl/src/users/entities/user.entity.ts
Normal file
1
integration/repl/src/users/entities/user.entity.ts
Normal file
@@ -0,0 +1 @@
|
||||
export class User {}
|
||||
20
integration/repl/src/users/users.controller.spec.ts
Normal file
20
integration/repl/src/users/users.controller.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
describe('UsersController', () => {
|
||||
let controller: UsersController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [UsersController],
|
||||
providers: [UsersService],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<UsersController>(UsersController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
34
integration/repl/src/users/users.controller.ts
Normal file
34
integration/repl/src/users/users.controller.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
|
||||
@Controller('users')
|
||||
export class UsersController {
|
||||
constructor(private readonly usersService: UsersService) {}
|
||||
|
||||
@Post()
|
||||
create(@Body() createUserDto: CreateUserDto) {
|
||||
return this.usersService.create(createUserDto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.usersService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.usersService.findOne(+id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
||||
return this.usersService.update(+id, updateUserDto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.usersService.remove(+id);
|
||||
}
|
||||
}
|
||||
16
integration/repl/src/users/users.module.ts
Normal file
16
integration/repl/src/users/users.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersRepository } from './users.repository';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
@Module({
|
||||
controllers: [UsersController],
|
||||
providers: [
|
||||
UsersService,
|
||||
{
|
||||
provide: UsersRepository.name,
|
||||
useValue: new UsersRepository(),
|
||||
},
|
||||
],
|
||||
})
|
||||
export class UsersModule {}
|
||||
8
integration/repl/src/users/users.repository.ts
Normal file
8
integration/repl/src/users/users.repository.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class UsersRepository {
|
||||
async find() {
|
||||
return [{ id: 1, email: 'test@nestjs.com' }];
|
||||
}
|
||||
}
|
||||
18
integration/repl/src/users/users.service.spec.ts
Normal file
18
integration/repl/src/users/users.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
describe('UsersService', () => {
|
||||
let service: UsersService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [UsersService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<UsersService>(UsersService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
32
integration/repl/src/users/users.service.ts
Normal file
32
integration/repl/src/users/users.service.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
import { UsersRepository } from './users.repository';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(
|
||||
@Inject('UsersRepository')
|
||||
private readonly usersRepository: UsersRepository,
|
||||
) {}
|
||||
|
||||
create(createUserDto: CreateUserDto) {
|
||||
return 'This action adds a new user';
|
||||
}
|
||||
|
||||
findAll() {
|
||||
return `This action returns all users`;
|
||||
}
|
||||
|
||||
findOne(id: number) {
|
||||
return `This action returns a #${id} user`;
|
||||
}
|
||||
|
||||
update(id: number, updateUserDto: UpdateUserDto) {
|
||||
return `This action updates a #${id} user`;
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
return `This action removes a #${id} user`;
|
||||
}
|
||||
}
|
||||
22
integration/repl/tsconfig.json
Normal file
22
integration/repl/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
@@ -18,5 +18,6 @@ export * from './middleware';
|
||||
export * from './nest-application';
|
||||
export * from './nest-application-context';
|
||||
export { NestFactory } from './nest-factory';
|
||||
export * from './repl';
|
||||
export * from './router';
|
||||
export * from './services';
|
||||
|
||||
1
packages/core/repl/constants.ts
Normal file
1
packages/core/repl/constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const REPL_INITIALIZED_MESSAGE = 'REPL initialized';
|
||||
1
packages/core/repl/index.ts
Normal file
1
packages/core/repl/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './repl';
|
||||
167
packages/core/repl/repl-context.ts
Normal file
167
packages/core/repl/repl-context.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import {
|
||||
DynamicModule,
|
||||
INestApplication,
|
||||
InjectionToken,
|
||||
Logger,
|
||||
Type,
|
||||
} from '@nestjs/common';
|
||||
import { clc } from '@nestjs/common/utils/cli-colors.util';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { ModuleRef, NestContainer } from '../injector';
|
||||
import { InternalCoreModule } from '../injector/internal-core-module';
|
||||
import { Module } from '../injector/module';
|
||||
import { MetadataScanner } from '../metadata-scanner';
|
||||
|
||||
type ModuleKey = string;
|
||||
type ModuleDebugEntry = {
|
||||
controllers: Record<string, InjectionToken>;
|
||||
providers: Record<string, InjectionToken>;
|
||||
};
|
||||
|
||||
export class ReplContext {
|
||||
private debugRegistry: Record<ModuleKey, ModuleDebugEntry> = {};
|
||||
private readonly container: NestContainer;
|
||||
private readonly logger = new Logger(ReplContext.name);
|
||||
private readonly metadataScanner = new MetadataScanner();
|
||||
|
||||
constructor(private readonly app: INestApplication) {
|
||||
this.container = (app as any).container;
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
$(token: string | symbol | Function | Type<any>) {
|
||||
return this.get(token);
|
||||
}
|
||||
|
||||
get(token: string | symbol | Function | Type<any>) {
|
||||
return this.app.get(token);
|
||||
}
|
||||
|
||||
resolve(token: string | symbol | Function | Type<any>, contextId: any) {
|
||||
return this.app.resolve(token, contextId);
|
||||
}
|
||||
|
||||
select(token: DynamicModule | Type<unknown>) {
|
||||
return this.app.select(token);
|
||||
}
|
||||
|
||||
debug(moduleCls?: Type | string) {
|
||||
this.writeToStdout('\n');
|
||||
|
||||
if (moduleCls) {
|
||||
const token =
|
||||
typeof moduleCls === 'function' ? moduleCls.name : moduleCls;
|
||||
const moduleEntry = this.debugRegistry[token];
|
||||
if (!moduleEntry) {
|
||||
return this.logger.error(
|
||||
`"${token}" has not been found in the modules registry`,
|
||||
);
|
||||
}
|
||||
this.printCtrlsAndProviders(token, moduleEntry);
|
||||
} else {
|
||||
Object.keys(this.debugRegistry).forEach(moduleKey => {
|
||||
this.printCtrlsAndProviders(moduleKey, this.debugRegistry[moduleKey]);
|
||||
});
|
||||
}
|
||||
this.writeToStdout('\n');
|
||||
}
|
||||
|
||||
methods(token: Type | string) {
|
||||
const proto =
|
||||
typeof token !== 'function'
|
||||
? Object.getPrototypeOf(this.app.get(token))
|
||||
: token?.prototype;
|
||||
|
||||
const methods = new Set(
|
||||
this.metadataScanner.getAllFilteredMethodNames(proto),
|
||||
);
|
||||
|
||||
this.writeToStdout('\n');
|
||||
this.writeToStdout(`${clc.green('Methods')}: \n`);
|
||||
methods.forEach(methodName =>
|
||||
this.writeToStdout(` ${clc.yellow('◻')} ${methodName}\n`),
|
||||
);
|
||||
this.writeToStdout('\n');
|
||||
}
|
||||
|
||||
private initialize() {
|
||||
const globalRef = globalThis;
|
||||
const modules = this.container.getModules();
|
||||
|
||||
modules.forEach(moduleRef => {
|
||||
let moduleName = moduleRef.metatype.name;
|
||||
if (moduleName === InternalCoreModule.name) {
|
||||
return;
|
||||
}
|
||||
if (globalRef[moduleName]) {
|
||||
moduleName += ` (${moduleRef.token})`;
|
||||
}
|
||||
|
||||
this.introspectCollection(moduleRef, moduleName, 'providers');
|
||||
this.introspectCollection(moduleRef, moduleName, 'controllers');
|
||||
|
||||
globalRef[moduleName] = moduleRef.metatype;
|
||||
});
|
||||
}
|
||||
|
||||
private introspectCollection(
|
||||
moduleRef: Module,
|
||||
moduleKey: ModuleKey,
|
||||
collection: keyof ModuleDebugEntry,
|
||||
) {
|
||||
let moduleDebugEntry = {};
|
||||
moduleRef[collection].forEach(({ token }) => {
|
||||
const stringifiedToken = this.stringifyToken(token);
|
||||
if (
|
||||
stringifiedToken === ApplicationConfig.name ||
|
||||
stringifiedToken === moduleRef.metatype.name
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// For in REPL auto-complete functionality
|
||||
globalThis[stringifiedToken] = token;
|
||||
|
||||
if (stringifiedToken === ModuleRef.name) {
|
||||
return;
|
||||
}
|
||||
moduleDebugEntry[stringifiedToken] = token;
|
||||
});
|
||||
|
||||
this.debugRegistry[moduleKey] = {
|
||||
...this.debugRegistry?.[moduleKey],
|
||||
[collection]: moduleDebugEntry,
|
||||
};
|
||||
}
|
||||
|
||||
private stringifyToken(token: unknown): string {
|
||||
return typeof token !== 'string'
|
||||
? typeof token === 'function'
|
||||
? token.name
|
||||
: token?.toString()
|
||||
: token;
|
||||
}
|
||||
|
||||
private printCtrlsAndProviders(
|
||||
moduleName: string,
|
||||
moduleDebugEntry: ModuleDebugEntry,
|
||||
) {
|
||||
const printCollection = (collection: keyof ModuleDebugEntry) => {
|
||||
const collectionEntries = Object.keys(moduleDebugEntry[collection]);
|
||||
if (collectionEntries.length <= 0) {
|
||||
return;
|
||||
}
|
||||
this.writeToStdout(` ${clc.yellow(`- ${collection}`)}: \n`);
|
||||
collectionEntries.forEach(provider =>
|
||||
this.writeToStdout(` ${clc.green('◻')} ${provider}\n`),
|
||||
);
|
||||
};
|
||||
|
||||
this.writeToStdout(`${clc.green(moduleName)}: \n`);
|
||||
printCollection('controllers');
|
||||
printCollection('providers');
|
||||
}
|
||||
|
||||
private writeToStdout(text: string) {
|
||||
process.stdout.write(text);
|
||||
}
|
||||
}
|
||||
18
packages/core/repl/repl-logger.ts
Normal file
18
packages/core/repl/repl-logger.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ConsoleLogger } from '@nestjs/common';
|
||||
import { NestApplication } from '../nest-application';
|
||||
import { RouterExplorer } from '../router/router-explorer';
|
||||
import { RoutesResolver } from '../router/routes-resolver';
|
||||
|
||||
export class ReplLogger extends ConsoleLogger {
|
||||
private static readonly ignoredContexts = [
|
||||
RoutesResolver.name,
|
||||
RouterExplorer.name,
|
||||
NestApplication.name,
|
||||
];
|
||||
log(_message: any, context?: string) {
|
||||
if (ReplLogger.ignoredContexts.includes(context)) {
|
||||
return;
|
||||
}
|
||||
return super.log.apply(this, Array.from(arguments) as [any, string?]);
|
||||
}
|
||||
}
|
||||
31
packages/core/repl/repl.ts
Normal file
31
packages/core/repl/repl.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Logger, Type } from '@nestjs/common';
|
||||
import * as _repl from 'repl';
|
||||
import { NestFactory } from '../nest-factory';
|
||||
import { REPL_INITIALIZED_MESSAGE } from './constants';
|
||||
import { ReplContext } from './repl-context';
|
||||
import { ReplLogger } from './repl-logger';
|
||||
|
||||
export async function repl(module: Type) {
|
||||
const app = await NestFactory.create(module, {
|
||||
abortOnError: false,
|
||||
logger: new ReplLogger(),
|
||||
});
|
||||
await app.init();
|
||||
|
||||
const replContext = new ReplContext(app);
|
||||
Logger.log(REPL_INITIALIZED_MESSAGE);
|
||||
|
||||
const replServer = _repl.start({
|
||||
prompt: '\x1b[32m>\x1b[0m ',
|
||||
ignoreUndefined: true,
|
||||
});
|
||||
|
||||
replServer.context.$ = replContext.$.bind(replContext);
|
||||
replServer.context.get = replContext.get.bind(replContext);
|
||||
replServer.context.resolve = replContext.resolve.bind(replContext);
|
||||
replServer.context.select = replContext.select.bind(replContext);
|
||||
replServer.context.debug = replContext.debug.bind(replContext);
|
||||
replServer.context.methods = replContext.methods.bind(replContext);
|
||||
|
||||
return replServer;
|
||||
}
|
||||
185
packages/core/test/repl/repl-context.spec.ts
Normal file
185
packages/core/test/repl/repl-context.spec.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import { clc } from '@nestjs/common/utils/cli-colors.util';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
import { ReplContext } from '../../repl/repl-context';
|
||||
|
||||
describe('ReplContext', () => {
|
||||
let replContext: ReplContext;
|
||||
let mockApp: {
|
||||
container: NestContainer;
|
||||
get: sinon.SinonStub;
|
||||
resolve: sinon.SinonSpy;
|
||||
select: sinon.SinonSpy;
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
const container = new NestContainer();
|
||||
const aModuleRef = await container.addModule(class ModuleA {}, []);
|
||||
const bModuleRef = await container.addModule(class ModuleB {}, []);
|
||||
|
||||
container.addController(class ControllerA {}, aModuleRef.token);
|
||||
container.addProvider(class ProviderA1 {}, aModuleRef.token);
|
||||
container.addProvider(class ProviderA2 {}, aModuleRef.token);
|
||||
|
||||
container.addProvider(class ProviderB1 {}, bModuleRef.token);
|
||||
container.addProvider(class ProviderB2 {}, bModuleRef.token);
|
||||
|
||||
mockApp = {
|
||||
container,
|
||||
get: sinon.stub(),
|
||||
resolve: sinon.spy(),
|
||||
select: sinon.spy(),
|
||||
};
|
||||
replContext = new ReplContext(mockApp as any);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
sinon.stub(clc, 'yellow').callsFake(text => text);
|
||||
sinon.stub(clc, 'green').callsFake(text => text);
|
||||
});
|
||||
afterEach(() => sinon.restore());
|
||||
|
||||
describe('debug', () => {
|
||||
it('should print all modules along with their controllers and providers', () => {
|
||||
let outputText = '';
|
||||
|
||||
sinon
|
||||
.stub(replContext as any, 'writeToStdout')
|
||||
.callsFake(text => (outputText += text));
|
||||
replContext.debug();
|
||||
|
||||
expect(outputText).to.equal(`
|
||||
ModuleA:
|
||||
- controllers:
|
||||
◻ ControllerA
|
||||
- providers:
|
||||
◻ ProviderA1
|
||||
◻ ProviderA2
|
||||
ModuleB:
|
||||
- providers:
|
||||
◻ ProviderB1
|
||||
◻ ProviderB2
|
||||
|
||||
`);
|
||||
});
|
||||
|
||||
describe('when module passed as a class reference', () => {
|
||||
it("should print a specified module's controllers and providers", () => {
|
||||
let outputText = '';
|
||||
|
||||
sinon
|
||||
.stub(replContext as any, 'writeToStdout')
|
||||
.callsFake(text => (outputText += text));
|
||||
replContext.debug(class ModuleA {});
|
||||
|
||||
expect(outputText).to.equal(`
|
||||
ModuleA:
|
||||
- controllers:
|
||||
◻ ControllerA
|
||||
- providers:
|
||||
◻ ProviderA1
|
||||
◻ ProviderA2
|
||||
|
||||
`);
|
||||
});
|
||||
});
|
||||
describe("when module passed as a string (module's key)", () => {
|
||||
it("should print a specified module's controllers and providers", () => {
|
||||
let outputText = '';
|
||||
|
||||
sinon
|
||||
.stub(replContext as any, 'writeToStdout')
|
||||
.callsFake(text => (outputText += text));
|
||||
replContext.debug('ModuleA');
|
||||
|
||||
expect(outputText).to.equal(`
|
||||
ModuleA:
|
||||
- controllers:
|
||||
◻ ControllerA
|
||||
- providers:
|
||||
◻ ProviderA1
|
||||
◻ ProviderA2
|
||||
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
describe('when token is a class reference', () => {
|
||||
it('should print all class methods', () => {
|
||||
class BaseService {
|
||||
create() {}
|
||||
}
|
||||
class TestService extends BaseService {
|
||||
findAll() {}
|
||||
findOne() {}
|
||||
}
|
||||
|
||||
let outputText = '';
|
||||
|
||||
sinon
|
||||
.stub(replContext as any, 'writeToStdout')
|
||||
.callsFake(text => (outputText += text));
|
||||
replContext.methods(TestService);
|
||||
|
||||
expect(outputText).to.equal(`
|
||||
Methods:
|
||||
◻ findAll
|
||||
◻ findOne
|
||||
◻ create
|
||||
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when token is a string', () => {
|
||||
it('should grab provider from the container and print its all methods', () => {
|
||||
class ProviderA1 {
|
||||
findAll() {}
|
||||
findOne() {}
|
||||
}
|
||||
let outputText = '';
|
||||
|
||||
sinon
|
||||
.stub(replContext as any, 'writeToStdout')
|
||||
.callsFake(text => (outputText += text));
|
||||
|
||||
mockApp.get.callsFake(() => new ProviderA1());
|
||||
replContext.methods('ProviderA1');
|
||||
|
||||
expect(outputText).to.equal(`
|
||||
Methods:
|
||||
◻ findAll
|
||||
◻ findOne
|
||||
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
it('should pass arguments down to the application context', () => {
|
||||
const token = 'test';
|
||||
replContext.get(token);
|
||||
expect(mockApp.get.calledWith(token)).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('resolve', () => {
|
||||
it('should pass arguments down to the application context', async () => {
|
||||
const token = 'test';
|
||||
const contextId = {};
|
||||
|
||||
await replContext.resolve(token, contextId);
|
||||
expect(mockApp.resolve.calledWith(token, contextId)).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('select', () => {
|
||||
it('should pass arguments down to the application context', () => {
|
||||
const moduleCls = class TestModule {};
|
||||
replContext.select(moduleCls);
|
||||
expect(mockApp.select.calledWith(moduleCls)).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user