fix(core): run `APP_INITIALIZER`s before accessing `LOCALE_ID` token in Ivy TestBed (#36237)

Prior to this commit, Ivy TestBed was accessing locale ID before `APP_INITIALIZER` functions were called. This execution order is not consistent with the app bootstrap logic in `application_ref.ts`. This commit updates Ivy TestBed execution order to call initializers first (since they might affect `LOCALE_ID` token value) and accessing and setting locale ID after that.

Fixes #36230.

PR Close #36237
This commit is contained in:
Andrew Kushnir 2020-03-24 17:19:47 -07:00 committed by Alex Rickabaugh
parent b54db86f43
commit 16497438d6
2 changed files with 22 additions and 5 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef, Compiler, Component, Directive, ErrorHandler, Inject, Injectable, InjectionToken, Injector, Input, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core';
import {APP_INITIALIZER, ChangeDetectorRef, Compiler, Component, Directive, ErrorHandler, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core';
import {TestBed, getTestBed} from '@angular/core/testing/src/test_bed';
import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
@ -245,6 +245,21 @@ describe('TestBed', () => {
expect(hello.nativeElement).toHaveText('Hello World!');
});
it('should run `APP_INITIALIZER` before accessing `LOCALE_ID` provider', () => {
let locale: string = '';
@NgModule({
providers: [
{provide: APP_INITIALIZER, useValue: () => locale = 'fr-FR', multi: true},
{provide: LOCALE_ID, useFactory: () => locale}
]
})
class TestModule {
}
TestBed.configureTestingModule({imports: [TestModule]});
expect(TestBed.inject(LOCALE_ID)).toBe('fr-FR');
});
it('allow to override a provider', () => {
TestBed.overrideProvider(NAME, {useValue: 'injected World!'});
const hello = TestBed.createComponent(HelloWorld);

View File

@ -257,14 +257,16 @@ export class R3TestBedCompiler {
const parentInjector = this.platform.injector;
this.testModuleRef = new NgModuleRef(this.testModuleType, parentInjector);
// Set the locale ID, it can be overridden for the tests
const localeId = this.testModuleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
setLocaleId(localeId);
// ApplicationInitStatus.runInitializers() is marked @internal to core.
// Cast it to any before accessing it.
(this.testModuleRef.injector.get(ApplicationInitStatus) as any).runInitializers();
// Set locale ID after running app initializers, since locale information might be updated while
// running initializers. This is also consistent with the execution order while bootstrapping an
// app (see `packages/core/src/application_ref.ts` file).
const localeId = this.testModuleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
setLocaleId(localeId);
return this.testModuleRef;
}