Skip to content

Commit 0045fb2

Browse files
committed
add better key support to harnesses
1 parent 12da281 commit 0045fb2

File tree

12 files changed

+198
-11
lines changed

12 files changed

+198
-11
lines changed

src/cdk-experimental/testing/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ ng_module(
1111
"**/*.spec.ts",
1212
],
1313
),
14+
deps = [
15+
"//src/cdk/testing",
16+
],
1417
module_name = "@angular/cdk-experimental/testing",
1518
)
1619

src/cdk-experimental/testing/protractor/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ ts_library(
1212
deps = [
1313
"//src/cdk-experimental/testing",
1414
"@npm//protractor",
15+
"//src/cdk/testing"
1516
],
1617
)

src/cdk-experimental/testing/protractor/protractor-element.ts

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,42 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {browser, ElementFinder} from 'protractor';
10-
import {TestElement} from '../test-element';
9+
import {ModifierKeys} from '@angular/cdk/testing';
10+
import {browser, ElementFinder, Key} from 'protractor';
11+
import {TestElement, TestKey} from '../test-element';
12+
13+
const keyMap = {
14+
[TestKey.BACKSPACE]: Key.BACK_SPACE,
15+
[TestKey.TAB]: Key.TAB,
16+
[TestKey.ENTER]: Key.ENTER,
17+
[TestKey.SHIFT]: Key.SHIFT,
18+
[TestKey.CONTROL]: Key.CONTROL,
19+
[TestKey.ALT]: Key.ALT,
20+
[TestKey.ESCAPE]: Key.ESCAPE,
21+
[TestKey.PAGE_UP]: Key.PAGE_UP,
22+
[TestKey.PAGE_DOWN]: Key.PAGE_DOWN,
23+
[TestKey.END]: Key.END,
24+
[TestKey.HOME]: Key.HOME,
25+
[TestKey.LEFT_ARROW]: Key.ARROW_LEFT,
26+
[TestKey.UP_ARROW]: Key.ARROW_UP,
27+
[TestKey.RIGHT_ARROW]: Key.ARROW_RIGHT,
28+
[TestKey.DOWN_ARROW]: Key.ARROW_DOWN,
29+
[TestKey.INSERT]: Key.INSERT,
30+
[TestKey.DELETE]: Key.DELETE,
31+
[TestKey.F1]: Key.F1,
32+
[TestKey.F2]: Key.F2,
33+
[TestKey.F3]: Key.F3,
34+
[TestKey.F4]: Key.F4,
35+
[TestKey.F5]: Key.F5,
36+
[TestKey.F6]: Key.F6,
37+
[TestKey.F7]: Key.F7,
38+
[TestKey.F8]: Key.F8,
39+
[TestKey.F9]: Key.F9,
40+
[TestKey.F10]: Key.F10,
41+
[TestKey.F11]: Key.F11,
42+
[TestKey.F12]: Key.F12,
43+
[TestKey.META]: Key.META
44+
};
1145

