Skip to content

Commit

Permalink
fixup! feat(cdk/testing): add BUILD file for webdriver and make it build
Browse files Browse the repository at this point in the history
  • Loading branch information
mmalerba committed Mar 24, 2021
1 parent ad5599d commit e6bc426
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 97 deletions.
104 changes: 24 additions & 80 deletions src/cdk/testing/webdriver/webdriver-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,66 +15,15 @@ import {
TestKey,
TextOptions
} from '@angular/cdk/testing';
import {Button, By, Key, WebElement} from 'selenium-webdriver';

/**
* Maps the `TestKey` constants to WebDriver's `Key` constants.
* See https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/webdriver/key.js#L29
*/
const keyMap = {
[TestKey.BACKSPACE]: Key.BACK_SPACE,
[TestKey.TAB]: Key.TAB,
[TestKey.ENTER]: Key.ENTER,
[TestKey.SHIFT]: Key.SHIFT,
[TestKey.CONTROL]: Key.CONTROL,
[TestKey.ALT]: Key.ALT,
[TestKey.ESCAPE]: Key.ESCAPE,
[TestKey.PAGE_UP]: Key.PAGE_UP,
[TestKey.PAGE_DOWN]: Key.PAGE_DOWN,
[TestKey.END]: Key.END,
[TestKey.HOME]: Key.HOME,
[TestKey.LEFT_ARROW]: Key.ARROW_LEFT,
[TestKey.UP_ARROW]: Key.ARROW_UP,
[TestKey.RIGHT_ARROW]: Key.ARROW_RIGHT,
[TestKey.DOWN_ARROW]: Key.ARROW_DOWN,
[TestKey.INSERT]: Key.INSERT,
[TestKey.DELETE]: Key.DELETE,
[TestKey.F1]: Key.F1,
[TestKey.F2]: Key.F2,
[TestKey.F3]: Key.F3,
[TestKey.F4]: Key.F4,
[TestKey.F5]: Key.F5,
[TestKey.F6]: Key.F6,
[TestKey.F7]: Key.F7,
[TestKey.F8]: Key.F8,
[TestKey.F9]: Key.F9,
[TestKey.F10]: Key.F10,
[TestKey.F11]: Key.F11,
[TestKey.F12]: Key.F12,
[TestKey.META]: Key.META
};

/** Converts a `ModifierKeys` object to a list of Protractor `Key`s. */
function toWebDriverModifierKeys(modifiers: ModifierKeys): string[] {
const result: string[] = [];
if (modifiers.control) {
result.push(Key.CONTROL);
}
if (modifiers.alt) {
result.push(Key.ALT);
}
if (modifiers.shift) {
result.push(Key.SHIFT);
}
if (modifiers.meta) {
result.push(Key.META);
}
return result;
}
import {
getWebDriverModifierKeys,
webDriverKeyMap
} from '@angular/cdk/testing/webdriver/webdriver-keys';
import * as webdriver from 'selenium-webdriver';

