Current Dev State

This commit is contained in:
Tim Lorsbach
2025-06-23 20:13:54 +02:00
parent b4f9bb277d
commit ded50edaa2
22617 changed files with 4345095 additions and 174 deletions

View File

@ -0,0 +1,40 @@
/**
*
* Accepts the currently displayed alert dialog. Usually, this is equivalent to
* clicking on the 'OK' button in the dialog.
*
* <example>
:alertAccept.js
it('demonstrate the alertAccept command', function () {
if (browser.alertText()) {
browser.alertAccept();
}
// ...
});
* </example>
*
* @throws {RuntimeError} If no alert is present. The seleniumStack.type parameter will equal 'NoAlertOpenError'.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#accept-alert
* @type protocol
*
*/
export default function alertAccept () {
const requestOptions = {
path: '/session/:sessionId/accept_alert',
method: 'POST'
}
return this.requestHandler.create(requestOptions).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
requestOptions.path = '/session/:sessionId/alert/accept'
return this.requestHandler.create(requestOptions)
}
throw err
})
}

View File

@ -0,0 +1,41 @@
/**
*
* Dismisses the currently displayed alert dialog. For confirm() and prompt()
* dialogs, this is equivalent to clicking the 'Cancel' button. For alert()
* dialogs, this is equivalent to clicking the 'OK' button.
*
* <example>
:alertAccept.js
it('demonstrate the alertDismiss command', function () {
if (browser.alertText()) {
browser.alertDismiss();
}
// ...
});
* </example>
*
* @throws {RuntimeError} If no alert is present. The seleniumStack.type parameter will equal 'NoAlertOpenError'.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dismiss-alert
* @type protocol
*
*/
export default function alertDismiss () {
const requestOptions = {
path: '/session/:sessionId/dismiss_alert',
method: 'POST'
}
return this.requestHandler.create(requestOptions).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
requestOptions.path = '/session/:sessionId/alert/dismiss'
return this.requestHandler.create(requestOptions)
}
throw err
})
}

View File

@ -0,0 +1,54 @@
/**
*
* Gets the text of the currently displayed JavaScript alert(), confirm(), or prompt() dialog.
*
* <example>
:alertText.js
it('demonstrate the alertDismiss command', function () {
if (browser.alertText()) {
browser.alertDismiss();
}
// ...
});
* </example>
*
* @param {String=} text Keystrokes to send to the prompt() dialog.
* @return {String} The text of the currently displayed alert.
* @throws {RuntimeError} If no alert is present. The seleniumStack.type parameter will equal 'NoAlertOpenError'.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#get-alert-text
* @see https://w3c.github.io/webdriver/webdriver-spec.html#send-alert-text
* @type protocol
*
*/
let alertText = function (text) {
const requestOptions = {
path: '/session/:sessionId/alert_text',
method: 'GET'
}
const data = {}
if (typeof text === 'string') {
requestOptions.method = 'POST'
data.text = text
}
const request = this.requestHandler.create(requestOptions, data).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
requestOptions.path = '/session/:sessionId/alert/text'
return this.requestHandler.create(requestOptions, data)
}
throw err
})
return this.unify(request, {
extractValue: true
})
}
export default alertText

View File

@ -0,0 +1,20 @@
/**
*
* Get the status of the html5 application cache.
*
* This command is depcrecated and will be removed soon. Make sure you don't use it in your
* automation/test scripts anymore to avoid errors.
*
* @return {Number} Status code for application cache: **{UNCACHED = 0, IDLE = 1, CHECKING = 2, DOWNLOADING = 3, UPDATE_READY = 4, OBSOLETE = 5}**
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidapplication_cachestatus
* @type protocol
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function applicationCacheStatus () {
depcrecate('applicationCacheStatus')
return this.requestHandler.create('/session/:sessionId/application_cache/status')
}

View File

@ -0,0 +1,24 @@
/**
*
* Navigate backwards in the browser history, if possible.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#back
* @type protocol
*
*/
export default function back () {
if (this.desiredCapabilities.browserName === 'safari') {
/*!
* helper for safaridriver which doesn not support forward
* Reason: "Yikes! Safari history navigation does not work. We can go forward or back,
* but once we do, we can no longer communicate with the page"
*/
return this.execute('history.go(-1)')
}
return this.requestHandler.create({
path: '/session/:sessionId/back',
method: 'POST'
})
}

View File

@ -0,0 +1,23 @@
/**
*
* Send the currently active app to the background.
*
* <example>
:backgroundApp.js
browser.background(1);
* </example>
*
* @param {Number} seconds number of seconds after the app gets send to background
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#background-app
* @type mobile
* @for android
*
*/
export default function background (seconds = 0) {
return this.requestHandler.create({
path: '/session/:sessionId/appium/app/background',
method: 'POST'
}, { seconds })
}

View File

@ -0,0 +1,28 @@
/**
*
* Click and hold the left mouse button (at the coordinates set by the last moveto
* command). Note that the next mouse-related command that should follow is buttonup.
* Any other mouse command (such as click or another call to buttondown) will yield
* undefined behaviour.
*
* This command is depcrecated and will be removed soon. Make sure you don't use it in your
* automation/test scripts anymore to avoid errors.
*
* @param {Number} button Which button, enum: *{LEFT = 0, MIDDLE = 1 , RIGHT = 2}*. Defaults to the left mouse button if not specified.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidbuttondown
* @type protocol
*
*/
import handleMouseButtonProtocol from '../helpers/handleMouseButtonProtocol'
import depcrecate from '../helpers/depcrecationWarning'
export default function buttonDown (button) {
depcrecate('buttonDown')
return handleMouseButtonProtocol.call(
this,
'/session/:sessionId/buttondown',
button
)
}

View File

@ -0,0 +1,25 @@
/**
*
* Click any mouse button (at the coordinates set by the last moveto command). Note
* that calling this command after calling buttondown and before calling button up
* (or any out-of-order interactions sequence) will yield undefined behaviour.
*
* This command is depcrecated and will be removed soon. Make sure you don't use it in your
* automation/test scripts anymore to avoid errors.
*
* @param {Number} button Which button, enum: *{LEFT = 0, MIDDLE = 1 , RIGHT = 2}*. Defaults to the left mouse button if not specified.
* @type protocol
*
*/
import handleMouseButtonProtocol from '../helpers/handleMouseButtonProtocol'
import depcrecate from '../helpers/depcrecationWarning'
export default function buttonPress (button) {
depcrecate('buttonPress')
return handleMouseButtonProtocol.call(
this,
'/session/:sessionId/click',
button
)
}

View File

@ -0,0 +1,27 @@
/**
*
* Releases the mouse button previously held (where the mouse is currently at). Must
* be called once for every buttondown command issued. See the note in click and
* buttondown about implications of out-of-order commands.
*
* This command is depcrecated and will be removed soon. Make sure you don't use it in your
* automation/test scripts anymore to avoid errors.
*
* @param {Number} button Which button, enum: *{LEFT = 0, MIDDLE = 1 , RIGHT = 2}*. Defaults to the left mouse button if not specified.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidbuttonup
* @type protocol
*
*/
import handleMouseButtonProtocol from '../helpers/handleMouseButtonProtocol'
import depcrecate from '../helpers/depcrecationWarning'
export default function buttonUp (button) {
depcrecate('buttonUp')
return handleMouseButtonProtocol.call(
this,
'/session/:sessionId/buttonup',
button
)
}

View File

@ -0,0 +1,21 @@
/**
*
* Close the given application.
*
* <example>
:closeApp.js
browser.closeApp()
* </example>
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#close-app
* @type mobile
* @for ios
*
*/
export default function closeApp () {
return this.requestHandler.create({
path: '/session/:sessionId/appium/app/close',
method: 'POST'
})
}

View File

@ -0,0 +1,30 @@
/**
*
* Retrieve current context or switch to the specified context
*
* @param {String=} id the context to switch to
*
* @see http://appium.io/slate/en/v1.1.0/?javascript#automating-hybrid-ios-apps
* @see https://github.com/admc/wd/blob/master/lib/commands.js#L279
* @type mobile
* @for android, ios
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function context (id) {
const data = {}
const requestOptions = {
path: '/session/:sessionId/context',
method: 'GET'
}
if (typeof id === 'string') {
requestOptions.method = 'POST'
data.name = id
}
depcrecate('context')
return this.requestHandler.create(requestOptions, data)
}

View File

@ -0,0 +1,17 @@
/**
*
* Returns an object with a value field containing the list of all available contexts
*
* @see http://appium.io/slate/en/v1.1.0/?javascript#automating-hybrid-ios-apps
* @see https://github.com/admc/wd/blob/master/lib/commands.js#L279
* @type mobile
* @for android, ios
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function contexts () {
depcrecate('contexts')
return this.requestHandler.create('/session/:sessionId/contexts')
}

View File

@ -0,0 +1,54 @@
/**
* Protocol binding to operate with cookies on the current page.
*
* <example>
:cookie.js
it('should get/set cookies using protocol command', function () {
// get all cookies
var cookies = browser.cookie();
console.log(cookies); // outputs: [{ name: 'test', value: '123' }]
// set cookie
browser.cookie('post', {
name: 'myCookie',
value: 'some content'
});
// delete cookie (sync)
browser.cookie('delete','myCookie');
})
* </example>
*
* @param {String=} method request method
* @param {Object=|String=} args contains cookie information if you want to set a cookie or contains name of cookie if you want to delete it
*
* @return {Object} cookie data
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#cookies
* @type protocol
*
*/
export default function cookie (method = 'GET', args) {
const data = {}
const requestOptions = {
path: '/session/:sessionId/cookie',
method: method
}
/**
* set cookie param for POST method
*/
if (method.toUpperCase() === 'POST' && typeof args === 'object') {
data.cookie = args
}
/**
* add cookie name tp path URL to delete a specific cookie object
*/
if (method.toUpperCase() === 'DELETE' && typeof args === 'string') {
requestOptions.path += '/' + args
}
return this.requestHandler.create(requestOptions, data)
}

