Skip to content

Commit 8a654f9

Browse files
committed
fix(cdk/testing): require at least one argument for locator functions
Successor to #23384. Reworks the typings so that users get a TypeScript error if they don't provide at least one argument to a locator function. This isn't a breaking change, because currently it results in a runtime error.
1 parent f282bd6 commit 8a654f9

File tree

5 files changed

+29
-20
lines changed

5 files changed

+29
-20
lines changed

src/cdk/testing/component-harness.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ export type AsyncOptionPredicate<T, O> = (item: T, option: O) => Promise<boolean
2525
export type HarnessQuery<T extends ComponentHarness> =
2626
ComponentHarnessConstructor<T> | HarnessPredicate<T>;
2727

28+
/** Queries that can be passed into a locator function. */
29+
export type LocatorQueries = [HarnessQuery<any> | string, ...(HarnessQuery<any> | string)[]];
30+
2831
/**
2932
* The result type obtained when searching using a particular list of queries. This type depends on
3033
* the particular items being queried.
@@ -137,7 +140,7 @@ export interface LocatorFactory {
137140
* - `await lf.locatorFor('div', DivHarness)()` gets a `TestElement` instance for `#d1`
138141
* - `await lf.locatorFor('span')()` throws because the `Promise` rejects.
139142
*/
140-
locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T):
143+
locatorFor<T extends LocatorQueries>(...queries: T):
141144
AsyncFactoryFn<LocatorFnResult<T>>;
142145

143146
/**
@@ -161,7 +164,7 @@ export interface LocatorFactory {
161164
* - `await lf.locatorForOptional('div', DivHarness)()` gets a `TestElement` instance for `#d1`
162165
* - `await lf.locatorForOptional('span')()` gets `null`.
163166
*/
164-
locatorForOptional<T extends (HarnessQuery<any> | string)[]>(...queries: T):
167+
locatorForOptional<T extends LocatorQueries>(...queries: T):
165168
AsyncFactoryFn<LocatorFnResult<T> | null>;
166169

167170
/**
@@ -200,7 +203,7 @@ export interface LocatorFactory {
200203
* ]`
201204
* - `await lf.locatorForAll('span')()` gets `[]`.
202205
*/
203-
locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T):
206+
locatorForAll<T extends LocatorQueries>(...queries: T):
204207
AsyncFactoryFn<LocatorFnResult<T>[]>;
205208

