From 713b52a4cef604cee0d5dadff9dbe12cef89eca3 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 19 Sep 2019 11:29:09 -0700 Subject: [PATCH 1/2] 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()` --- src/cdk/testing/component-harness.ts | 16 ++++++++++++ src/cdk/testing/harness-environment.ts | 3 +++ .../testing/protractor/protractor-element.ts | 2 -- .../protractor-harness-environment.ts | 4 ++- src/cdk/testing/test-element.ts | 7 ----- .../testbed/testbed-harness-environment.ts | 26 +++++++++---------- src/cdk/testing/testbed/unit-test-element.ts | 4 --- 7 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/cdk/testing/component-harness.ts b/src/cdk/testing/component-harness.ts index 1deb658a8a03..736dca4897b2 100644 --- a/src/cdk/testing/component-harness.ts +++ b/src/cdk/testing/component-harness.ts @@ -142,6 +142,13 @@ export interface LocatorFactory { */ locatorForAll( harnessType: ComponentHarnessConstructor | HarnessPredicate): AsyncFactoryFn; + + /** + * Flushes change detection and async tasks. + * In most cases it should not be necessary to call this manually. However, there may be some edge + * cases where it is needed to fully flush animation events. + */ + forceStabilize(): Promise; } /** @@ -245,6 +252,15 @@ export abstract class ComponentHarness { protected locatorForAll(arg: any) { return this.locatorFactory.locatorForAll(arg); } + + /** + * Flushes change detection and async tasks. + * In most cases it should not be necessary to call this manually. However, there may be some edge + * cases where it is needed to fully flush animation events. + */ + protected async forceStabilize() { + return this.locatorFactory.forceStabilize(); + } } /** Constructor for a ComponentHarness subclass. */ diff --git a/src/cdk/testing/harness-environment.ts b/src/cdk/testing/harness-environment.ts index b05bb364330c..83117803ff14 100644 --- a/src/cdk/testing/harness-environment.ts +++ b/src/cdk/testing/harness-environment.ts @@ -110,6 +110,9 @@ export abstract class HarnessEnvironment implements HarnessLoader, LocatorFac return new harnessType(this.createEnvironment(element)); } + // Part of LocatorFactory interface, subclasses will implement. + abstract forceStabilize(): Promise; + /** Gets the root element for the document. */ protected abstract getDocumentRoot(): E; diff --git a/src/cdk/testing/protractor/protractor-element.ts b/src/cdk/testing/protractor/protractor-element.ts index 7ca9aa562e65..59e9f33901c7 100644 --- a/src/cdk/testing/protractor/protractor-element.ts +++ b/src/cdk/testing/protractor/protractor-element.ts @@ -148,6 +148,4 @@ export class ProtractorElement implements TestElement { Element.prototype.msMatchesSelector).call(arguments[0], arguments[1]) `, this.element, selector); } - - async forceStabilize(): Promise {} } diff --git a/src/cdk/testing/protractor/protractor-harness-environment.ts b/src/cdk/testing/protractor/protractor-harness-environment.ts index 3b6c097cf15b..1dcc5e3c76e1 100644 --- a/src/cdk/testing/protractor/protractor-harness-environment.ts +++ b/src/cdk/testing/protractor/protractor-harness-environment.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {HarnessEnvironment} from '@angular/cdk/testing'; import {by, element as protractorElement, ElementFinder} from 'protractor'; import {HarnessLoader} from '../component-harness'; -import {HarnessEnvironment} from '../harness-environment'; import {TestElement} from '../test-element'; import {ProtractorElement} from './protractor-element'; @@ -23,6 +23,8 @@ export class ProtractorHarnessEnvironment extends HarnessEnvironment {} + protected getDocumentRoot(): ElementFinder { return protractorElement(by.css('body')); } diff --git a/src/cdk/testing/test-element.ts b/src/cdk/testing/test-element.ts index 078876dcde43..bc9679b78c73 100644 --- a/src/cdk/testing/test-element.ts +++ b/src/cdk/testing/test-element.ts @@ -104,11 +104,4 @@ export interface TestElement { /** Checks whether this element matches the given selector. */ matchesSelector(selector: string): Promise; - - /** - * Flushes change detection and async tasks. - * In most cases it should not be necessary to call this. However, there may be some edge cases - * where it is needed to fully flush animation events. - */ - forceStabilize(): Promise; } diff --git a/src/cdk/testing/testbed/testbed-harness-environment.ts b/src/cdk/testing/testbed/testbed-harness-environment.ts index f6c9d74a45fb..6918fd890d4d 100644 --- a/src/cdk/testing/testbed/testbed-harness-environment.ts +++ b/src/cdk/testing/testbed/testbed-harness-environment.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {HarnessEnvironment} from '@angular/cdk/testing'; import {ComponentFixture} from '@angular/core/testing'; import {ComponentHarness, ComponentHarnessConstructor, HarnessLoader} from '../component-harness'; -import {HarnessEnvironment} from '../harness-environment'; import {TestElement} from '../test-element'; import {UnitTestElement} from './unit-test-element'; @@ -43,16 +43,25 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment { static async harnessForFixture( fixture: ComponentFixture, harnessType: ComponentHarnessConstructor): Promise { const environment = new TestbedHarnessEnvironment(fixture.nativeElement, fixture); - await environment._stabilize(); + await environment.forceStabilize(); return environment.createComponentHarness(harnessType, fixture.nativeElement); } + async forceStabilize(): Promise { + if (this._destroyed) { + throw Error('Harness is attempting to use a fixture that has already been destroyed.'); + } + + this._fixture.detectChanges(); + await this._fixture.whenStable(); + } + protected getDocumentRoot(): Element { return document.body; } protected createTestElement(element: Element): TestElement { - return new UnitTestElement(element, this._stabilize.bind(this)); + return new UnitTestElement(element, () => this.forceStabilize()); } protected createEnvironment(element: Element): HarnessEnvironment { @@ -60,16 +69,7 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment { } protected async getAllRawElements(selector: string): Promise { - await this._stabilize(); + await this.forceStabilize(); return Array.from(this.rawRootElement.querySelectorAll(selector)); } - - private async _stabilize(): Promise { - if (this._destroyed) { - throw Error('Harness is attempting to use a fixture that has already been destroyed.'); - } - - this._fixture.detectChanges(); - await this._fixture.whenStable(); - } } diff --git a/src/cdk/testing/testbed/unit-test-element.ts b/src/cdk/testing/testbed/unit-test-element.ts index 876f69ac89a4..d785bf82e332 100644 --- a/src/cdk/testing/testbed/unit-test-element.ts +++ b/src/cdk/testing/testbed/unit-test-element.ts @@ -144,8 +144,4 @@ export class UnitTestElement implements TestElement { return (elementPrototype['matches'] || elementPrototype['msMatchesSelector']) .call(this.element, selector); } - - async forceStabilize(): Promise { - return this._stabilize(); - } } From 1d946d4fd47bc5299e2232f4dfc476c5dc229f9a Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 19 Sep 2019 13:06:40 -0700 Subject: [PATCH 2/2] fix api test --- tools/public_api_guard/cdk/testing.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/public_api_guard/cdk/testing.d.ts b/tools/public_api_guard/cdk/testing.d.ts index 91c76566d24f..350a11f239a1 100644 --- a/tools/public_api_guard/cdk/testing.d.ts +++ b/tools/public_api_guard/cdk/testing.d.ts @@ -14,6 +14,7 @@ export declare function clearElement(element: HTMLInputElement | HTMLTextAreaEle export declare abstract class ComponentHarness { constructor(locatorFactory: LocatorFactory); protected documentRootLocatorFactory(): LocatorFactory; + protected forceStabilize(): Promise; host(): Promise; protected locatorFor(selector: string): AsyncFactoryFn; protected locatorFor(harnessType: ComponentHarnessConstructor | HarnessPredicate): AsyncFactoryFn; @@ -54,6 +55,7 @@ export declare abstract class HarnessEnvironment implements HarnessLoader, Lo protected abstract createEnvironment(element: E): HarnessEnvironment; protected abstract createTestElement(element: E): TestElement; documentRootLocatorFactory(): LocatorFactory; + abstract forceStabilize(): Promise; getAllChildLoaders(selector: string): Promise; getAllHarnesses(harnessType: ComponentHarnessConstructor | HarnessPredicate): Promise; protected abstract getAllRawElements(selector: string): Promise; @@ -92,6 +94,7 @@ export declare function isTextInput(element: Element): element is HTMLInputEleme export interface LocatorFactory { rootElement: TestElement; documentRootLocatorFactory(): LocatorFactory; + forceStabilize(): Promise; locatorFor(selector: string): AsyncFactoryFn; locatorFor(harnessType: ComponentHarnessConstructor | HarnessPredicate): AsyncFactoryFn; locatorForAll(selector: string): AsyncFactoryFn; @@ -114,7 +117,6 @@ export interface TestElement { clear(): Promise; click(relativeX?: number, relativeY?: number): Promise; focus(): Promise; - forceStabilize(): Promise; getAttribute(name: string): Promise; getCssValue(property: string): Promise; getDimensions(): Promise;