View File

@ -0,0 +1,21 @@
/**
*
* Receive the current activity on an Android device.
*
* <example>
:rotateAsync.js
it('should get the activity of the android device', function () {
var activity = browser.currentActivity()
console.log(activity); // returns android activity information
});
* </example>
*
* @see https://github.com/appium/appium-android-driver/blob/master/lib/commands/general.js#L59-L61
* @type mobile
* @for android
*
*/
export default function currentActivity () {
return this.requestHandler.create('/session/:sessionId/appium/device/current_activity')
}

View File

@ -0,0 +1,28 @@
/**
*
* send a key event to the device
*
* @param {Number} keyValue device specifc key value
*
* @see https://github.com/appium/appium/blob/master/docs/en/appium-bindings.md#key-event
* @type mobile
* @for android
*
*/
export default function deviceKeyEvent (keycode, metastate) {
let data = {
keycode: keycode
}
if (metastate) {
data.metastate = metastate
}
let requestOptions = {
path: '/session/:sessionId/appium/device/keyevent',
method: 'POST'
}
return this.requestHandler.create(requestOptions, data)
}

View File

@ -0,0 +1,21 @@
/**
*
* Double-clicks at the current mouse coordinates (set by moveto.
*
* This command is depcrecated and will be removed soon. Make sure you don't use it in your
* automation/test scripts anymore to avoid errors.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessioniddoubleclick
* @type protocol
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function doDoubleClick () {
depcrecate('doDoubleClick')
return this.requestHandler.create({
path: '/session/:sessionId/doubleclick',
method: 'POST'
})
}

View File

@ -0,0 +1,80 @@
/**
* Search for an element on the page, starting from the document root.
* The located element will be returned as a WebElement JSON object.
* The table below lists the locator strategies that each server should support.
* Each locator must return the first matching element located in the DOM.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#find-element
*
* @param {String} selector selector to query the element
* @return {String} A WebElement JSON object for the located element.
*
* @type protocol
*
*/
import findStrategy from '../helpers/findElementStrategy'
import hasElementResult from '../helpers/hasElementResultHelper'
import q from 'q'
export default function element (selector) {
let requestPath = '/session/:sessionId/element'
let lastPromise = this.lastResult ? q(this.lastResult).inspect() : this.lastPromise.inspect()
let relative = false
if (lastPromise.state === 'fulfilled' && hasElementResult(lastPromise.value) === 1) {
if (!selector) {
return lastPromise.value
}
/**
* format xpath selector (global -> relative)
*/
if (selector.slice(0, 2) === '//') {
selector = '.' + selector.slice(1)
}
let elem = lastPromise.value.value.ELEMENT
relative = true
requestPath = `/session/:sessionId/element/${elem}/element`
}
let found = findStrategy(selector, relative)
return this.requestHandler.create(
requestPath,
{ using: found.using, value: found.value }
).then((result) => {
result.selector = selector
/**
* W3C webdriver protocol has changed element identifier from `ELEMENT` to
* `element-6066-11e4-a52e-4f735466cecf`. Let's make sure both identifier
* are supported.
*/
const elemValue = result.value.ELEMENT || result.value['element-6066-11e4-a52e-4f735466cecf']
if (elemValue) {
result.value = {
ELEMENT: elemValue,
'element-6066-11e4-a52e-4f735466cecf': elemValue
}
}
return result
}, (e) => {
let result = e.seleniumStack
/**
* if error is not NoSuchElement throw it
*/
if (!result || result.type !== 'NoSuchElement') {
throw e
}
result.state = 'failure'
result.sessionId = this.requestHandler.sessionID
result.value = null
result.selector = selector
delete result.orgStatusMessage
return result
})
}

View File

@ -0,0 +1,29 @@
/**
*
* Get the element on the page that currently has focus. The element will be returned as a WebElement JSON object.
*
* @return {String} A WebElement JSON object for the active element.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#get-active-element
* @type protocol
*
*/
export default function elementActive () {
const requestOptions = {
path: '/session/:sessionId/element/active',
method: 'POST'
}
return this.requestHandler.create(requestOptions).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
requestOptions.method = 'GET'
return this.requestHandler.create(requestOptions)
}
throw err
})
}

View File

@ -0,0 +1,23 @@
/**
*
* Get the value of an element's attribute.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @param {String} attributeName attribute name of element you want to receive
*
* @return {String|null} The value of the attribute, or null if it is not set on the element.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dfn-get-element-attribute
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdAttribute (id, attributeName) {
if ((typeof id !== 'string' && typeof id !== 'number') || typeof attributeName !== 'string') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdAttribute protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/attribute/${attributeName}`)
}

View File

@ -0,0 +1,23 @@
/**
*
* Clear a `TEXTAREA` or text `INPUT element's value.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dfn-element-clear
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdClear (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdClear protocol command')
}
return this.requestHandler.create({
path: `/session/:sessionId/element/${id}/clear`,
method: 'POST'
})
}

View File

@ -0,0 +1,23 @@
/**
*
* Click on an element.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dfn-element-click
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdClick (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdClick protocol command')
}
return this.requestHandler.create({
path: `/session/:sessionId/element/${id}/click`,
method: 'POST'
})
}

View File

@ -0,0 +1,25 @@
/**
*
* 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).
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @param {String} cssPropertyName CSS property
*
* @return {String} The value of the specified CSS property.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#get-element-property
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdCssProperty (id, cssPropertyName) {
if ((typeof id !== 'string' && typeof id !== 'number') || typeof cssPropertyName !== 'string') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdCssProperty protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/css/${cssPropertyName}`)
}

View File

@ -0,0 +1,21 @@
/**
*
* Determine if an element is currently displayed.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {Boolean} true if the element is displayed
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#element-displayedness
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdDisplayed (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdDisplayed protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/displayed`)
}

View File

@ -0,0 +1,61 @@
/**
*
* Search for an element on the page, starting from an element.
* The located element will be returned as a WebElement JSON object.
* The table below lists the locator strategies that each server should support.
* Each locator must return the first matching element located in the DOM.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @param {String} selector selector to query the element
* @return {String} A WebElement JSON object for the located element.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#find-element-from-element
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import findStrategy from '../helpers/findElementStrategy'
export default function elementIdElement (id, selector) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdElement protocol command')
}
let found = findStrategy(selector, true)
return this.requestHandler.create(`/session/:sessionId/element/${id}/element`, {
using: found.using,
value: found.value
}).then((result) => {
result.selector = selector
/**
* W3C webdriver protocol has changed element identifier from `ELEMENT` to
* `element-6066-11e4-a52e-4f735466cecf`. Let's make sure both identifier
* are supported.
*/
const elemValue = result.value.ELEMENT || result.value['element-6066-11e4-a52e-4f735466cecf']
result.value = {
ELEMENT: elemValue,
'element-6066-11e4-a52e-4f735466cecf': elemValue
}
return result
}, (e) => {
let result = e.seleniumStack
/**
* if error is not NoSuchElement throw it
*/
if (!result || result.type !== 'NoSuchElement') {
throw e
}
result.state = 'failure'
result.sessionId = this.requestHandler.sessionID
result.value = null
result.selector = selector
delete result.orgStatusMessage
return result
})
}

View File

@ -0,0 +1,47 @@
/**
*
* Search for multiple elements on the page, starting from an element. The located
* elements will be returned as a WebElement JSON objects. The table below lists the
* locator strategies that each server should support. Elements should be returned in
* the order located in the DOM.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @param {String} selector selector to query the elements
* @return {Object[]} A list of WebElement JSON objects for the located elements.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#find-elements-from-element
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import findStrategy from '../helpers/findElementStrategy'
export default function elementIdElements (id, selector) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdElements protocol command')
}
let found = findStrategy(selector, true)
return this.requestHandler.create(`/session/:sessionId/element/${id}/elements`, {
using: found.using,
value: found.value
}).then((result) => {
result.selector = selector
/**
* W3C webdriver protocol has changed element identifier from `ELEMENT` to
* `element-6066-11e4-a52e-4f735466cecf`. Let's make sure both identifier
* are supported.
*/
result.value = result.value.map((elem) => {
const elemValue = elem.ELEMENT || elem['element-6066-11e4-a52e-4f735466cecf']
return {
ELEMENT: elemValue,
'element-6066-11e4-a52e-4f735466cecf': elemValue
}
})
return result
})
}

View File

