Skip to content

Commit 3d30bf1

Browse files
authored
fix(cdk/testing): account for new DirectiveFixture API (#33771)
Since angular/angular#70453, the framework has a `DirectiveFixture` in addition to the `ComponentFixture`. These changes expand the APIs in the `TestbedHarnessEnvironment` to account for directive fixtures.
1 parent 0bb7b18 commit 3d30bf1

3 files changed

Lines changed: 319 additions & 137 deletions

File tree

‎goldens/cdk/testing/testbed/index.api.md‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@
55
```ts
66

77
import { ComponentFixture } from '@angular/core/testing';
8+
import { DirectiveFixture } from '@angular/core/testing';
9+
10+
// @public
11+
export type Fixture<T = unknown> = ComponentFixture<T> | DirectiveFixture<T>;
812

913
// @public
1014
export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
11-
protected constructor(rawRootElement: Element, _fixture: ComponentFixture<unknown>, options?: TestbedHarnessEnvironmentOptions);
15+
protected constructor(rawRootElement: Element, _fixture: Fixture, options?: TestbedHarnessEnvironmentOptions);
1216
protected createEnvironment(element: Element): HarnessEnvironment<Element>;
1317
protected createTestElement(element: Element): TestElement;
14-
static documentRootLoader(fixture: ComponentFixture<unknown>, options?: TestbedHarnessEnvironmentOptions): HarnessLoader;
18+
static documentRootLoader(fixture: Fixture, options?: TestbedHarnessEnvironmentOptions): HarnessLoader;
1519
forceStabilize(): Promise<void>;
1620
protected getAllRawElements(selector: string): Promise<Element[]>;
1721
protected getDocumentRoot(): Element;
1822
static getNativeElement(el: TestElement): Element;
19-
static harnessForFixture<T extends ComponentHarness>(fixture: ComponentFixture<unknown>, harnessType: ComponentHarnessConstructor<T>, options?: TestbedHarnessEnvironmentOptions): Promise<T>;
20-
static loader(fixture: ComponentFixture<unknown>, options?: TestbedHarnessEnvironmentOptions): HarnessLoader;
23+
static harnessForFixture<T extends ComponentHarness>(fixture: Fixture, harnessType: ComponentHarnessConstructor<T>, options?: TestbedHarnessEnvironmentOptions): Promise<T>;
24+
static loader(fixture: Fixture, options?: TestbedHarnessEnvironmentOptions): HarnessLoader;
2125
waitForTasksOutsideAngular(): Promise<void>;
2226
}
2327

‎src/cdk/testing/testbed/testbed-harness-environment.ts‎

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ import {
1515
stopHandlingAutoChangeDetectionStatus,
1616
TestElement,
1717
} from '../../testing';
18-
import {ComponentFixture, flush} from '@angular/core/testing';
18+
import {ComponentFixture, DirectiveFixture, flush, TestBed} from '@angular/core/testing';
1919
import {Observable} from 'rxjs';
2020
import {takeWhile} from 'rxjs/operators';
2121
import {TaskState, TaskStateZoneInterceptor} from './task-state-zone-interceptor';
2222
import {UnitTestElement} from './unit-test-element';
23+
import {DestroyRef} from '@angular/core';
2324

2425
/** Options to configure the environment. */
2526
export interface TestbedHarnessEnvironmentOptions {
@@ -32,19 +33,22 @@ const defaultEnvironmentOptions: TestbedHarnessEnvironmentOptions = {
3233
queryFn: (selector: string, root: Element) => root.querySelectorAll(selector),
3334
};
3435

36+
/** Covers all fixtures supported by `TestBed`. */
37+
export type Fixture<T = unknown> = ComponentFixture<T> | DirectiveFixture<T>;
38+
3539
/** Whether auto change detection is currently disabled. */
3640
let disableAutoChangeDetection = false;
3741

3842
/**
3943
* The set of non-destroyed fixtures currently being used by `TestbedHarnessEnvironment` instances.
4044
*/
41-
const activeFixtures = new Set<ComponentFixture<unknown>>();
45+
const activeFixtures = new Set<Fixture>();
4246

4347
/**
4448
* Installs a handler for change detection batching status changes for a specific fixture.
4549
* @param fixture The fixture to handle change detection batching for.
4650
*/
47-
function installAutoChangeDetectionStatusHandler(fixture: ComponentFixture<unknown>) {
51+
function installAutoChangeDetectionStatusHandler(fixture: Fixture) {
4852
if (!activeFixtures.size) {
4953
handleAutoChangeDetectionStatus(({isDisabled, onDetectChangesNow}) => {
5054
disableAutoChangeDetection = isDisabled;
@@ -60,7 +64,7 @@ function installAutoChangeDetectionStatusHandler(fixture: ComponentFixture<unkno
6064
* Uninstalls a handler for change detection batching status changes for a specific fixture.
6165
* @param fixture The fixture to stop handling change detection batching for.
6266
*/
63-
function uninstallAutoChangeDetectionStatusHandler(fixture: ComponentFixture<unknown>) {
67+
function uninstallAutoChangeDetectionStatusHandler(fixture: Fixture) {
6468
activeFixtures.delete(fixture);
6569
if (!activeFixtures.size) {
6670
stopHandlingAutoChangeDetectionStatus();
@@ -76,7 +80,7 @@ function isInFakeAsyncZone() {
7680
* Triggers change detection for a specific fixture.
7781
* @param fixture The fixture to trigger change detection for.
7882
*/
79-
async function detectChanges(fixture: ComponentFixture<unknown>) {
83+
async function detectChanges(fixture: Fixture) {
8084
fixture.detectChanges();
8185
if (isInFakeAsyncZone()) {
8286
flush();
@@ -101,7 +105,7 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
101105

102106
protected constructor(
103107
rawRootElement: Element,
104-
private _fixture: ComponentFixture<unknown>,
108+
private _fixture: Fixture,
105109
options?: TestbedHarnessEnvironmentOptions,
106110
) {
107111
super(rawRootElement);
@@ -111,17 +115,22 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
111115
}
112116
this._stabilizeCallback = () => this.forceStabilize();
113117
installAutoChangeDetectionStatusHandler(_fixture);
114-
_fixture.componentRef.onDestroy(() => {
118+
119+
const onDestroy = () => {
115120
uninstallAutoChangeDetectionStatusHandler(_fixture);
116121
this._destroyed = true;
117-
});
122+
};
123+
124+
if (_fixture instanceof ComponentFixture) {
125+
_fixture.componentRef.onDestroy(onDestroy);
126+
} else {
127+
// TODO(crisbeto): use host ref in directive fixture once it's available.
128+
TestBed.inject(DestroyRef).onDestroy(onDestroy);
129+
}
118130
}
119131

120132
/** Creates a `HarnessLoader` rooted at the given fixture's root element. */
121-
static loader(
122-
fixture: ComponentFixture<unknown>,
123-
options?: TestbedHarnessEnvironmentOptions,
124-
): HarnessLoader {
133+
static loader(fixture: Fixture, options?: TestbedHarnessEnvironmentOptions): HarnessLoader {
125134
return new TestbedHarnessEnvironment(fixture.nativeElement, fixture, options);
126135
}
127136

@@ -130,7 +139,7 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
130139
* located outside of a fixture (e.g. overlays appended to the document body).
131140
*/
132141
static documentRootLoader(
133-
fixture: ComponentFixture<unknown>,
142+
fixture: Fixture,
134143
options?: TestbedHarnessEnvironmentOptions,
135144
): HarnessLoader {
136145
return new TestbedHarnessEnvironment(document.body, fixture, options);
@@ -151,7 +160,7 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
151160
* of the fixture.
152161
*/
153162
static async harnessForFixture<T extends ComponentHarness>(
154-
fixture: ComponentFixture<unknown>,
163+
fixture: Fixture,
155164
harnessType: ComponentHarnessConstructor<T>,
156165
options?: TestbedHarnessEnvironmentOptions,
157166
): Promise<T> {

0 commit comments

Comments
 (0)