From 481dc8dd2ec46c833d3e885408b8cb6bc417adc4 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir Date: Wed, 13 Jul 2022 12:31:37 -0700 Subject: [PATCH] refactor(core): improve an error message when `ENVIRONMENT_INITIALIZER` is not a multi provider (#46829) Currently if the `ENVIRONMENT_INITIALIZER` token is not configured with `multi: true` flag, the code fails while trying to iterate over the value. This commit checks whether the `ENVIRONMENT_INITIALIZER` token value type is an array and throws a helpful error message. PR Close #46829 --- goldens/public-api/core/errors.md | 2 ++ packages/core/src/di/r3_injector.ts | 8 ++++++++ packages/core/src/errors.ts | 1 + .../test/acceptance/environment_injector_spec.ts | 16 +++++++++++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/goldens/public-api/core/errors.md b/goldens/public-api/core/errors.md index 3838e00d62bd8..5fc140815380a 100644 --- a/goldens/public-api/core/errors.md +++ b/goldens/public-api/core/errors.md @@ -47,6 +47,8 @@ export const enum RuntimeErrorCode { // (undocumented) INVALID_INJECTION_TOKEN = 204, // (undocumented) + INVALID_MULTI_PROVIDER = 209, + // (undocumented) MISSING_GENERATED_DEF = 906, // (undocumented) MISSING_INJECTION_CONTEXT = -203, diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index 6d4e94774381f..81cc5a3e1a826 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -247,6 +247,14 @@ export class R3Injector extends EnvironmentInjector { const previousInjectImplementation = setInjectImplementation(undefined); try { const initializers = this.get(ENVIRONMENT_INITIALIZER.multi, EMPTY_ARRAY, InjectFlags.Self); + if (ngDevMode && !Array.isArray(initializers)) { + throw new RuntimeError( + RuntimeErrorCode.INVALID_MULTI_PROVIDER, + 'Unexpected type of the `ENVIRONMENT_INITIALIZER` token value ' + + `(expected an array, but got ${typeof initializers}). ` + + 'Please check that the `ENVIRONMENT_INITIALIZER` token is configured as a ' + + '`multi: true` provider.'); + } for (const initializer of initializers) { initializer(); } diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index 003f795e97714..d517878135d0f 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -32,6 +32,7 @@ export const enum RuntimeErrorCode { INJECTOR_ALREADY_DESTROYED = 205, PROVIDER_IN_WRONG_CONTEXT = 207, MISSING_INJECTION_TOKEN = 208, + INVALID_MULTI_PROVIDER = 209, // Template Errors MULTIPLE_COMPONENTS_MATCH = -300, diff --git a/packages/core/test/acceptance/environment_injector_spec.ts b/packages/core/test/acceptance/environment_injector_spec.ts index 2ad7eb5e1a06d..0c91f074a5262 100644 --- a/packages/core/test/acceptance/environment_injector_spec.ts +++ b/packages/core/test/acceptance/environment_injector_spec.ts @@ -88,7 +88,7 @@ describe('environment injector', () => { expect(cRef.instance.service).toBeInstanceOf(Service); }); - it('should support the ENVIRONMENT_INITIALIZER muli-token', () => { + it('should support the ENVIRONMENT_INITIALIZER multi-token', () => { let initialized = false; createEnvironmentInjector([{ provide: ENVIRONMENT_INITIALIZER, @@ -99,6 +99,20 @@ describe('environment injector', () => { expect(initialized).toBeTrue(); }); + it('should throw when the ENVIRONMENT_INITIALIZER is not a multi-token', () => { + const parentEnvInjector = TestBed.inject(EnvironmentInjector); + const providers = [{ + provide: ENVIRONMENT_INITIALIZER, + useValue: () => {}, + }]; + expect(() => createEnvironmentInjector(providers, parentEnvInjector)) + .toThrowError( + 'NG0209: Unexpected type of the `ENVIRONMENT_INITIALIZER` token value ' + + '(expected an array, but got function). ' + + 'Please check that the `ENVIRONMENT_INITIALIZER` token is configured as ' + + 'a `multi: true` provider.'); + }); + it('should adopt environment-scoped providers', () => { const injector = createEnvironmentInjector([]); const EnvScopedToken = new InjectionToken('env-scoped token', {