Skip to content

Commit ebd7a8b

Browse files
committed
feat(cdk-experimental): expose root loader instance in testbed 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 #16697 and #16709.
1 parent 77994e9 commit ebd7a8b

File tree

5 files changed

+52
-3
lines changed

5 files changed

+52
-3
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {UnitTestElement} from './unit-test-element';
1414

1515
/** A `HarnessEnvironment` implementation for Angular's Testbed. */
1616
export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
17-
constructor(rawRootElement: Element, private _fixture: ComponentFixture<unknown>) {
17+
protected constructor(rawRootElement: Element, private _fixture: ComponentFixture<unknown>) {
1818
super(rawRootElement);
1919
}
2020

@@ -23,6 +23,14 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment<Element> {
2323
return new TestbedHarnessEnvironment(fixture.nativeElement, fixture);
2424
}
2525

26+
/**
27+
* Creates a `HarnessLoader` at the document root. This can be used if harnesses are
28+
* located outside of a fixture (e.g. overlays appended to the document body).
29+
*/
30+
static documentRootLoader(fixture: ComponentFixture<unknown>): HarnessLoader {
31+
return new TestbedHarnessEnvironment(document.body, fixture);
32+
}
33+
2634
/**
2735
* Creates an instance of the given harness type, using the fixture's root element as the
2836
* harness's host element. This method should be used when creating a harness for the root element
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 '../../component-harness';
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/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/testing/tests/testbed.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {HarnessLoader} from '@angular/cdk/testing';
22
import {TestbedHarnessEnvironment} from '@angular/cdk/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,16 @@ describe('TestbedHarnessEnvironment', () => {
7778
const harnesses = await loader.getAllHarnesses(SubComponentHarness);
7879
expect(harnesses.length).toBe(4);
7980
});
81+
82+
it('should be able to load harness through document root loader', async () => {
83+
const documentRootHarnesses =
84+
await TestbedHarnessEnvironment.documentRootLoader(fixture).getAllHarnesses(
85+
FakeOverlayHarness);
86+
const fixtureHarnesses = await loader.getAllHarnesses(FakeOverlayHarness);
87+
expect(fixtureHarnesses.length).toBe(0);
88+
expect(documentRootHarnesses.length).toBe(1);
89+
expect(await documentRootHarnesses[0].getDescription()).toBe('This is a fake overlay.');
90+
});
8091
});
8192

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

src/material-experimental/mdc-dialog/harness/dialog-harness.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('MatDialogHarness', () => {
2424

2525
fixture = TestBed.createComponent(DialogHarnessTest);
2626
fixture.detectChanges();
27-
loader = new TestbedHarnessEnvironment(document.body, fixture);
27+
loader = TestbedHarnessEnvironment.documentRootLoader(fixture);
2828
dialogHarness = MatDialogHarness;
2929
inject([OverlayContainer], (oc: OverlayContainer) => {
3030
overlayContainer = oc;

0 commit comments

Comments
 (0)