/** A `TestElement` implementation for WebDriver. */
export class WebdriverElement implements TestElement {
constructor(private readonly _webElement: () => WebElement) {}
export class WebDriverElement implements TestElement {
constructor(private readonly _webElement: () => webdriver.WebElement) {}

async blur(): Promise<void> {
return this._executeScript(((element: HTMLElement) => element.blur()), this._webElement());
Expand All @@ -86,12 +35,12 @@ export class WebdriverElement implements TestElement {

async click(...args: [ModifierKeys?] | ['center', ModifierKeys?] |
[number, number, ModifierKeys?]): Promise<void> {
await this._dispatchClickEventSequence(args, Button.LEFT);
await this._dispatchClickEventSequence(args, webdriver.Button.LEFT);
}

async rightClick(...args: [ModifierKeys?] | ['center', ModifierKeys?] |
[number, number, ModifierKeys?]): Promise<void> {
await this._dispatchClickEventSequence(args, Button.RIGHT);
await this._dispatchClickEventSequence(args, webdriver.Button.RIGHT);
}

async focus(): Promise<void> {
Expand Down Expand Up @@ -124,12 +73,12 @@ export class WebdriverElement implements TestElement {
rest = modifiersAndKeys;
}

const modifierKeys = toWebDriverModifierKeys(modifiers);
const keys = rest.map(k => typeof k === 'string' ? k.split('') : [keyMap[k]])
const modifierKeys = getWebDriverModifierKeys(modifiers);
const keys = rest.map(k => typeof k === 'string' ? k.split('') : [webDriverKeyMap[k]])
.reduce((arr, k) => arr.concat(k), [])
// Key.chord doesn't work well with geckodriver (mozilla/geckodriver#1502),
// webdriver.Key.chord doesn't work well with geckodriver (mozilla/geckodriver#1502),
// so avoid it if no modifier keys are required.
.map(k => modifierKeys.length > 0 ? Key.chord(...modifierKeys, k) : k);
.map(k => modifierKeys.length > 0 ? webdriver.Key.chord(...modifierKeys, k) : k);

return this._webElement().sendKeys(...keys);
}
Expand Down Expand Up @@ -171,7 +120,7 @@ export class WebdriverElement implements TestElement {
}

async selectOptions(...optionIndexes: number[]): Promise<void> {
const options = await this._webElement().findElements(By.css('option'));
const options = await this._webElement().findElements(webdriver.By.css('option'));
const indexes = new Set(optionIndexes); // Convert to a set to remove duplicates.

if (options.length && indexes.size) {
Expand All @@ -183,9 +132,9 @@ export class WebdriverElement implements TestElement {
if (indexes.has(i)) {
// We have to hold the control key while clicking on options so that multiple can be
// selected in multi-selection mode. The key doesn't do anything for single selection.
await this._actions().keyDown(Key.CONTROL).perform();
await this._actions().keyDown(webdriver.Key.CONTROL).perform();
await options[i].click();
await this._actions().keyUp(Key.CONTROL).perform();
await this._actions().keyUp(webdriver.Key.CONTROL).perform();
}
}
}
Expand All @@ -199,12 +148,12 @@ export class WebdriverElement implements TestElement {
}

async isFocused(): Promise<boolean> {
return WebElement.equals(
return webdriver.WebElement.equals(
this._webElement(), this._webElement().getDriver().switchTo().activeElement());
}

async dispatchEvent(name: string, data?: Record<string, EventData>): Promise<void> {
return this._executeScript(_dispatchEvent, name, this._webElement(), data);
return this._executeScript(dispatchEvent, name, this._webElement(), data);
}

private _actions() {
Expand All @@ -223,7 +172,7 @@ export class WebdriverElement implements TestElement {
if (args.length && typeof args[args.length - 1] === 'object') {
modifiers = args.pop() as ModifierKeys;
}
const modifierKeys = toWebDriverModifierKeys(modifiers);
const modifierKeys = getWebDriverModifierKeys(modifiers);

// Omitting the offset argument to mouseMove results in clicking the center.
// This is the default behavior we want, so we use an empty array of offsetArgs if
Expand All @@ -246,18 +195,13 @@ export class WebdriverElement implements TestElement {
}

/**
* Dispatches an event with a particular name and data to an element.
* Note that this needs to be a pure function, because it gets stringified by
* Protractor and is executed inside the browser.
* Dispatches an event with a particular name and data to an element. Note that this needs to be a
* pure function, because it gets stringified by WebDriver and is executed inside the browser.
*/
function _dispatchEvent(name: string, element: Element, data?: Record<string, EventData>) {
function dispatchEvent(name: string, element: Element, data?: Record<string, EventData>) {
const event = document.createEvent('Event');
event.initEvent(name);

if (data) {
// tslint:disable-next-line:ban Have to use `Object.assign` to preserve the original object.
Object.assign(event, data);
}

// tslint:disable-next-line:ban Have to use `Object.assign` to preserve the original object.
Object.assign(event, data || {});
element.dispatchEvent(event);
}
35 changes: 18 additions & 17 deletions src/cdk/testing/webdriver/webdriver-harness-environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
*/

import {HarnessEnvironment, HarnessLoader, TestElement} from '@angular/cdk/testing';
import {By, WebDriver, WebElement} from 'selenium-webdriver';
import {WebdriverElement} from './webdriver-element';
import * as webdriver from 'selenium-webdriver';
import {WebDriverElement} from './webdriver-element';

/** A `HarnessEnvironment` implementation for Protractor. */
export class WebdriverHarnessEnvironment extends HarnessEnvironment<() => WebElement> {
protected constructor(rawRootElement: () => WebElement) {
/** A `HarnessEnvironment` implementation for WebDriver. */
export class WebDriverHarnessEnvironment extends HarnessEnvironment<() => webdriver.WebElement> {
protected constructor(rawRootElement: () => webdriver.WebElement) {
super(rawRootElement);
}

/** Creates a `HarnessLoader` rooted at the document root. */
static loader(driver: WebDriver): HarnessLoader {
return new WebdriverHarnessEnvironment(() => driver.findElement(By.css('body')));
static loader(driver: webdriver.WebDriver): HarnessLoader {
return new WebDriverHarnessEnvironment(() => driver.findElement(webdriver.By.css('body')));
}

async forceStabilize(): Promise<void> {
Expand All @@ -31,22 +31,23 @@ export class WebdriverHarnessEnvironment extends HarnessEnvironment<() => WebEle
// https://github.com/angular/components/issues/17412
}

protected getDocumentRoot(): () => WebElement {
return () => this.rawRootElement().getDriver().findElement(By.css('body'));
protected getDocumentRoot(): () => webdriver.WebElement {
return () => this.rawRootElement().getDriver().findElement(webdriver.By.css('body'));
}

protected createTestElement(element: () => WebElement): TestElement {
return new WebdriverElement(element);
protected createTestElement(element: () => webdriver.WebElement): TestElement {
return new WebDriverElement(element);
}

protected createEnvironment(element: () => WebElement): HarnessEnvironment<() => WebElement> {
return new WebdriverHarnessEnvironment(element);
protected createEnvironment(element: () => webdriver.WebElement):
HarnessEnvironment<() => webdriver.WebElement> {
return new WebDriverHarnessEnvironment(element);
}

// TODO(mmalerba): I'm not so sure about this...
// it feels like maybe the return type should be `() => Promise<WebElement[]>` instead.
protected async getAllRawElements(selector: string): Promise<(() => WebElement)[]> {
const els = await this.rawRootElement().findElements(By.css(selector));
return els.map((x: WebElement) => () => x);
// it feels like maybe the return type should be `() => Promise<webdriver.WebElement[]>` instead.
protected async getAllRawElements(selector: string): Promise<(() => webdriver.WebElement)[]> {
const els = await this.rawRootElement().findElements(webdriver.By.css(selector));
return els.map((x: webdriver.WebElement) => () => x);
}
}
65 changes: 65 additions & 0 deletions src/cdk/testing/webdriver/webdriver-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {ModifierKeys, TestKey} from '@angular/cdk/testing';
import * as webdriver from 'selenium-webdriver';

/**
* Maps the `TestKey` constants to WebDriver's `webdriver.Key` constants.
* See https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/webdriver/key.js#L29
*/
export const webDriverKeyMap = {
[TestKey.BACKSPACE]: webdriver.Key.BACK_SPACE,
[TestKey.TAB]: webdriver.Key.TAB,
[TestKey.ENTER]: webdriver.Key.ENTER,
[TestKey.SHIFT]: webdriver.Key.SHIFT,
[TestKey.CONTROL]: webdriver.Key.CONTROL,
[TestKey.ALT]: webdriver.Key.ALT,
[TestKey.ESCAPE]: webdriver.Key.ESCAPE,
[TestKey.PAGE_UP]: webdriver.Key.PAGE_UP,
[TestKey.PAGE_DOWN]: webdriver.Key.PAGE_DOWN,
[TestKey.END]: webdriver.Key.END,
[TestKey.HOME]: webdriver.Key.HOME,
[TestKey.LEFT_ARROW]: webdriver.Key.ARROW_LEFT,
[TestKey.UP_ARROW]: webdriver.Key.ARROW_UP,
[TestKey.RIGHT_ARROW]: webdriver.Key.ARROW_RIGHT,
[TestKey.DOWN_ARROW]: webdriver.Key.ARROW_DOWN,
[TestKey.INSERT]: webdriver.Key.INSERT,
[TestKey.DELETE]: webdriver.Key.DELETE,
[TestKey.F1]: webdriver.Key.F1,
[TestKey.F2]: webdriver.Key.F2,
[TestKey.F3]: webdriver.Key.F3,
[TestKey.F4]: webdriver.Key.F4,
[TestKey.F5]: webdriver.Key.F5,
[TestKey.F6]: webdriver.Key.F6,
[TestKey.F7]: webdriver.Key.F7,
[TestKey.F8]: webdriver.Key.F8,
[TestKey.F9]: webdriver.Key.F9,
[TestKey.F10]: webdriver.Key.F10,
[TestKey.F11]: webdriver.Key.F11,
[TestKey.F12]: webdriver.Key.F12,
[TestKey.META]: webdriver.Key.META
};

/** Gets a list of WebDriver `Key`s for the given `ModifierKeys`. */
export function getWebDriverModifierKeys(modifiers: ModifierKeys): string[] {
const result: string[] = [];
if (modifiers.control) {
result.push(webdriver.Key.CONTROL);
}
if (modifiers.alt) {
result.push(webdriver.Key.ALT);
}
if (modifiers.shift) {
result.push(webdriver.Key.SHIFT);
}
if (modifiers.meta) {
result.push(webdriver.Key.META);
}
return result;
}

0 comments on commit e6bc426

Please sign in to comment.