1246
/** A `TestElement` implementation for Protractor. */
1347
export class ProtractorElement implements TestElement {
@@ -39,8 +73,31 @@ export class ProtractorElement implements TestElement {
3973
.perform();
4074
}
4175

42-
async sendKeys(keys: string): Promise<void> {
43-
return this.element.sendKeys(keys);
76+
async sendKeys(...keys: (string | TestKey)[]): Promise<void>;
77+
async sendKeys(modifiers: ModifierKeys, ...keys: (string | TestKey)[]): Promise<void>;
78+
async sendKeys(...modifiersAndKeys: any[]): Promise<void> {
79+
const first = modifiersAndKeys[0];
80+
let modifiers: ModifierKeys;
81+
let rest: (string | TestKey)[];
82+
if (typeof first !== 'string' && typeof first !== 'number') {
83+
modifiers = first;
84+
rest = modifiersAndKeys.slice(1);
85+
} else {
86+
modifiers = {};
87+
rest = modifiersAndKeys;
88+
}
89+
90+
const modifierKeys = [
91+
modifiers.control ? Key.CONTROL : '',
92+
modifiers.alt ? Key.ALT : '',
93+
modifiers.shift ? Key.SHIFT : '',
94+
modifiers.meta ? Key.META : ''
95+
].filter(k => k);
96+
const keys = rest.map(k => typeof k === 'string' ? k.split('') : [keyMap[k]])
97+
.reduce((arr, k) => arr.concat(k), [])
98+
.map(k => Key.chord(...modifierKeys, k));
99+
100+
return this.element.sendKeys(...keys);
44101
}
45102

46103
async text(): Promise<string> {

src/cdk-experimental/testing/test-element.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,42 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
/** Keyboard keys that do not result in input characters. */
10+
import {ModifierKeys} from '@angular/cdk/testing';
11+
12+
export enum TestKey {
13+
BACKSPACE,
14+
TAB,
15+
ENTER,
16+
SHIFT,
17+
CONTROL,
18+
ALT,
19+
ESCAPE,
20+
PAGE_UP,
21+
PAGE_DOWN,
22+
END,
23+
HOME,
24+
LEFT_ARROW,
25+
UP_ARROW,
26+
RIGHT_ARROW,
27+
DOWN_ARROW,
28+
INSERT,
29+
DELETE,
30+
F1,
31+
F2,
32+
F3,
33+
F4,
34+
F5,
35+
F6,
36+
F7,
37+
F8,
38+
F9,
39+
F10,
40+
F11,
41+
F12,
42+
META
43+
}
44+
945
/**
1046
* This acts as a common interface for DOM elements across both unit and e2e tests. It is the
1147
* interface through which the ComponentHarness interacts with the component's DOM.
@@ -33,7 +69,13 @@ export interface TestElement {
3369
* Sends the given string to the input as a series of key presses. Also fires input events
3470
* and attempts to add the string to the Element's value.
3571
*/
36-
sendKeys(keys: string): Promise<void>;
72+
sendKeys(...keys: (string | TestKey)[]): Promise<void>;
73+
74+
/**
75+
* Sends the given string to the input as a series of key presses. Also fires input events
76+
* and attempts to add the string to the Element's value.
77+
*/
78+
sendKeys(modifiers: ModifierKeys, ...keys: (string | TestKey)[]): Promise<void>;
3779

3880
/** Gets the text from the element. */
3981
text(): Promise<string>;

src/cdk-experimental/testing/testbed/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ts_library(
1212
deps = [
1313
"//src/cdk-experimental/testing",
1414
"//src/cdk/testing",
15+
"//src/cdk/keycodes",
1516
"@npm//@angular/core",
1617
],
1718
)

src/cdk-experimental/testing/testbed/unit-test-element.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,46 @@
99
import {
1010
clearElement,
1111
dispatchMouseEvent,
12-
isTextInput,
12+
isTextInput, ModifierKeys,
1313
triggerBlur,
1414
triggerFocus,
1515
typeInElement
1616
} from '@angular/cdk/testing';
17-
import {TestElement} from '../test-element';
17+
import {TestElement, TestKey} from '../test-element';
18+
import * as keyCodes from '@angular/cdk/keycodes';
19+
20+
const keyMap = {
21+
[TestKey.BACKSPACE]: {keyCode: keyCodes.BACKSPACE, key: 'Backspace'},
22+
[TestKey.TAB]: {keyCode: keyCodes.TAB, key: 'Tab'},
23+
[TestKey.ENTER]: {keyCode: keyCodes.ENTER, key: 'Enter'},
24+
[TestKey.SHIFT]: {keyCode: keyCodes.SHIFT, key: 'Shift'},
25+
[TestKey.CONTROL]: {keyCode: keyCodes.CONTROL, key: 'Control'},
26+
[TestKey.ALT]: {keyCode: keyCodes.ALT, key: 'Alt'},
27+
[TestKey.ESCAPE]: {keyCode: keyCodes.ESCAPE, key: 'Escape'},
28+
[TestKey.PAGE_UP]: {keyCode: keyCodes.PAGE_UP, key: 'PageUp'},
29+
[TestKey.PAGE_DOWN]: {keyCode: keyCodes.PAGE_DOWN, key: 'PageDown'},
30+
[TestKey.END]: {keyCode: keyCodes.END, key: 'End'},
31+
[TestKey.HOME]: {keyCode: keyCodes.HOME, key: 'Home'},
32+
[TestKey.LEFT_ARROW]: {keyCode: keyCodes.LEFT_ARROW, key: 'ArrowLeft'},
33+
[TestKey.UP_ARROW]: {keyCode: keyCodes.UP_ARROW, key: 'ArrowUp'},
34+
[TestKey.RIGHT_ARROW]: {keyCode: keyCodes.RIGHT_ARROW, key: 'ArrowRight'},
35+
[TestKey.DOWN_ARROW]: {keyCode: keyCodes.DOWN_ARROW, key: 'ArrowDown'},
36+
[TestKey.INSERT]: {keyCode: keyCodes.INSERT, key: 'Insert'},
37+
[TestKey.DELETE]: {keyCode: keyCodes.DELETE, key: 'Delete'},
38+
[TestKey.F1]: {keyCode: keyCodes.F1, key: 'F1'},
39+
[TestKey.F2]: {keyCode: keyCodes.F2, key: 'F2'},
40+
[TestKey.F3]: {keyCode: keyCodes.F3, key: 'F3'},
41+
[TestKey.F4]: {keyCode: keyCodes.F4, key: 'F4'},
42+
[TestKey.F5]: {keyCode: keyCodes.F5, key: 'F5'},
43+
[TestKey.F6]: {keyCode: keyCodes.F6, key: 'F6'},
44+
[TestKey.F7]: {keyCode: keyCodes.F7, key: 'F7'},
45+
[TestKey.F8]: {keyCode: keyCodes.F8, key: 'F8'},
46+
[TestKey.F9]: {keyCode: keyCodes.F9, key: 'F9'},
47+
[TestKey.F10]: {keyCode: keyCodes.F10, key: 'F10'},
48+
[TestKey.F11]: {keyCode: keyCodes.F11, key: 'F11'},
49+
[TestKey.F12]: {keyCode: keyCodes.F12, key: 'F12'},
50+
[TestKey.META]: {keyCode: keyCodes.META, key: 'Meta'}
51+
};
1852

1953
/** A `TestElement` implementation for unit tests. */
2054
export class UnitTestElement implements TestElement {
@@ -60,9 +94,12 @@ export class UnitTestElement implements TestElement {
6094
await this._stabilize();
6195
}
6296

63-
async sendKeys(keys: string): Promise<void> {
97+
async sendKeys(...keys: (string | TestKey)[]): Promise<void>;
98+
async sendKeys(modifiers: ModifierKeys, ...keys: (string | TestKey)[]): Promise<void>;
99+
async sendKeys(...modifiersAndKeys: any[]): Promise<void> {
64100
await this._stabilize();
65-
typeInElement(this.element as HTMLElement, keys);
101+
const args = modifiersAndKeys.map(k => typeof k === 'number' ? keyMap[k as TestKey] : k);
102+
typeInElement(this.element as HTMLElement, ...args);
66103
await this._stabilize();
67104
}
68105

src/cdk-experimental/testing/tests/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ ng_module(
1515
module_name = "@angular/cdk-experimental/testing/tests",
1616
deps = [
1717
"@npm//@angular/forms",
18+
"//src/cdk/keycodes",
1819
],
1920
)
2021

src/cdk-experimental/testing/tests/harnesses/main-component-harness.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {ComponentHarness} from '../../component-harness';
10-
import {TestElement} from '../../test-element';
10+
import {TestElement, TestKey} from '../../test-element';
1111
import {SubComponentHarness} from './sub-component-harness';
1212

1313
export class WrongComponentHarness extends ComponentHarness {
@@ -47,6 +47,7 @@ export class MainComponentHarness extends ComponentHarness {
4747
readonly testLists = this.locatorForAll(SubComponentHarness.with({title: /test/}));
4848
readonly requiredFourIteamToolsLists =
4949
this.locatorFor(SubComponentHarness.with({title: 'List of test tools', itemCount: 4}));
50+
readonly specaialKey = this.locatorFor('.special-key');
5051

5152
private _testTools = this.locatorFor(SubComponentHarness);
5253

@@ -66,4 +67,12 @@ export class MainComponentHarness extends ComponentHarness {
6667
const subComponent = await this._testTools();
6768
return subComponent.getItems();
6869
}
70+
71+
async sendEnter(): Promise<void> {
72+
return (await this.input()).sendKeys(TestKey.ENTER);
73+
}
74+
75+
async sendAltJ(): Promise<void> {
76+
return (await this.input()).sendKeys({alt: true}, 'j');
77+
}
6978
}

src/cdk-experimental/testing/tests/protractor.e2e.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,18 @@ describe('ProtractorHarnessEnvironment', () => {
155155
const globalEl = await harness.globalEl();
156156
expect(await globalEl.text()).toBe('I am a sibling!');
157157
});
158+
159+
it('should send enter key', async () => {
160+
const specialKey = await harness.specaialKey();
161+
await harness.sendEnter();
162+
expect(await specialKey.text()).toBe('enter');
163+
});
164+
165+
it('should send alt+j key', async () => {
166+
const specialKey = await harness.specaialKey();
167+
await harness.sendAltJ();
168+
expect(await specialKey.text()).toBe('alt-j');
169+
});
158170
});
159171

160172
describe('TestElement', () => {

src/cdk-experimental/testing/tests/test-main-component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ <h1 style="height: 50px">Main Component</h1>
88
<div id="asyncCounter">{{asyncCounter}}</div>
99
</div>
1010
<div class="inputs">
11-
<input [(ngModel)]="input" id="input" aria-label="input">
11+
<input [(ngModel)]="input" id="input" aria-label="input" (keydown)="onKeyDown($event)">
12+
<span class="special-key">{{specialKey}}</span>
1213
<div id="value">Input: {{input}}</div>
1314
<textarea id="memo" aria-label="memo">{{memo}}</textarea>
1415
</div>

src/cdk-experimental/testing/tests/test-main-component.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {ENTER} from '@angular/cdk/keycodes';
910
import {
1011
ChangeDetectionStrategy,
1112
ChangeDetectorRef,
@@ -35,6 +36,7 @@ export class TestMainComponent {
3536
testTools: string[];
3637
testMethods: string[];
3738
_isHovering: boolean;
39+
specialKey = '';
3840

3941
onMouseOver() {
4042
this._isHovering = true;
@@ -64,4 +66,13 @@ export class TestMainComponent {
6466
this._cdr.markForCheck();
6567
}, 500);
6668
}
69+
70+
onKeyDown(event: KeyboardEvent) {
71+
if (event.keyCode === ENTER && event.key === 'Enter') {
72+
this.specialKey = 'enter';
73+
}
74+
if (event.key === 'j' && event.altKey) {
75+
this.specialKey = 'alt-j';
76+
}
77+
}
6778
}

src/cdk-experimental/testing/tests/testbed.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,18 @@ describe('TestbedHarnessEnvironment', () => {
174174
expect(globalEl).not.toBeNull();
175175
expect(await globalEl.text()).toBe('Hello Yi from Angular 2!');
176176
});
177+
178+
it('should send enter key', async () => {
179+
const specialKey = await harness.specaialKey();
180+
await harness.sendEnter();
181+
expect(await specialKey.text()).toBe('enter');
182+
});
183+
184+
it('should send alt+j key', async () => {
185+
const specialKey = await harness.specaialKey();
186+
await harness.sendAltJ();
187+
expect(await specialKey.text()).toBe('alt-j');
188+
});
177189
});
178190

179191
describe('TestElement', () => {

0 commit comments

Comments
 (0)