Skip to content

Commit 6458c3b

Browse files
authored
refactor: move force-stabilize from TestElement to ComponentHa… (#17149)
* refactor: move force-stabilize from TestElement to ComponentHarness Currently the `forceStabilize` method lives on `TestElement`. This is not the most ergonomic place, given its intended use. This PR moves it to the `ComponentHarness` base class so that subclasses can simply call `await this.forceStabilize()` * fix api test
1 parent e62e6bd commit 6458c3b

File tree

8 files changed

+38
-28
lines changed

8 files changed

+38
-28
lines changed

src/cdk/testing/component-harness.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ export interface LocatorFactory {
142142
*/
143143
locatorForAll<T extends ComponentHarness>(
144144
harnessType: ComponentHarnessConstructor<T> | HarnessPredicate<T>): AsyncFactoryFn<T[]>;
145+
146+
/**
147+
* Flushes change detection and async tasks.
148+
* In most cases it should not be necessary to call this manually. However, there may be some edge
149+
* cases where it is needed to fully flush animation events.
150+
*/
151+
forceStabilize(): Promise<void>;
145152
}
146153

147154
/**
@@ -245,6 +252,15 @@ export abstract class ComponentHarness {
245252
protected locatorForAll(arg: any) {
246253
return this.locatorFactory.locatorForAll(arg);
247254
}
255+
256+
/**
257+
* Flushes change detection and async tasks.
258+
* In most cases it should not be necessary to call this manually. However, there may be some edge
259+
* cases where it is needed to fully flush animation events.
260+
*/
261+
protected async forceStabilize() {
262+
return this.locatorFactory.forceStabilize();
263+
}
248264
}
249265

250266
/** Constructor for a ComponentHarness subclass. */

src/cdk/testing/harness-environment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
110110
return new harnessType(this.createEnvironment(element));
111111
}
112112

113+
// Part of LocatorFactory interface, subclasses will implement.
114+
abstract forceStabilize(): Promise<void>;
115+
113116
/** Gets the root element for the document. */
114117
protected abstract getDocumentRoot(): E;
115118

