Skip to content

Commit b4cb20f

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 202c667 commit b4cb20f

File tree

5 files changed

+29
-28
lines changed

5 files changed

+29
-28
lines changed

src/cdk/testing/component-harness.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export type HarnessQuery<T extends ComponentHarness> =
2626
| ComponentHarnessConstructor<T>
2727
| HarnessPredicate<T>;
2828

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

145146
/**
146147
* Creates an asynchronous locator function that can be used to find a `ComponentHarness` instance
@@ -163,7 +164,7 @@ export interface LocatorFactory {
163164
* - `await lf.locatorForOptional('div', DivHarness)()` gets a `TestElement` instance for `#d1`
164165
* - `await lf.locatorForOptional('span')()` gets `null`.
165166
*/
166-
locatorForOptional<T extends (HarnessQuery<any> | string)[]>(
167+
locatorForOptional<T extends LocatorQueries>(
167168
...queries: T
168169
): AsyncFactoryFn<LocatorFnResult<T> | null>;
169170

@@ -203,9 +204,7 @@ export interface LocatorFactory {
203204
* ]`
204205
* - `await lf.locatorForAll('span')()` gets `[]`.
205206
*/
206-
locatorForAll<T extends (HarnessQuery<any> | string)[]>(
207-
...queries: T
208-
): AsyncFactoryFn<LocatorFnResult<T>[]>;
207+
locatorForAll<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
209208

210209
/** @return A `HarnessLoader` rooted at the root element of this `LocatorFactory`. */
211210
rootHarnessLoader(): Promise<HarnessLoader>;
@@ -290,7 +289,7 @@ export abstract class ComponentHarness {
290289
* - `await ch.locatorFor('div', DivHarness)()` gets a `TestElement` instance for `#d1`
291290
* - `await ch.locatorFor('span')()` throws because the `Promise` rejects.
292291
*/
293-
protected locatorFor<T extends (HarnessQuery<any> | string)[]>(
292+
protected locatorFor<T extends LocatorQueries>(
294293
...queries: T
295294
): AsyncFactoryFn<LocatorFnResult<T>> {
296295
return this.locatorFactory.locatorFor(...queries);
@@ -317,7 +316,7 @@ export abstract class ComponentHarness {
317316
* - `await ch.locatorForOptional('div', DivHarness)()` gets a `TestElement` instance for `#d1`
318317
* - `await ch.locatorForOptional('span')()` gets `null`.
319318
*/
320-
protected locatorForOptional<T extends (HarnessQuery<any> | string)[]>(
319+
protected locatorForOptional<T extends LocatorQueries>(
321320
...queries: T
322321
): AsyncFactoryFn<LocatorFnResult<T> | null> {
323322
return this.locatorFactory.locatorForOptional(...queries);
@@ -359,7 +358,7 @@ export abstract class ComponentHarness {
359358
* ]`
360359
* - `await ch.locatorForAll('span')()` gets `[]`.
361360
*/
362-
protected locatorForAll<T extends (HarnessQuery<any> | string)[]>(
361+
protected locatorForAll<T extends LocatorQueries>(
363362
...queries: T
364363
): AsyncFactoryFn<LocatorFnResult<T>[]> {
365364
return this.locatorFactory.locatorForAll(...queries);

src/cdk/testing/harness-environment.ts

Lines changed: 4 additions & 7 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,9 +58,7 @@ 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)[]>(
61-
...queries: T
62-
): AsyncFactoryFn<LocatorFnResult<T>> {
61+
locatorFor<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>> {
6362
return () =>
6463
_assertResultFound(
6564
this._getAllHarnessesAndTestElements(queries),
@@ -68,16 +67,14 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
6867
}
6968

7069
// Implemented as part of the `LocatorFactory` interface.
71-
locatorForOptional<T extends (HarnessQuery<any> | string)[]>(
70+
locatorForOptional<T extends LocatorQueries>(
7271
...queries: T
7372
): AsyncFactoryFn<LocatorFnResult<T> | null> {
7473
return async () => (await this._getAllHarnessesAndTestElements(queries))[0] || null;
7574
}
7675

7776
// Implemented as part of the `LocatorFactory` interface.
78-
locatorForAll<T extends (HarnessQuery<any> | string)[]>(
79-
...queries: T
80-
): AsyncFactoryFn<LocatorFnResult<T>[]> {
77+
locatorForAll<T extends LocatorQueries>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]> {
8178
return () => this._getAllHarnessesAndTestElements(queries);
8279
}
8380

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';
@@ -176,6 +177,6 @@ export abstract class MatListHarnessBase<
176177
if (filters.divider !== false) {
177178
query.push(MatDividerHarness.with(filters.divider));
178179
}
179-
return this.locatorForAll(...query)();
180+
return this.locatorForAll(...(query as LocatorQueries))();
180181
}
181182
}

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';
@@ -175,6 +176,6 @@ export abstract class MatListHarnessBase<
175176
if (filters.divider !== false) {
176177
query.push(MatDividerHarness.with(filters.divider));
177178
}
178-
return this.locatorForAll(...query)();
179+
return this.locatorForAll(...(query as LocatorQueries))();
179180
}
180181
}

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)