Skip to content

Commit f97a374

Browse files
committed
WIP: address @jelbourn's comments
1 parent 109868d commit f97a374

File tree

3 files changed

+63
-67
lines changed

3 files changed

+63
-67
lines changed

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

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,56 +7,59 @@
77
*/
88

99
/**
10-
* Test Element interface
11-
* This is a wrapper of native element
10+
* This acts as a common interface for DOM elements across both unit and e2e tests. It is the
11+
* interface through which the ComponentHarness interacts with the component's DOM.
1212
*/
1313
export interface TestElement {
14+
/** Blur the element. */
1415
blur(): Promise<void>;
16+
/** Clear the element's input (for input elements only). */
1517
clear(): Promise<void>;
18+
/** Click the element. */
1619
click(): Promise<void>;
20+
/** Focus the element. */
1721
focus(): Promise<void>;
22+
/** Get the computed value of the given CSS property for the element. */
1823
getCssValue(property: string): Promise<string>;
24+
/** Hovers the mouse over the element. */
1925
hover(): Promise<void>;
26+
/**
27+
* Sends the given string to the input as a series of key presses. Also fires input events
28+
* and attempts to add the string to the Element's value.
29+
*/
2030
sendKeys(keys: string): Promise<void>;
31+
/** Gets the text from the element. */
2132
text(): Promise<string>;
33+
/**
34+
* Gets the value for the given attribute from the element. If the attribute does not exist,
35+
* falls back to reading the property.
36+
*/
2237
getAttribute(name: string): Promise<string|null>;
2338
}
2439

25-
/**
26-
* Extra searching options used by searching functions
27-
*
28-
* @param allowNull Optional, whether the found element can be null. If
29-
* allowNull is set, the searching function will always try to fetch the element
30-
* at once. When the element cannot be found, the searching function should
31-
* return null if allowNull is set to true, throw an error if allowNull is set
32-
* to false. If allowNull is not set, the framework will choose the behaviors
33-
* that make more sense for each test type (e.g. for unit test, the framework
34-
* will make sure the element is not null; otherwise throw an error); however,
35-
* the internal behavior is not guaranteed and user should not rely on it. Note
36-
* that in most cases, you don't need to care about whether an element is
37-
* present when loading the element and don't need to set this parameter unless
38-
* you do want to check whether the element is present when calling the
39-
* searching function. e.g. you want to make sure some element is not there when
40-
* loading the element in order to check whether a "ngif" works well.
41-
*
42-
* @param global Optional. If global is set to true, the selector will match any
43-
* element on the page and is not limited to the root of the harness. If
44-
* global is unset or set to false, the selector will only find elements under
45-
* the current root.
46-
*/
47-
export interface Options {
40+
/** Options that can be specified when querying for an Element. */
41+
export interface QueryOptions {
42+
/**
43+
* Whether the found element can be null. If allowNull is set, the searching function will always
44+
* try to fetch the element at once. When the element cannot be found, the searching function
45+
* should return null if allowNull is set to true, throw an error if allowNull is set to false.
46+
* If allowNull is not set, the framework will choose the behaviors that make more sense for each
47+
* test type (e.g. for unit test, the framework will make sure the element is not null; otherwise
48+
* throw an error); however, the internal behavior is not guaranteed and user should not rely on
49+
* it. Note that in most cases, you don't need to care about whether an element is present when
50+
* loading the element and don't need to set this parameter unless you do want to check whether
51+
* the element is present when calling the searching function. e.g. you want to make sure some
52+
* element is not there when loading the element in order to check whether a "ngif" works well.
53+
*/
4854
allowNull?: boolean;
55+
/**
56+
* If global is set to true, the selector will match any element on the page and is not limited to
57+
* the root of the harness. If global is unset or set to false, the selector will only find
58+
* elements under the current root.
59+
*/
4960
global?: boolean;
5061
}
5162

52-
/**
53-
* Type narrowing of Options to allow the overloads of ComponentHarness.find to
54-
* return null only if allowNull is set to true.
55-
*/
56-
interface OptionsWithAllowNullSet extends Options {
57-
allowNull: true;
58-
}
59-
6063
/**
6164
* Locator interface
6265
*/
@@ -71,7 +74,7 @@ export interface Locator {
7174
* @param selector The CSS selector of the test elements.
7275
* @param options Optional, extra searching options
7376
*/
74-
querySelector(selector: string, options?: Options): Promise<TestElement|null>;
77+
querySelector(selector: string, options?: QueryOptions): Promise<TestElement|null>;
7578

7679
/**
7780
* Search all matched test elements under current root by CSS selector.
@@ -87,7 +90,7 @@ export interface Locator {
8790
*/
8891
load<T extends ComponentHarness>(
8992
componentHarness: ComponentHarnessType<T>, root: string,
90-
options?: Options): Promise<T|null>;
93+
options?: QueryOptions): Promise<T|null>;
9194

9295
/**
9396
* Load all Component Harnesses under current root.
@@ -127,7 +130,7 @@ export class ComponentHarness {
127130
* @param selector The CSS selector of the test element.
128131
* @param options Extra searching options
129132
*/
130-
protected find(selector: string, options: OptionsWithAllowNullSet):
133+
protected find(selector: string, options: QueryOptions & {allowNull: true}):
131134
() => Promise<TestElement|null>;
132135

133136
/**
@@ -136,7 +139,7 @@ export class ComponentHarness {
136139
* @param selector The CSS selector of the test element.
137140
* @param options Extra searching options
138141
*/
139-
protected find(selector: string, options: Options): () => Promise<TestElement>;
142+
protected find(selector: string, options: QueryOptions): () => Promise<TestElement>;
140143

141144
/**
142145
* Generate a function to find the first matched Component Harness.
@@ -155,7 +158,7 @@ export class ComponentHarness {
155158
*/
156159
protected find<T extends ComponentHarness>(
157160
componentHarness: ComponentHarnessType<T>, root: string,
158-
options: OptionsWithAllowNullSet): () => Promise<T|null>;
161+
options: QueryOptions & {allowNull: true}): () => Promise<T|null>;
159162

