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,54 @@
name: autocompletion
category: usage
tags: guide
index: 8
title: WebdriverIO - Autocompletion
---
Autocompletion
=====================
If you have been writing program code for a while, you probably like autocompletion.
Autocomplete is available out of the box in many code editors. However if autocompletion is required for packages that are not installed in the usual locations or are excluded from indexing for some reasons, these too could be added via configuration changes.
![Autocompletion](/images/autocompletion/0.png)
[JSDoc](http://usejsdoc.org/) is used for documenting code. It helps to see more additional details about parameters and their types.
![Autocompletion](/images/autocompletion/1.png)
Use standard shortcuts *⇧ + ⌥ + SPACE* on IntelliJ Platform to see available documentation:
![Autocompletion](/images/autocompletion/2.png)
So, let's start to consider an example of adding autocompletion to code editors on the IntelliJ Platform like WebStorm.
### Node.js Core modules as External library
Open *Settings -> Preferences -> Languages & Frameworks -> JavaScript -> Libraries*
![Autocompletion](/images/autocompletion/3.png)
Add new library
![Autocompletion](/images/autocompletion/4.png)
Add directory with WebdriverIO commands
![Autocompletion](/images/autocompletion/5.png)
![Autocompletion](/images/autocompletion/6.png)
![Autocompletion](/images/autocompletion/7.png)
Enter documentation URL
![Autocompletion](/images/autocompletion/8.png)
![Autocompletion](/images/autocompletion/9.png)
![Autocompletion](/images/autocompletion/10.png)
### Using TypeScript community stubs (TypeScript definition files)
WebStorm provides one more workaround for adding coding assistance. It allows you to download [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) stubs.
![Autocompletion](/images/autocompletion/11.png)
![Autocompletion](/images/autocompletion/12.png)

View File

@ -0,0 +1,94 @@
name: bindingscommands
category: usage
tags: guide
index: 2
title: WebdriverIO - Bindings & Commands
---
Bindings & Commands
=====================
WebdriverIO differentiates between two different method types: protocol bindings and commands. Protocol bindings are the exact representation of the JSONWire protocol interface. They expect the same parameters as described in the [protocol docs](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol).
```js
console.log(browser.url());
/**
* returns:
*
* { state: null,
* sessionId: '684cb251-f0bd-4910-a43d-f3413206e652',
* hCode: 2611472,
* value: 'http://webdriver.io',
* class: 'org.openqa.selenium.remote.Response',
* status: 0 } }
*
*/
});
```
WebdriverIO supports all JSONWire protocol bindings (including the new ones from the Webdriver spec) implemented and even a whole bunch of [Appium](http://appium.io/) specific ones for mobile testing.
All other methods like `getValue` or `dragAndDrop` using these commands to provide handy functions who simplify your tests to look more concise and expressive. So instead of doing this:
```js
var element = browser.element('#myElem');
var res = browser.elementIdCssProperty(element.value.ELEMENT, 'width');
assert(res.value === '100px');
});
```
you can simply do this:
```js
var width = browser.getCssProperty('#myElem', 'width')
assert(width.parsed.value === 100);
/**
* console.log(width) returns:
*
* { property: 'width',
* value: '100px',
* parsed: { type: 'number', string: '100px', unit: 'px', value: 100 } }
*/
});
```
It not only shortens your code it also makes the return value testable. You don't have to worry about how to combine the JSONWire bindings to achieve a certain action, just use the command methods.
When you call a command WebdriverIO automatically tries to propagate the prototype to the result. This of course only works if the result prototype can be modified (e.g. for objects). This allows the developer to chain commands like this:
```js
browser.click('#elem1').click('#elem2');
```
It also enables the ability to call commands on element results. The browser instance remembers the last result of each command and can propagate it as a parameter for the next command. This way you can call commands directly on element results:
```html
<div id="elem1" onClick="document.getElementById('elem1').innerHTML = 'some new text'">some text</div>
```
```js
var element = browser.element('#elem1');
console.log(element.getText()); // outputs: "some text"
element.click();
console.log(element.getText()); // outputs: "some new text"
```
With this method you can seamlessly encapsulate your page information into a [page object](http://webdriver.io/guide/testrunner/pageobjects.html) which will allow you to write highly expressive tests like:
```js
var expect = require('chai').expect;
var FormPage = require('../pageobjects/form.page');
describe('auth form', function () {
it('should deny access with wrong creds', function () {
FormPage.open();
FormPage.username.setValue('foo');
FormPage.password.setValue('bar');
FormPage.submit();
expect(FormPage.flash.getText()).to.contain('Your username is invalid!');
});
});
```
Check out the documentation page on [page objects](http://webdriver.io/guide/testrunner/pageobjects.html) or have a look on our [examples](https://github.com/webdriverio/webdriverio/tree/master/examples/pageobject)

View File

@ -0,0 +1,128 @@
name: cloudservices
category: usage
tags: guide
index: 2
title: WebdriverIO - Using Cloud Services
---
# Using Cloud Services
Using ondemand services like Sauce Labs, Browserstack or TestingBot with WebdriverIO is pretty simple.
1. Make sure WebdriverIO uses their host (e.g. `ondemand.saucelabs.com` for Sauce Labs) as the selenium server, either by setting the `host` config or letting WebdriverIO configure that automatically based on the value of `user` and `key`.
2. (optional) Set service specific values for each browser in `desiredCapabilities` (e.g. `build` to specify the build number and cluster multiple tests together).
3. (optional) Tunnel local traffic to provider, so that your tests can access `localhost`.
If you only want to run cloud services in Travis, you can use the `CI` environment variable to check if you are in Travis and modify the config accordingly.
```javascript
// wdio.conf.js
var config = {...}
if (process.env.CI) {
config.user = process.env.SAUCE_USERNAME;
config.key = process.env.SAUCE_ACCESS_KEY;
}
exports.config = config
```
## [Sauce Labs](https://saucelabs.com/)
It is easy to set up your tests to run remotely in Sauce Labs.
The only requirement is to set the `user` and `key` in your config (either exported by `wdio.conf.js` or passed into `webdriverio.remote(...)`) to your Sauce Labs username and access key.
You can also pass in any optional [test configuration option](https://docs.saucelabs.com/reference/test-configuration/#webdriver-api) as a key/value in the capabilities for any browser.
### [Sauce Connect](https://wiki.saucelabs.com/display/DOCS/Sauce+Connect+Proxy)
If you want to run tests against a server that is not accessible to the Internet (like on `localhost`), then you need to use Sauce Connect.
It is out of the scope of WebdriverIO to support this, so you must start it by yourself.
If you are using the WDIO testrunner download and configure the [`wdio-sauce-service`](https://github.com/webdriverio/wdio-sauce-service) in your `wdio.conf.js`. It helps getting Sauce Connect running and comes with additional features that better integrate your tests into the Sauce service.
### With Travis CI
Travis CI, however, does [have support](http://docs.travis-ci.com/user/sauce-connect/#Setting-up-Sauce-Connect) for starting Sauce Connect before each test, so follow their directions for that if you are interested.
If you do so, you must set the `tunnel-identifier` test configuration option in each browser's capabilities. Travis sets this to the `TRAVIS_JOB_NUMBER` environmental variable by default.
Also if you want to have Sauce Labs group your tests by build number, you can set the `build` to `TRAVIS_BUILD_NUMBER`.
Lastly if you set the `name`, this changes the name of this test in Sauce Labs for this build. If you are using the WDIO testrunner combined with the [`wdio-sauce-service`](https://github.com/webdriverio/wdio-sauce-service) WebdriverIO automatically sets a proper name for the test.
Example `desiredCapabilities`:
```javascript
browserName: 'chrome',
version: '27.0',
platform: 'XP',
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
name: 'integration',
build: process.env.TRAVIS_BUILD_NUMBER
```
### Timeouts
Since you are running your tests remotely, it might be necessary to increase some timeouts.
You can change the [idle timeout](https://docs.saucelabs.com/reference/test-configuration/#idle-test-timeout) by passing `idle-timeout` as a test configuration option. This controls how long Sauce will wait between commands before closing the connection.
## [BrowserStack](https://www.browserstack.com/)
Browserstack is also supported easily.
The only requirement is to set the `user` and `key` in your config (either exported by `wdio.conf.js` or passed into `webdriverio.remote(...)`) to your Browserstack automate username and access key.
You can also pass in any optional [supported capabilities](https://www.browserstack.com/automate/capabilities) as a key/value in the capabilities for any browser. If you set `browserstack.debug` to `true` it will record a screencast of the session, which might be helpful.
### [Local Testing](https://www.browserstack.com/local-testing#command-line)
If you want to run tests against a server that is not accessible to the Internet (like on `localhost`), then you need to use Local Testing.
It is out of the scope of WebdriverIO to support this, so you must start it by yourself.
If you do use local, you should set `browserstack.local` to `true` in your capabilities.
If you are using the WDIO testrunner download and configure the [`wdio-browserstack-service`](https://github.com/itszero/wdio-browserstack-service) in your `wdio.conf.js`. It helps getting BrowserStack running and comes with additional features that better integrate your tests into the BrowserStack service.
### With Travis CI
If you want to add Local Testing in Travis you have to start it by yourself.
The following script will download and start it in the background. You should run this in Travis before starting the tests.
```bash
wget https://www.browserstack.com/browserstack-local/BrowserStackLocal-linux-x64.zip
unzip BrowserStackLocal-linux-x64.zip
./BrowserStackLocal -v -onlyAutomate -forcelocal $BROWSERSTACK_ACCESS_KEY &
sleep 3
```
Also, you might wanna set the `build` to the Travis build number.
Example `desiredCapabilities`:
```javascript
browserName: 'chrome',
project: 'myApp',
version: '44.0',
build: 'myApp #' + process.env.TRAVIS_BUILD_NUMBER + '.' + process.env.TRAVIS_JOB_NUMBER,
'browserstack.local': 'true',
'browserstack.debug': 'true'
```
## [TestingBot](https://testingbot.com/)
The only requirement is to set the `user` and `key` in your config (either exported by `wdio.conf.js` or passed into `webdriverio.remote(...)`) to your TestingBot username and secret key.
You can also pass in any optional [supported capabilities](https://testingbot.com/support/other/test-options) as a key/value in the capabilities for any browser.
### [Local Testing](https://testingbot.com/support/other/tunnel)
If you want to run tests against a server that is not accessible to the Internet (like on `localhost`), then you need to use Local Testing. TestingBot provides a JAVA based tunnel to allow you to test websites not accessible from the internet.
Their tunnel support page contains the information necessary to get this up and running.
If you are using the WDIO testrunner download and configure the [`wdio-testingbot-service`](https://github.com/testingbot/wdio-testingbot-service) in your `wdio.conf.js`. It helps getting TestingBot running and comes with additional features that better integrate your tests into the TestingBot service.

View File

@ -0,0 +1,69 @@
name: customcommands
category: usage
tags: guide
index: 1
title: WebdriverIO - Custom Commands
---
Custom Commands
===============
If you want to extend the browser instance with your own set of commands there is a method called `addCommand` available from the browser object. You can write your command in a synchronous (default) way the same way as in your specs or asynchronous (like when using WebdriverIO in standalone mode). The following example shows how to add a new command that returns the current url and title as one result only using synchronous commands:
```js
browser.addCommand("getUrlAndTitle", function (customVar) {
return {
url: this.getUrl(),
title: this.getTitle(),
customVar: customVar
};
});
```
Custom commands give you the opportunity to bundle a specific sequence of commands that are used frequently in a handy single command call. You can define custom commands at any point in your test suite, just make sure that the command is defined before you first use it (the before hook in your wdio.conf.js might be a good point to create them). Also to note: custom commands, like all WebdriverIO commmands, can only be called inside a test hook or it block. In your spec file you can use them like this:
```js
it('should use my custom command', function () {
browser.url('http://www.github.com');
var result = browser.getUrlAndTitle('foobar');
assert.strictEqual(result.url, 'https://github.com/');
assert.strictEqual(result.title, 'GitHub · Where software is built');
assert.strictEqual(result.customVar, 'foobar');
});
```
As mentioned earlier, you can define your command using good old promise syntax. This makes sense if you work with an additional 3rd party library that supports promises or if you want to execute both commands at the same time. Here is the async example, note that the custom command callback has a function name called `async`:
```js
client.addCommand("getUrlAndTitle", function async () {
return Promise.all([
this.getUrl(),
this.getTitle()
]);
});
```
## Integrate 3rd party libraries
If you use external libraries (e.g. to do database calls) that support promises, a nice approach to easily integrate them is to wrap certain API methods within a custom command:
```js
browser.addCommand('doExternalJob', function async (params) {
return externalLib.command(params);
});
```
Then just use it in your wdio test specs synchronously:
```js
it('execute external library in a sync way', function() {
browser.url('...');
browser.doExternalJob('someParam');
console.log(browser.getTitle()); // returns some title
});
```
Note that the result of your custom command will be the result of the promise you return. Also there is no support for synchronous commands in standalone mode therefore you always have to handle asynchronous commands using Promises.
By default WebdriverIO will throw an error if you try to overwrite an existing command. You can bypass this behavior by passing `true` as 3rd parameter to the `addCommand` function.

View File

@ -0,0 +1,55 @@
name: eventhandling
category: usage
tags: guide
index: 6
title: WebdriverIO - Eventhandling
---
Eventhandling
=============
The following functions are supported: `on`,`once`,`emit`,`removeListener`,`removeAllListeners`.
They behave exactly as described in the official NodeJS [docs](http://nodejs.org/api/events.html).
There are some predefined events (`error`,`init`,`end`, `command`, `log`) which cover important
WebdriverIO events.
## Examples
```js
browser.on('error', function(e) {
// will be executed everytime an error occurred
// e.g. when element couldn't be found
console.log(e.body.value.class); // -> "org.openqa.selenium.NoSuchElementException"
console.log(e.body.value.message); // -> "no such element ..."
})
```
Use the `log()` event to log arbitrary data, which can then be logged or displayed by a reporter:
```js
browser
.init()
.emit('log', 'Before my method')
.click('h2.subheading a')
.emit('log', 'After my method', {more: 'data'})
.end();
```
All commands are chainable, so you can use them while chaining your commands
```js
var cnt;
browser
.init()
.once('countme', function(e) {
console.log(e.elements.length, 'elements were found');
})
.elements('.myElem').then(function(res) {
cnt = res.value;
})
.emit('countme', cnt)
.end();
```
Note that you can't execute any WebdriverIO commands or any other async operation within the listener function. Event handling comes handy when you want to log certain information but is not considered to be used to do action on certain events like taking a screenshot if an error happens. For use the `onError` hook in your wdio test runner configuration file.

View File

@ -0,0 +1,121 @@
name: multiremote
category: usage
tags: guide
index: 4
title: WebdriverIO - Multiremote
---
Run multiple browser at the same time
=====================================
WebdriverIO allows you to run multiple Selenium sessions in a single test. This becomes handy when you need to test application features where multiple users are required (e.g. chat or WebRTC applications). Instead of creating a couple of remote instances where you need to execute common commands like [init](http://webdriver.io/api/protocol/init.html) or [url](http://webdriver.io/api/protocol/url.html) on each of those instances, you can simply create a multiremote instance and control all browser at the same time. To do so just use the `multiremote` function and pass an object with named browser with their capabilities into it. By giving each capability a name you will be able to easy select and access that single instance when executing commands on a single instance. Here is an example demonstrating a how to create a multiremote WebdriverIO instance in standalone mode:
```js
var webdriverio = require('webdriverio');
var browser = webdriverio.multiremote({
myChromeBrowser: {
desiredCapabilities: {
browserName: 'chrome'
}
},
myFirefoxBrowser: {
desiredCapabilities: {
browserName: 'firefox'
}
}
});
```
This would create two Selenium sessions with Chrome and Firefox. Instead of just Chrome and Firefox you can also boot up two mobile devices using [Appium](http://appium.io/). Any kind of OS/browser combination is possible here. All commands you call with the `browser` variable gets executed in parallel with each instance. This helps to streamline your integration test and speedup the execution a bit. For example initialise the session and open up an url:
```js
browser.init().url('http://chat.socket.io/');
```
Using the multiremote instance changes the way how results are accessible in callback functions. Since more than one browser executes the command we also receive more than one result.
```js
browser
.init()
.url('https://www.whatismybrowser.com/')
.getText('.string-major').then(function(result) {
console.log(result.resultChrome); // returns: 'Chrome 40 on Mac OS X (Yosemite)'
console.log(result.resultFirefox); // returns: 'Firefox 35 on Mac OS X (Yosemite)'
})
.end();
```
You will notice that each command gets executed one by one. That means that the command finishes once all browser have executed it. This is helpful because it keeps the browser actions synced and it makes it easier to understand what currently happens.
Sometimes it is necessary to do different things with each browser in order to test something. For instance if we want to test a chat application, there has to be one browser who inputs a text message while the other browser waits to receive that message and do an assertion on it. You can get access to a single instance by using the `select` method.
```js
var myChromeBrowser = browser.select('myChromeBrowser');
var myFirefoxBrowser = browser.select('myFirefoxBrowser');
myChromeBrowser
.setValue('#message', 'Hi, I am Chrome')
.click('#send');
myFirefoxBrowser
.waitForExist('.messages', 5000)
.getText('.messages').then(function(messages) {
assert.equal(messages, 'Hi, I am Chrome');
});
```
In that example the `myFirefoxBrowser` instance will start waiting on a messages once the `myChromeBrowser` instance clicked on the send button. The execution is in parallel. Multiremote makes it easy and convenient to control multiple browser either doing the same thing in parallel or something different. In the latter case it might be the case where you want to sync up your instances to do something in parallel again. To do so just call the `sync` method. All methods which are chained behind the `sync` method get executed in parallel again:
```js
// these commands get executed in parallel by all defined instances
browser.init().url('http://example.com');
// do something with the Chrome browser
myChromeBrowser.setValue('.chatMessage', 'Hey Whats up!').keys('Enter')
// do something with the Firefox browser
myFirefoxBrowser.getText('.message').then(function (message) {
console.log(messages);
// returns: "Hey Whats up!"
});
// now sync instances again
browser.sync().url('http://anotherwebsite.com');
```
All these examples demonstrate the usage of multiremote in standalone mode. You can of course also use it with the wdio test runner. To do so just define the `capabilities` object in your `wdio.conf.js` as an object with the browser names as keys:
```js
export.config = {
// ...
capabilities: {
myChromeBrowser: {
desiredCapabilities: {
browserName: 'chrome'
}
},
myFirefoxBrowser: {
desiredCapabilities: {
browserName: 'firefox'
}
}
}
// ...
};
```
Since all commands are running synchronous with the wdio test runner, all multiremote commands are synchronous as well. That means that the previous described `sync` method got obsolete. In your test specs each single browser is globally available by its browser name:
```js
it('should do something with two browser', function () {
browser.url('http://google.com');
console.log(browser.getTitle()); // returns {myChromeBrowser: 'Google', myFirefoxBrowser: 'Google'}
myFirefoxBrowser.url('http://yahoo.com');
console.log(myFirefoxBrowser.getTitle()); // return 'Yahoo'
console.log(browser.getTitle()); // returns {myChromeBrowser: 'Google', myFirefoxBrowser: 'Yahoo'}
});
```
__Note:__ Multiremote is not meant to execute all your tests in parallel. It should help you to coordinate more than one browser for sophisticated integration tests.

View File

@ -0,0 +1,27 @@
name: repl
category: usage
tags: guide
index: 9
title: WebdriverIO - REPL interface
---
REPL interface
==============
With `v4.5.0` WebdriverIO introduces a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) interface that helps you to not only discover the framework API but also debug and inspect your tests. It can be used in multiple ways. First you can use it as CLI command and spawn a Selenium session from the command line, e.g.
```sh
$ wdio repl chrome
```
This would open a Chrome browser that you can control with the REPL interface. Make sure you have a Selenium server running on port `4444` in order to initiate the session. If you have a [SauceLabs](https://saucelabs.com) (or other cloud vendor) account you can also directly run the browser on your command line in the cloud via:
```sh
$ wdio repl chrome -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY
```
You can apply any options (see `wdio --help`) available for your REPL session. It is recommended to install the [`wdio-sync`](https://github.com/webdriverio/wdio-sync) (if not already installed with the framework adapter) package when using the REPL as it allows you to use some advanced features (e.g. like the `$` and `$$` functions).
![WebdriverIO REPL](http://webdriver.io/images/repl.gif)
Another way to use the REPL is in between your tests via the [`debug`](/api/utility/debug.html) command. It will stop the browser when executed and enables you to jump into the application (e.g. to the dev tools) or control the browser from the command line. This is helpful when some commands don't trigger a certain action as expected. With the REPL you can then try out the commands to see which are working most reliable.

View File

@ -0,0 +1,177 @@
name: selectors
category: usage
tags: guide
index: 0
title: WebdriverIO - Selectors
---
Selectors
=========
The JsonWireProtocol provides several strategies to query an element. WebdriverIO simplifies these to make it more familiar with the common existing selector libraries like [Sizzle](http://sizzlejs.com/). The following selector types are supported:
## CSS Query Selector
```js
browser.click('h2.subheading a');
```
## Link Text
To get an anchor element with a specific text in it, query the text starting with an equal (=) sign.
For example:
```html
<a href="http://webdriver.io">WebdriverIO</a>
```
```js
console.log(browser.getText('=WebdriverIO')); // outputs: "WebdriverIO"
console.log(browser.getAttribute('=WebdriverIO', 'href')); // outputs: "http://webdriver.io"
```
## Partial Link Text
To find a anchor element whose visible text partially matches your search value, query it by using `*=`
in front of the query string (e.g. `*=driver`)
```html
<a href="http://webdriver.io">WebdriverIO</a>
```
```js
console.log(browser.getText('*=driver')); // outputs: "WebdriverIO"
```
## Element with certain text
The same technique can be applied to elements as well, e.g. query a level 1 heading with the text "Welcome to my Page":
```html
<h1>Welcome to my Page</h1>
```
```js
console.log(browser.getText('h1=Welcome to my Page')); // outputs: "Welcome to my Page"
console.log(browser.getTagName('h1=Welcome to my Page')); // outputs: "h1"
```
or using query partial text
```js
console.log(browser.getText('h1*=Welcome')); // outputs: "Welcome to my Page"
```
The same works for ids and class names:
```html
<i class="someElem" id="elem">WebdriverIO is the best</i>
```
```js
console.log(browser.getText('.someElem=WebdriverIO is the best')); // outputs: "WebdriverIO is the best"
console.log(browser.getText('#elem=WebdriverIO is the best')); // outputs: "WebdriverIO is the best"
console.log(browser.getText('.someElem*=WebdriverIO')); // outputs: "WebdriverIO is the best"
console.log(browser.getText('#elem*=WebdriverIO')); // outputs: "WebdriverIO is the best"
```
## Tag Name
To query an element with a specific tag name use `<tag>` or `<tag />`
## Name Attribute
For querying elements with a specific name attribute you can either use a normal CSS3 selector or the
provided name strategy from the JsonWireProtocol by passing something like `[name="some-name"]` as
selector parameter
## xPath
It is also possible to query elements via a specific xPath. The selector has to have a format like
for example `//BODY/DIV[6]/DIV[1]/SPAN[1]`
In near future WebdriverIO will cover more selector features like form selector (e.g. `:password`,`:file` etc)
or positional selectors like `:first` or `:nth`.
## Mobile Selectors
For (hybrid/native) mobile testing you have to use mobile strategies and use the underlying device automation technology directly. This is especially useful when a test needs some fine-grained control over finding elements.
### Android UiAutomator
Androids UI Automator framework provides a number of ways to find elements. You can use the [UI Automator API](https://developer.android.com/tools/testing-support-library/index.html#uia-apis), in particular the [UiSelector class](https://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html) to locate elements. In Appium you send the Java code, as a string, to the server, which executes it in the applications environment, returning the element or elements.
```js
var selector = 'new UiSelector().text("Cancel")).className("android.widget.Button")';
browser.click('android=' + selector);
```
### iOS UIAutomation
When automating an iOS application, Apples [UI Automation framework](https://developer.apple.com/library/prerelease/tvos/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UIAutomation.html) can be used to find elements. This JavaScript [API](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/index.html#//apple_ref/doc/uid/TP40009771) has methods to access to the view and everything on it.
```js
var selector = 'UIATarget.localTarget().frontMostApp().mainWindow().buttons()[0]'
browser.click('ios=' + selector);
```
You can also use predicate searching within iOS UI Automation in Appium, to control element finding even further. See [here](https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios_predicate.md) for details.
### Accessibility ID
The `accessibility id` locator strategy is designed to read a unique identifier for a UI element. This has the benefit of not changing during localization or any other process that might change text. In addition, it can be an aid in creating cross-platform tests, if elements that are functionally the same have the same accessibility id.
- For iOS this is the `accessibility identifier` laid out by Apple [here](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIAccessibilityIdentification_Protocol/index.html).
- For Android the `accessibility id` maps to the `content-description` for the element, as described [here](https://developer.android.com/training/accessibility/accessible-app.html).
For both platforms getting an element, or multiple elements, by their `accessibility id` is usually the best method. It is also the preferred way, in replacement of the deprecated `name` strategy.
```js
browser.click(`~my_accessibility_identifier`);
```
### Class Name
The `class name` strategy is a `string` representing a UI element on the current view.
- For iOS it is the full name of a [UIAutomation class](https://developer.apple.com/library/prerelease/tvos/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UIAutomation.html), and will begin with `UIA-`, such as `UIATextField` for a text field. A full reference can be found [here](https://developer.apple.com/library/ios/navigation/#section=Frameworks&topic=UIAutomation).
- For Android it is the fully qualified name of a [UI Automator](https://developer.android.com/tools/testing-support-library/index.html#UIAutomator) [class](https://developer.android.com/reference/android/widget/package-summary.html), such `android.widget.EditText` for a text field. A full reference can be found [here](https://developer.android.com/reference/android/widget/package-summary.html).
```js
// iOS example
browser.click(`UIATextField`);
// Android example
browser.click(`android.widget.DatePicker`);
```
## Chain Selectors
If you want to be more specific in your query, you can chain your selector until you've found the right
element. If you call element before your actual command, WebdriverIO starts query from that element. For example
if you have a DOM structure like:
```html
<div class="row">
<div class="entry">
<label>Product A</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product B</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product C</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
</div>
```
And you want to add product B to the cart it would be difficult to do that just by using the CSS selector.
With selector chaining it gets way easier as you can narrow down the desired element step by step:
```js
browser.element('.row .entry:nth-child(1)').click('button*=Add');
```

View File

@ -0,0 +1,68 @@
name: seleniumgrid
category: usage
tags: guide
index: 7
title: WebdriverIO - Selenium Grid
---
Selenium Grid
=====================
As well as JSONWire protocol bindings, Webdriverio also offers a few utility commands for working with the Selenium Grid. It's often useful to know the details of the Grid node which is actually running the current session. Use `getGridNodeDetails()` to get a JSON object with details like ID, hostname and port, configured timeouts, plus any command-line params used to start the node.
```js
var gridDetails = browser.getGridNodeDetails();
console.log(gridDetails);
/**
* returns:
*
* { request:
* { configuration:
* { port: 5557,
* nodeConfig: '/path/to/config.json',
* servlets: [],
* host: '192.168.2.1',
* cleanUpCycle: 2000,
* browserTimeout: 120000,
* hubHost: 'example.com',
* registerCycle: 10000,
* capabilityMatcher: 'org.openqa.grid.internal.utils.DefaultCapabilityMatcher',
* newSessionWaitTimeout: -1,
* url: 'http://example.com:5557',
* remoteHost: 'http://example.com:5557',
* register: true,
* id: 'MacMiniA10',
* throwOnCapabilityNotPresent: true,
* nodePolling: 2000,
* proxy: 'org.openqa.grid.selenium.proxy.DefaultRemoteProxy',
* maxSession: 4,
* role: 'node',
* jettyMaxThreads: -1,
* nodeTimeout: 120,
* hubPort: 80,
* timeout: 90000 },
* capabilities:
* [ { seleniumProtocol: 'WebDriver',
* platform: 'MAC',
* firefoxVersion: '42',
* browserName: 'firefox',
* maxInstances: 2,
* version: 'latest' },
* { seleniumProtocol: 'WebDriver',
* platform: 'MAC',
* browserName: 'chrome',
* maxInstances: 8,
* chromeVersion: '46',
* version: 'latest' },
* { seleniumProtocol: 'WebDriver',
* platform: 'MAC',
* browserName: 'safari',
* maxInstances: 1,
* version: 'latest' } ] },
* session: '33c2d04d-6bc1-424e-ba6f-63c400114554',
* internalKey: 'd710b167-6f29-4097-a15c-7f7bbdb73edb',
* inactivityTime: 78,
* proxyId: 'MacMiniA10' }
*
*/
```

View File

@ -0,0 +1,41 @@
name: transferpromises
category: usage
tags: guide
index: 5
title: WebdriverIO - Transfer Promises
---
Transfer Promises
=================
Per default the wdio testrunner transforms all commands to act like real synchronous commands. This way you don't need to deal with promises in any way. However if you don't use the wdio test runner or you have this behavior disabled you can use neat features of promises to write expressive tests with promise-based assertion libraries like [chai-as-promised](https://github.com/domenic/chai-as-promised/).
```js
var client = require('webdriverio').remote({
desiredCapabilities: {
browserName: 'chrome'
}
});
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.Should();
chai.use(chaiAsPromised);
chaiAsPromised.transferPromiseness = client.transferPromiseness;
describe('my app', function() {
before(function () {
return client.init();
});
it('should contain a certain text after clicking', function() {
return client
.click('button=Send')
.isVisible('#status_message').should.eventually.be.true
.getText('#status_message').should.eventually.be.equal('Message sent!');
});
});
```
The example above shows a simple integration test where a user clicks on a "Send" button and a message gets sent. The test checks if a status message gets displayed with a certain text. By setting the `transferPromiseness` function to the internal correspondent of WebdriverIO you can start chaining assertions together with commands.