/
githubmirror
/
nest
Обзор
Документация
Войти
/
githubmirror
/
nest
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
packages/core/test/injector/instance-wrapper.spec.ts
1 051 строка
38 KB
Puneet Dixit
fix(core): propagate dependency tree cache resets
24 май 2026, 09:13
24 май 2026, 09:13
1b8c8b0
Код
Авторство
О чём код?
import { Scope } from '@nestjs/common'; import { expect } from 'chai'; import * as sinon from 'sinon'; import { createContextId } from '../../helpers'; import { STATIC_CONTEXT } from '../../injector/constants'; import { InstanceWrapper } from '../../injector/instance-wrapper'; class TestClass {} describe('InstanceWrapper', () => { describe('initialize', () => { const partial = { name: 'test', metatype: TestClass, scope: Scope.DEFAULT, instance: new TestClass(), }; it('should assign partial', () => { const instance = new InstanceWrapper(partial); expect(instance.name).to.be.eql(partial.name); expect(instance.scope).to.be.eql(partial.scope); expect(instance.metatype).to.be.eql(partial.metatype); }); it('should set instance by context id', () => { const instance = new InstanceWrapper(partial); expect( instance.getInstanceByContextId(STATIC_CONTEXT).instance, ).to.be.eql(partial.instance); }); }); describe('isDependencyTreeStatic', () => { describe('when circular reference', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); const otherWrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, otherWrapper); otherWrapper.addCtorMetadata(0, wrapper); expect(wrapper.isDependencyTreeStatic()).to.be.true; expect(otherWrapper.isDependencyTreeStatic()).to.be.true; }); }); describe('when circular reference and one non static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); const otherWrapper = new InstanceWrapper({ scope: Scope.REQUEST }); wrapper.addCtorMetadata(0, otherWrapper); otherWrapper.addCtorMetadata(0, wrapper); expect(wrapper.isDependencyTreeStatic()).to.be.false; expect(otherWrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('when circular reference and one durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); const otherWrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addCtorMetadata(0, otherWrapper); otherWrapper.addCtorMetadata(0, wrapper); expect(wrapper.isDependencyTreeStatic()).to.be.false; expect(otherWrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('when request scoped', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, }); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('when request scoped durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('when request scoped explicit non durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: false, }); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('when default', () => { it('should return true', () => { const wrapper = new InstanceWrapper({}); expect(wrapper.isDependencyTreeStatic()).to.be.true; }); it('should recompute when dependencies are added after static introspection', () => { const wrapper = new InstanceWrapper({}); expect(wrapper.isDependencyTreeStatic()).to.be.true; wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST, }), ); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); it('should recompute when transitive dependencies change after static introspection', () => { const wrapper = new InstanceWrapper({}); const dependency = new InstanceWrapper({}); wrapper.addCtorMetadata(0, dependency); expect(wrapper.isDependencyTreeStatic()).to.be.true; dependency.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST, }), ); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('when statically scoped', () => { describe('dependencies, properties, enhancers', () => { describe('dependencies non static, properties static, enhancers static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('dependencies static, properties non static, enhancers static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); describe('dependencies static, properties static, enhancers non static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); }); describe('dependencies', () => { describe('when each is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); expect(wrapper.isDependencyTreeStatic()).to.be.true; }); }); describe('when one is not static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); wrapper.addCtorMetadata( 1, new InstanceWrapper({ scope: Scope.REQUEST, }), ); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); }); describe('properties', () => { describe('when each is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); wrapper.addPropertiesMetadata('key2', new InstanceWrapper()); expect(wrapper.isDependencyTreeStatic()).to.be.true; }); }); describe('when one is not static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addPropertiesMetadata('key2', new InstanceWrapper()); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); }); describe('enhancers', () => { describe('when each is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); wrapper.addEnhancerMetadata(new InstanceWrapper()); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeStatic()).to.be.true; }); }); describe('when one is not static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeStatic()).to.be.false; }); }); }); }); }); describe('isDependencyTreeDurable', () => { describe('when circular reference and default scope', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); const otherWrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, otherWrapper); otherWrapper.addCtorMetadata(0, wrapper); expect(wrapper.isDependencyTreeDurable()).to.be.false; expect(otherWrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when circular reference and one non durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); const otherWrapper = new InstanceWrapper({ scope: Scope.REQUEST }); wrapper.addCtorMetadata(0, otherWrapper); otherWrapper.addCtorMetadata(0, wrapper); expect(wrapper.isDependencyTreeDurable()).to.be.false; expect(otherWrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when circular reference and one durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); const otherWrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addCtorMetadata(0, otherWrapper); otherWrapper.addCtorMetadata(0, wrapper); expect(wrapper.isDependencyTreeDurable()).to.be.true; expect(otherWrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when request scoped and durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when request scoped and non durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, }); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when request scoped and explicit non durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: false, }); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when default scope', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when statically scoped', () => { describe('dependencies, properties, enhancers', () => { describe('dependencies non durable, properties non durable, enhancers durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addCtorMetadata(1, new InstanceWrapper()); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('dependencies non durable, properties durable, enhancers durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addCtorMetadata(1, new InstanceWrapper()); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('dependencies non durable, properties durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addCtorMetadata(1, new InstanceWrapper()); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); wrapper.addPropertiesMetadata( 'key2', new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('properties durable, enhancers non durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); wrapper.addPropertiesMetadata( 'key2', new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('dependencies durable, enhancers non durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); }); describe('dependencies', () => { describe('when wrapper is non durable and dependency is static', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST }); wrapper.addCtorMetadata(0, new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when wrapper is durable and dependency is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addCtorMetadata(0, new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when wrapper is non durable and dependency is durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, }); wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when wrapper is durable and dependency is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addCtorMetadata(0, new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when wrapper is durable and dependency is non durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addCtorMetadata( 0, new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when each is static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when one is not static and non-durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); wrapper.addCtorMetadata( 1, new InstanceWrapper({ scope: Scope.REQUEST, }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when one is not static and durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); wrapper.addCtorMetadata( 1, new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }), ); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when one is not static, durable and non durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addCtorMetadata(0, new InstanceWrapper()); wrapper.addCtorMetadata( 1, new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }), ); wrapper.addCtorMetadata( 2, new InstanceWrapper({ scope: Scope.REQUEST, }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); }); describe('properties', () => { describe('when wrapper is non durable and dependency is static', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST }); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when wrapper is durable and dependency is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when wrapper is non durable and dependency is durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, }); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when wrapper is durable and dependency is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when wrapper is durable and dependency is non durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when each is static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addPropertiesMetadata('key1', new InstanceWrapper()); wrapper.addPropertiesMetadata('key2', new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when one is not static and non-durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addPropertiesMetadata('key2', new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when one is not static and durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); wrapper.addPropertiesMetadata('key2', new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when one is not static, non durable and durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addPropertiesMetadata( 'key1', new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); wrapper.addPropertiesMetadata('key2', new InstanceWrapper()); wrapper.addPropertiesMetadata( 'key3', new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); }); describe('enhancers', () => { describe('when wrapper is non durable and dependency is static', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST }); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when wrapper is durable and dependency is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when wrapper is non durable and dependency is durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, }); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when wrapper is durable and dependency is static', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when wrapper is durable and dependency is non durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, durable: true, }); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when each is static', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addEnhancerMetadata(new InstanceWrapper()); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when one is not static and non-durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST }), ); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); describe('when one is not static and durable', () => { it('should return true', () => { const wrapper = new InstanceWrapper(); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); wrapper.addEnhancerMetadata(new InstanceWrapper()); expect(wrapper.isDependencyTreeDurable()).to.be.true; }); }); describe('when one is not static, non durable and durable', () => { it('should return false', () => { const wrapper = new InstanceWrapper(); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST, durable: true }), ); wrapper.addEnhancerMetadata(new InstanceWrapper()); wrapper.addEnhancerMetadata( new InstanceWrapper({ scope: Scope.REQUEST }), ); expect(wrapper.isDependencyTreeDurable()).to.be.false; }); }); }); }); }); describe('isNotMetatype', () => { describe('when metatype is nil', () => { it('should return true', () => { const instance = new InstanceWrapper({ metatype: null }); expect(instance.isNotMetatype).to.be.true; }); }); describe('when metatype is not nil', () => { it('should return false', () => { const instance = new InstanceWrapper({ metatype: TestClass }); expect(instance.isNotMetatype).to.be.false; }); }); }); describe('addEnhancerMetadata', () => { it('should add enhancers metadata', () => { const instance = new InstanceWrapper(); const enhancers = [new InstanceWrapper()]; instance.addEnhancerMetadata(enhancers[0]); expect(instance.getEnhancersMetadata()).to.be.eql(enhancers); }); }); describe('when set instance has been called', () => { it('should set static context value', () => { const instance = { test: true }; const wrapper = new InstanceWrapper(); wrapper.instance = instance; expect(wrapper.getInstanceByContextId(STATIC_CONTEXT).instance).to.be.eql( instance, ); }); }); describe('cloneStaticInstance', () => { describe('when wrapper is static', () => { it('should return static instance', () => { const instance = { test: true }; const wrapper = new InstanceWrapper({ instance }); expect(wrapper.cloneStaticInstance({ id: 0 }).instance).to.be.eql( instance, ); }); }); describe('when wrapper is not static', () => { it('should clone instance by context id', () => { const instance = { test: true }; const wrapper = new InstanceWrapper({ instance, scope: Scope.REQUEST }); expect(wrapper.cloneStaticInstance({ id: 0 }).instance).to.be.undefined; }); }); }); describe('getInstanceByContextId', () => { describe('when transient and inquirer has been passed', () => { it('should call "getInstanceByInquirerId"', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); const getInstanceByInquirerIdSpy = sinon.spy( wrapper, 'getInstanceByInquirerId', ); wrapper.getInstanceByContextId(STATIC_CONTEXT, 'inquirerId'); expect(getInstanceByInquirerIdSpy.called).to.be.true; }); }); }); describe('setInstanceByContextId', () => { describe('when transient and inquirer has been passed', () => { it('should call "setInstanceByInquirerId"', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); const setInstanceByInquirerIdSpy = sinon.spy( wrapper, 'setInstanceByInquirerId', ); wrapper.setInstanceByContextId( STATIC_CONTEXT, { instance: {} }, 'inquirerId', ); expect(setInstanceByInquirerIdSpy.called).to.be.true; }); }); }); describe('removeInstanceByContextId', () => { describe('without inquirer', () => { it('should remove instance for given context', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); const contextId = createContextId(); wrapper.setInstanceByContextId(contextId, { instance: {} }); const existingContext = wrapper.getInstanceByContextId(contextId); expect(existingContext.instance).to.be.not.undefined; wrapper.removeInstanceByContextId(contextId); const removedContext = wrapper.getInstanceByContextId(contextId); expect(removedContext.instance).to.be.undefined; }); }); describe('when transient and inquirer has been passed', () => { it('should remove instance for given context', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); wrapper.setInstanceByContextId( STATIC_CONTEXT, { instance: {} }, 'inquirerId', ); const existingContext = wrapper.getInstanceByContextId( STATIC_CONTEXT, 'inquirerId', ); expect(existingContext.instance).to.be.not.undefined; wrapper.removeInstanceByContextId(STATIC_CONTEXT, 'inquirerId'); const removedContext = wrapper.getInstanceByContextId( STATIC_CONTEXT, 'inquirerId', ); expect(removedContext.instance).to.be.undefined; }); }); }); describe('isInRequestScope', () => { describe('when tree and context are not static and is not transient', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, }); expect(wrapper.isInRequestScope({ id: 3 })).to.be.true; }); }); describe('otherwise', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); expect(wrapper.isInRequestScope({ id: 3 })).to.be.false; const wrapper2 = new InstanceWrapper({ scope: Scope.REQUEST, }); expect(wrapper2.isInRequestScope(STATIC_CONTEXT)).to.be.false; }); }); }); describe('isLazyTransient', () => { describe('when inquirer is request scoped and context is not static and is transient', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); expect( wrapper.isLazyTransient( { id: 3 }, new InstanceWrapper({ scope: Scope.REQUEST, }), ), ).to.be.true; }); }); describe('otherwise', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); expect(wrapper.isLazyTransient({ id: 3 }, new InstanceWrapper())).to.be .false; const wrapper2 = new InstanceWrapper({ scope: Scope.REQUEST, }); expect( wrapper2.isLazyTransient( STATIC_CONTEXT, new InstanceWrapper({ scope: Scope.TRANSIENT, }), ), ).to.be.false; }); }); }); describe('isStatic', () => { describe('when inquirer is not request scoped and context and tree are static', () => { it('should return true', () => { const wrapper = new InstanceWrapper({ scope: Scope.DEFAULT, }); expect( wrapper.isStatic( STATIC_CONTEXT, new InstanceWrapper({ scope: Scope.DEFAULT, }), ), ).to.be.true; }); }); describe('otherwise', () => { it('should return false', () => { const wrapper = new InstanceWrapper({ scope: Scope.REQUEST, }); expect(wrapper.isStatic({ id: 3 }, new InstanceWrapper())).to.be.false; const wrapper2 = new InstanceWrapper({ scope: Scope.TRANSIENT, }); expect( wrapper2.isStatic( STATIC_CONTEXT, new InstanceWrapper({ scope: Scope.REQUEST, }), ), ).to.be.false; }); }); }); describe('getStaticTransientInstances', () => { describe('when instance is not transient', () => { it('should return an empty array', () => { const wrapper = new InstanceWrapper({ scope: Scope.DEFAULT, }); expect(wrapper.getStaticTransientInstances()).to.be.eql([]); }); }); describe('when instance is transient', () => { it('should return instances where constructor was called', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); const instanceHost = { instance: {}, isConstructorCalled: true, }; wrapper.setInstanceByInquirerId(STATIC_CONTEXT, 'test', instanceHost); expect(wrapper.getStaticTransientInstances()).to.be.eql([instanceHost]); }); describe('lifecycle hooks on transient services', () => { // Tests for issue #15553: prevent lifecycle hooks on non-instantiated transient services it('should filter out instances created with Object.create (prototype only)', () => { const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, }); // Simulates what happens in cloneTransientInstance const prototypeOnlyInstance = { instance: Object.create({}), isResolved: true, // This is set to true incorrectly in injector.ts isConstructorCalled: false, // But constructor was never called }; wrapper.setInstanceByInquirerId( STATIC_CONTEXT, 'inquirer', prototypeOnlyInstance, ); // Should not include this instance for lifecycle hooks expect(wrapper.getStaticTransientInstances()).to.be.eql([]); }); it('should include instances where constructor was actually invoked', () => { class TestService {} const wrapper = new InstanceWrapper({ scope: Scope.TRANSIENT, metatype: TestService, }); // Simulates what happens after instantiateClass const properInstance = { instance: new TestService(), isResolved: true, isConstructorCalled: true, }; wrapper.setInstanceByInquirerId( STATIC_CONTEXT, 'inquirer', properInstance, ); // Should include this instance for lifecycle hooks expect(wrapper.getStaticTransientInstances()).to.be.eql([ properInstance, ]); }); }); }); }); describe('mergeWith', () => { describe('when provider is a ValueProvider', () => { it('should provide the given value in the STATIC_CONTEXT', () => { const wrapper = new InstanceWrapper(); wrapper.mergeWith({ useValue: 'value', provide: 'token', }); expect( wrapper.getInstanceByContextId(STATIC_CONTEXT).instance, ).to.be.equal('value'); }); }); describe('when provider is a ClassProvider', () => { it('should alter the instance wrapper metatype with the given class', () => { const wrapper = new InstanceWrapper(); wrapper.mergeWith({ useClass: TestClass, provide: 'token', }); expect(wrapper.metatype).to.be.eql(TestClass); }); }); describe('when provider is a FactoryProvider', () => { describe('and it has injected dependencies', () => { it('should alter the instance wrapper metatype and inject attributes with the given values', () => { const wrapper = new InstanceWrapper(); const factory = (_dependency1: any, _dependency2: any) => {}; const injectedDependencies = ['dependency1', 'dependency2']; wrapper.mergeWith({ provide: 'token', useFactory: factory, inject: injectedDependencies, }); expect(wrapper.metatype).to.be.eql(factory); expect(wrapper.inject).to.be.eq(injectedDependencies); }); }); describe('and it has no injected dependencies', () => { it('should alter the instance wrapper metatype with the given values', () => { const wrapper = new InstanceWrapper(); const factory = (_dependency1: any, _dependency2: any) => {}; wrapper.mergeWith({ provide: 'token', useFactory: factory, }); expect(wrapper.metatype).to.be.eql(factory); expect(wrapper.inject).to.be.eql([]); }); }); }); }); });