src/cdk/testing/protractor/protractor-element.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,4 @@ export class ProtractorElement implements TestElement {
148148
Element.prototype.msMatchesSelector).call(arguments[0], arguments[1])
149149
`, this.element, selector);
150150
}
151-
152-
async forceStabilize(): Promise<void> {}
153151
}

src/cdk/testing/protractor/protractor-harness-environment.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {HarnessEnvironment} from '@angular/cdk/testing';
910
import {by, element as protractorElement, ElementFinder} from 'protractor';
1011
import {HarnessLoader} from '../component-harness';
11-
import {HarnessEnvironment} from '../harness-environment';
1212
import {TestElement} from '../test-element';
1313
import {ProtractorElement} from './protractor-element';
1414

@@ -23,6 +23,8 @@ export class ProtractorHarnessEnvironment extends HarnessEnvironment<ElementFind
2323
return new ProtractorHarnessEnvironment(protractorElement(by.css('body')));
2424
}
2525

26+
async forceStabilize(): Promise<void> {}
27+
2628
protected getDocumentRoot(): ElementFinder {
2729
return protractorElement(by.css('body'));
2830
}

src/cdk/testing/test-element.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,4 @@ export interface TestElement {
104104

105105
/** Checks whether this element matches the given selector. */
106106
matchesSelector(selector: string): Promise<boolean>;
107-
108-
/**
109-
* Flushes change detection and async tasks.
110-
* In most cases it should not be necessary to call this. However, there may be some edge cases
111-
* where it is needed to fully flush animation events.
112-
*/
113-
forceStabilize(): Promise<void>;
114107
}

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {HarnessEnvironment} from '@angular/cdk/testing';
910
import {ComponentFixture} from '@angular/core/testing';
1011
import {ComponentHarness, ComponentHarnessConstructor, HarnessLoader} from '../component-harness';
11-
import {HarnessEnvironment} from '../harness-environment';
1212
import {TestElement} from '../test-element';
1313
import {UnitTestElement} from './unit-test-element';
1414

@@ -43,33 +43,33 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
4343
static async harnessForFixture<T extends ComponentHarness>(
4444
fixture: ComponentFixture<unknown>, harnessType: ComponentHarnessConstructor<T>): Promise<T> {
4545
const environment = new TestbedHarnessEnvironment(fixture.nativeElement, fixture);
46-
await environment._stabilize();
46+
await environment.forceStabilize();
4747
return environment.createComponentHarness(harnessType, fixture.nativeElement);
4848
}
4949

50+
async forceStabilize(): Promise<void> {
51+
if (this._destroyed) {
52+
throw Error('Harness is attempting to use a fixture that has already been destroyed.');
53+
}
54+
55+
this._fixture.detectChanges();
56+
await this._fixture.whenStable();
57+
}
58+
5059
protected getDocumentRoot(): Element {
5160
return document.body;
5261
}
5362

5463
protected createTestElement(element: Element): TestElement {
55-
return new UnitTestElement(element, this._stabilize.bind(this));
64+
return new UnitTestElement(element, () => this.forceStabilize());
5665
}
5766

5867
protected createEnvironment(element: Element): HarnessEnvironment<Element> {
5968
return new TestbedHarnessEnvironment(element, this._fixture);
6069
}
6170

6271
protected async getAllRawElements(selector: string): Promise<Element[]> {
63-
await this._stabilize();
72+
await this.forceStabilize();
6473
return Array.from(this.rawRootElement.querySelectorAll(selector));
6574
}
66-
67-
private async _stabilize(): Promise<void> {
68-
if (this._destroyed) {
69-
throw Error('Harness is attempting to use a fixture that has already been destroyed.');
70-
}
71-
72-
this._fixture.detectChanges();
73-
await this._fixture.whenStable();
74-
}
7575
}

src/cdk/testing/testbed/unit-test-element.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,4 @@ export class UnitTestElement implements TestElement {
144144
return (elementPrototype['matches'] || elementPrototype['msMatchesSelector'])
145145
.call(this.element, selector);
146146
}
147-
148-
async forceStabilize(): Promise<void> {
149-
return this._stabilize();
150-
}
151147
}

tools/public_api_guard/cdk/testing.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export declare function clearElement(element: HTMLInputElement | HTMLTextAreaEle
1414
export declare abstract class ComponentHarness {
1515
constructor(locatorFactory: LocatorFactory);
1616
protected documentRootLocatorFactory(): LocatorFactory;
17+
protected forceStabilize(): Promise<void>;
1718
host(): Promise<TestElement>;
1819
protected locatorFor(selector: string): AsyncFactoryFn<TestElement>;
1920
protected locatorFor<T extends ComponentHarness>(harnessType: ComponentHarnessConstructor<T> | HarnessPredicate<T>): AsyncFactoryFn<T>;
@@ -54,6 +55,7 @@ export declare abstract class HarnessEnvironment<E> implements HarnessLoader, Lo
5455
protected abstract createEnvironment(element: E): HarnessEnvironment<E>;
5556
protected abstract createTestElement(element: E): TestElement;
5657
documentRootLocatorFactory(): LocatorFactory;
58+
abstract forceStabilize(): Promise<void>;
5759
getAllChildLoaders(selector: string): Promise<HarnessLoader[]>;
5860
getAllHarnesses<T extends ComponentHarness>(harnessType: ComponentHarnessConstructor<T> | HarnessPredicate<T>): Promise<T[]>;
5961
protected abstract getAllRawElements(selector: string): Promise<E[]>;
@@ -92,6 +94,7 @@ export declare function isTextInput(element: Element): element is HTMLInputEleme
9294
export interface LocatorFactory {
9395
rootElement: TestElement;
9496
documentRootLocatorFactory(): LocatorFactory;
97+
forceStabilize(): Promise<void>;
9598
locatorFor(selector: string): AsyncFactoryFn<TestElement>;
9699
locatorFor<T extends ComponentHarness>(harnessType: ComponentHarnessConstructor<T> | HarnessPredicate<T>): AsyncFactoryFn<T>;
97100
locatorForAll(selector: string): AsyncFactoryFn<TestElement[]>;
@@ -114,7 +117,6 @@ export interface TestElement {
114117
clear(): Promise<void>;
115118
click(relativeX?: number, relativeY?: number): Promise<void>;
116119
focus(): Promise<void>;
117-
forceStabilize(): Promise<void>;
118120
getAttribute(name: string): Promise<string | null>;
119121
getCssValue(property: string): Promise<string>;
120122
getDimensions(): Promise<ElementDimensions>;

0 commit comments

Comments
 (0)