Skip to content

Commit

Permalink
feat(ng-dev): ComponentContext will now run APP_INITIALIZERs befo…
Browse files Browse the repository at this point in the history
…re instantiating your component. This requires all work in your initializers to complete with a call to `tick()`.
  • Loading branch information
ersimont committed Aug 16, 2022
1 parent 09b1d55 commit 4f5a0a2
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ComponentHarness } from '@angular/cdk/testing';
import {
APP_INITIALIZER,
Component,
InjectionToken,
Input,
Expand All @@ -15,6 +16,7 @@ import {
} from '@angular/platform-browser/animations';
import { RouterModule, Routes } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { sleep } from '@s-libs/js-core';
import { noop } from '@s-libs/micro-dash';
import { ComponentContext } from './component-context';

Expand Down Expand Up @@ -179,6 +181,34 @@ describe('ComponentContext', () => {
expect(spy).toHaveBeenCalledTimes(1);
});
});

it('causes APP_INITIALIZERs to complete before instantiating the component', () => {
const appInitSpy = jasmine.createSpy('app init');
const componentInitSpy = jasmine.createSpy('component init');

@Component({ template: '' })
class InitializingComponent {
constructor() {
componentInitSpy();
}
}

const ctx = new ComponentContext(InitializingComponent, {
providers: [
{
provide: APP_INITIALIZER,
useFactory: () => async (): Promise<void> => {
await sleep(0);
appInitSpy();
},
multi: true,
},
],
});
ctx.run(async () => {
expect(appInitSpy).toHaveBeenCalledBefore(componentInitSpy);
});
});
});

describe('.runChangeDetection()', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Type } from '@angular/core';
import { ApplicationInitStatus, Type } from '@angular/core';
import {
ComponentFixture,
TestBed,
TestModuleMetadata,
tick,
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
Expand All @@ -22,6 +23,7 @@ import { WrapperComponent } from './wrapper.component';
* - Wraps your component in a parent that you can easily style however you like.
* - Lets you use {@link https://material.angular.io/cdk/test-harnesses/overview|component harnesses} in the `fakeAsync` zone, which is normally a challenge.
* - Automatically disables animations.
* - Causes {@link https://angular.io/api/core/APP_INITIALIZER APP_INITIALIZER}s to run before instantiating the component. However, this requires all work in your initializers to complete with a call to `tick()`.
*
* A very simple example:
* ```ts
Expand Down Expand Up @@ -230,6 +232,11 @@ export class ComponentContext<T> extends AngularContext {
*/
protected override init(): void {
super.init();

// Inject something (I think anything) to finalize the compiler and trigger any registered APP_INITIALIZER. Then `tick()` to (hopefully) run it, assuming the user is only doing things that will be flushed right away.
this.inject(ApplicationInitStatus);
tick(); // can't use `this.tick()` until the component exists

this.fixture = TestBed.createComponent(WrapperComponent);

this.flushStylesToWrapper();
Expand Down

0 comments on commit 4f5a0a2

Please sign in to comment.