@ -0,0 +1,21 @@
/**
*
* Determine if an element is currently enabled.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {Boolean} true if the element is enabled
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#is-element-enabled
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdEnabled (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdEnabled protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/enabled`)
}

View File

@ -0,0 +1,39 @@
/**
*
* Determine an element's location on the page. The point (0, 0) refers to the
* upper-left corner of the page. The element's coordinates are returned as a
* JSON object with x and y properties.
*
* Depcrecated command, please use [`elementIdRect`](http://webdriver.io/api/protocol/elementIdRect.html).
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {Object} The X and Y coordinates for the element on the page (`{x:number, y:number}`)
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelementidlocation
* @type protocol
* @deprecated
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdLocation (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdLocation protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/location`).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
return this.elementIdRect(id).then((result) => {
const { x, y } = result.value
result.value = { x, y }
return result
})
}
throw err
})
}

View File

@ -0,0 +1,29 @@
/**
*
* Determine an element's location on the screen once it has been scrolled into view.
*
* *Note:* This is considered an internal command and should only be used to determine
* an element's location for correctly generating native events.
*
* Depcrecated command, please use `elementIdRect`.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {Object} The X and Y coordinates for the element (`{x:number, y:number}`)
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelementidlocation_in_view
* @type protocol
* @deprecated
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import depcrecate from '../helpers/depcrecationWarning'
export default function elementIdLocationInView (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdLocationInView protocol command')
}
depcrecate('elementIdLocationInView')
return this.requestHandler.create(`/session/:sessionId/element/${id}/location_in_view`)
}

View File

@ -0,0 +1,21 @@
/**
*
* Query for an element's tag name.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {String} the element's tag name, as a lowercase string
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#get-element-tag-name
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdName (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdName protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/name`)
}

View File

@ -0,0 +1,27 @@
/**
*
* The Get Element Rect command returns the dimensions and coordinates of the given web element.
* The returned value is a dictionary with `x`. `y`, `width` and `height` properties.
*
* Note: this command was recently added to the official Webdriver protocol and might not be
* working with current Selenium driver.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#get-element-rect
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdRect (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdRect protocol command')
}
return this.requestHandler.create({
path: `/session/:sessionId/element/${id}/rect`,
method: 'GET'
})
}

View File

@ -0,0 +1,24 @@
/**
*
* The Take Element Screenshot command takes a screenshot of the visible region encompassed
* by the bounding rectangle of an element. If given a parameter argument scroll that
* evaluates to false, the element will not be scrolled into view.
*
* @return {String} screenshot The screenshot as a base64 encoded PNG.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#take-screenshot
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdScreenshot (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError(
'number or type of arguments don\'t agree with elementIdScreenshot protocol command'
)
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/screenshot`)
}

View File

@ -0,0 +1,22 @@
/**
*
* Determine if an OPTION element, or an INPUT element of type checkbox or
* radiobutton is currently selected.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {Boolean} true if the element is selected.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#is-element-selected
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdSelected (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdSelected protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/selected`)
}

View File

@ -0,0 +1,38 @@
/**
*
* Determine an element's size in pixels. The size will be returned as a JSON object
* with width and height properties.
*
* Depcrecated command, please use [`elementIdRect`](http://webdriver.io/api/protocol/elementIdRect.html).
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {Object} The width and height of the element, in pixels (`{width:number, height:number}`)
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelementidsize
* @type protocol
* @deprecated
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdSize (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdSize protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/size`).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
return this.elementIdRect(id).then((result) => {
const { width, height } = result.value
result.value = { width, height }
return result
})
}
throw err
})
}

View File

@ -0,0 +1,21 @@
/**
*
* Returns the visible text for the element.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @return {String} visible text for the element
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#getelementtext
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdText (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdText protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/text`)
}

View File

@ -0,0 +1,49 @@
/**
*
* Send a sequence of key strokes to an element.
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @param {String|String[]} value The sequence of keys to type. An array must be provided. The server should flatten the array items to a single string to be typed.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#element-send-keys
* @type protocol
*
*/
import { UNICODE_CHARACTERS } from '../helpers/constants'
import { ProtocolError } from '../utils/ErrorHandler'
export default function elementIdValue (id, value) {
let key = []
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdValue protocol command')
}
/**
* replace key with corresponding unicode character
*/
if (typeof value === 'string') {
key = checkUnicode(value)
} else if (value instanceof Array) {
for (let charSet of value) {
key = key.concat(checkUnicode(charSet))
}
} else {
throw new ProtocolError('number or type of arguments don\'t agree with elementIdValue protocol command')
}
return this.requestHandler.create(`/session/:sessionId/element/${id}/value`, {
value: key, // json wire conform way: `['f', 'o', 'o']`
text: key.join('') // webdriver conform way: `foo`
})
}
/*!
* check for unicode character or split string into literals
* @param {String} value text
* @return {Array} set of characters or unicode symbols
*/
function checkUnicode (value) {
return UNICODE_CHARACTERS.hasOwnProperty(value) ? [UNICODE_CHARACTERS[value]] : Array.from(value)
}

View File

@ -0,0 +1,106 @@
/**
*
* Search for multiple elements on the page, starting from the document root. The located
* elements will be returned as a WebElement JSON objects. The table below lists the
* locator strategies that each server should support. Elements should be returned in
* the order located in the DOM.
*
* The array of elements can be retrieved using the 'response.value' which is a
* collection of element ID's and can be accessed in the subsequent commands
* using the '.ELEMENT' method.
*
* @param {String} selector selector to query the elements
* @return {Object[]} A list of WebElement JSON objects for the located elements.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#find-elements
* @type protocol
*
*/
import q from 'q'
import findStrategy from '../helpers/findElementStrategy'
import hasElementResult from '../helpers/hasElementResultHelper'
import { CommandError } from '../utils/ErrorHandler'
let elements = function (selector) {
let requestPath = '/session/:sessionId/elements'
let lastPromise = this.lastResult ? q(this.lastResult).inspect() : this.lastPromise.inspect()
let relative = false
const elementResult = hasElementResult(lastPromise.value)
if (lastPromise.state === 'fulfilled' && elementResult) {
if (!selector) {
let newSelector = Object.assign({}, lastPromise.value)
/**
* if last result was an element result transform result into an array
*/
newSelector.value = Array.isArray(newSelector.value)
? newSelector.value : newSelector.value !== null
? [newSelector.value] : []
/**
* Only return new selector if existing otherwise fetch again for selector.
* This is important in cases you do a waitForExist and use the same element
* variable again after the element has appeared.
*/
if (newSelector.value.length === 0) {
this.lastResult = null
return elements.call(this, newSelector.selector)
}
return newSelector
}
/**
* only run elementIdElement if lastPromise was an element command
*/
if (elementResult === 1) {
if (lastPromise.value.value === null) {
throw new CommandError(7, lastPromise.value.selector)
}
/**
* format xpath selector (global -> relative)
*/
if (selector.slice(0, 2) === '//') {
selector = '.' + selector.slice(1)
}
var elem = lastPromise.value.value.ELEMENT
relative = true
requestPath = `/session/:sessionId/element/${elem}/elements`
}
}
let found = findStrategy(selector, relative)
return this.requestHandler.create(requestPath, {
using: found.using,
value: found.value
}).then((result) => {
result.selector = selector
/**
* W3C webdriver protocol has changed element identifier from `ELEMENT` to
* `element-6066-11e4-a52e-4f735466cecf`. Let's make sure both identifier
* are supported.
*/
result.value = result.value.map((elem) => {
const elemValue = elem.ELEMENT || elem['element-6066-11e4-a52e-4f735466cecf']
return {
ELEMENT: elemValue,
'element-6066-11e4-a52e-4f735466cecf': elemValue
}
})
return result
}, (err) => {
if (err.message === 'no such element') {
return []
}
throw err
})
}
export default elements

View File

@ -0,0 +1,68 @@
/**
*
* Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.
* The executed script is assumed to be synchronous and the result of evaluating the script is returned to
* the client.
*
* The script argument defines the script to execute in the form of a function body. The value returned by
* that function will be returned to the client. The function will be invoked with the provided args array
* and the values may be accessed via the arguments object in the order specified.
*
* Arguments may be any JSON-primitive, array, or JSON object. JSON objects that define a WebElement
* reference will be converted to the corresponding DOM element. Likewise, any WebElements in the script
* result will be returned to the client as WebElement JSON objects.
*
* <example>
:execute.js
it('should inject javascript on the page', function () {
var result = browser.execute(function(a, b, c, d) {
// browser context - you may not access client or console
return a + b + c + d;
}, 1, 2, 3, 4)
// node.js context - client and console are available
console.log(result.value); // outputs: 10
});
* </example>
*
* @param {String|Function} script The script to execute.
* @param {*} [argument1,...,argumentN] script arguments
*
* @return {*} The script result.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dfn-execute-script
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function execute (...args) {
let script = args.shift()
/*!
* parameter check
*/
if ((typeof script !== 'string' && typeof script !== 'function')) {
throw new ProtocolError('number or type of arguments don\'t agree with execute protocol command')
}
/*!
* instances started as multibrowserinstance can't getting called with
* a function paramter, therefor we need to check if it starts with "function () {"
*/
if (typeof script === 'function' || (this.inMultibrowserMode && script.indexOf('function (') === 0)) {
script = `return (${script}).apply(null, arguments)`
}
return this.requestHandler.create('/session/:sessionId/execute', { script, args }).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
return this.requestHandler.create('/session/:sessionId/execute/sync', { script, args })
}
throw err
})
}

View File

