cabbie-sync
Version:
A synchronous webdriver client
295 lines (266 loc) • 9.02 kB
Flow
/**
* @flow
* This file is generated automatically, run npm run build to re-generate.
**/
import { inspect } from 'util';
import type Driver from './driver';
import type { ElementHandle } from './flow-types/element-handle';
import type { SelectorType } from './enums/selector-types';
import addDebugging from './add-debugging';
import BaseClass from './base-class';
import Mouse from './mouse';
import SelectorTypes from './enums/selector-types';
import Touch from './touch';
import waitFor from './utils/wait-for';
/*
* A representation of a remote element. You can use it to click on, type text into and check the attributes of.
*
* ```js
* const element = await driver.activeWindow.getElement('[data-test-id="my-test-element"]');
*
* const elements = await driver.activeWindow.getElements('.some-class-name');
* ```
*/
class Element extends BaseClass {
_parent: Element | Driver;
_selector: string;
/*
* The selenium id of the element
*/
elementID: string;
/*
* Utility methods for clicking on the element
*/
mouse: Mouse;
/*
* Methods for interacting with the element via touch
*/
touch: Touch;
constructor(driver: Driver, parent: Element | Driver, selector: string, elementHandle: ElementHandle) {
const prefix = '/element/' + elementHandle.ELEMENT;
super(driver, prefix);
this._parent = parent;
this._selector = selector;
this.elementID = elementHandle.ELEMENT;
this.mouse = new Mouse(this.driver, this);
this.touch = new Touch(this.driver, this);
}
/*
* Get the value of an attribute.
*/
getAttribute(attribute: string): string {
return this.requestJSON('GET', '/attribute/' + attribute);
}
/*
* Test if the element have a specific class
*/
hasClass(className: string): boolean {
const classNames = this.getAttribute('class');
return !!classNames.match(new RegExp('\\b' + className + '\\b'));
}
/*
* Get the text body of an element.
*/
getText(): string {
return this.requestJSON('GET', '/text');
}
/*
* Get the tag-name of an element.
*/
getTagName(): string {
return this.requestJSON('GET', '/name');
}
/*
* Query the value of an element's computed CSS property. The CSS property to query
* should be specified using the CSS property name, not the JavaScript property name
* (e.g. background-color instead of backgroundColor).
*/
getCssValue(property: string): string {
return this.requestJSON('GET', '/css/' + property);
}
/*
* Return true if the element is currently displayed on the page
*/
isDisplayed(): boolean {
return this.requestJSON('GET', '/displayed');
}
/*
* Return true if the form element is selected
*/
isSelected(): boolean {
return this.requestJSON('GET', '/selected');
}
/*
* Return true if the current element is equal to the supplied element
*/
isEqual(element: Element): boolean {
return this.requestJSON('GET', '/equals/' + element.elementID);
}
/*
* Return true if the form element is enabled
*/
isEnabled(): boolean {
return this.requestJSON('GET', '/enabled');
}
/*
* Return true if the form element is disabled
*/
isDisabled(): boolean {
const isEnabled = this.isEnabled();
return !isEnabled;
}
// todo: uploading files ala wd.Element.sendKeys
/*
* Type a string of characters into an input
*/
sendKeys(str: string | Array<string>): void {
this.requestJSON('POST', '/value', { value: Array.isArray(str) ? str : [str] });
}
/*
* Clear the value of an input
*/
clear(): void {
this.requestJSON('POST', '/clear');
}
/*
* Submit a form element
*/
submit(): void {
this.requestJSON('POST', '/submit');
}
/*
* Get the size of an element
*/
getSize(): { width: number; height: number; } {
const size = this.requestJSON('GET', '/size');
return { width: size.width, height: size.height };
}
/*
* Get the position of an element
*/
getPosition(): { x: number; y: number; } {
const position = this.requestJSON('GET', '/location');
return { x: position.x, y: position.y };
}
/*
* Get the frame of an element
*/
getFrame(): { x: number; y: number; width: number; height: number; } {
const position = this.getPosition();
const size = this.getSize();
return { x: position.x, y: position.y, width: size.width, height: size.height };
}
/*
* Get the absolute center of an element
*/
getAbsoluteCenter(): { x: number; y: number; } {
const frame = this.getFrame();
return { x: Math.floor(frame.width / 2) + frame.x, y: Math.floor(frame.height / 2) + frame.y };
}
/*
* Get the relative center of an element
*/
getRelativeCenter(): { x: number; y: number; } {
const size = this.getSize();
return { x: Math.floor(size.width / 2), y: Math.floor(size.height / 2) };
}
/*
* Get an element via a selector.
* Will throw an error if the element does not exist.
*/
getElement(selector: string, selectorType: SelectorType = SelectorTypes.CSS): Element {
const elementHandle = waitFor(() => this.requestJSON('POST', '/element', { using: selectorType, value: selector }));
return new Element(this.driver, this, [this._selector, selector].join(' '), elementHandle);
}
/*
* Get an element via a selector.
* Will return null if the element does not exist
*/
tryGetElement(selector: string, selectorType: SelectorType = SelectorTypes.CSS): Element | null {
try {
const elementHandle = this.requestJSON('POST', '/element', { using: selectorType, value: selector });
return new Element(this.driver, this, [this._selector, selector].join(' '), elementHandle);
} catch (ex) {
if (ex.code === 'NoSuchElement' || ex.code === 'ElementNotVisible' || ex.code === 'ElementIsNotSelectable') {
return null;
}
throw ex;
}
}
/*
* Get elements via a selector.
*/
getElements(selector: string, selectorType: SelectorType = SelectorTypes.CSS): Array<Element> {
const elementHandles = this.requestJSON('POST', '/elements', { using: selectorType, value: selector });
return elementHandles.map(elementHandle => {
return new Element(this.driver, this, [this._selector, selector].join(' '), elementHandle);
});
}
/*
* Get elements by its text content, optionally narrowed down using a selector.
*
* N.B. this is **much** slower than getting elements by ID or css selector.
*/
getElementsByTextContent(textContent: string, selector: string = '*', selectorType: SelectorType = SelectorTypes.CSS): Array<Element> {
if (selector === 'a' && (selectorType === SelectorTypes.CSS || selectorType === SelectorTypes.TAG)) {
selector = textContent;
selectorType = SelectorTypes.PARTIAL_LINK_TEXT;
}
textContent = textContent.trim();
const elements = this.getElements(selector, selectorType);
const elementsToReturn = [];
for (let i = 0; i < elements.length; i++) {
if (textContent === elements[i].getText().trim()) {
elementsToReturn.push(elements[i]);
}
}
return elementsToReturn;
}
/*
* Get elements by its text content, optionally narrowed down using a selector.
*
* N.B. this is **much** slower than getting elements by ID or css selector.
*/
getElementByTextContent(textContent: string, selector: string = '*', selectorType: SelectorType = SelectorTypes.CSS): Element {
const element = waitFor(() => this.tryGetElementByTextContent(textContent, selector, selectorType));
if (element) {
return element;
}
const err = new Error('Could not find an element with the text content: ' + textContent);
err.name = 'NoSuchElement';
(err: any).code = 'NoSuchElement';
throw err;
}
/*
* Get elements by its text content, optionally narrowed down using a selector.
*
* N.B. this is **much** slower than getting elements by ID or css selector.
*/
tryGetElementByTextContent(textContent: string, selector: string = '*', selectorType: SelectorType = SelectorTypes.CSS): Element | null {
if (selector === 'a' && (selectorType === SelectorTypes.CSS || selectorType === SelectorTypes.TAG)) {
selector = textContent;
selectorType = SelectorTypes.PARTIAL_LINK_TEXT;
}
textContent = textContent.trim().toLowerCase();
const elements = this.getElements(selector, selectorType);
for (let i = 0; i < elements.length; i++) {
if (textContent === elements[i].getText().trim().toLowerCase()) {
return elements[i];
}
}
return null;
}
/*
* Does a specific element exist?
*/
hasElement(selector: string, selectorType: SelectorType = SelectorTypes.CSS): boolean {
const elements = this.getElements(selector, selectorType);
return elements.length > 0;
}
}
addDebugging(Element, {
inspect(obj, depth, options) {
return 'Element(' + inspect(obj._selector, options) + ')';
}
});
export default Element;