Skip to content

Commit fdd31f9

Browse files
committed
feat(cdk-experimental): expose root loader instance in harness environment
Adds a new method that can be used by harness consumers to load a harness through `HarnessLoader` from the document root. This is helpful for harnesses which need to match elements outside of testbed fixtures (e.g. snack-bars, overlays etc.). Needed for angular#16697 and angular#16709.
1 parent d3f63a3 commit fdd31f9

File tree

6 files changed

+61
-1
lines changed

6 files changed

+61
-1
lines changed

src/cdk-experimental/testing/component-harness.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ export type AsyncOptionPredicate<T, O> = (item: T, option: O) => Promise<boolean
2222
* instantiate `ComponentHarness`es.
2323
*/
2424
export interface HarnessLoader {
25+
26+
/**
27+
* Gets the harness loader at the document root. This can be used if harnesses are
28+
* located outside of the current loader (e.g. overlays appended to the document body).
29+
*/
30+
documentRootLoader(): HarnessLoader;
31+
2532
/**
2633
* Searches for an element with the given selector under the current instances's root element,
2734
* and returns a `HarnessLoader` rooted at the matching element. If multiple elements match the

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
4848
this.rootElement = this.createTestElement(rawRootElement);
4949
}
5050

51+
// Implemented as part of the `HarnessLoader` interface.
52+
documentRootLoader(): HarnessLoader {
53+
return this.createEnvironment(this.getDocumentRoot());
54+
}
55+
5156
// Implemented as part of the `LocatorFactory` interface.
5257
documentRootLocatorFactory(): LocatorFactory {
5358
return this.createEnvironment(this.getDocumentRoot());
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ComponentHarness} from '@angular/cdk-experimental/testing';
10+
11+
export class FakeOverlayHarness extends ComponentHarness {
12+
static readonly hostSelector = '.fake-overlay';
13+
14+
/** Gets the description of the fake overlay. */
15+
async getDescription(): Promise<string> {
16+
return (await this.host()).text();
17+
}
18+
}

src/cdk-experimental/testing/tests/protractor.e2e.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {HarnessLoader} from '@angular/cdk-experimental/testing';
22
import {ProtractorHarnessEnvironment} from '@angular/cdk-experimental/testing/protractor';
33
import {browser} from 'protractor';
4+
import {FakeOverlayHarness} from './harnesses/fake-overlay-harness';
45
import {MainComponentHarness} from './harnesses/main-component-harness';
56
import {SubComponentHarness} from './harnesses/sub-component-harness';
67

@@ -62,6 +63,13 @@ describe('ProtractorHarnessEnvironment', () => {
6263
const harnesses = await loader.getAllHarnesses(SubComponentHarness);
6364
expect(harnesses.length).toBe(2);
6465
});
66+
67+
it('should be able to load harness through document root loader', async () => {
68+
const documentRootHarnesses = await loader
69+
.documentRootLoader().getAllHarnesses(FakeOverlayHarness);
70+
expect(documentRootHarnesses.length).toBe(1);
71+
expect(await documentRootHarnesses[0].getDescription()).toBe('This is a fake overlay.');
72+
});
6573
});
6674

6775
describe('ComponentHarness', () => {

src/cdk-experimental/testing/tests/test-main-component.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
ChangeDetectorRef,
1313
Component,
1414
ElementRef,
15+
OnDestroy,
1516
ViewChild,
1617
ViewEncapsulation
1718
} from '@angular/core';
@@ -29,7 +30,7 @@ import {
2930
changeDetection: ChangeDetectionStrategy.OnPush,
3031
})
3132

32-
export class TestMainComponent {
33+
export class TestMainComponent implements OnDestroy {
3334
username: string;
3435
counter: number;
3536
asyncCounter: number;
@@ -44,6 +45,8 @@ export class TestMainComponent {
4445

4546
@ViewChild('clickTestElement', {static: false}) clickTestElement: ElementRef<HTMLElement>;
4647

48+
private _fakeOverlayElement: HTMLElement;
49+
4750
onMouseOver() {
4851
this._isHovering = true;
4952
}
@@ -63,6 +66,15 @@ export class TestMainComponent {
6366
this.asyncCounter = 5;
6467
this._cdr.markForCheck();
6568
}, 1000);
69+
70+
this._fakeOverlayElement = document.createElement('div');
71+
this._fakeOverlayElement.classList.add('fake-overlay');
72+
this._fakeOverlayElement.innerText = 'This is a fake overlay.';
73+
document.body.appendChild(this._fakeOverlayElement);
74+
}
75+
76+
ngOnDestroy() {
77+
document.body.removeChild(this._fakeOverlayElement);
6678
}
6779

6880
click() {

src/cdk-experimental/testing/tests/testbed.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {HarnessLoader} from '@angular/cdk-experimental/testing';
22
import {TestbedHarnessEnvironment} from '@angular/cdk-experimental/testing/testbed';
33
import {ComponentFixture, TestBed} from '@angular/core/testing';
4+
import {FakeOverlayHarness} from './harnesses/fake-overlay-harness';
45
import {MainComponentHarness} from './harnesses/main-component-harness';
56
import {SubComponentHarness} from './harnesses/sub-component-harness';
67
import {TestComponentsModule} from './test-components-module';
@@ -77,6 +78,15 @@ describe('TestbedHarnessEnvironment', () => {
7778
const harnesses = await loader.getAllHarnesses(SubComponentHarness);
7879
expect(harnesses.length).toBe(2);
7980
});
81+
82+
it('should be able to load harness through document root loader', async () => {
83+
const documentRootHarnesses = await loader
84+
.documentRootLoader().getAllHarnesses(FakeOverlayHarness);
85+
const fixtureHarnesses = await loader.getAllHarnesses(FakeOverlayHarness);
86+
expect(fixtureHarnesses.length).toBe(0);
87+
expect(documentRootHarnesses.length).toBe(1);
88+
expect(await documentRootHarnesses[0].getDescription()).toBe('This is a fake overlay.');
89+
});
8090
});
8191

8292
describe('ComponentHarness', () => {

0 commit comments

Comments
 (0)