@ -0,0 +1,77 @@
/**
*
* Inject a snippet of JavaScript into the page for execution in the context of the currently selected
* frame. The executed script is assumed to be asynchronous and must signal that is done by invoking
* the provided callback, which is always provided as the final argument to the function. The value
* to this callback will be returned to the client.
*
* Asynchronous script commands may not span page loads. If an unload event is fired while waiting
* for a script result, an error should be returned to the client.
*
* The script argument defines the script to execute in the form of a function body. The function will
* be invoked with the provided args array and the values may be accessed via the arguments object
* in the order specified. The final argument will always be a callback function that must be invoked
* to signal that the script has finished.
*
* Arguments may be any JSON-primitive, array, or JSON object. JSON objects that define a WebElement
* reference will be converted to the corresponding DOM element. Likewise, any WebElements in the script
* result will be returned to the client as WebElement JSON objects.
*
* <example>
:executeAsync.js
it('should execute async JavaScript on the page', function () {
browser.timeoutsAsyncScript(5000);
var result = browser.executeAsync(function(a, b, c, d, done) {
// browser context - you may access neither client nor console
setTimeout(function() {
done(a + b + c + d);
}, 3000);
}, 1, 2, 3, 4)
// node.js context - client and console are available
console.log(result.value); // outputs: 10
});
* </example>
*
* @param {String|Function} script The script to execute.
* @param {*} arguments script arguments
*
* @return {*} The script result.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dfn-execute-async-script
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function executeAsync (...args) {
let script = args.shift()
/*!
* parameter check
*/
if ((typeof script !== 'string' && typeof script !== 'function')) {
throw new ProtocolError('number or type of arguments don\'t agree with execute protocol command')
}
/*!
* instances started as multibrowserinstance can't getting called with
* a function parameter, therefor we need to check if it starts with "function () {"
*/
if (typeof script === 'function' || (this.inMultibrowserMode && script.indexOf('function (') === 0)) {
script = `return (${script}).apply(null, arguments)`
}
return this.requestHandler.create('/session/:sessionId/execute_async', { script, args }).catch((err) => {
/**
* jsonwire command not supported try webdriver endpoint
*/
if (err.message.match(/did not match a known command/)) {
return this.requestHandler.create('/session/:sessionId/execute/async', { script, args })
}
throw err
})
}

View File

@ -0,0 +1,15 @@
/**
*
* Uploads a base64 data object. (not documented, not part of Webdriver specs)
*
* @param {Object} data base64 data object
*
* @type protocol
*
*/
export default function file (base64data) {
return this.requestHandler.create('/session/:sessionId/file', {
file: base64data
})
}

View File

@ -0,0 +1,23 @@
/**
* Navigate forwards in the browser history, if possible.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#forward
* @type protocol
*
*/
export default function forward () {
/*!
* helper for safaridriver which doesn not support forward
* Reason: "Yikes! Safari history navigation does not work. We can go forward or back,
* but once we do, we can no longer communicate with the page"
*/
if (this.desiredCapabilities.browserName === 'safari') {
return this.execute('history.go(+1)').waitForExist('body', 5000)
}
return this.requestHandler.create({
path: '/session/:sessionId/forward',
method: 'POST'
})
}

View File

@ -0,0 +1,24 @@
/**
* Change focus to another frame on the page. If the frame id is null,
* the server should switch to the page's default content.
*
* <example>
:frame.js
it('should switch focus to iFrame', function () {
// Using `element` to find an iframe and providing it to `frame` method
browser.waitForExist('iframe[name="my_iframe"]');
var my_frame = $('iframe[name="my_iframe"]').value;
browser.frame(my_frame);
});
* </example>
*
* @param {String|Number|null|WebElementJSONObject} id Identifier for the frame to change focus to.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#switch-to-frame
* @type protocol
*
*/
export default function frame (frameId = null) {
return this.requestHandler.create('/session/:sessionId/frame', { id: frameId })
}

View File

@ -0,0 +1,15 @@
/**
* Change focus to the parent context. If the current context is the top level browsing context,
* the context remains unchanged.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#switch-to-parent-frame
* @type protocol
*
*/
export default function frameParent () {
return this.requestHandler.create({
path: '/session/:sessionId/frame/parent',
method: 'POST'
})
}

View File

@ -0,0 +1,20 @@
/**
*
* Get all defined Strings from an app for the default language.
*
* @param {String} language strings language code
*
* @see https://github.com/appium/appium/blob/master/docs/en/appium-bindings.md#app-strings
* @type mobile
* @for android
*
*/
export default function getAppStrings (language) {
const requestOptions = {
path: '/session/:sessionId/appium/app/strings',
method: 'POST'
}
return this.requestHandler.create(requestOptions, { language })
}

View File

@ -0,0 +1,26 @@
/**
*
* Get current device activity.
*
* <example>
:getCurrentDeviceActivity.js
it('should get current Android activity', function () {
var activity = browser.getCurrentDeviceActivity();
console.log(activity); // returns ".MainActivity"
});
* </example>
*
* @see https://github.com/appium/appium/blob/master/docs/en/appium-bindings.md#current-activity
* @type mobile
* @for android
*
*/
export default function getCurrentDeviceActivity () {
return this.unify(this.requestHandler.create({
path: '/session/:sessionId/appium/device/current_activity',
method: 'GET'
}), {
extractValue: true
})
}

View File

@ -0,0 +1,13 @@
/**
*
* Captures iOS device date and time (command works only for real devices).
*
* @see https://github.com/appium/appium-ios-driver/blob/master/lib/commands/general.js#L19-L35
* @type mobile
* @for ios
*
*/
export default function getDeviceTime () {
return this.requestHandler.create('/session/:sessionId/appium/device/system_time')
}

View File

@ -0,0 +1,41 @@
/**
*
* Get informations about the current network connection (Data/WIFI/Airplane). The actual
* server value will be a number (see `getNetworkConnection.js` example). However WebdriverIO
* additional properties to the response object to allow easier assertions (see
* `getNetworkConnectionEasier.js` example).
*
* <example>
:getNetworkConnection.js
it('should get network connection of Android device', function () {
var connection = browser.getNetworkConnection();
console.log(connection.value); // returns 6
console.log(connection.inAirplaneMode); // returns false
console.log(connection.hasWifi); // returns true
console.log(connection.hasData); // returns true
});
* </example>
*
* @type mobile
* @see https://github.com/appium/appium-android-driver/blob/master/lib/commands/network.js#L8-L22
* @for android
*
*/
import merge from 'deepmerge'
export default function getNetworkConnection () {
return this.requestHandler.create({
path: '/session/:sessionId/network_connection',
method: 'GET'
}).then((result) => {
result = merge(result, {
value: result.value,
inAirplaneMode: result.value === 1,
hasWifi: result.value === 2 || result.value === 6,
hasData: result.value === 4 || result.value === 6
})
return result
})
}

View File

@ -0,0 +1,48 @@
/**
*
* Get the details of the Selenium Grid node running a session
*
* <example>
:grid.js
it('should get grid proxy details', function () {
var details = browser.gridProxyDetails(proxyId)
console.log(details);
// {
// success: true,
// msg: "proxy found !",
// id: "MacMiniA10",
// request: {
// ...
// configuration: {
// ...
// },
// capabilities: [
// {
// ...
// }
// ]
// }
// }
});
* </example>
*
* @type grid
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function gridProxyDetails (proxyId) {
/*!
* parameter check
*/
if (typeof proxyId !== 'string') {
throw new ProtocolError('The gridProxyDetails command needs a proxyId to work with.')
}
return this.requestHandler.create({
path: `/proxy?id=${proxyId}`,
method: 'GET',
requiresSession: false,
gridCommand: true
})
}

View File

@ -0,0 +1,44 @@
/**
*
* Get the details of the Selenium Grid node running a session
*
* <example>
:grid.js
it('should get current session information', function () {
var details = browser.gridTestSession();
console.log(details);
// {
// msg: 'slot found !',
// success: true,
// session: '51797b64-43e1-4018-b7fb-f900d80a37a4',
// internalKey: '413741ea-d48e-4346-844b-b1a90a69b3ed',
// inactivityTime: 219,
// proxyId: 'MacMiniA10
// }
});
* </example>
*
* @type grid
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function gridTestSession (sessionId) {
/*!
* parameter check
*/
if (typeof sessionId !== 'string') {
if (!this.requestHandler.sessionID) {
throw new ProtocolError('The gridTestSession command needs a sessionID to work with.')
}
sessionId = this.requestHandler.sessionID
}
return this.requestHandler.create({
path: `/testsession?session=${sessionId}`,
method: 'GET',
requiresSession: false,
gridCommand: true
})
}

View File

@ -0,0 +1,36 @@
/**
*
* Hide the keyboard.
*
* <example>
:hideKeyboard.js
it('should hide keyboard by tapping outside of it', function () {
browser.hideDeviceKeyboard(); // taps outside to hide keyboard per default
browser.hideDeviceKeyboard('tapOutside');
});
it('should hide keyboard by pressing done', function () {
browser.hideDeviceKeyboard('pressKey', 'Done');
});
* </example>
*
* @param {String} strategy desired strategy to close keyboard ('tapOutside' or 'pressKey')
*
* @see https://github.com/appium/appium/blob/master/docs/en/appium-bindings.md#hide-keyboard-ios-only
* @type mobile
* @for ios, android
*
*/
export default function hideDeviceKeyboard (strategy = 'tapOutside', key) {
let args = { strategy }
if (key) {
args.key = key
}
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/hide_keyboard',
method: 'POST'
}, args)
}

View File

