Skip to content

Commit 64606fa

Browse files
authored
feat(cdk/testing): add methods getOptionalHarness and hasHarness (#24355)
1 parent dd59b4a commit 64606fa

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

src/cdk/testing/component-harness.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,31 @@ export interface HarnessLoader {
9696
*/
9797
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;
9898

99+
/**
100+
* Searches for an instance of the component corresponding to the given harness type under the
101+
* `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If multiple
102+
* matching components are found, a harness for the first one is returned. If no matching
103+
* component is found, null is returned.
104+
* @param query A query for a harness to create
105+
* @return An instance of the given harness type (or null if not found).
106+
*/
107+
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;
108+
99109
/**
100110
* Searches for all instances of the component corresponding to the given harness type under the
101111
* `HarnessLoader`'s root element, and returns a list `ComponentHarness` for each instance.
102112
* @param query A query for a harness to create
103113
* @return A list instances of the given harness type.
104114
*/
105115
getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]>;
116+
117+
/**
118+
* Searches for an instance of the component corresponding to the given harness type under the
119+
* `HarnessLoader`'s root element, and returns a boolean indicating if any were found.
120+
* @param query A query for a harness to create
121+
* @return A boolean indicating if an instance was found.
122+
*/
123+
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
106124
}
107125

108126
/**
@@ -403,10 +421,18 @@ export abstract class ContentContainerComponentHarness<S extends string = string
403421
return (await this.getRootHarnessLoader()).getHarness(query);
404422
}
405423

424+
async getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null> {
425+
return (await this.getRootHarnessLoader()).getHarnessOrNull(query);
426+
}
427+
406428
async getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]> {
407429
return (await this.getRootHarnessLoader()).getAllHarnesses(query);
408430
}
409431

432+
async hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean> {
433+
return (await this.getRootHarnessLoader()).hasHarness(query);
434+
}
435+
410436
/**
411437
* Gets the root harness loader from which to start
412438
* searching for content contained by this harness.

src/cdk/testing/harness-environment.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,21 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
117117
return this.locatorFor(query)();
118118
}
119119

120+
// Implemented as part of the `HarnessLoader` interface.
121+
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null> {
122+
return this.locatorForOptional(query)();
123+
}
124+
120125
// Implemented as part of the `HarnessLoader` interface.
121126
getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]> {
122127
return this.locatorForAll(query)();
123128
}
124129

130+
// Implemented as part of the `HarnessLoader` interface.
131+
async hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean> {
132+
return (await this.locatorForOptional(query)()) !== null;
133+
}
134+
125135
// Implemented as part of the `HarnessLoader` interface.
126136
async getChildLoader(selector: string): Promise<HarnessLoader> {
127137
return this.createEnvironment(

src/cdk/testing/tests/cross-environment.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,28 @@ export function crossEnvironmentSpecs(
8989
}
9090
});
9191

92+
it('should get first matching component for optional harness', async () => {
93+
const harness = await loader.getHarnessOrNull(SubComponentHarness);
94+
expect(harness).not.toBeNull();
95+
expect(await (await harness!.title()).text()).toBe('List of test tools');
96+
});
97+
98+
it('should get null if no matching component found for optional harness', async () => {
99+
const countersLoader = await loader.getChildLoader('.counters');
100+
const harness = await countersLoader.getHarnessOrNull(SubComponentHarness);
101+
expect(harness).toBeNull();
102+
});
103+
92104
it('should get all matching components for all harnesses', async () => {
93105
const harnesses = await loader.getAllHarnesses(SubComponentHarness);
94106
expect(harnesses.length).toBe(4);
95107
});
108+
109+
it('should check if harness is found', async () => {
110+
const countersLoader = await loader.getChildLoader('.counters');
111+
expect(await loader.hasHarness(SubComponentHarness)).toBe(true);
112+
expect(await countersLoader.hasHarness(SubComponentHarness)).toBe(false);
113+
});
96114
});
97115

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

tools/public_api_guard/cdk/testing.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ export abstract class ContentContainerComponentHarness<S extends string = string
5656
getChildLoader(selector: S): Promise<HarnessLoader>;
5757
// (undocumented)
5858
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;
59+
// (undocumented)
60+
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;
5961
protected getRootHarnessLoader(): Promise<HarnessLoader>;
62+
// (undocumented)
63+
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
6064
}
6165

6266
// @public
@@ -103,12 +107,16 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
103107
// (undocumented)
104108
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;
105109
// (undocumented)
110+
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;
111+
// (undocumented)
106112
harnessLoaderFor(selector: string): Promise<HarnessLoader>;
107113
// (undocumented)
108114
harnessLoaderForAll(selector: string): Promise<HarnessLoader[]>;
109115
// (undocumented)
110116
harnessLoaderForOptional(selector: string): Promise<HarnessLoader | null>;
111117
// (undocumented)
118+
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
119+
// (undocumented)
112120
locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
113121
// (undocumented)
114122
locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
@@ -131,6 +139,8 @@ export interface HarnessLoader {
131139
getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]>;
132140
getChildLoader(selector: string): Promise<HarnessLoader>;
133141
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;
142+
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;
143+
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
134144
}
135145

136146
// @public

0 commit comments

Comments
 (0)