160163
/**
161164
* Generate a function to find the first matched Component Harness.
@@ -165,15 +168,15 @@ export class ComponentHarness {
165168
*/
166169
protected find<T extends ComponentHarness>(
167170
componentHarness: ComponentHarnessType<T>, root: string,
168-
options: Options): () => Promise<T>;
171+
options: QueryOptions): () => Promise<T>;
169172

170173
protected find<T extends ComponentHarness>(
171174
selectorOrComponentHarness: string|ComponentHarnessType<T>,
172-
selectorOrOptions?: string|Options,
173-
options?: Options): () => Promise<TestElement|T|null> {
175+
selectorOrOptions?: string|QueryOptions,
176+
options?: QueryOptions): () => Promise<TestElement|T|null> {
174177
if (typeof selectorOrComponentHarness === 'string') {
175178
const selector = selectorOrComponentHarness;
176-
return () => this.locator.querySelector(selector, selectorOrOptions as Options);
179+
return () => this.locator.querySelector(selector, selectorOrOptions as QueryOptions);
177180
} else {
178181
const componentHarness = selectorOrComponentHarness;
179182
const selector = selectorOrOptions as string;

src/cdk-experimental/testing/protractor.ts

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
ComponentHarness,
1616
ComponentHarnessType,
1717
Locator,
18-
Options,
18+
QueryOptions,
1919
TestElement
2020
} from './component-harness';
2121

@@ -43,11 +43,11 @@ export async function load<T extends ComponentHarness>(
4343
*/
4444
export async function load<T extends ComponentHarness>(
4545
componentHarness: ComponentHarnessType<T>, rootSelector?: string,
46-
options?: Options): Promise<T|null>;
46+
options?: QueryOptions): Promise<T|null>;
4747

4848
export async function load<T extends ComponentHarness>(
4949
componentHarness: ComponentHarnessType<T>, rootSelector = 'body',
50-
options?: Options): Promise<T|null> {
50+
options?: QueryOptions): Promise<T|null> {
5151
const root = await getElement(rootSelector, undefined, options);
5252
return root && new componentHarness(new ProtractorLocator(root));
5353
}
@@ -74,25 +74,22 @@ class ProtractorLocator implements Locator {
7474
return this._root;
7575
}
7676

77-
async querySelector(selector: string, options?: Options): Promise<TestElement|null> {
77+
async querySelector(selector: string, options?: QueryOptions): Promise<TestElement|null> {
7878
const finder = await getElement(selector, this._rootFinder, options);
7979
return finder && new ProtractorElement(finder);
8080
}
8181

8282
async querySelectorAll(selector: string): Promise<TestElement[]> {
8383
const elementFinders = this._rootFinder.all(by.css(selector));
84-
const res: TestElement[] = [];
85-
await elementFinders.each(el => {
86-
if (el) {
87-
res.push(new ProtractorElement(el));
88-
}
89-
});
90-
return res;
84+
return elementFinders.reduce(
85+
(result: TestElement[], el: ElementFinder) =>
86+
el ? result.concat([new ProtractorElement(el)]) : result,
87+
[]);
9188
}
9289

9390
async load<T extends ComponentHarness>(
9491
componentHarness: ComponentHarnessType<T>, selector: string,
95-
options?: Options): Promise<T|null> {
92+
options?: QueryOptions): Promise<T|null> {
9693
const root = await getElement(selector, this._rootFinder, options);
9794
return root && new componentHarness(new ProtractorLocator(root));
9895
}
@@ -101,14 +98,10 @@ class ProtractorLocator implements Locator {
10198
componentHarness: ComponentHarnessType<T>,
10299
rootSelector: string): Promise<T[]> {
103100
const roots = this._rootFinder.all(by.css(rootSelector));
104-
const res: T[] = [];
105-
await roots.each(el => {
106-
if (el) {
107-
const locator = new ProtractorLocator(el);
108-
res.push(new componentHarness(locator));
109-
}
110-
});
111-
return res;
101+
return roots.reduce(
102+
(result: T[], el: ElementFinder) =>
103+
el ? result.concat(new componentHarness(new ProtractorLocator(el))) : result,
104+
[]);
112105
}
113106
}
114107

@@ -163,7 +156,7 @@ class ProtractorElement implements TestElement {
163156
* search element globally. If options.global is set, root is ignored.
164157
* @param options Optional, extra searching options
165158
*/
166-
async function getElement(selector: string, root?: ElementFinder, options?: Options):
159+
async function getElement(selector: string, root?: ElementFinder, options?: QueryOptions):
167160
Promise<ElementFinder|null> {
168161
const useGlobalRoot = options && !!options.global;
169162
const elem = root === undefined || useGlobalRoot ?

src/cdk-experimental/testing/testbed.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
ComponentHarness,
2424
ComponentHarnessType,
2525
Locator,
26-
Options,
26+
QueryOptions,
2727
TestElement
2828
} from './component-harness';
2929

@@ -68,7 +68,7 @@ export class UnitTestLocator implements Locator {
6868
return this._rootElement;
6969
}
7070

71-
async querySelector(selector: string, options?: Options): Promise<TestElement|null> {
71+
async querySelector(selector: string, options?: QueryOptions): Promise<TestElement|null> {
7272
await this._stabilize();
7373
const e = getElement(selector, this._root, options);
7474
return e && new UnitTestElement(e, this._stabilize);
@@ -83,7 +83,7 @@ export class UnitTestLocator implements Locator {
8383

8484
async load<T extends ComponentHarness>(
8585
componentHarness: ComponentHarnessType<T>, selector: string,
86-
options?: Options): Promise<T|null> {
86+
options?: QueryOptions): Promise<T|null> {
8787
await this._stabilize();
8888
const root = getElement(selector, this._root, options);
8989
return root && new componentHarness(new UnitTestLocator(root, this._stabilize));
@@ -187,7 +187,7 @@ class UnitTestElement implements TestElement {
187187
* to true, throw an error if Options.allowNull is set to false; otherwise,
188188
* return the element
189189
*/
190-
function getElement(selector: string, root: Element, options?: Options): Element|null {
190+
function getElement(selector: string, root: Element, options?: QueryOptions): Element|null {
191191
const useGlobalRoot = options && !!options.global;
192192
const elem = (useGlobalRoot ? document : root).querySelector(selector);
193193
const allowNull = options !== undefined && options.allowNull !== undefined ?

0 commit comments

Comments
 (0)