@ -0,0 +1,26 @@
/**
*
* Make an engines that is available (appears on the list returned by getAvailableEngines) active.
* After this call, the engine will be added to the list of engines loaded in the IME daemon and the
* input sent using sendKeys will be converted by the active engine. Note that this is a
* platform-independent method of activating IME (the platform-specific way being using keyboard shortcuts.
* (Not part of the official Webdriver specification)
*
* @param {String} engine Name of the engine to activate.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidimeactive_engine
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import depcrecate from '../helpers/depcrecationWarning'
export default function imeActivate (engine) {
if (typeof engine !== 'string') {
throw new ProtocolError('number or type of arguments don\'t agree with imeActivate protocol command')
}
depcrecate('imeActivate')
return this.requestHandler.create('/session/:sessionId/ime/activate', { engine })
}

View File

@ -0,0 +1,18 @@
/**
*
* Indicates whether IME input is active at the moment (not if it's available.
* (Not part of the official Webdriver specification)
*
* @return {boolean} true if IME input is available and currently active, false otherwise
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidimeactivated
* @type protocol
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function imeActivated () {
depcrecate('imeActivated')
return this.requestHandler.create('/session/:sessionId/ime/activated')
}

View File

@ -0,0 +1,18 @@
/**
*
* Get the name of the active IME engine. The name string is platform specific. (Not part of the
* official Webdriver specification)
*
* @return {String} engine The name of the active IME engine.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidimeactive_engine
* @type protocol
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function imeActiveEngine () {
depcrecate('imeActiveEngine')
return this.requestHandler.create('/session/:sessionId/ime/active_engine')
}

View File

@ -0,0 +1,18 @@
/**
*
* List all available engines on the machine. To use an engine, it has to be present
* in this list. (Not part of the official Webdriver specification)
*
* @return {Object[]} engines A list of available engines
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidimeavailable_engines
* @type protocol
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function imeAvailableEngines () {
depcrecate('imeAvailableEngines')
return this.requestHandler.create('/session/:sessionId/ime/available_engines')
}

View File

@ -0,0 +1,15 @@
/**
*
* De-activates the currently-active IME engine. (Not part of the official Webdriver specification)
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidimedeactivate
* @type protocol
*
*/
import depcrecate from '../helpers/depcrecationWarning'
export default function imeDeactivated () {
depcrecate('imeDeactivated')
return this.requestHandler.create('/session/:sessionId/ime/deactivated')
}

View File

@ -0,0 +1,65 @@
/**
*
* Create a new session. The server should attempt to create a session that most
* closely matches the desired and required capabilities. Required capabilities
* have higher priority than desired capabilities and must be set for the session
* to be created.
*
* @param {Object} [capabilities] An object describing the session's [desired capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities).
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dfn-new-session
* @type protocol
*
*/
import { CommandError, ProtocolError } from '../utils/ErrorHandler'
import pkg from '../../package.json'
import merge from 'deepmerge'
export default function init (desiredCapabilities = {}) {
const lastCommand = this.commandList.slice(-4, -3)
const isInternalCall = lastCommand.length && lastCommand[0].name === 'reload'
/**
* make sure we don't run this command within wdio test run
*/
if (this.options.isWDIO && !isInternalCall) {
throw new CommandError(
'Don\'t call the \'init\' command when using the wdio test runner. ' +
'Your session will get initialised and closed automatically.'
)
}
/*!
* check if session was already established
*/
if (this.requestHandler.sessionID) {
throw new ProtocolError(
'Cannot init a new session, please end your current session first'
)
}
this.desiredCapabilities = merge(this.desiredCapabilities, desiredCapabilities)
if (desiredCapabilities.sessionId) {
this.sessionId = desiredCapabilities.sessionId
}
/**
* report library identity to server
* @see https://groups.google.com/forum/#!topic/selenium-developers/Zj1ikTz632o
*/
this.desiredCapabilities = merge(this.desiredCapabilities, {
requestOrigins: {
url: pkg.homepage,
version: pkg.version,
name: pkg.name
}
})
return this.requestHandler.create({
path: '/session',
method: 'POST'
}, {
desiredCapabilities: this.desiredCapabilities
})
}

View File

@ -0,0 +1,31 @@
/**
*
* Install an app on device.
*
* <example>
:installApp.js
it('should install app from file system', function () {
browser.installApp('/path/to/my/App.app');
});
* </example>
*
* @param {String} path path to Android application
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#install-app
* @type mobile
* @for android
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function installApp (appPath) {
if (typeof appPath !== 'string') {
throw new ProtocolError('installApp command requires appPath parameter from type string')
}
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/install_app',
method: 'POST'
}, { appPath })
}

View File

@ -0,0 +1,32 @@
/**
*
* Check if an app is installed.
*
* <example>
:isAppInstalled.js
it('should check if app is installed', function () {
var isAppInstalled = browser.isAppInstalled('com.example.android.apis');
console.log(isAppInstalled); // outputs: true
});
* </example>
*
* @param {String} bundleId ID of bundled app
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#is-installed
* @type mobile
* @for android
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function isAppInstalled (bundleId) {
if (typeof bundleId !== 'string') {
throw new ProtocolError('isAppInstalled command requires bundleId parameter from type string')
}
return this.unify(this.requestHandler.create({
path: '/session/:sessionId/appium/device/app_installed',
method: 'POST'
}, { bundleId }))
}

View File

@ -0,0 +1,26 @@
/**
*
* Check whether the device is locked or not.
*
* <example>
:lockIt.js
it('demonstrate the lock and unlock command', function () {
browser.lock();
console.log(browser.isLocked()); // true
browser.unlock();
console.log(browser.isLocked()); // false
});
* </example>
*
* @type mobile
* @for android
*
*/
export default function isLocked () {
return this.unify(this.requestHandler.create({
path: '/session/:sessionId/appium/device/is_locked',
method: 'POST'
}))
}

View File

@ -0,0 +1,54 @@
/**
*
* Send a sequence of key strokes to the active element. This command is similar to the
* send keys command in every aspect except the implicit termination: The modifiers are
* *not* released at the end of the call. Rather, the state of the modifier keys is kept
* between calls, so mouse interactions can be performed while modifier keys are depressed.
*
* You can also use characters like "Left arrow" or "Back space". WebdriverIO will take
* care of translating them into unicode characters. Youll find all supported characters
* [here](https://w3c.github.io/webdriver/webdriver-spec.html#keyboard-actions).
* To do that, the value has to correspond to a key from the table.
*
* @param {String|String[]} value The sequence of keys to type. An array must be provided. The server should flatten the array items to a single string to be typed.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidkeys
* @type protocol
* @deprecated
*
*/
import { UNICODE_CHARACTERS } from '../helpers/constants'
import depcrecateCommand from '../helpers/depcrecationWarning'
import { ProtocolError } from '../utils/ErrorHandler'
module.exports = function keys (value) {
let key = []
/**
* replace key with corresponding unicode character
*/
if (typeof value === 'string') {
key = checkUnicode(value)
} else if (value instanceof Array) {
for (let charSet of value) {
key = key.concat(checkUnicode(charSet))
}
} else {
throw new ProtocolError('number or type of arguments don\'t agree with keys protocol command')
}
depcrecateCommand('keys')
return this.requestHandler.create('/session/:sessionId/keys', {
'value': key
})
}
/*!
* check for unicode character or split string into literals
* @param {String} value text
* @return {Array} set of characters or unicode symbols
*/
function checkUnicode (value) {
return UNICODE_CHARACTERS.hasOwnProperty(value) ? [UNICODE_CHARACTERS[value]] : value.split('')
}

View File

@ -0,0 +1,27 @@
/**
*
* Launch the session for the desired capabilities. Note that this is the companion
* to the `autoLaunch=false` capability. This is not for launching arbitrary
* apps/activities --- for that use [`startActivity`](/api/mobile/startActivity.html).
* This is for continuing the initialization ("launch") process if you have used
* `autoLaunch=false`.
*
* <example>
:launch.js
it('should launch capability', function () {
browser.launch();
});
* </example>
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#launch
* @type mobile
* @for ios, android
*
*/
export default function launch () {
return this.requestHandler.create({
path: '/session/:sessionId/appium/app/launch',
method: 'POST'
})
}

View File

@ -0,0 +1,60 @@
/**
*
* Protocol bindings for all localStorage operations. This command is not part of the official Webdriver
* specification and might not be supported for your browser.
*
* <example>
:localStorage.js
it('should set/receive values from local storage', function () {
// get the storage item for the given key
var values = browser.localStorage('GET', someKey);
// get all key/value pairs of the storage
var storage = browser.localStorage();
// set the storage item for the given key
browser.localStorage('POST', {key: someKey, value: someValue});
// remove the storage item for the given key
browser.localStorage('DELETE', 'someKey');
// clear the storage
browser.localStorage('DELETE');
});
* </example>
*
* @param {String} method method for storage operation
* @param {Object|String=} args operation arguments
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidlocal_storage
* @type protocol
*
*/
export default function localStorage (method = 'GET', args) {
/**
* set default options
*/
let data = {}
let requestOptions = {
path: '/session/:sessionId/local_storage',
method: method.toUpperCase()
}
if (requestOptions.method === 'POST' && typeof args === 'object') {
data = {
key: args.key,
value: args.value
}
}
/**
* add/delete specific key
*/
if ((requestOptions.method === 'DELETE' && typeof args === 'string') ||
(requestOptions.method === 'GET' && typeof args === 'string')) {
requestOptions.path += '/key/' + args
}
return this.requestHandler.create(requestOptions, data)
}

View File

@ -0,0 +1,15 @@
/**
*
* protocol bindings to get local_storage size. This command is not part of the official Webdriver
* specification and might not be supported for your browser.
*
* @return {Number} The number of items in the storage.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidlocal_storagesize
* @type protocol
*
*/
export default function localStorageSize () {
return this.requestHandler.create('/session/:sessionId/local_storage/size')
}

View File

@ -0,0 +1,50 @@
/**
*
* Protocol bindings for all geolocation operations. (Not part of the official Webdriver specification).
*
* <example>
:location.js
it('should set geo location for device', function () {
// set the current geo location
client.location({latitude: 121.21, longitude: 11.56, altitude: 94.23})
// get the current geo location
client.location().then(function(res) { ... });
});
* </example>
*
* @param {Object} location the new location
* @return {Object} the current geo location
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidlocation
* @type protocol
*
*/
import depcrecateCommand from '../helpers/depcrecationWarning'
export default function location (l) {
let location = null
if (typeof l === 'object' &&
l.latitude !== undefined &&
l.longitude !== undefined &&
l.altitude !== undefined) {
location = l
}
depcrecateCommand('location')
/**
* get geo location
*/
if (!location) {
return this.requestHandler.create('/session/:sessionId/location')
}
/**
* set geo location
* @type {[type]}
*/
return this.requestHandler.create('/session/:sessionId/location', { location })
}

