From f6ae117a949c353267ccd21bb7b5239705c6a62e Mon Sep 17 00:00:00 2001 From: Iku-turso Date: Tue, 22 Nov 2022 13:55:18 +0200 Subject: [PATCH] feat: Permit override of single injectable using injection token --- .../createContainer.js | 22 ++++- .../createContainer.override.test.js | 86 +++++++++++++++++++ 2 files changed, 106 insertions(+), 2 deletions(-) diff --git a/packages/injectable/core/src/dependency-injection-container/createContainer.js b/packages/injectable/core/src/dependency-injection-container/createContainer.js index 116a01a9..5abafe86 100644 --- a/packages/injectable/core/src/dependency-injection-container/createContainer.js +++ b/packages/injectable/core/src/dependency-injection-container/createContainer.js @@ -238,9 +238,25 @@ export default containerId => { }, override: (alias, instantiateStub) => { - const originalInjectable = injectableMap.get(alias.id); + const relatedInjectables = getRelatedInjectables(alias); + + if (relatedInjectables.length > 1) { + throw new Error( + `Tried to override single implementation of injection token "${ + alias.id + }", but found multiple registered implementations: "${relatedInjectables + .map(x => x.id) + .join('", "')}".`, + ); + } + + if (relatedInjectables.length === 0) { + if (alias.aliasType === 'injection-token') { + throw new Error( + `Tried to override single implementation of injection token "${alias.id}", but found no registered implementations.`, + ); + } - if (!originalInjectable) { throw new Error( `Tried to override "${alias.id}" which is not registered.`, ); @@ -252,6 +268,8 @@ export default containerId => { ); } + const originalInjectable = relatedInjectables[0]; + overridingInjectables.set(originalInjectable.id, { ...originalInjectable, causesSideEffects: false, diff --git a/packages/injectable/core/src/dependency-injection-container/createContainer.override.test.js b/packages/injectable/core/src/dependency-injection-container/createContainer.override.test.js index ff0bb385..47c1f35e 100644 --- a/packages/injectable/core/src/dependency-injection-container/createContainer.override.test.js +++ b/packages/injectable/core/src/dependency-injection-container/createContainer.override.test.js @@ -203,4 +203,90 @@ describe('createContainer.override', () => { expect(actual).toEqual(['some-override']); }); + + it('given single registered injectable with injection token, and the injection token is overridden, when the injection token is inject-singled, injects the overridden instance', () => { + const di = createContainer('some-container'); + + const someInjectionToken = getInjectionToken({ + id: 'some-injection-token', + }); + + const injectable = getInjectable({ + id: 'some-injectable', + instantiate: () => 'irrelevant', + injectionToken: someInjectionToken, + }); + + di.register(injectable); + + di.override(someInjectionToken, () => 'some-override'); + + const actual = di.inject(someInjectionToken); + + expect(actual).toBe('some-override'); + }); + + it('given single registered injectable with injection token, and the injection token is overridden, when the injection token is inject-many, injects the overridden instance', () => { + const di = createContainer('some-container'); + + const someInjectionToken = getInjectionToken({ + id: 'some-injection-token', + }); + + const injectable = getInjectable({ + id: 'some-injectable', + instantiate: () => 'irrelevant', + injectionToken: someInjectionToken, + }); + + di.register(injectable); + + di.override(someInjectionToken, () => 'some-override'); + + const actual = di.injectMany(someInjectionToken); + + expect(actual).toEqual(['some-override']); + }); + + it('given multiple registered injectables with injection token, and the injection token is overridden, throws', () => { + const di = createContainer('some-container'); + + const someInjectionToken = getInjectionToken({ + id: 'some-injection-token', + }); + + const injectable1 = getInjectable({ + id: 'some-injectable-1', + instantiate: () => 'irrelevant', + injectionToken: someInjectionToken, + }); + + const injectable2 = getInjectable({ + id: 'some-injectable-2', + instantiate: () => 'irrelevant', + injectionToken: someInjectionToken, + }); + + di.register(injectable1, injectable2); + + expect(() => { + di.override(someInjectionToken, () => 'some-override'); + }).toThrow( + 'Tried to override single implementation of injection token "some-injection-token", but found multiple registered implementations: "some-injectable-1", "some-injectable-2".', + ); + }); + + it('given no registered injectable with injection token, when the injection token is overridden, throws', () => { + const di = createContainer('some-container'); + + const someInjectionToken = getInjectionToken({ + id: 'some-injection-token', + }); + + expect(() => { + di.override(someInjectionToken, () => 'some-override'); + }).toThrow( + 'Tried to override single implementation of injection token "some-injection-token", but found no registered implementations.', + ); + }); });