Skip to content

Commit 99770b5

Browse files
tests(@nestjs/core) increase injector test coverage
1 parent 1d87e18 commit 99770b5

2 files changed

Lines changed: 152 additions & 4 deletions

File tree

src/core/injector/injector.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ export class Injector {
4040
}
4141

4242
public loadPrototypeOfInstance<T>({ metatype, name }: InstanceWrapper<T>, collection: Map<string, InstanceWrapper<T>>) {
43-
if (!collection) return;
43+
if (!collection) return null;
4444

4545
const target = collection.get(name);
46-
if (target.isResolved || !isNil(target.inject)) return;
46+
if (target.isResolved || !isNil(target.inject)) return null;
4747

4848
collection.set(name, {
4949
...collection.get(name),
@@ -73,8 +73,8 @@ export class Injector {
7373
if (isUndefined(currentMetatype)) {
7474
throw new RuntimeException();
7575
}
76+
if (currentMetatype.isResolved) return null;
7677

77-
if (currentMetatype.isResolved) return;
7878
await this.resolveConstructorParams<T>(wrapper, module, inject, context, async (instances) => {
7979
if (isNil(inject)) {
8080
currentMetatype.instance = Object.assign(

src/core/test/injector/injector.spec.ts

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Module } from '../../injector/module';
88
import { UnknownDependenciesException } from '../../errors/exceptions/unknown-dependencies.exception';
99
import * as chai from 'chai';
1010
import * as chaiAsPromised from 'chai-as-promised';
11+
import { UndefinedDependencyException } from "../../errors/exceptions/undefined-dependency.exception";
1112
chai.use(chaiAsPromised);
1213

1314
describe('Injector', () => {
@@ -58,6 +59,7 @@ describe('Injector', () => {
5859
moduleDeps.components.set('MainTest', mainTest);
5960
moduleDeps.components.set('DependencyOne', depOne);
6061
moduleDeps.components.set('DependencyTwo', depTwo);
62+
moduleDeps.components.set('MainTestResolved', { ...mainTest, isResolved: true });
6163
});
6264

6365
it('should create an instance of component with proper dependencies', async () => {
@@ -93,6 +95,17 @@ describe('Injector', () => {
9395
}, moduleDeps.components, moduleDeps);
9496
expect(result).to.be.eql(value);
9597
});
98+
99+
it('should return null when metatype is resolved', async () => {
100+
const value = 'test';
101+
const result = await injector.loadInstance({
102+
name: 'MainTestResolved',
103+
metatype: MainTest,
104+
instance: Object.create(MainTest.prototype),
105+
isResolved: true,
106+
}, moduleDeps.components, moduleDeps);
107+
expect(result).to.be.null;
108+
});
96109
});
97110

98111
describe('loadPrototypeOfInstance', () => {
@@ -125,6 +138,26 @@ describe('Injector', () => {
125138
expect(moduleDeps.components.get('Test')).to.deep.equal(expectedResult);
126139
});
127140

141+
it('should return null when collection is nil', () => {
142+
const result = injector.loadPrototypeOfInstance(test, null);
143+
expect(result).to.be.null;
144+
});
145+
146+
it('should return null when target isResolved', () => {
147+
const collection = {
148+
get: () => ({ isResolved: true }),
149+
};
150+
const result = injector.loadPrototypeOfInstance(test, collection as any);
151+
expect(result).to.be.null;
152+
});
153+
154+
it('should return null when "inject" is not nil', () => {
155+
const collection = {
156+
get: () => ({ inject: [] }),
157+
};
158+
const result = injector.loadPrototypeOfInstance(test, collection as any);
159+
expect(result).to.be.null;
160+
});
128161
});
129162

130163
describe('resolveSingleParam', () => {
@@ -370,5 +403,120 @@ describe('Injector', () => {
370403
sinon.stub(injector, 'scanForComponent').throws('exception');
371404
expect(injector.scanForComponentInScope({} as any, '', {})).to.eventually.be.null;
372405
});
406+
407+
it('should rethrow UndefinedDependencyException', () => {
408+
sinon.stub(injector, 'scanForComponent').throws(new UndefinedDependencyException('type'));
409+
expect(injector.scanForComponentInScope({} as any, '', {})).to.eventually.throw();
410+
});
411+
412+
describe('when instanceWrapper is not resolved and does not have forward ref', () => {
413+
it('should call loadInstanceOfComponent', async () => {
414+
const loadStub = sinon.stub(injector, 'loadInstanceOfComponent').callsFake(() => null);
415+
sinon.stub(injector, 'scanForComponent').returns({ isResolved: false });
416+
417+
await injector.scanForComponentInScope([] as any, 'name', {} as any);
418+
expect(loadStub.called).to.be.true;
419+
});
420+
it('should not call loadInstanceOfComponent (isResolved)', async () => {
421+
const loadStub = sinon.stub(injector, 'loadInstanceOfComponent').callsFake(() => null);
422+
sinon.stub(injector, 'scanForComponent').returns({ isResolved: true });
423+
424+
await injector.scanForComponentInScope([] as any, 'name', {} as any);
425+
expect(loadStub.called).to.be.false;
426+
});
427+
it('should not call loadInstanceOfComponent (forwardRef)', async () => {
428+
const loadStub = sinon.stub(injector, 'loadInstanceOfComponent').callsFake(() => null);
429+
sinon.stub(injector, 'scanForComponent').returns({ isResolved: false, forwardRef: true });
430+
431+
await injector.scanForComponentInScope([] as any, 'name', {} as any);
432+
expect(loadStub.called).to.be.false;
433+
});
434+
});
435+
});
436+
437+
describe('resolveParamToken', () => {
438+
let forwardRef;
439+
let wrapper;
440+
let param;
441+
442+
describe('when "forwardRef" property is not nil', () => {
443+
beforeEach(() => {
444+
forwardRef = 'test';
445+
wrapper = {};
446+
param = {
447+
forwardRef: () => forwardRef,
448+
};
449+
});
450+
it('return forwardRef() result', () => {
451+
expect(injector.resolveParamToken(wrapper, param)).to.be.eql(forwardRef);
452+
});
453+
it('set wrapper "forwardRef" property to true', () => {
454+
injector.resolveParamToken(wrapper, param);
455+
expect(wrapper.forwardRef).to.be.true;
456+
});
457+
});
458+
describe('when "forwardRef" property is nil', () => {
459+
beforeEach(() => {
460+
forwardRef = 'test';
461+
wrapper = {};
462+
param = {};
463+
});
464+
it('set wrapper "forwardRef" property to false', () => {
465+
injector.resolveParamToken(wrapper, param);
466+
expect(wrapper.forwardRef).to.be.undefined;
467+
});
468+
it('return param', () => {
469+
expect(injector.resolveParamToken(wrapper, param)).to.be.eql(param);
470+
});
471+
});
472+
});
473+
474+
describe('resolveComponentInstance', () => {
475+
let module;
476+
beforeEach(() => {
477+
module = {
478+
components: [],
479+
};
480+
});
481+
482+
describe('when instanceWrapper is not resolved and does not have forward ref', () => {
483+
it('should call loadInstanceOfComponent', async () => {
484+
const loadStub = sinon.stub(injector, 'loadInstanceOfComponent').callsFake(() => null);
485+
sinon.stub(injector, 'scanForComponent').returns({ isResolved: false });
486+
487+
await injector.resolveComponentInstance(module, '', {} as any, []);
488+
expect(loadStub.called).to.be.true;
489+
});
490+
it('should not call loadInstanceOfComponent (isResolved)', async () => {
491+
const loadStub = sinon.stub(injector, 'loadInstanceOfComponent').callsFake(() => null);
492+
sinon.stub(injector, 'scanForComponent').returns({ isResolved: true });
493+
494+
await injector.resolveComponentInstance(module, '', {} as any, []);
495+
expect(loadStub.called).to.be.false;
496+
});
497+
it('should not call loadInstanceOfComponent (forwardRef)', async () => {
498+
const loadStub = sinon.stub(injector, 'loadInstanceOfComponent').callsFake(() => null);
499+
sinon.stub(injector, 'scanForComponent').returns({ isResolved: false, forwardRef: true });
500+
501+
await injector.resolveComponentInstance(module, '', {} as any, []);
502+
expect(loadStub.called).to.be.false;
503+
});
504+
});
505+
506+
describe('when instanceWraper has async property', () => {
507+
it('should await instance', async () => {
508+
const loadStub = sinon.stub(injector, 'loadInstanceOfComponent').callsFake(() => null);
509+
510+
const instance = Promise.resolve(true);
511+
sinon.stub(injector, 'scanForComponent').returns({
512+
isResolved: false,
513+
forwardRef: true,
514+
async: true,
515+
instance,
516+
});
517+
const result = await injector.resolveComponentInstance(module, '', {} as any, []);
518+
expect(result.instance).to.be.true;
519+
});
520+
});
373521
});
374-
});
522+
});

0 commit comments

Comments
 (0)