View File

@ -0,0 +1,29 @@
/**
*
* Lock the device.
*
* <example>
:lockIt.js
it('demonstrate the lock and unlock command', function () {
browser.lock();
console.log(browser.isLocked()); // true
browser.unlock();
console.log(browser.isLocked()); // false
});
* </example>
*
* @param {Number} seconds wait in seconds until lock screen
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#lock
* @type mobile
* @for android
*
*/
export default function lock (seconds = 0) {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/lock',
method: 'POST'
}, { seconds })
}

View File

@ -0,0 +1,40 @@
/**
*
* Get the log for a given log type. Log buffer is reset after each request.
* (Not part of the official Webdriver specification).
*
* @param {String} type The [log type](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#log-type). This must be provided.
* @return {Object[]} The list of [log entries](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#log-entry-json-object)
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidlog
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
let logTypes
function getLogTypes () {
return logTypes ? Promise.resolve(logTypes) : this.logTypes()
.then((types) => {
logTypes = types
return logTypes
})
}
export default function log (type) {
if (typeof type !== 'string' || type === '') {
throw new ProtocolError('number or type of arguments don\'t agree with log command')
}
return getLogTypes.call(this).then((types) => {
if (types.value.indexOf(type) === -1) {
throw new ProtocolError(`this log type ("${type}") is not available for this browser/device`)
}
return this.requestHandler.create('/session/:sessionId/log', {
type: type
})
})
}

View File

@ -0,0 +1,24 @@
/**
*
* Get available log types. This command is not part of the official Webdriver specification.
* Therefor the result can vary depending on the capability you are runnint the test.
* (Not part of the official Webdriver specification).
*
* <example>
:logTypes.js
it('demonstrate all available log types', function () {
var logTypes = browser.logTypes();
console.log(logTypes); // outputs: ['browser', 'driver', 'client', 'server']
});
* </example>
*
* @return {Strings[]} The list of available [log types](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#log-type)
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidlogtypes
* @type protocol
*
*/
export default function logTypes () {
return this.requestHandler.create('/session/:sessionId/log/types')
}

View File

@ -0,0 +1,25 @@
/**
*
* Press a particular key code on the device.
*
* <example>
:longPressKeycode.js
// press the home button long
browser.longPressKeycode(3)
* </example>
*
* @param {String} keycode key code to press
* @param {String} metastate meta state to be activated
*
* @see http://developer.android.com/reference/android/view/KeyEvent.html
* @type mobile
* @for android
*
*/
export default function longPressKeycode (keycode, metastate) {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/long_press_keycode',
method: 'POST'
}, { keycode, metastate })
}

View File

@ -0,0 +1,63 @@
/**
*
* Move the mouse by an offset of the specificed element. If no element is specified,
* the move is relative to the current mouse cursor. If an element is provided but
* no offset, the mouse will be moved to the center of the element. If the element
* is not visible, it will be scrolled into view.
*
* (Not part of the official Webdriver specification).
*
* @param {String} element Opaque ID assigned to the element to move to, as described in the WebElement JSON Object. If not specified or is null, the offset is relative to current position of the mouse.
* @param {Number} xoffset X offset to move to, relative to the top-left corner of the element. If not specified, the mouse will move to the middle of the element.
* @param {Number} yoffset Y offset to move to, relative to the top-left corner of the element. If not specified, the mouse will move to the middle of the element.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidmoveto
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import eventSimulator from '../scripts/eventSimulator'
import depcrecateCommand from '../helpers/depcrecationWarning'
export default function moveTo (element, xoffset, yoffset) {
let data = {}
if (typeof element === 'string') {
data.element = element
}
if (typeof xoffset === 'number') {
data.xoffset = xoffset
}
if (typeof yoffset === 'number') {
data.yoffset = yoffset
}
/**
* if no attribute is set, throw error
*/
if (Object.keys(data).length === 0) {
throw new ProtocolError('number or type of arguments don\'t agree with moveTo command')
}
depcrecateCommand('moveTo')
/**
* simulate event in safari
*/
if (this.desiredCapabilities.browserName === 'safari') {
xoffset = xoffset || 0
yoffset = yoffset || 0
let target = { x: xoffset, y: yoffset }
return this.elementIdLocation(element).then((res) => {
target = { x: res.value.x + xoffset, y: res.value.y + yoffset }
}).execute(eventSimulator).execute((elem, x, y) => {
return window._wdio_simulate(elem, 'mousemove', x, y)
}, { ELEMENT: element }, target.x, target.y)
}
return this.requestHandler.create('/session/:sessionId/moveto', data)
}

View File

@ -0,0 +1,20 @@
/**
*
* Open the notifications pane on the device.
*
* <example>
:openNotificationsSync.js
browser.openNotifications();
* </example>
*
* @type mobile
* @for android
*
*/
export default function openNotifications () {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/open_notifications',
method: 'POST'
})
}

View File

@ -0,0 +1,37 @@
/**
*
* Protocol bindings for all mobile orientation operations. (Not part of the official Webdriver specification).
*
* <example>
:orientation.js
it('should set/get orientation using protocol command', function () {
// set the browser orientation. The orientation should be
// specified as defined in ScreenOrientation: {LANDSCAPE|PORTRAIT}
browser.orientation('landscape');
// get the current browser orientation. The server should
// return a valid orientation value as defined in
// screen orientation: {LANDSCAPE|PORTRAIT}
var orientation = browser.orientation();
console.log(orientation.value); // outputs: "landscape"
});
* </example>
*
* @param {String=} deviceOrientation The new browser orientation as defined in ScreenOrientation: `{LANDSCAPE|PORTRAIT}`
* @return {String} device orientation (`LANDSCAPE/PORTRAIT`)
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidorientation
* @type mobile
* @for android, ios
*
*/
export default function orientation (deviceOrientation) {
let data = {}
if (typeof deviceOrientation === 'string') {
data.orientation = deviceOrientation.toUpperCase()
}
return this.requestHandler.create('/session/:sessionId/orientation', data)
}

View File

@ -0,0 +1,18 @@
/**
*
* Perform multi touch action
*
* @param {Object} touchAttr contains attributes of touch gesture (e.g. `element`, `x` and `y`)
*
* @see https://github.com/appium/appium/blob/master/docs/en/appium-bindings.md#touchaction--multitouchaction
* @type mobile
* @for android, ios
*
*/
export default function performMultiAction (multiTouchAction = {}) {
return this.requestHandler.create({
path: '/session/:sessionId/touch/multi/perform',
method: 'POST'
}, multiTouchAction)
}

View File

@ -0,0 +1,24 @@
/**
*
* Perform touch action
*
* @param {Object} touchAttr contains attributes of touch gesture (e.g. `element`, `x` and `y`)
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#touchaction--multitouchaction
* @type mobile
* @for android, ios
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function performTouchAction (action) {
if (typeof action !== 'object') {
throw new ProtocolError('number or type of arguments don\'t agree with performTouchAction protocol command')
}
return this.requestHandler.create({
path: '/session/:sessionId/touch/perform',
method: 'POST'
}, action)
}

View File

@ -0,0 +1,25 @@
/**
*
* Press a particular key code on the device.
*
* <example>
:pressKeycode.js
// press the home button
browser.pressKeycode(3)
* </example>
*
* @param {String} keycode key code to press
* @param {String} metastate meta state to be activated
*
* @see http://developer.android.com/reference/android/view/KeyEvent.html
* @type mobile
* @for android
*
*/
export default function pressKeycode (keycode, metastate) {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/press_keycode',
method: 'POST'
}, { keycode, metastate })
}

View File

@ -0,0 +1,29 @@
/**
*
* Pulls a file from the device.
*
* <example>
:pullFile.js
browser.pullFile('/data/local/tmp/file.txt')
* </example>
*
* @param {String} path device path to file
*
* @see https://github.com/appium/appium/blob/master/docs/en/appium-bindings.md#pull-file
* @type mobile
* @for ios, android
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function pullFile (path) {
if (typeof path !== 'string') {
throw new ProtocolError('pullFile requires a parameter (path to file) from type string')
}
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/pull_file',
method: 'POST'
}, { path })
}

View File

@ -0,0 +1,28 @@
/**
*
* Pulls a folder from the device's file system.
*
* <example>
:pullFolder.js
browser.pullFolder('/data/local/tmp')
* </example>
*
* @param {String} path device path to folder
*
* @type mobile
* @for ios, android
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function pullFolder (path) {
if (typeof path !== 'string') {
throw new ProtocolError('pullFolder requires a parameter (path to folder) from type string')
}
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/pull_folder',
method: 'POST'
}, { path })
}

View File

@ -0,0 +1,33 @@
/**
*
* Pushes a file to the device.
*
* <example>
:pushFile.js
var data = new Buffer("Hello World").toString('base64'))
browser.pushFile('/data/local/tmp/file.txt', data)
* </example>
*
* @param {String} path local path to file
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#push-file
* @type mobile
* @for ios, android
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function pushFile (path, base64Data) {
if (typeof path !== 'string' || typeof base64Data !== 'string') {
throw new ProtocolError('pushFile requires two parameters (path, base64Data) from type string')
}
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/push_file',
method: 'POST'
}, {
path,
data: base64Data
})
}

View File

@ -0,0 +1,15 @@
/**
*
* Refresh the current page.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#refresh
* @type protocol
*
*/
export default function refresh () {
return this.requestHandler.create({
path: '/session/:sessionId/refresh',
method: 'POST'
})
}