206209
/** @return A `HarnessLoader` rooted at the root element of this `LocatorFactory`. */
@@ -286,7 +289,7 @@ export abstract class ComponentHarness {
286289
* - `await ch.locatorFor('div', DivHarness)()` gets a `TestElement` instance for `#d1`
287290
* - `await ch.locatorFor('span')()` throws because the `Promise` rejects.
288291
*/
289-
protected locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T):
292+
protected locatorFor<T extends LocatorQueries>(...queries: T):
290293
AsyncFactoryFn<LocatorFnResult<T>> {
291294
return this.locatorFactory.locatorFor(...queries);
292295
}
@@ -312,7 +315,7 @@ export abstract class ComponentHarness {
312315
* - `await ch.locatorForOptional('div', DivHarness)()` gets a `TestElement` instance for `#d1`
313316
* - `await ch.locatorForOptional('span')()` gets `null`.
314317
*/
315-
protected locatorForOptional<T extends (HarnessQuery<any> | string)[]>(...queries: T):
318+
protected locatorForOptional<T extends LocatorQueries>(...queries: T):
316319
AsyncFactoryFn<LocatorFnResult<T> | null> {
317320
return this.locatorFactory.locatorForOptional(...queries);
318321
}
@@ -353,7 +356,7 @@ export abstract class ComponentHarness {
353356
* ]`
354357
* - `await ch.locatorForAll('span')()` gets `[]`.
355358
*/
356-
protected locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T):
359+
protected locatorForAll<T extends LocatorQueries>(...queries: T):
357360
AsyncFactoryFn<LocatorFnResult<T>[]> {
358361
return this.locatorFactory.locatorForAll(...queries);
359362
}

src/cdk/testing/harness-environment.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
HarnessQuery,
1717
LocatorFactory,
1818
LocatorFnResult,
19+
LocatorQueries,
1920
} from './component-harness';
2021
import {TestElement} from './test-element';
2122

@@ -57,21 +58,21 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
5758
}
5859

5960
// Implemented as part of the `LocatorFactory` interface.
60-
locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T):
61+
locatorFor<T extends LocatorQueries>(...queries: T):
6162
AsyncFactoryFn<LocatorFnResult<T>> {
6263
return () => _assertResultFound(
6364
this._getAllHarnessesAndTestElements(queries),
6465
_getDescriptionForLocatorForQueries(queries));
6566
}
6667

6768
// Implemented as part of the `LocatorFactory` interface.
68-
locatorForOptional<T extends (HarnessQuery<any> | string)[]>(...queries: T):
69+
locatorForOptional<T extends LocatorQueries>(...queries: T):
6970
AsyncFactoryFn<LocatorFnResult<T> | null> {
7071
return async () => (await this._getAllHarnessesAndTestElements(queries))[0] || null;
7172
}
7273

7374
// Implemented as part of the `LocatorFactory` interface.
74-
locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T):
75+
locatorForAll<T extends LocatorQueries>(...queries: T):
7576
AsyncFactoryFn<LocatorFnResult<T>[]> {
7677
return () => this._getAllHarnessesAndTestElements(queries);
7778
}

src/material-experimental/mdc-list/testing/list-harness-base.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
ComponentHarness,
1111
ComponentHarnessConstructor,
1212
HarnessPredicate,
13+
LocatorQueries,
1314
parallel
1415
} from '@angular/cdk/testing';
1516
import {DividerHarnessFilters, MatDividerHarness} from '@angular/material/divider/testing';
@@ -154,6 +155,6 @@ export abstract class MatListHarnessBase<
154155
if (filters.divider !== false) {
155156
query.push(MatDividerHarness.with(filters.divider));
156157
}
157-
return this.locatorForAll(...query)();
158+
return this.locatorForAll(...query as LocatorQueries)();
158159
}
159160
}

src/material/list/testing/list-harness-base.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
ComponentHarness,
1111
ComponentHarnessConstructor,
1212
HarnessPredicate,
13+
LocatorQueries,
1314
parallel
1415
} from '@angular/cdk/testing';
1516
import {DividerHarnessFilters, MatDividerHarness} from '@angular/material/divider/testing';
@@ -166,6 +167,6 @@ export abstract class MatListHarnessBase
166167
if (filters.divider !== false) {
167168
query.push(MatDividerHarness.with(filters.divider));
168169
}
169-
return this.locatorForAll(...query)();
170+
return this.locatorForAll(...query as LocatorQueries)();
170171
}
171172
}

tools/public_api_guard/cdk/testing.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ export abstract class ComponentHarness {
3333
host(): Promise<TestElement>;
3434
// (undocumented)
3535
protected readonly locatorFactory: LocatorFactory;
36-
protected locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
37-
protected locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
38-
protected locatorForOptional<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T> | null>;
36+
protected locatorFor<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
37+
protected locatorForAll<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
38+
protected locatorForOptional<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T> | null>;
3939
protected waitForTasksOutsideAngular(): Promise<void>;
4040
}
4141

@@ -109,11 +109,11 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
109109
// (undocumented)
110110
harnessLoaderForOptional(selector: string): Promise<HarnessLoader | null>;
111111
// (undocumented)
112-
locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
112+
locatorFor<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
113113
// (undocumented)
114-
locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
114+
locatorForAll<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
115115
// (undocumented)
116-
locatorForOptional<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T> | null>;
116+
locatorForOptional<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T> | null>;
117117
// (undocumented)
118118
protected rawRootElement: E;
119119
// (undocumented)
@@ -156,9 +156,9 @@ export interface LocatorFactory {
156156
harnessLoaderFor(selector: string): Promise<HarnessLoader>;
157157
harnessLoaderForAll(selector: string): Promise<HarnessLoader[]>;
158158
harnessLoaderForOptional(selector: string): Promise<HarnessLoader | null>;
159-
locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
160-
locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
161-
locatorForOptional<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T> | null>;
159+
locatorFor<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
160+
locatorForAll<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
161+
locatorForOptional<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T> | null>;
162162
rootElement: TestElement;
163163
rootHarnessLoader(): Promise<HarnessLoader>;
164164
waitForTasksOutsideAngular(): Promise<void>;
@@ -171,6 +171,9 @@ export type LocatorFnResult<T extends (HarnessQuery<any> | string)[]> = {
171171
} ? C : T[I] extends string ? TestElement : never;
172172
}[number];
173173

174+
// @public
175+
export type LocatorQueries = [HarnessQuery<any> | string, ...(HarnessQuery<any> | string)[]];
176+
174177
// @public
175178
export function manualChangeDetection<T>(fn: () => Promise<T>): Promise<T>;
176179

0 commit comments

Comments
 (0)