View File

@ -0,0 +1,29 @@
/**
*
* Remove an app from the device.
*
* <example>
:removeApp.js
browser.removeApp('com.example.android.apis');
* </example>
*
* @param {String} bundleId bundle ID of application
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#remove-app
* @type mobile
* @for android
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function removeApp (bundleId) {
if (typeof bundleId !== 'string') {
throw new ProtocolError('removeApp command requires bundleId parameter from type string')
}
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/remove_app',
method: 'POST'
}, { bundleId })
}

View File

@ -0,0 +1,21 @@
/**
*
* Reset the device by clearing the device un- and reinstalling app package (if existing).
*
* <example>
:resetApp.js
browser.reset()
* </example>
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#reset
* @type mobile
* @for android
*
*/
export default function reset () {
return this.requestHandler.create({
path: '/session/:sessionId/appium/app/reset',
method: 'POST'
})
}

View File

@ -0,0 +1,28 @@
/**
*
* Perform a rotation gesture centered on the specified element.
*
* <example>
:rotate.js
browser.rotate(114, 198);
* </example>
*
* @param {Number} x x offset to use for the center of the rotate gesture (default 0)
* @param {Number} y y offset to use for the center of the rotate gesture (default 0)
* @param {Number} duration The length of hold time for the specified gesture, in seconds. (default 1)
* @param {Number} radius The distance in points from the center to the edge of the circular path.
* @param {Number} rotation The length of rotation in radians. (default pi (π))
* @param {Number} touchCount The number of touches to use in the specified gesture. (Effectively, the number of fingers a user would use to make the specified gesture.) Valid values are 1 to 5. (default 2)
*
* @see https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAElementClassReference/#//apple_ref/javascript/instm/UIAElement/rotateWithOptions
* @type mobile
* @for ios
*
*/
export default function rotate (x = 0, y = 0, duration = 1, radius = 0, rotation = Math.PI, touchCount = 2) {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/rotate',
method: 'POST'
}, { x, y, duration, radius, rotation, touchCount })
}

View File

@ -0,0 +1,15 @@
/**
*
* Take a screenshot of the current viewport. To get the screenshot of the whole page
* use the action command `saveScreenshot`
*
* @return {String} screenshot The screenshot as a base64 encoded PNG.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#take-screenshot
* @type protocol
*
*/
export default function screenshot () {
return this.requestHandler.create('/session/:sessionId/screenshot')
}

View File

@ -0,0 +1,94 @@
/**
*
* Protocol bindings for all session operations. In case you are looking for
* `[POST] session` to initialise a session on the server, take a look at `/lib/protocol/init`.
*
* <example>
:session.js
it('should get/delete current session using the protocol command', function () {
// retrieve the resolved capabilities of the specified session
var caps = browser.session();
console.log(caps); // outputs: { browserName: "...", ... }
// you can also just call (see http://webdriver.io/guide/testrunner/browserobject.html)
console.log(browser.desiredCapabilities);
// delete the session (equivalent to `end` action command)
// Note: the wdio testrunner doesn't allow to call this command manually. It will close the session
// when the test has ended.
browser.session('delete'); // throws an error
});
* </example>
*
* @param {String=} doWhat session operation (`get` (default)|`delete`)
* @param {String} sessionId session id to operate on
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#dfn-delete-session
* @type protocol
*
*/
import { ProtocolError, CommandError } from '../utils/ErrorHandler'
export default function session (doWhat = 'GET', sessionId) {
/*!
* parameter check
*/
if (typeof sessionId !== 'string') {
/*!
* if session was already closed return `undefined`
* ToDo or maybe throw an error
*/
if (!this.requestHandler.sessionID) {
return null
}
sessionId = this.requestHandler.sessionID
}
doWhat = doWhat.toUpperCase()
/*!
* get session
*/
if (doWhat === 'GET') {
return this.requestHandler.create({
path: `/session/${sessionId}`,
method: 'GET',
requiresSession: false
})
}
const lastCommand = this.commandList.slice(-3, -2)
const isInternalCall = lastCommand.length && lastCommand[0].name === 'reload'
/*!
* delete session
*/
if (doWhat === 'DELETE') {
/**
* make sure we don't run this command within wdio test run
*/
if (this.options.isWDIO && !isInternalCall) {
throw new CommandError('Don\'t end the session manually. This will be done automatically.')
}
this.emit('end', {
sessionId: this.requestHandler.sessionID
})
return this.requestHandler.create({
path: '/session/' + sessionId,
method: 'DELETE',
requiresSession: false
}).then((res) => {
/*!
* delete sessionID in RequestHandler
*/
this.requestHandler.sessionID = null
return res
})
}
throw new ProtocolError('The session command need either a \'delete\' or \'get\'attribute to know what to do. example: client.session(\'get\').then(callback) to get the capabilities of the session.')
}

View File

@ -0,0 +1,60 @@
/**
*
* Protocol bindings for all sessionStorage operations. This command is not part of the official Webdriver
* specification. Therefor it might not be supported in your browser.
*
* <example>
:sessionStorage.js
it('should set/receive values from session storage', function () {
// get the storage item for the given key
var values = browser.sessionStorage('GET', someKey);
// get all key/value pairs of the storage
var storage = browser.sessionStorage();
// set the storage item for the given key
browser.sessionStorage('POST', {key: someKey, value: someValue});
// remove the storage item for the given key
browser.sessionStorage('DELETE', 'someKey');
// clear the storage
browser.sessionStorage('DELETE');
});
* </example>
*
* @param {String=} method method for storage operation
* @param {Object|String=} args operation arguments
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidsession_storage
* @type protocol
*
*/
export default function sessionStorage (method = 'GET', args) {
/**
* set default options
*/
let data = {}
let requestOptions = {
path: '/session/:sessionId/session_storage',
method: method.toUpperCase()
}
if (requestOptions.method === 'POST' && typeof args === 'object') {
data = {
key: args.key,
value: args.value
}
}
/**
* add/delete specific key
*/
if ((requestOptions.method === 'DELETE' && typeof args === 'string') ||
(requestOptions.method === 'GET' && typeof args === 'string')) {
requestOptions.path += '/key/' + args
}
return this.requestHandler.create(requestOptions, data)
}

View File

@ -0,0 +1,15 @@
/**
*
* Protocol bindings to get the session storage size. (Not part of the official
* Webdriver specification).
*
* @return {Number} The number of items in the storage.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidsession_storagesize
* @type protocol
*
*/
export default function sessionStorageSize () {
return this.requestHandler.create('/session/:sessionId/session_storage/size')
}

View File

@ -0,0 +1,27 @@
/**
*
* Returns a list of the currently active sessions. Each session will be returned
* as a list of JSON objects with the following keys:
*
* | Key | Type | Description |
* |--------------|--------|----------------|
* | id | string | The session ID |
* | capabilities | object | An object describing the [session capabilities](https://w3c.github.io/webdriver/webdriver-spec.html#capabilities) |
*
* (Not part of the official Webdriver specification).
*
* @return {Object[]} a list of the currently active sessions
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessions
* @type protocol
* @depcrecated
*
*/
export default function sessions () {
return this.requestHandler.create({
path: '/sessions',
method: 'GET',
requiresSession: false
})
}

View File

@ -0,0 +1,31 @@
/**
*
* Set immediate value in app.
*
* <example>
:setImmediateValue.js
browser.setImmediateValue(el, 'foo')
* </example>
*
* @param {String} ID ID of a WebElement JSON object to route the command to
* @param {String|String[]} value The sequence of keys to type. An array must be provided. The server should flatten the array items to a single string to be typed.
*
* @type mobile
* @for ios
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function setImmediateValue (id, value) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError(
'setImmediateValue requires two parameters (id, value) from type string'
)
}
return this.requestHandler.create({
path: `/session/:sessionId/appium/element/${id}/value`,
method: 'POST'
}, { value })
}

View File

@ -0,0 +1,54 @@
/**
*
* Set network connection.<br>
* Types:<br>
* - airplane mode
* - wifi on
* - data on
*
* These properties behave like a bitmask so if you set the network connection to 0
* everything will get turned off. However if you for example set the network connection
* to 4 it will disable the airplane mode and turn off the wifi so that only data will
* be enabled. WebdriverIO provides a simplified interface to set these values without
* calculating bitmasks.
*
* Note: if you have airplane mode enabled you can't have wifi or data be enabled too
* (for obvious reasons)
*
* <example>
:setNetworkConnection.js
it('should emulate network connection', function () {
browser.setNetworkConnection(0) // airplane mode off, wifi off, data off
browser.setNetworkConnection(1) // airplane mode on, wifi off, data off
browser.setNetworkConnection(2) // airplane mode off, wifi on, data off
browser.setNetworkConnection(4) // airplane mode off, wifi off, data on
browser.setNetworkConnection(6) // airplane mode off, wifi on, data on
});
* </example>
*
* @type mobile
* @for selendroid
* @see https://github.com/appium/appium-android-driver/blob/master/lib/commands/network.js#L24-L46
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function setNetworkConnection (type) {
if (typeof type !== 'number') {
throw new ProtocolError('Number or type of arguments don\'t agree with setNetworkConnection protocol command.')
} else if (type > 6 || type < 0) {
throw new ProtocolError('Invalid value for network connection.')
} else if (type === 3 || type === 5) {
throw new ProtocolError('You can\'t have wifi or data enabled while in airplane mode.')
}
return this.requestHandler.create({
path: '/session/:sessionId/network_connection',
method: 'POST'
}, {
parameters: {
type: type
}
})
}

View File

@ -0,0 +1,37 @@
/**
*
* Either retrieve a JSON hash of all the currently specified settings or update the current setting on the device.
*
* <example>
:settings.js
it('should update/get settinsg on the device', function () {
// update setting on the device
browser.settings({ cyberdelia: 'open' });
// get current settings
var settings = browser.settings()
console.log(settings.cyberdelia); // returns 'open'
});
* </example>
*
* @type mobile
* @param {Object=} settings key/value pairs defining settings on the device
* @return {Object} current settings (only if method was called without parameters)
*
*/
export default function settings (settings) {
const settingsRoute = '/session/:sessionId/appium/settings'
/**
* get current settings
*/
if (!settings) {
return this.requestHandler.create(settingsRoute)
}
return this.requestHandler.create({
path: settingsRoute,
method: 'POST'
}, { settings })
}

View File

@ -0,0 +1,21 @@
/**
*
* Perform a shake action on the device.
*
* <example>
:shakeIt.js
browser.shake()
* </example>
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#shake
* @type mobile
* @for ios
*
*/
export default function shake () {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/shake',
method: 'POST'
})
}

View File

@ -0,0 +1,14 @@
/**
*
* Get the current page source.
*
* @return {String} The current page source.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#get-page-source
* @type protocol
*
*/
export default function source () {
return this.requestHandler.create('/session/:sessionId/source')
}

View File

@ -0,0 +1,33 @@
/**
*
* Start an arbitrary Android activity during a session.
*
* <example>
:startActivity.js
browser.startActivity({
appPackage: 'io.appium.android.apis',
appActivity: '.view.DragAndDropDemo'
});
* </example>
*
* @param {String} appPackage name of app
* @param {String} appActivity name of activity
* @type mobile
* @for android
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
export default function startActivity (appPackage, appActivity) {
if (typeof appPackage !== 'string' || typeof appActivity !== 'string') {
throw new ProtocolError(
'startActivity command requires two parameter (appPackage, appActivity) from type string'
)
}
return this.requestHandler.create(
'/session/:sessionId/appium/device/start_activity',
{ appPackage, appActivity }
)
}

View File

@ -0,0 +1,35 @@
/**
*
* Query the server's current status. The server should respond with a general
* "HTTP 200 OK" response if it is alive and accepting commands. The response
* body should be a JSON object describing the state of the server. All server
* implementations should return two basic objects describing the server's
* current platform and when the server was built. All fields are optional;
* if omitted, the client should assume the value is uknown. Furthermore,
* server implementations may include additional fields not listed here.
*
* | Key | Type | Description |
* | -------------- | ------ | ----------- |
* | build.version | string | A generic release label (i.e. "2.0rc3") |
* | build.revision | string | The revision of the local source control client from which the server was built |
* | build.time | string | A timestamp from when the server was built |
* | os.arch | string | The current system architecture |
* | os.name | string | The name of the operating system the server is currently running on: "windows", "linux", etc. |
* | os.version | string | The operating system version |
*
* (Not part of the official Webdriver specification).
*
* @return {Object} An object describing the general status of the server
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#status
* @type protocol
*
*/
export default function status () {
return this.requestHandler.create({
path: '/status',
method: 'GET',
requiresSession: false
})
}

View File

@ -0,0 +1,29 @@
/**
*
* Returns application strings of the application in a specific language.
*
* <example>
:stringsAsync.js
it('should return app strings for Android application', function () {
var appStrings = browser.strings();
console.log(appStrings); // outputs all app strings
var russianAppStrings = browser.strings('ru')
console.log(russianAppStrings); // outputs all russian app strings (if available)
});
* </example>
*
* @param {String} language if set it returns app strings only for that specific language
*
* @see https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#app-strings
* @type mobile
* @for android
*
*/
export default function strings (language) {
return this.requestHandler.create({
path: '/session/:sessionId/appium/app/strings',
method: 'POST'
}, { language })
}

View File

@ -0,0 +1,28 @@
/**
*
* Submit a FORM element. The submit command may also be applied to any element
* that is a descendant of a FORM element. (Not part of the official Webdriver specification).
*
* @param {String} ID ID of a `<form />` WebElement JSON object to route the command to
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelementidsubmit
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import depcrecate from '../helpers/depcrecationWarning'
export default function submit (id) {
if (typeof id !== 'string' && typeof id !== 'number') {
throw new ProtocolError(
'number or type of arguments don\'t agree with submit protocol command'
)
}
depcrecate('submit')
return this.requestHandler.create({
path: `/session/:sessionId/element/${id}/submit`,
method: 'POST'
})
}

View File

@ -0,0 +1,28 @@
/**
* Configure the amount of time that a particular type of operation can execute
* for before they are aborted and a |Timeout| error is returned to the client.
*
* If no parameter are given it returns the current timeout settings (only supported
* by drivers which have the W3C Webdriver protocol implemented)
*
* @param {String=} type The type of operation to set the timeout for. Valid values are:<br>- **script** Determines when to interrupt a script that is being [evaluated](https://www.w3.org/TR/webdriver/#executing-script).<br>- **implicit** Gives the timeout of when to abort [locating an element](https://www.w3.org/TR/webdriver/#element-retrieval).<br>- **pageLoad** Provides the timeout limit used to interrupt [navigation](https://html.spec.whatwg.org/#navigate) of the [browsing context](https://html.spec.whatwg.org/#browsing-context). <br />The `pageLoad` keyword is a part of the official WebDriver [specification](https://www.w3.org/TR/webdriver/#set-timeouts), but might not be [supported](https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/687) for your browser (the previous name is `page load`).
* @param {Number=} ms The amount of time, in milliseconds, that time-limited commands are permitted to run.
*
* @see https://www.w3.org/TR/webdriver/#get-timeouts
* @type protocol
*
*/
export default function timeouts (type, ms) {
/*!
* get timeouts (W3C Webdriver protocol only)
*/
if (typeof type !== 'string' || typeof ms !== 'number') {
return this.requestHandler.create('/session/:sessionId/timeouts')
}
return this.requestHandler.create('/session/:sessionId/timeouts', {
type: type,
ms: ms
})
}

View File

@ -0,0 +1,30 @@
/**
*
* Set the amount of time, in milliseconds, that asynchronous scripts executed
* by /session/:sessionId/execute_async are permitted to run before they are
* aborted and a |Timeout| error is returned to the client.
*
* Deprecated! Please use the `timeouts` command instead.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidtimeoutsasync_script
*
* @param {Number} ms The amount of time, in milliseconds, that time-limited commands are permitted to run.
* @type protocol
* @deprecated
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import depcrecate from '../helpers/depcrecationWarning'
export default function timeoutsAsyncScript (ms) {
/*!
* parameter check
*/
if (typeof ms !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with timeoutsAsyncScript protocol command')
}
depcrecate('timeoutsAsyncScript')
return this.requestHandler.create('/session/:sessionId/timeouts/async_script', { ms })
}

View File

@ -0,0 +1,32 @@
/**
*
* Set the amount of time the driver should wait when searching for elements. When searching for a single element,
* the driver should poll the page until an element is found or the timeout expires, whichever occurs first. When
* searching for multiple elements, the driver should poll the page until at least one element is found or the
* timeout expires, at which point it should return an empty list.
*
* If this command is never sent, the driver should default to an implicit wait of 0ms.
*
* Depcrecated! Please use the `timeouts` command instead.
*
* @param {Number} ms The amount of time to wait, in milliseconds. This value has a lower bound of 0.
*
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidtimeoutsimplicit_wait
* @type protocol
*
*/
import { ProtocolError } from '../utils/ErrorHandler'
import depcrecate from '../helpers/depcrecationWarning'
export default function timeoutsImplicitWait (ms) {
/*!
* parameter check
*/
if (typeof ms !== 'number') {
throw new ProtocolError('number or type of arguments don\'t agree with timeoutsImplicitWait protocol command')
}
depcrecate('timeoutsImplicitWait')
return this.requestHandler.create('/session/:sessionId/timeouts/implicit_wait', { ms })
}

View File

@ -0,0 +1,33 @@
/**
*
* Gets an object containing the current page title.
*
* <example>
:title.js
it('should return title using protocol command', function () {
browser.url('http://webdriver.io');
var title = browser.title();
console.log(title);
// outputs the following:
// {
// state: 'success',
// sessionId: '0c49951c-eb15-4053-96af-c1ebc79fb8b7',
// hCode: 388233301,
// value: 'WebdriverIO - WebDriver bindings for Node.js',
// class: 'org.openqa.selenium.remote.Response',
// status: 0
// }
});
* </example>
*
* @return {String} The current page title.
*
* @see https://w3c.github.io/webdriver/webdriver-spec.html#get-title
* @type protocol
*
*/
export default function title () {
return this.requestHandler.create('/session/:sessionId/title')
}

View File

@ -0,0 +1,20 @@
/**
*
* Switch the state (enabled/disabled) of airplane mode.
*
* <example>
:toggleAirplaneMode.js
browser.toggleAirplaneMode()
* </example>
*
* @type mobile
* @for android
*
*/
export default function toggleAirplaneMode () {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/toggle_airplane_mode',
method: 'POST'
})
}

View File

@ -0,0 +1,20 @@
/**
*
* Switch the state (enabled/disabled) of data service.
*
* <example>
:toggleData.js
browser.toggleData()
* </example>
*
* @type mobile
* @for android
*
*/
export default function toggleData () {
return this.requestHandler.create({
path: '/session/:sessionId/appium/device/toggle_data',
method: 'POST'
})
}

Some files were not shown because too many files have changed in this diff Show More