Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8375b291b | ||
|
|
01d6d1cf9a | ||
|
|
92bce718ab | ||
|
|
c237de1e4b | ||
|
|
d4a4c865c1 | ||
|
|
b03f3a045e | ||
|
|
9dc9505c00 | ||
|
|
a6079ff9d2 | ||
|
|
1263d5755c | ||
|
|
7770f8b927 | ||
|
|
61149c9c0a | ||
|
|
ed6e6b2505 | ||
|
|
74d87250da | ||
|
|
fe5f2179fe | ||
|
|
1b1d1024cc | ||
|
|
2413974517 | ||
|
|
c0ed34cad9 | ||
|
|
51549ccf16 | ||
|
|
e2f8d2e13f | ||
|
|
3585978c36 | ||
|
|
405afe065b | ||
|
|
62c66c32ea | ||
|
|
fc024bd2cb | ||
|
|
53f283f03d | ||
|
|
2da45d2154 | ||
|
|
e4bfd7c9cf | ||
|
|
f3c4817bfa | ||
|
|
fb3ef327a0 | ||
|
|
3991ba3f79 | ||
|
|
e2a5546be1 | ||
|
|
16af4f49f4 | ||
|
|
88685dcb69 | ||
|
|
5a5748cb16 | ||
|
|
cdabc1cea7 | ||
|
|
deaf7c4835 | ||
|
|
b3f3b2132b | ||
|
|
47166af12c | ||
|
|
74e6419ab7 | ||
|
|
f95eb6c4f5 | ||
|
|
00aab07e2c | ||
|
|
d8fcc7d850 | ||
|
|
d027f64700 | ||
|
|
ce479a577d | ||
|
|
2ddb1208f4 | ||
|
|
df2a2a3da0 | ||
|
|
e10bb290ea | ||
|
|
f0f71faa15 | ||
|
|
964a511be9 | ||
|
|
8e9252f12e | ||
|
|
c57d17541e | ||
|
|
757c20e486 | ||
|
|
696e4dea3f | ||
|
|
2c52e4661c | ||
|
|
11f5a0f5c0 | ||
|
|
ea4e55ad20 | ||
|
|
215c649545 | ||
|
|
c05fd69088 | ||
|
|
369946f5c8 | ||
|
|
3f273bd5f7 | ||
|
|
b1a39ec8f0 | ||
|
|
5486055fd3 | ||
|
|
0fd38c8ab1 | ||
|
|
65d8f4a606 | ||
|
|
c0f3d7a311 | ||
|
|
aaad6acaa9 | ||
|
|
30629133ec | ||
|
|
f1f821c44d | ||
|
|
5817d3125a | ||
|
|
41a4c33fdc | ||
|
|
d7f9dba9a1 | ||
|
|
a66e159cc2 | ||
|
|
74dfda9a8d | ||
|
|
84377d91fe | ||
|
|
60c7d73c39 | ||
|
|
939fff4c91 | ||
|
|
19fd7646a4 | ||
|
|
aa295a481e | ||
|
|
faabdc1942 | ||
|
|
0a80b7f5ac | ||
|
|
2e9181db93 | ||
|
|
657a83bdcb | ||
|
|
e5ca5b55fc | ||
|
|
6624802ece | ||
|
|
790d9e8df0 | ||
|
|
ec3e0bc7b3 |
@@ -14,17 +14,19 @@ Briefly describe the issue you are experiencing (or the feature you want to see
|
||||
|
||||
## Details
|
||||
|
||||
Describe in more detail the problem you have been experiencing, if necessary.
|
||||
If necessary, describe the problem you have been experiencing in more detail.
|
||||
|
||||
## Link to Appium logs
|
||||
|
||||
Create a [gist](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here. Do _not_ paste your full Appium logs here, as it will make this issue very long and hard to read! If you are reporting a bug, _always_ include Appium logs!
|
||||
Create a [GIST](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here.
|
||||
Do _NOT_ paste your full Appium logs here, as it will make this issue very long and hard to read!
|
||||
If you are reporting a bug, _always_ include Appium logs!
|
||||
|
||||
|
||||
## Code To Reproduce Issue [ Good To Have ]
|
||||
|
||||
Please remember that, with sample code; it's easier to reproduce bug and much faster to fix it.
|
||||
Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it.
|
||||
|
||||
Please git clone https://github.com/appium/sample-code and use one of your favourite languages and sample apps to reproduce issue.
|
||||
Please git clone https://github.com/appium/sample-code and use one of your favourite languages and sample apps to reproduce the issue.
|
||||
|
||||
In case a similar scenario is missing in sample-code, please submit a PR with one of the sample apps provided.
|
||||
In case a similar scenario is missing in sample-code, please submit a PR with one of the sample apps provided.
|
||||
|
||||
@@ -16,7 +16,7 @@ _Put an `x` in the boxes that apply_
|
||||
_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
|
||||
|
||||
- [ ] I have read the [CONTRIBUTING](/CONTRIBUTING.md) doc
|
||||
- [ ] I have signed the [CLA](https://docs.google.com/forms/d/1lOfXRw_0VCk7gYzjj4WLetGu7yelDVo5LWh0z7pGftE/viewform)
|
||||
- [ ] I have signed the [CLA](https://cla.js.foundation/appium/appium)
|
||||
- [ ] Lint and unit tests pass locally with my changes
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] I have added necessary documentation (if appropriate)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- "stable"
|
||||
- "7"
|
||||
- "6"
|
||||
- "4"
|
||||
script:
|
||||
- npm run lint
|
||||
|
||||
@@ -1,3 +1,213 @@
|
||||
CHANGES IN VERSION 1.6.4 Beta (from 1.6.3)
|
||||
===================================
|
||||
|
||||
**Note:** This is a **_BETA_** release. Please direct any issues to the [Appium
|
||||
issue tracker](https://github.com/appium/appium/issues) and provide as much
|
||||
information as possible.
|
||||
|
||||
#### General
|
||||
* Fixed `UnhandledPromiseRejection` errors when running Appium with Node version
|
||||
7
|
||||
* Better indicate missing necessary programs to users
|
||||
* Fix session creation logging
|
||||
* Fix server shutdown on `SIGINT` and `SIGTERM` signals
|
||||
* Ensure that all requests have `application/json` content-type
|
||||
|
||||
#### iOS
|
||||
* Fix issues with error handling in Safari/Webview handling
|
||||
* Increase simulator launch timeout for iOS 10+
|
||||
* Better handling of page selection in Safari
|
||||
* Fix memory usage issues when device logs get large
|
||||
|
||||
#### iOS - XCUITest
|
||||
* Changed the way the Appium checks that WebDriverAgent is running on the device,
|
||||
so that rather than searching the logs, the device is pinged until it is
|
||||
ready.
|
||||
- Removed `realDeviceLogger` capability, since we no longer check the logs
|
||||
* Add `useNewWDA` capability, which forces uninstall of the WDA app from the
|
||||
device before each session
|
||||
* Add `wdaLaunchTimeout` capability, which specified the time, in `ms`, to wait
|
||||
for WDA to be loaded and launched on the device
|
||||
* Allow for the auto-generation of the Xcode config file used to configurable
|
||||
WDA before launch. This includes _two_ new desired capabilities
|
||||
- `xcodeOrgId` - the Apple developer team identifier string
|
||||
- `xcodeSigningId` - a string representing a signing certificate, defaulting to
|
||||
"iPhone Developer"
|
||||
* Allow for automatic changing of bundle id for WDA in cases where a
|
||||
provisioning profile cannot be made for default bundle
|
||||
- add `updatedWDABundleId` capability to specify bundle id for which there is
|
||||
a valid provisioning profile
|
||||
* Speed up setting the value of text fields
|
||||
* Add `wdaConnectionTimeout` to control how long the server waits for WDA to
|
||||
allow connections
|
||||
* Fix handling of local port on real devices
|
||||
* Speed up Safari interactions
|
||||
* Fix session deletion to ensure that clean up happens
|
||||
* Add `mobile: swipe` execute method
|
||||
* Ensure that scrolling through `mobile: scroll` works in web context
|
||||
|
||||
#### Android
|
||||
* Default installation to ChromeDriver 2.26
|
||||
* Add device manufacturer, model, and screen size to session details
|
||||
* Fix bug in checking avd status on some systems
|
||||
* Allow wildcards in `appWaitActivity` capability
|
||||
|
||||
#### Android - Selendroid
|
||||
* Fix handling of host binary configuration for more precise installation options
|
||||
|
||||
|
||||
CHANGES IN VERSION 1.6.3 (from 1.6.2)
|
||||
===================================
|
||||
|
||||
_This is another emergency release due to an issue with the NPM shrinkwrap_
|
||||
|
||||
#### iOS
|
||||
|
||||
* Fix issue where we might try and uninstall an ssl cert from a real device
|
||||
where this isn't sensible
|
||||
* Fix another issue with acceptSslCerts where it might potentially miss the
|
||||
correct sim UDID
|
||||
|
||||
#### iOS - XCUITest
|
||||
* Upgrade version of WebDriverAgent used. Includes following updates:
|
||||
* Improve xpath query performance
|
||||
* Verify predicates
|
||||
* Fix crash for some xpath selectors
|
||||
* Decorate proxied getSession response with Appium's capabilities (fixes
|
||||
issues with clients that call getSession to determine server capabilities
|
||||
and are confused by WDA's non-standard response) ([#7480](https://github.com/appium/appium/issues/7480))
|
||||
* Fix issue with starting XCUITests on a real device, due to changes in WDA
|
||||
that invalidated our startup detection logic. ([#7313](https://github.com/appium/appium/issues/7313))
|
||||
* Allow connecting to an already-running WebDriverAgent through the
|
||||
`webDriverAgentUrl` capability, rather than starting our own
|
||||
|
||||
#### Android
|
||||
* Fix bug where we would attempt to get target SDK version from manifests
|
||||
even when they might not include it. ([#7353](https://github.com/appium/appium/issues/7353))
|
||||
* Actually pass the `acceptSslCerts` capability to the underlying automation
|
||||
so that it can have an effect ([#7326](https://github.com/appium/appium/issues/7326))
|
||||
* Updated permission granting logic to speed up permission granting by doing
|
||||
it in bulk rather than one at a time ([#7493](https://github.com/appium/appium/issues/7493))
|
||||
* Hide the new permission granting logic behind an `autoGrantPermissions`
|
||||
capability which doesn't attempt to grant permissions unless it's `true`
|
||||
([#7497](https://github.com/appium/appium/issues/7497))
|
||||
|
||||
#### Android - Uiautomator2
|
||||
|
||||
* Add ability to verify TOAST messages (these can't be interacted with, only
|
||||
text retrieval allowed)
|
||||
|
||||
#### Windows
|
||||
* _Actually_ upgrade WinAppDriver to 0.7 ([#7445](https://github.com/appium/appium/issues/7445)). Includes following updates:
|
||||
* Click on arbitrary elements
|
||||
* Support for sendKeys modifiers
|
||||
* Various bugfixes
|
||||
* Added `GET /orientation`
|
||||
* Added support for WPF apps
|
||||
|
||||
|
||||
CHANGES IN VERSION 1.6.2 (from 1.6.1)
|
||||
===================================
|
||||
|
||||
_This is a small, mostly-emergency release because we realized we omitted
|
||||
XCUITest upgrades via WebDriverAgent that we had mistakenly presumed were part
|
||||
of 1.6.1._
|
||||
|
||||
#### iOS - XCUITest
|
||||
* Upgrade version of WebDriverAgent used. Includes following updates:
|
||||
* Support for setting values on sliders
|
||||
* Fix tapping in various orientations
|
||||
* Allow tapping on arbitrary coordinates
|
||||
* Support for pinch gestures
|
||||
* Make `clear` faster
|
||||
* Improve xpath query performance
|
||||
* Add `preventWDAAttachments` capability to help with XCUITest speed and disk usage
|
||||
|
||||
#### Android - UiAutomator2
|
||||
* Code refactoring to pave the way for some UiAutomator2 wifi automation work
|
||||
* Find an unused system port automatically to avoid port clashes
|
||||
|
||||
#### Windows
|
||||
* Upgrade WinAppDriver to 0.7. Includes following updates:
|
||||
* Click on arbitrary elements
|
||||
* Support for sendKeys modifiers
|
||||
* Various bugfixes
|
||||
* Added `GET /orientation`
|
||||
* Added support for WPF apps
|
||||
|
||||
|
||||
CHANGES IN VERSION 1.6.1 (from 1.6.0)
|
||||
===================================
|
||||
|
||||
Appium 1.6.1 is the first release since bringing Appium into the [JS Foundation](https://js.foundation/)
|
||||
(see [press release](https://js.foundation/announcements/2016/10/17/Linux-Foundation-Unites-JavaScript-Community-Open-Web-Development/)).
|
||||
|
||||
Much of the development energy has been spent on fixing issues that have come up
|
||||
from the newly-integrated XCUITest and UI Automator 2 vendor-provided test
|
||||
backends.
|
||||
|
||||
#### General
|
||||
* Add `clearSystemFiles` desired capability, to specify whether to delete any generated
|
||||
files at the end of a session (see iOS and Android entries for particulars)
|
||||
* Better handle signals for stopping server
|
||||
* Fix operation of Selenium 3 Grid
|
||||
* Log more of the proxied requests and responses, for better debugging
|
||||
* Better handle source mapping for IDE support
|
||||
* Move `appium-doctor` into globally-installed utility, not bundled with server
|
||||
* Move `appium-logger` into `appium-base-driver`
|
||||
* Better handle downloading of zip files which may not have a `.zip` extension (like `.apk`)
|
||||
|
||||
|
||||
##### iOS
|
||||
* Add support for iOS 10.1
|
||||
* Add support for iOS 10.2 Beta 1
|
||||
* Add `clearSystemFiles` desired capability to specify whether to Core Simulator
|
||||
files, and Instruments (for iOS Driver) or XCUITest (for XCUITest Driver) generated files
|
||||
* Ensure correct files are tested when checking for Simulator newness
|
||||
* Map `iPad Simulator` `deviceName` to iPad Retina instead of discontinued iPad 2
|
||||
* Gracefully return when Webkit Remote Debugger doesn't return on a real device
|
||||
* Better log errors from xcode handling
|
||||
* Add `customSSLCert` capability to pre-authorize a specific SSL cert in the iOS trust store
|
||||
* During reset, don't try to uninstall an app from a real device if it's not installed
|
||||
|
||||
|
||||
##### iOS - XCUITest specific
|
||||
* clean up logging to remove confusing "Waiting..." lines
|
||||
* Fix issue in which switching to NATIVE_APP would still proxy find commands to Remote debugger
|
||||
* Fix handling of Selenium Grids
|
||||
* Correctly handle long press so duration is respected
|
||||
* Add `tapWithShortPressDuration` desired capability to specify a length for tapping,
|
||||
if the regular tap is too long for the app under test
|
||||
* Add support for scrolling through Touch Actions
|
||||
* Make sure keyboard is available when keys are sent to Text Fields
|
||||
* Add support for Zoom via Touch Action API (Pinch still not supported by Apple)
|
||||
* Fix implementation of double tap
|
||||
* Improvements in startup flow for real devices
|
||||
* Allow gestures on coordinates, not just elements
|
||||
* Add `scaleFactor` capability to direct Appium to set the simulator scale
|
||||
|
||||
|
||||
##### Android
|
||||
* Use ChromeDriver version 2.25
|
||||
* Correctly handle `--suppress-adb-kill-server` command line argument
|
||||
* Pass actual failure back when session fail and deleting the session also fails
|
||||
* Add `clearSystemFiles` desired capability to specify whether to delete temporary
|
||||
copies of the application under test at the end of the session
|
||||
* Fix issue where finding UI Automator process id would throw an error
|
||||
* Add `chromeAndroidPackage` capability which will be passed to `chromeOptions`
|
||||
* Add APIs for gathering various kinds of performance data
|
||||
* Ensure we don't try to stop app if `dontStopAppOnReset` is in force
|
||||
* Fix issue where we tried to determine the bounds of a non-existent element
|
||||
|
||||
|
||||
##### Android - UiAutomator2
|
||||
* Fix handling of element attributes
|
||||
* Better handle element finding
|
||||
* Toast message verification support
|
||||
* Ensure that there is a <hierarchy> root tag for xml/xpath source
|
||||
* Implement /rotation endpoint (supports 4 rotations)
|
||||
|
||||
|
||||
CHANGES IN VERSION 1.6.0 (from 1.5.3)
|
||||
===================================
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Google Summer of Code Ideas
|
||||
=====
|
||||
|
||||
Appium is excited to participate as a [Google Summer of Code](https://summerofcode.withgoogle.com/) sponsor project. Here's a fun list of ideas that a Summer of Code student participant can use as a foundation for thinking about what to contribute to Appium!
|
||||
|
||||
|Idea|Description|
|
||||
|----|-----------|
|
||||
|Apple tvOS Support|Our users have been asking for an Appium driver for Apple tvOS apps. Is this possible? We're not entirely sure! Why not be awesome and build it?|
|
||||
|Test App revamp|Appium uses a number of poorly-designed mobile applications in its own testing. We have to use a variety of apps because we need to test that Appium can automate all the various controls and platform features that mobile vendors provide. Really what we need is one cross-platform app (or one app per platform) that exhibit all and only the features we need to test. This would be a fun project to build some mobile apps used for testing and also demoing Appium at events and in training videos, etc...|
|
||||
|Tooling and Performance|We haven't instrumented Appium with very many performance metrics, and don't really know if we're missing some low-hanging fruit in terms of performance. Maybe you can help us do that?|
|
||||
|Babel|We have a lot of repos, and they're all on a really old version of Babel. They all need to stay in sync. How can we make this situation better, and upgrade to the latest and greatest?|
|
||||
|Unity3d Driver|Historically, Appium hasn't been great at automating games. We don't have any particular support for the frameworks used to create games. Unity is a popular one, for example. What if we could write an Appium driver that talked to an embedded process in a test version of a Unity game, that allowed us to find and interact with 3d elements? It would be amazing! You can also be amazing and lead Appium into this new world.|
|
||||
|Testing the Internet of Things|Appium's architecture makes it dead simple to integrate drivers for automating new technologies. What about _really_ new technologies like IoT devices? Help to redefine the semantics of the WebDriver protocol for use with IoT, and build a driver for an IoT device to prove it out.|
|
||||
|Driver for X|Have an idea of something else Appium could automate that it doesn't already? Build a driver for it! This would involve some awesome Node.js code, plus whatever else is needed to integrate with the platform you have in mind.|
|
||||
|
||||
Hopefully this gives you some ideas of fun projects that would be substantial and long-lasting contributions to the Appium community.
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2012-2016 Sauce Labs, Inc.
|
||||
Copyright 2012-2016 JS Foundation and other contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
[](https://team-appium.ci.cloudbees.com/job/Appium/)
|
||||
|
||||
Appium is an open source, cross-platform test automation tool for native, hybrid and mobile web apps, tested on simulators (iOS, FirefoxOS), emulators (Android), and real devices (iOS, Android, Windows, FirefoxOS).
|
||||
Appium is an open source, cross-platform test automation tool for native, hybrid and mobile web and desktop apps, tested on simulators (iOS), emulators (Android), and real devices (iOS, Android, Windows, Mac).
|
||||
|
||||
|
||||
### Supported Platforms
|
||||
@@ -18,7 +18,7 @@ Appium is an open source, cross-platform test automation tool for native, hybrid
|
||||
* iOS
|
||||
* Android
|
||||
* Windows
|
||||
* FirefoxOS
|
||||
* Mac
|
||||
|
||||
See the [platform support doc](/docs/en/appium-setup/platform-support.md) for more detailed information.
|
||||
|
||||
@@ -77,15 +77,16 @@ You also need to download the Appium client for your language so you can write t
|
||||
* [linux](/docs/en/appium-setup/running-on-linux.md)
|
||||
* [osx](/docs/en/appium-setup/running-on-osx.md)
|
||||
* [windows](/docs/en/appium-setup/running-on-windows.md)
|
||||
|
||||
|
||||
#### Windows Requirements
|
||||
|
||||
* Windows 10
|
||||
* [Documentation](/docs/en/appium-setup/running-on-windows.md)
|
||||
|
||||
#### FirefoxOS Requirements
|
||||
#### Mac Requirements
|
||||
|
||||
* [Firefox OS Simulator](https://developer.mozilla.org/en/docs/Tools/Firefox_OS_Simulator)
|
||||
* Mac OS X 10.7 +
|
||||
* [Documentation](https://github.com/penguinho/appium/blob/mac-driver/docs/en/appium-setup/running-on-osx.md#testing-mac-apps)
|
||||
|
||||
### Quick Start
|
||||
|
||||
@@ -99,7 +100,14 @@ $ npm install -g appium
|
||||
$ appium
|
||||
```
|
||||
|
||||
#### Using the App
|
||||
As we said above, you may want to run `appium-doctor` to ensure your system is set up properly:
|
||||
|
||||
```
|
||||
$ npm install -g appium-doctor
|
||||
$ appium-doctor
|
||||
```
|
||||
|
||||
#### Using the Appium Desktop App
|
||||
|
||||
* [Download the Appium app](https://bitbucket.org/appium/appium.app/downloads/)
|
||||
* Run it!
|
||||
@@ -108,6 +116,8 @@ $ appium
|
||||
|
||||
The main guide for getting started writing and running tests is [the running tests](/docs/en/writing-running-appium/running-tests.md) doc, which includes explanations for iOS, Android, and Android older devices. If you're interested in testing on physical hardware, you might be interested in our [real devices guide](/docs/en/appium-setup/real-devices.md).
|
||||
|
||||
(*Note*: If you're automating iOS 10+, be sure to check out our [XCUITest Migration Guide](/docs/en/advanced-concepts/migrating-to-xcuitest.md) since Apple's automation support has changed significantly since iOS 10, with corresponding changes in Appium).
|
||||
|
||||
Essentially, we support a subset of the [Selenium WebDriver JSON Wire Protocol](https://w3c.github.io/webdriver/webdriver-spec.html), and extend it so that you can specify mobile-targeted [desired capabilities](/docs/en/writing-running-appium/caps.md) to run your test through Appium.
|
||||
|
||||
You find elements by using a subset of WebDriver's element-finding strategies.
|
||||
@@ -124,18 +134,15 @@ For the full list of Appium doc pages, visit [this directory](/docs/en/).
|
||||
Appium drives various native automation frameworks and provides an API based on
|
||||
Selenium's [WebDriver JSON wire protocol](https://w3c.github.io/webdriver/webdriver-spec.html).
|
||||
|
||||
Appium drives Apple's UIAutomation library for iOS support, which is based on
|
||||
[Dan Cuellar's](http://github.com/penguinho) work on iOS Auto.
|
||||
For new iOS versions (9.3 and up), Appium drives Apple's XCUITest library. Our support for XCUITest utilizes Facebook's [WebDriverAgent](https://github.com/facebook/webdriveragent) project.
|
||||
|
||||
For older iOS versions (9.3 and below), Appium drives Apple's UIAutomation library, using a strategy which is based on [Dan Cuellar's](http://github.com/penguinho) work on iOS Auto.
|
||||
|
||||
Android support uses the UiAutomator framework for newer platforms and
|
||||
[Selendroid](http://github.com/DominikDary/selendroid) for older Android platforms.
|
||||
|
||||
Windows support uses Microsoft's [WinAppDriver](https://github.com/Microsoft/WinAppDriver)
|
||||
|
||||
FirefoxOS support leverages [Marionette](https://developer.mozilla.org/en-US/docs/Marionette),
|
||||
an automation driver that is compatible with WebDriver and is used to automate
|
||||
Gecko-based platforms.
|
||||
|
||||
### Contributing
|
||||
|
||||
Please take a look at our [contribution documentation](CONTRIBUTING.md)
|
||||
@@ -145,11 +152,12 @@ for instructions on how to build, test and run Appium from source.
|
||||
|
||||
Interested in where Appium is heading in the future? Check out the [Roadmap](ROADMAP.md)
|
||||
|
||||
### Project Credits & Inspiration
|
||||
### Project History, Credits & Inspiration
|
||||
|
||||
[Credits](/docs/en/contributing-to-appium/credits.md)
|
||||
* [History](http://appium.io/history)
|
||||
* [Credits](/docs/en/contributing-to-appium/credits.md)
|
||||
|
||||
### Mailing List
|
||||
### User Forums
|
||||
|
||||
Announcements and debates often take place on the [Discussion Group](https://discuss.appium.io), be sure to sign up!
|
||||
|
||||
|
||||
@@ -17,31 +17,41 @@ exists to outline large-scale future plans for Appium.
|
||||
|
||||
| Project | Description | ETD | Projected Appium Release |
|
||||
|---------|-------------|-----|--------------------------|
|
||||
|[Architecture Overhaul](https://github.com/appium/appium/issues/5169)|Appium's architecture has grown unwieldy enough that adding new features and preventing regressions has become difficult. A rearchitecture is in order to solve these issues as well as migrate the codebase to a form of JS much easier to work in and understand.|1/2016|1.5|
|
||||
|XCUITest backend integration|Instruments + UIAutomation has been working well for many Appium users, but requires crazy workarounds to deal with bugs which remain unfixed on the Apple side. We should explore Apple's newer technology, XCUITest, in order to see if the overall experience is more stable. This new backend would exist alongside the UIAutomation backend.|3/2016?|Beta in 1.6?|
|
||||
|UiAutomator2 backend integration|Google has released [UiAutomator 2](http://developer.android.com/reference/android/support/test/uiautomator/package-summary.html), and it promises to fix some issues and limitations with the previous UiAutomator support. We will build this inside of Selendroid since it requires an instrumentation context.|3/2016?|TBD|
|
||||
|iOS 9.3 support|Appium should support iOS 9.3 / Xcode 7.3|2/2016|1.6?||
|
||||
|[Appium CI + Metrics Improvements](https://github.com/appium/appium/issues/7168)|We have CI servers running via Cloudbees that we don't understand and which break. Let's document and own them so they work reliably. Also, let's implement gathering various metrics about driver performance so we can track this over time and ensure we're not releasing a driver which has decreased in performance or reliability.|Q2 2017|N/A|
|
||||
|
||||
## Upcoming Projects (in rough order of priority)
|
||||
|
||||
| Project | Description |
|
||||
|---------|-------------|
|
||||
|Apple Watch support|Appium should support Apple Watch apps via the Watch simulator|
|
||||
|Onboarding Overhaul|The current Appium docs leave a lot to be desired. The format is confusing (it would be better for API docs), the content is outdated, and many things are still undocumented. This project would go back to the drawing board in all of these areas and put together something genuinely helpful for the community, which hopefully reduces the kind of support issues we're currently flooded by.|
|
||||
|New Appium GUIs|The current Appium GUIs (Appium.app and Appium.exe) have a number of issues. They aren't maintained by the core Appium team. They're written in Objective-C and C# respectively: two languages, and specifically, two languages other than Appium's core language. Because of this they lag behind the Appium server and are often broken. However, users love them primarily because of the Inspector feature (the thing that lets them graphically navigate their app), so we have to field a ton of complaints about these projects. There's an opportunity to start over. With [Electron](http://electron.atom.io/), we'd be able to take the new version of Appium we're working on and embed it directly inside a Node-based GUI app written using the languages and technologies the core team is experienced with. We'd have one codebase and could distribute the app on Mac, Windows, and Linux. The GUIs would become an official part of Appium's release cycle so they wouldn't be broken.|
|
||||
|Unity3d backend POC|This is a research project to determine whether we can add some kind of support for 3d game automation, probably based on the Unity3d game development platform.|
|
||||
|Dynamic Test App|Our current test applications (the ones used to test Appium's iOS and Android support) are not ideal. We use too many of them and the ones we use have a random hodgepodge of app SDK features, sometimes not enough to sufficiently test automation support. Using [Titanium](https://github.com/appcelerator/titanium_mobile), we can develop an app that allows us to inject whatever native code we need, as we need it. The app thus changes itself test-by-test to have whatever UI features we need for that particular test. It gives us much more fine-grained control over what we're testing. The app code would also be cross-platform and written in JS, which would make it easier for the core team to write and maintain.|
|
||||
|[Onboarding Overhaul](https://github.com/appium/appium/issues/7169)|The current Appium docs leave a lot to be desired. The format is confusing (it would be better for API docs), the content is outdated, and many things are still undocumented. This project would go back to the drawing board in all of these areas and put together something genuinely helpful for the community, which hopefully reduces the kind of support issues we're currently flooded by.|
|
||||
|[Appium Client Library Updates](https://github.com/appium/appium/issues/7170)|It's been too long since we ensured that Appium's client libraries were up to date with the server|
|
||||
|[Sample Code Overhaul](https://github.com/appium/appium/issues/7171)|Our sample code repo has grown tangled and broken. Let's make a new one with minimal examples which are the same across every language, and actually maintain the repo so as not to let it become overgrown.|
|
||||
|[Test App Overhaul](https://github.com/appium/appium/issues/7172)|Our current test applications (the ones used to test Appium's iOS and Android support) are not ideal. We use too many of them and the ones we use have a random hodgepodge of app SDK features, sometimes not enough to sufficiently test automation support. It'd be great to find a way to ensure our test app(s) have all the features we need to test, and keep in sync with our requirements.|
|
||||
|[iOS Test Startup Time Improvement](https://github.com/appium/appium/issues/7173)|iOS startup times have gotten progressively longer with each iOS release. In part this is Apple's fault and there's not anything we can do about it. But we should investigate and see if we can be more efficient in how we start, especially given that we can now focus on XCUITest and leave Instruments behind|
|
||||
|[Appium Dearchitecture](https://github.com/appium/appium/issues/7174)|OK, we went a bit overboard in Appium 1.5 by exploding Appium into 40+ repos and NPM packages. Let's think a little more critically about it and consolidate into the minimal number of repos/packages that make sense for our code and community patterns.|
|
||||
|[Appium 2.0](https://github.com/appium/appium/issues/7175)|Appium, rather than bundling all the separate drivers by default, becomes a driver management interface (in addition to continuing to play the role of automation frontend server). Appium gets a set of CLI tools for users to pick and choose which drivers and versions of drivers they want to use via Appium|
|
||||
|
||||
## Projects Under Consideration (unprioritized)
|
||||
## Projects Under Consideration (unplanned and unprioritized)
|
||||
|
||||
| Project | Description |
|
||||
|---------|-------------|
|
||||
|Windows Phone Support|There has been some work done on automating Windows Phone apps. We could take this all the way to integration with Appium in the form of a WindowsDriver.|
|
||||
|Apple Watch support|Appium should support Apple Watch apps via the Watch simulator|
|
||||
|Unity3d backend POC|This is a research project to determine whether we can add some kind of support for 3d game automation, probably based on the Unity3d game development platform.|
|
||||
|
||||
## Completed Roadmap Projects
|
||||
|
||||
| Project | Description | Completed | Appium Release | Notes |
|
||||
|---------|-------------|-----------|----------------|-------|
|
||||
|[New Appium GUIs](https://github.com/appium/appium/issues/7167)|The current Appium GUIs (Appium.app and Appium.exe) have a number of issues. They aren't maintained by the core Appium team. They're written in Objective-C and C# respectively: two languages, and specifically, two languages other than Appium's core language. Because of this they lag behind the Appium server and are often broken. However, users love them primarily because of the Inspector feature (the thing that lets them graphically navigate their app), so we have to field a ton of complaints about these projects. There's an opportunity to start over. With [Electron](http://electron.atom.io/), we'd be able to take the new version of Appium we're working on and embed it directly inside a Node-based GUI app written using the languages and technologies the core team is experienced with. We'd have one codebase and could distribute the app on Mac, Windows, and Linux. The GUIs would become an official part of Appium's release cycle so they wouldn't be broken.|3/2017|N/A|[Appium Desktop website](https://github.com/appium/appium-desktop)|
|
||||
|[Android 7.1.1 Support](https://github.com/appium/appium/issues/7165)|Google has released Android 7.1.1 (API Level 25). Ensure it works with UiAutomator 1/2|2/2017|1.6.4||
|
||||
|[Android 7.0 Support](https://github.com/appium/appium/issues/7156)|Support Android 7 (Nougat)|11/2016|1.6.3||
|
||||
|[iOS 10.2 Support](https://github.com/appium/appium/issues/7166)|Support iOS 10.2|11/2016|1.6.1||
|
||||
|[iOS 10.1 Support](https://github.com/appium/appium/issues/7105)|Support iOS 10.1|11/2016|1.6.1||
|
||||
|UiAutomator2 integration|Google has released [UiAutomator 2](http://developer.android.com/reference/android/support/test/uiautomator/package-summary.html), and it promises to fix some issues and limitations with the previous UiAutomator support. We will build this inside of Selendroid since it requires an instrumentation context.|10/2016?|1.6.0|
|
||||
|XCUITest integration / iOS 10 support|Instruments + UIAutomation has been working well for many Appium users, but requires crazy workarounds to deal with bugs which remain unfixed on the Apple side. Also, UIAutomation has been removed in favor of XCUITest for iOS 10+. This new backend would exist alongside the UIAutomation backend.|10/2016|1.6.0||
|
||||
|iOS 9.3 support|Appium should support iOS 9.3 / Xcode 7.3|3/2016|1.5.1||
|
||||
|[Architecture Overhaul](https://github.com/appium/appium/issues/5169)|Appium's architecture has grown unwieldy enough that adding new features and preventing regressions has become difficult. A rearchitecture is in order to solve these issues as well as migrate the codebase to a form of JS much easier to work in and understand.|2/2015|1.5.0||
|
||||
|iOS 9.2 support|Appium should support iOS 9.2 / Xcode 7.2|11/2015|1.4.14||
|
||||
|iOS 9.1 support|Appium should support iOS 9.1 / Xcode 7.1|10/2015|1.4.12||
|
||||
|iOS 9.0 support|Appium should support iOS 9.0 / Xcode 7.0|10/2015|1.4.11||
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
## Introduction to Appium
|
||||
|
||||
Appium is an open-source tool for automating native,
|
||||
mobile web, and hybrid applications on iOS and Android platforms.
|
||||
**Native apps** are those written using the iOS, Android, or Windows SDKs. **Mobile web apps** are web apps accessed using a mobile browser (Appium supports
|
||||
Safari on iOS and Chrome or the built-in 'Browser' app on Android). **Hybrid apps** have a
|
||||
wrapper around a "webview" -- a native control that enables interaction with
|
||||
web content. Projects like [Phonegap](http://phonegap.com/),
|
||||
make it easy to build apps using web technologies that are then bundled into
|
||||
a native wrapper, creating a hybrid app.
|
||||
Appium is an open-source tool for automating native, mobile web, and hybrid applications on iOS mobile, Android mobile, and Windows desktop platforms. **Native apps** are those written using the iOS, Android, or Windows SDKs. **Mobile web apps** are web apps accessed using a mobile browser (Appium supports Safari on iOS and Chrome or the built-in 'Browser' app on Android). **Hybrid apps** have a wrapper around a "webview" -- a native control that enables interaction with web content. Projects like [Phonegap](http://phonegap.com/), make it easy to build apps using web technologies that are then bundled into a native wrapper, creating a hybrid app.
|
||||
|
||||
Importantly, Appium is "cross-platform": it allows you to write tests against
|
||||
multiple platforms (iOS, Android, Windows), using the same API. This enables code reuse between iOS, Android, and Windows testsuites.
|
||||
@@ -31,10 +24,11 @@ meet requirement #1 by using vendor-provided automation frameworks under the
|
||||
hood. That way, we don't need to compile in any Appium-specific or
|
||||
third-party code or frameworks to your app. This means **you're testing the same app you're shipping**. The vendor-provided frameworks we use are:
|
||||
|
||||
* iOS: Apple's [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
|
||||
* iOS 9.3 and above: Apple's [XCUITest](https://developer.apple.com/reference/xctest)
|
||||
* iOS 9.3 and lower: Apple's [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
|
||||
* Android 4.2+: Google's [UiAutomator](http://developer.android.com/tools/help/uiautomator/index.html)
|
||||
* Android 2.3+: Google's [Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html). (Instrumentation support is provided by bundling a separate project, [Selendroid](http://selendroid.io))
|
||||
* Windows: Microsoft's [WinAppDriver](http://github.com/microsoft/winappdriver)
|
||||
* Windows: Microsoft's [WinAppDriver](http://github.com/microsoft/winappdriver)
|
||||
|
||||
We meet requirement #2 by wrapping the vendor-provided frameworks in one API,
|
||||
the [WebDriver](http://docs.seleniumhq.org/projects/webdriver/) API.
|
||||
|
||||
@@ -31,18 +31,18 @@ Here are the steps required to talk to a web view in your Appium test:
|
||||
// javascript
|
||||
// assuming we have an initialized `driver` object for an app
|
||||
driver
|
||||
.contexts().then(function (contexts) { // get list of available views. Returns array: ["NATIVE_APP","WEBVIEW_1"]
|
||||
return driver.context(contexts[1]); // choose the webview context
|
||||
})
|
||||
.contexts().then(function (contexts) { // get list of available views. Returns array: ["NATIVE_APP","WEBVIEW_1"]
|
||||
return driver.context(contexts[1]); // choose the webview context
|
||||
})
|
||||
|
||||
// do some web testing
|
||||
.elementsByCss('.green_button').click()
|
||||
// do some web testing
|
||||
.elementsByCss('.green_button').click()
|
||||
|
||||
.context('NATIVE_APP') // leave webview context
|
||||
.context('NATIVE_APP') // leave webview context
|
||||
|
||||
// do more native stuff here if we want
|
||||
// do more native stuff here if we want
|
||||
|
||||
.quit() // stop webdrivage
|
||||
.quit() // stop webdrivage
|
||||
```
|
||||
|
||||
```java
|
||||
@@ -52,7 +52,7 @@ driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities)
|
||||
|
||||
Set<String> contextNames = driver.getContextHandles();
|
||||
for (String contextName : contextNames) {
|
||||
System.out.println(contextNames); //prints out something like NATIVE_APP \n WEBVIEW_1
|
||||
System.out.println(contextNames); //prints out something like NATIVE_APP \n WEBVIEW_1
|
||||
}
|
||||
driver.context(contextNames.toArray()[1]); // set context to WEBVIEW_1
|
||||
|
||||
@@ -76,18 +76,18 @@ driver.quit();
|
||||
# Then switch to it using @driver.switch_to.context("WEBVIEW_6")
|
||||
|
||||
Given(/^I switch to webview$/) do
|
||||
webview = @driver.contexts.last
|
||||
@driver.switch_to.context(webview)
|
||||
webview = @driver.contexts.last
|
||||
@driver.switch_to.context(webview)
|
||||
end
|
||||
|
||||
Given(/^I switch out of webview$/) do
|
||||
@driver.switch_to.context(@driver.contexts.first)
|
||||
@driver.switch_to.context(@driver.contexts.first)
|
||||
end
|
||||
|
||||
# Now you can use CSS to select an element inside your webview
|
||||
|
||||
And(/^I click a webview button $/) do
|
||||
@driver.find_element(:css, ".green_button").click
|
||||
@driver.find_element(:css, ".green_button").click
|
||||
end
|
||||
```
|
||||
|
||||
@@ -116,23 +116,23 @@ driver.quit()
|
||||
|
||||
public function testThings()
|
||||
{
|
||||
$expected_contexts = array(
|
||||
0 => 'NATIVE_APP',
|
||||
1 => 'WEBVIEW_1'
|
||||
);
|
||||
$expected_contexts = array(
|
||||
0 => 'NATIVE_APP',
|
||||
1 => 'WEBVIEW_1'
|
||||
);
|
||||
|
||||
$contexts = $this->contexts();
|
||||
$this->assertEquals($expected_contexts, $contexts);
|
||||
$contexts = $this->contexts();
|
||||
$this->assertEquals($expected_contexts, $contexts);
|
||||
|
||||
$this->context($contexts[1]);
|
||||
$context = $this->context();
|
||||
$this->assertEquals('WEBVIEW_1', $context);
|
||||
$this->context($contexts[1]);
|
||||
$context = $this->context();
|
||||
$this->assertEquals('WEBVIEW_1', $context);
|
||||
|
||||
// do webby stuff
|
||||
// do webby stuff
|
||||
|
||||
$this->context('NATIVE_APP');
|
||||
$this->context('NATIVE_APP');
|
||||
|
||||
// do mobile stuff
|
||||
// do mobile stuff
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -50,12 +50,27 @@ Once installed you can start the proxy with the following command:
|
||||
> ios_webkit_debug_proxy -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d
|
||||
```
|
||||
|
||||
You may also use the ios-webkit-debug-proxy-launcher to launch the
|
||||
You can also set the desired capability called 'startIWDP' to true (https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md). This will run the above command as a subprocess from within Appium and will set the udid, so you don't have to run ios_webkit_debug_proxy yourself anymore. It monitors the proxy for crashes and relaunches when needed.
|
||||
|
||||
``` center
|
||||
// example desired capabilities
|
||||
{
|
||||
"browserName": "Safari",
|
||||
"platformName": "iOS",
|
||||
"deviceName": "iPhone 7",
|
||||
"automationName": "XCUITest",
|
||||
"startIWDP": true,
|
||||
"udid": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
You may also use `ios-webkit-debug-proxy-launcher`, a small script included with the Appium codebase, to launch the
|
||||
proxy. It monitors the proxy log for errors, and relaunch the proxy
|
||||
where needed. This is also optional and may help with recent devices:
|
||||
|
||||
``` center
|
||||
# change the udid
|
||||
# note, this is run from an Appium repository
|
||||
> ./bin/ios-webkit-debug-proxy-launcher.js -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d
|
||||
```
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
## Setting up instruments without delay (iwd) for xcode 7 and iOS >= 9.0
|
||||
|
||||
For iOS >= 9.0 instruments without delay (iwd) does not work by passing binaries through
|
||||
the command line (appium does this under the hood for xcode < 7). See [iwd](https://github.com/lawrencelomax/instruments-without-delay/tree/xcode7-quirks#xcode-7--ios-9-support)
|
||||
For iOS >= 9.0 instruments without delay (iwd) does not work by passing binaries through the command line (appium does this under the hood for xcode < 7). See [iwd](https://github.com/lawrencelomax/instruments-without-delay/tree/xcode7-quirks#xcode-7--ios-9-support)
|
||||
|
||||
For enabling iwd for xcode >= 7,
|
||||
- Checkout [appium-instruments](https://github.com/appium/appium-instruments)
|
||||
- Run `xcode-iwd.sh` present in `<appium-instruments>/bin/`
|
||||
- Check out [appium-instruments](https://github.com/appium/appium-instruments)
|
||||
- Run `xcode-iwd.sh` present in `<appium-instruments>/bin/`, with arguments as indicated below:
|
||||
|
||||
```
|
||||
sh <appium-instruments>/bin/xcode-iwd.sh <path to xcode> <path to appium-instruments>
|
||||
```
|
||||
eg. `sh ./bin/xcode-iwd.sh /Applications/Xcode.app /Users/xyz/appium-instruments/`
|
||||
|
||||
Note: iwd with xcode7 will only work for iOS >= 9.0, you can switch to older xcode for iOS < 9.0
|
||||
Note: iwd with Xcode 7 will only work for iOS >= 9.0, you can switch to an older version of Xcode for iOS < 9.0
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
*This document is old, and only of interest for those migrating to Appium 1.x from an earlier version*
|
||||
|
||||
## Migrating your tests from Appium 0.18.x to Appium 1.x
|
||||
|
||||
Appium 1.0 has removed a number of deprecated features from the previous versions. This guide will help you know what needs to change in your test suite to take advantage of Appium 1.0.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Migrating your iOS tests from UIAutomation (iOS 9.2 and below) to XCUITest (iOS 9.3 and up)
|
||||
## Migrating your iOS tests from UIAutomation (iOS 9.3 and below) to XCUITest (iOS 9.3 and up)
|
||||
|
||||
For iOS automation, Appium relies on system frameworks provided by Apple. For iOS 9.2 and below, Apple's only automation technology was called UIAutomation, and it ran in the context of a process called "Instruments". As of iOS 10, Apple has completely removed the UIAutomation instrument, thus making it impossible for Appium to allow testing in the way it used to. Fortunately, Apple introduced a new automation technology, called XCUITest, beginning with iOS 9.3. For iOS 10 and up, this will be the only supported automation framework from Apple.
|
||||
|
||||
@@ -21,6 +21,61 @@ As mentioned just above, if you rely on the app source XML from the `page source
|
||||
|
||||
This locator strategy was specifically built on UIAutomation, so it is not included in the XCUITest automation backend. We will be working on a similar "native"-type locator strategy in coming releases.
|
||||
|
||||
### `xpath` locator strategy
|
||||
|
||||
1. Try not to use XPath locators unless there is absolutely no other alternatives. In general, xpath locators might be times slower, than other types of locators like accessibility id, class name and predicate (up to 100 times slower in some special cases). They are so slow, because xpath location is not natively supported by Apple's XCTest framework.
|
||||
2. Use
|
||||
|
||||
```
|
||||
driver.findElement(x)
|
||||
```
|
||||
|
||||
call instead of
|
||||
|
||||
```
|
||||
driver.findElements(x)[0]
|
||||
```
|
||||
|
||||
to lookup single element by xpath. The more possible UI elements are matched by your locator the slower it is.
|
||||
3. Be very specific when locating elements by xpath. Such locators like
|
||||
|
||||
```
|
||||
//*
|
||||
```
|
||||
|
||||
may take minutes to complete depending on how many UI elements your application has (e. g.
|
||||
|
||||
```
|
||||
driver.findElement(By.xpath("//XCUIElementTypeButton[@value='blabla']"))
|
||||
```
|
||||
|
||||
is faster than
|
||||
|
||||
```
|
||||
driver.findElement(By.xpath("//*[@value='blabla']"))
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
driver.findElement(By.xpath("//XCUIElementTypeButton")))
|
||||
```
|
||||
|
||||
4. In most cases it would be faster to perform multiple nested findElement calls than to perform a single call by xpath (e.g.
|
||||
|
||||
```
|
||||
driver.findElement(x).findElement(y)
|
||||
```
|
||||
|
||||
is usually faster than
|
||||
|
||||
```
|
||||
driver.findElement(z)
|
||||
|
||||
```
|
||||
|
||||
where x and y are non-xpath locators and z is a xpath locator).
|
||||
|
||||
### System dependencies
|
||||
|
||||
In addition to the many gotchas that might come with upgrading any XCode installation (unrelated to Appium), Appium's XCUITest support requires a new system dependency: [Carthage](https://github.com/Carthage/Carthage). Appium Doctor has now been updated to ensure that the `carthage` binary is on your path.
|
||||
@@ -35,10 +90,21 @@ Unfortunately, the XCUITest API and the UIAutomation API are not equivalent. In
|
||||
|
||||
We will endeavor to add these features back in future releases of Appium.
|
||||
|
||||
#### Scrolling and clicking
|
||||
|
||||
In the previous UIAutomation-based driver, if you tried to click on an element that wasn't in view, UIAutomation would scroll to the element automatically and then tap it. With XCUITest, this is no longer the case. You are now responsible for ensuring your element is in view before interacting with it (the same way a user would be responsible for the same).
|
||||
|
||||
### Other known issues
|
||||
|
||||
Finally, a list of known issues with the initial 1.6 release:
|
||||
Finally, a list of known issues with the initial 1.6 release (we'll strike through issues which have been resolved):
|
||||
|
||||
* [Problems with processArguments](https://github.com/appium/appium/issues/6888)
|
||||
* ~~Unable to interact with elements on devices in Landscape mode (https://github.com/appium/appium/issues/6994)~~
|
||||
* `shake` is not implemented due to lack of support from Apple
|
||||
* `lock` is not implemented due to lack of support from Apple
|
||||
* Setting geo-location not supported due to lack of support from Apple
|
||||
* Through the TouchAction/MultiAction API, `zoom` gestures work but `pinch` gestures do not, due to an Apple issue.
|
||||
* ~~Through the TouchAction/MultiAction API, `swipe` gestures are currently not supported, though they should be soon (https://github.com/appium/appium/issues/7573)~~
|
||||
* The capabilities `autoAcceptAlerts` and `autoDismissAlerts` do not currently work, and there is continued debate about whether we will be able to implement them in the future.
|
||||
* There is an issue with the iOS SDK such that PickerWheels built using certain API methods are not automatable by XCUITest. See https://github.com/appium/appium/issues/6962 for the workaround, to ensure your PickerWheels are built properly.
|
||||
|
||||
As far as possible, we will add the missing features and fix other known issues in the [1.6.1 Milestone](https://github.com/appium/appium/milestone/27), so following that may be of interest to you.
|
||||
As far as possible, we will add the missing features and fix other known issues in future versions of Appium.
|
||||
|
||||
@@ -21,8 +21,8 @@ Settings are implemented via the following API endpoints:
|
||||
```
|
||||
{
|
||||
settings: {
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -31,10 +31,12 @@ Settings are implemented via the following API endpoints:
|
||||
>Returns a JSON hash of all the currently specified settings.
|
||||
```
|
||||
{
|
||||
ignoreUnimportantViews : true
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
```
|
||||
|
||||
Note that the actual commands you would use in your test script differ based on the language; see the specific Appium client documention for more information.
|
||||
|
||||
### Supported Settings
|
||||
|
||||
**"ignoreUnimportantViews"** - Boolean which sets whether Android devices should use `setCompressedLayoutHeirarchy()` which ignores all views which are marked IMPORTANT_FOR_ACCESSIBILITY_NO or IMPORTANT_FOR_ACCESSIBILITY_AUTO (and have been deemed not important by the system), in an attempt to make things less confusing or faster.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
## Android Setup
|
||||
|
||||
To get started, you'll need to install node.js (v4 or greater). Just
|
||||
To get started, you'll need to install Node.js (v4 or greater). Just
|
||||
follow the [instructions for your flavor of linux](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager).
|
||||
|
||||
Once you've got node.js installed, install the [Android SDK](http://developer.android.com/sdk/index.html).
|
||||
You will need to run the 'android' tool (included in the SDK, under the 'tools' directory).
|
||||
Once you've got Node.js installed, install the [Android SDK](http://developer.android.com/sdk/index.html).
|
||||
You will need to run the `android` tool (included in the SDK, under the 'tools' directory).
|
||||
|
||||
Run the 'android' tool and use it to install an API Level 17 or greater.
|
||||
Run the `android` tool and use it to install an API Level 17 or greater.
|
||||
|
||||
(If you want to run Appium from source, you will also need [Apache Ant](http://ant.apache.org/) to build the bootstrap jar that Appium uses for running against Android simulators/devices.)
|
||||
|
||||
@@ -16,13 +16,12 @@ shell startup:
|
||||
|
||||
export ANDROID_HOME="/usr/local/adt/sdk"
|
||||
|
||||
Now you're set up to run Appium! If you're running Appium from source, run
|
||||
`npm install` from your Appium checkout to install all the
|
||||
dependencies.
|
||||
Now you're set up to run Appium! (If you're running Appium from source, make sure to run `npm install` from your Appium checkout to install all the
|
||||
dependencies.)
|
||||
|
||||
### Additional Setup for Older Versions of Android
|
||||
|
||||
Appium uses, and comes prepackaged with, Selendroid for running Android
|
||||
Appium uses, and comes prepackaged with, a project called [Selendroid](https://selendroid.io) for running Android
|
||||
versions 2.3 to 4.1. Appium switches to using Selendroid automatically when it
|
||||
detects older versions, but there is some additional setup required if you're
|
||||
running from source.
|
||||
@@ -44,7 +43,7 @@ See the [server documentation](/docs/en/writing-running-appium/server-args.md) f
|
||||
limitations. For more information you can check out this
|
||||
[page](/docs/en/appium-setup/android-hax-emulator.md).
|
||||
* Make sure that `hw.battery=yes` in your AVD's `config.ini`, if you want to
|
||||
run any of the Appium tests, or use any of the power commands.
|
||||
* Selendroid requires the following permission for your app:
|
||||
run any of the Appium tests, or use any of the power commands. As of Android 5.0, this is the default.
|
||||
* Selendroid requires the following permission for instrumenting your app:
|
||||
`<uses-permission android:name="android.**permission.INTERNET"/>`,
|
||||
please make sure your app has internet permission set when you are using selendroid or older versions of Android i.e. 2.3 to 4.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Parallel Android Tests
|
||||
|
||||
Appium provides a way for users to automate multiple Android sessions on a single machine. All it involves is starting multiple Appium servers with different flags.
|
||||
Appium provides a way for users to automate multiple Android sessions on a single machine. All it involves is starting multiple Appium servers with different flags.
|
||||
|
||||
The important flags for automating multiple Android sessions are:
|
||||
|
||||
@@ -18,13 +18,13 @@ If we had two devices with the ID's 43364 and 32456, we would start two differen
|
||||
|
||||
`node . -p 4491 -bp 2252 -U 43364`
|
||||
|
||||
As long as your Appium and Appium bootstrap ports are between 0 and 65536, all they have to be is different so that two Appium servers aren't trying to listen on the same port. Be sure that your -u flag corresponds with the correct device ID. This is how Appium knows which device to communicate with, so it must be accurate.
|
||||
As long as your Appium and Appium bootstrap ports are between 0 and 65536, all they have to be is different so that two Appium servers aren't trying to listen on the same port. Be sure that your -u flag corresponds with the correct device ID. This is how Appium knows which device to communicate with, so it must be accurate.
|
||||
|
||||
If you are using chromedriver or selendroid, set a different port for each server.
|
||||
|
||||
### Parallel iOS Tests
|
||||
|
||||
Unfortunately, running local parallel iOS tests aren't possible. Unlike Android, only one version of the iOS simulator can be launched at a time, making it run multiple tests at once.
|
||||
Unfortunately, running local parallel iOS tests isn't currently possible. Unlike Android, only one version of the iOS simulator can be launched at a time, making it run multiple tests at once.
|
||||
|
||||
If you do want to run parallel iOS tests, you need to use Sauce. Simply upload your Appium test to Sauce, and it can run as many parallel iOS or Android tests as your account allows. See more about running your tests on Sauce [here](https://docs.saucelabs.com/tutorials/appium/).
|
||||
|
||||
|
||||
@@ -9,21 +9,21 @@ make explicit the level of support and requirements for each of these.
|
||||
See [Running on OS X: iOS](running-on-osx.md) for iOS requirements and setup
|
||||
instructions.
|
||||
|
||||
* Versions: 7.1, 8.0, 8.1, 8.2, 8.3, 8.4, 9.0, 9.1 and 9.2
|
||||
* Versions: 7.1 and up
|
||||
* Devices: iPhone Simulator, iPad Simulator, and real iPhones and iPads
|
||||
* Native app support: Yes, with debug version of .app (simulator),
|
||||
or correctly-signed .ipa (real devices). Underlying support is provided by
|
||||
Apple's [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
|
||||
Apple's [XCUITest](https://developer.apple.com/reference/xctest) (or [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/) for older versions)
|
||||
framework.
|
||||
* Mobile web support: Yes, via automation of mobile Safari. For real devices,
|
||||
ios-webkit-remote-debugger is required, and automation of native aspects of
|
||||
`ios-webkit-remote-debugger` is required, and automation of native aspects of
|
||||
the Safari interface is not possible. See the [mobile web doc](/docs/en/writing-running-appium/mobile-web.md) for instructions.
|
||||
* Hybrid support: Yes. For real devices, ios-webkit-remote-debugger is
|
||||
required. See the [hybrid doc](/docs/en/advanced-concepts/hybrid.md) for instructions.
|
||||
* Support for automating multiple apps in one session: No
|
||||
* Support for automating multiple devices simultaneously: No
|
||||
* Support for automating vendor-provided or third-party apps: Only
|
||||
vendor-provided apps (Preferences, Maps, etc...), and only on the simulator
|
||||
vendor-provided apps (Preferences, Maps, etc...), and only on the simulator. For iOS 10+, you can automate the home screen as well.
|
||||
* Support for automating custom, non-standard UI controls: Minimal. You need to
|
||||
set accessibility information on the control which enables some basic
|
||||
automation.
|
||||
@@ -62,8 +62,9 @@ instructions.
|
||||
when using the Selendroid backend)
|
||||
* Support for automating custom, non-standard UI controls: No
|
||||
|
||||
### Windows Support
|
||||
### Windows Desktop Support
|
||||
|
||||
See [running on Windows](running-on-windows.md) for details
|
||||
See these docs for details:
|
||||
|
||||
* [Windows App Testing](windows-app-testing.md)
|
||||
* [Running on Windows](running-on-windows.md)
|
||||
* [Windows App Testing](/docs/en/writing-running-appium/windows-app-testing.md)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
## Appium on Android Real Devices
|
||||
|
||||
Hooray! There is nothing extra to know about testing real Android devices: it
|
||||
works exactly the same as testing on emulators. Make sure that your device
|
||||
can connect to ADB and has Developer Mode enabled (the process for this differs
|
||||
for different vendors, so check their documentation). For testing Chrome on a real
|
||||
device, you are responsible for ensuring that Chrome of an appropriate version
|
||||
is installed.
|
||||
|
||||
Also, you will want to make sure that "Verify Apps" in settings is
|
||||
disabled/unchecked, otherwise it can prevent some of Appium's helper apps from
|
||||
launching and doing their job correctly.
|
||||
|
After Width: | Height: | Size: 832 KiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 765 KiB |
|
After Width: | Height: | Size: 928 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 650 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 849 KiB |
@@ -0,0 +1,280 @@
|
||||
## Appium on iOS Real Devices
|
||||
|
||||
Appium has support for iOS real device testing.
|
||||
|
||||
### Running your tests with Appium
|
||||
|
||||
Once your device and app are configured, you can run tests on that device by
|
||||
passing the `udid` desired capability, and the bundle ID (via the `bundleId`
|
||||
capability, if the app is installed on the device) or the path to the `.ipa` or
|
||||
`.app` file via the `app` desired capability.
|
||||
|
||||
### Desired Capabilities
|
||||
|
||||
You can launch the app on a device by including the following desired
|
||||
capabilities in your tests:
|
||||
|
||||
* `app` or `bundleId` - specifies the application, or, if it is already installed,
|
||||
simply the bundle identifier of the app so that Appium can launch it
|
||||
* `udid` - the specific id of the device to test on. This can also be set to
|
||||
`auto` if there is only a single device, in which case Appium will determine
|
||||
the device id and use it
|
||||
|
||||
Refer to the [Appium server capabilities](/docs/en/writing-running-appium/caps.md) page for more detail on
|
||||
the capabilities that you can use.
|
||||
|
||||
### Required Software
|
||||
|
||||
Appium iOS real device support depends on a central third-party software suite,
|
||||
[libimobiledevice](http://www.libimobiledevice.org/), which is easily installable
|
||||
with [Homebrew](http://brew.sh/))
|
||||
```
|
||||
brew install libimobiledevice
|
||||
```
|
||||
|
||||
## Configuring iOS Real Device Tests: Xcode 7 and iOS 9.3 or below
|
||||
|
||||
Automating real devices with iOS 9.3 or below, using Xcode 7.3 or below (i.e.,
|
||||
_Instruments_-based testing) requires a relatively small amount of configuration.
|
||||
The central requirement is to have a build of your app signed with a development
|
||||
provisioning profile. Unfortunately Apple has removed all of its documentation
|
||||
on using older versions of Xcode, but a good overview of the process can be
|
||||
found [here](https://medium.com/ios-os-x-development/ios-code-signing-provisioning-in-a-nutshell-d5b247760bef#.5hirl92tn)
|
||||
and [here](https://engineering.nodesagency.com/articles/iOS/Understanding-code-signing-for-iOS-apps/).
|
||||
|
||||
In a little more detail, to get started on a real device, you will need the following:
|
||||
|
||||
* An [Apple Developer ID](https://developer.apple.com/programs/ios/) and a valid
|
||||
Developer Account with a configured development certificate and provisioning
|
||||
profile.
|
||||
* A valid iOS Development Certificate and Provisioning Profile are necessary to
|
||||
test on a real device. Your app will also need to be signed. You can find
|
||||
information about this in the [Apple documentation](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/TestingYouriOSApp/TestingYouriOSApp.html).
|
||||
* An iPad or iPhone. Make sure this has been set up for development in Xcode.
|
||||
* A signed `.app` or `.ipa` file of your app, or the source code to build one.
|
||||
* A Mac with [Xcode](https://developer.apple.com/xcode/) and the Xcode Command
|
||||
Line Developer Tools.
|
||||
|
||||
Appium handles installing the application to the device, using `ideviceinstaller`
|
||||
(part of `libimobiledevice`), but it is sometimes easier to pre-install your app
|
||||
using Xcode to ensure there are no problems (see the [iOS deploy](ios-deploy.md)
|
||||
document for more information).
|
||||
|
||||
### Troubleshooting ideas
|
||||
|
||||
0. Make sure UDID is correct by checking it in Xcode Organizer or iTunes. It
|
||||
is a long string (20+ chars).
|
||||
0. Make sure that you can run your tests against the Simulator.
|
||||
0. Double check that you can invoke your automation from Instruments.
|
||||
0. Make sure Instruments is not already running.
|
||||
0. Make sure UI Automation is enabled on your device. Settings -> Developer -> Enable UI Automation
|
||||
|
||||
|
||||
|
||||
## Configuring iOS Real Device Tests: Xcode 8 and iOS 9.3 and above
|
||||
|
||||
In addition to the dependency on `libimobiledevice`, Appium support for real
|
||||
devices running iOS 9.3 and above using Xcode 8+ also depends on `ios-deploy`,
|
||||
which is easily available through [npm](https://www.npmjs.com/package/ios-deploy)
|
||||
```
|
||||
npm install -g ios-deploy
|
||||
```
|
||||
|
||||
Unfortunately, Apple changed the way it makes testing available, and the new
|
||||
way requires the installation of a helper application onto the device, through
|
||||
which the application under test is automated. While this is simple in theory,
|
||||
the hoops of code signing and provisioning applications for development and
|
||||
testing can make this a bit of a headache.
|
||||
|
||||
The application that Appium installs is called `WebDriverAgent-Runner` (found
|
||||
[here](https://github.com/facebook/WebDriverAgent/)), and to do the install
|
||||
Appium needs to be able to configure its build.
|
||||
|
||||
|
||||
### Basic (automatic) configuration
|
||||
|
||||
The easiest way to get up-and-running with Appium's XCUITest support on iOS
|
||||
real devices is to use the automatic configuration strategy. There are two ways
|
||||
to do this:
|
||||
|
||||
* Use the `xcodeOrgId` and `xcodeSigningId` desired capabilities:
|
||||
```json
|
||||
{
|
||||
"xcodeOrgId": "<Team ID>",
|
||||
"xcodeSigningId": "iPhone Developer"
|
||||
}
|
||||
```
|
||||
* Create a `.xcconfig` file somewhere on your file system and add the following to it:
|
||||
```
|
||||
DEVELOPMENT_TEAM = <Team ID>
|
||||
CODE_SIGN_IDENTITY = iPhone Developer
|
||||
```
|
||||
In either case, the Team ID is a unique 10-character string generated by Apple
|
||||
that is assigned to your team. You can find your Team ID using your developer
|
||||
account. Sign in to [developer.apple.com/account](http://developer.apple.com/account),
|
||||
and click Membership in the sidebar. Your Team ID appears in the Membership
|
||||
Information section under the team name. You can also find your team ID listed
|
||||
under the "Organizational Unit" field in your iPhone Developer certificate in
|
||||
your keychain.
|
||||
|
||||
Note that these are mutually exclusive strategies; use _either_ the
|
||||
`xcodeConfigFile` capability or the combination of `xcodeOrgId` and `xcodeSigningId`.
|
||||
|
||||
Once this configuration is done, it should just be a matter of starting your test
|
||||
specifying a real device in your `udid` desired capability.
|
||||
|
||||
If this has not worked it will usually manifest itself in the Appium server logs
|
||||
as some error followed by `info XCUITest xcodebuild exited with code '65' and
|
||||
signal 'null'`. This usually means that the necessary code signing is not set up
|
||||
correctly. Go on to the [Basic (manual) configuration](https://github.com/imurchie/appium-xcuitest-driver/blob/isaac-rs/docs/real-device-config.md#basic-manual-configuration)
|
||||
to fix.
|
||||
|
||||
If the `WebDriverAgentRunner` is successfully installed on the device, but in the
|
||||
Appium logs there is an error message something like:
|
||||
```
|
||||
2017-01-24 09:02:18.358 xcodebuild[30385:339674] Error Domain=com.apple.platform.iphoneos Code=-12 "Unable to launch com.apple.test.WebDriverAgentRunner-Runner" UserInfo={NSLocalizedDescription=Unable to launch com.apple.test.WebDriverAgentRunner-Runner, NSUnderlyingError=0x7fa839cadc60 {Error Domain=DTXMessage Code=1 "(null)" UserInfo={DTXExceptionKey=The operation couldn’t be completed. Unable to launch com.apple.test.WebDriverAgentRunner-Runner because it has an invalid code signature, inadequate entitlements or its profile has not been explicitly trusted by the user. : Failed to launch process with bundle identifier 'com.apple.test.WebDriverAgentRunner-Runner'}}}
|
||||
2017-01-24 09:02:18.358 xcodebuild[30385:339674] Error Domain=IDETestOperationsObserverErrorDomain Code=5 "Early unexpected exit, operation never finished bootstrapping - no restart will be attempted" UserInfo={NSLocalizedDescription=Early unexpected exit, operation never finished bootstrapping - no restart will be attempted}
|
||||
|
||||
Testing failed:
|
||||
Test target WebDriverAgentRunner encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted)
|
||||
```
|
||||
The problem is that the developer is not trusted on the device. If you manually
|
||||
try to run the `WebDriverAgentRunner` app on the device, you will see a popup
|
||||
message:
|
||||
|
||||

|
||||
|
||||
You can go to Settings => General => Device Management on the device to trust
|
||||
the developer and allow the `WebDriverAgentRunner` app to be run (see [Apple
|
||||
documentation for more information](https://support.apple.com/en-us/HT204460)).
|
||||
|
||||
|
||||
### Basic (manual) configuration
|
||||
|
||||
There are many cases in which the basic automatic configuration is not enough. This
|
||||
usually has to do with code signing and the configuration of the project to be
|
||||
able to be run on the real device under test. Often this happens when the
|
||||
development account being used is a "Free" one, in which case it is not possible
|
||||
to create a wildcard provisioning profile, and will often not create one for the
|
||||
default application bundle.
|
||||
|
||||
This will manifest as something like an error that Xcode **failed to create
|
||||
provisioning profile**:
|
||||
|
||||

|
||||
|
||||
The easiest way around this is to create a provisioning profile by opening
|
||||
[Xcode](https://developer.apple.com/xcode/) and creating a new project:
|
||||
|
||||

|
||||
|
||||
The type does not matter, other than it being "iOS". "Single View Application"
|
||||
is the easiest:
|
||||
|
||||

|
||||
|
||||
The important part is to use a unique "Product Name" and "Organization Name". Also,
|
||||
at this point, specify your "Team".
|
||||
|
||||

|
||||
|
||||
You can confirm that the provisioning profile was created by looking at the "Project"
|
||||
tab:
|
||||
|
||||

|
||||
|
||||
Or by going into your account preferences and seeing the provisioning profile:
|
||||
|
||||

|
||||
|
||||
At this point you have a valid provisioning profile. Make note of the bundle id
|
||||
you associated with it, and add that in the `updatedWDABundleId` desired
|
||||
capability for your tests. Then follow the [initial instructions for automatic
|
||||
configuration](#basic-automatic-configuration).
|
||||
|
||||
|
||||
### Full manual configuration
|
||||
|
||||
Alternatively, the provisioning profile can be manually associated with the
|
||||
project (keep in mind that this will have to be done each time the WebDriverAgent
|
||||
is updated, and is _not_ recommended):
|
||||
|
||||
* Find out where your Appium installation is:
|
||||
```
|
||||
$ which appium
|
||||
/path/where/installed/bin/appium
|
||||
```
|
||||
* Given this installation location, `/path/where/installed/bin/appium`, `WebDriverAgent`
|
||||
will be found in `/path/where/installed/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent`.
|
||||
Open a terminal and go to that location, then run the following in order to
|
||||
set the project up:
|
||||
```
|
||||
mkdir -p Resources/WebDriverAgent.bundle
|
||||
./Scripts/bootstrap.sh -d
|
||||
```
|
||||
* Open `WebDriverAgent.xcodeproj` in Xcode. For **both** the `WebDriverAgentLib`
|
||||
and `WebDriverAgentRunner` targets, select "Automatically manage signing"
|
||||
in the "General" tab, and then select your `Development Team`. This
|
||||
should also auto select `Signing Ceritificate`. The outcome should look as
|
||||
shown below:
|
||||
|
||||

|
||||
|
||||
* Xcode may fail to create a provisioning profile for the `WebDriverAgentRunner`
|
||||
target:
|
||||
|
||||

|
||||
|
||||
* This necessitates manually changing the bundle id for the target by going
|
||||
into the "Build Settings" tab, and changing the "Product Bundle Identifier"
|
||||
from `com.facebook.WebDriverAgentRunner` to something that Xcode will accept:
|
||||
|
||||

|
||||
|
||||
* Going back to the "General" tab for the `WebDriverAgentRunner` target, you
|
||||
should now see that it has created a provisioning profile and all is well:
|
||||
|
||||

|
||||
|
||||
* Finally, you can verify that everything works. Build the project:
|
||||
```
|
||||
xcodebuild -project WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=<udid>' test
|
||||
```
|
||||
If this was successful, the output should end with something like:
|
||||
```
|
||||
Test Suite 'All tests' started at 2017-01-23 15:49:12.585
|
||||
Test Suite 'WebDriverAgentRunner.xctest' started at 2017-01-23 15:49:12.586
|
||||
Test Suite 'UITestingUITests' started at 2017-01-23 15:49:12.587
|
||||
Test Case '-[UITestingUITests testRunner]' started.
|
||||
t = 0.00s Start Test at 2017-01-23 15:49:12.588
|
||||
t = 0.00s Set Up
|
||||
```
|
||||
* To completely verify, you can try accessing the WebDriverAgent server status
|
||||
(**note:** you _must_ be on the same network as the device, and know its IP
|
||||
address, from Settings => Wi-Fi => Current Network):
|
||||
```
|
||||
export DEVICE_URL='http://<device IP>:8100'
|
||||
export JSON_HEADER='-H "Content-Type: application/json;charset=UTF-8, accept: application/json"'
|
||||
curl -X GET $JSON_HEADER $DEVICE_URL/status
|
||||
```
|
||||
You ought to get back output something like this:
|
||||
```
|
||||
{
|
||||
"value" : {
|
||||
"state" : "success",
|
||||
"os" : {
|
||||
"name" : "iOS",
|
||||
"version" : "10.2"
|
||||
},
|
||||
"ios" : {
|
||||
"simulatorVersion" : "10.2",
|
||||
"ip" : "192.168.0.7"
|
||||
},
|
||||
"build" : {
|
||||
"time" : "Jan 23 2017 14:59:57"
|
||||
}
|
||||
},
|
||||
"sessionId" : "8951A6DD-F3AD-410E-A5DB-D042F42F68A7",
|
||||
"status" : 0
|
||||
}
|
||||
```
|
||||
@@ -1,91 +1,6 @@
|
||||
## Appium on real iOS devices
|
||||
## Appium Support for Real Device Testing
|
||||
|
||||
Appium has support for real device testing.
|
||||
|
||||
To get started on a real device, you will need the following:
|
||||
|
||||
* An [Apple Developer ID](https://developer.apple.com/programs/ios/)
|
||||
and a valid Developer Account with a configured distribution certificate and
|
||||
provisioning profile.
|
||||
* An iPad or iPhone. Make sure this has been set up for development in Xcode. See [this article](https://developer.apple.com/library/ios/recipes/xcode_help-devices_organizer/articles/provision_device_for_development-generic.html) for more information.
|
||||
* A signed `.ipa` file of your app, or the source code to build one.
|
||||
* A Mac with [Xcode](https://itunes.apple.com/en/app/xcode/id497799835?mt=12)
|
||||
and the Xcode Command Line Developer Tools.
|
||||
|
||||
### Provisioning Profile
|
||||
|
||||
A valid iOS Development Distribution Certificate and Provisioning Profile are
|
||||
necessary to test on a real device. Your app will also need to be signed. You
|
||||
can find information about this in the [Apple documentation](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/TestingYouriOSApp/TestingYouriOSApp.html).
|
||||
|
||||
Appium will attempt to install your app using Fruitstrap, but it is often easier
|
||||
to pre-install your app using Xcode to ensure there are no problems (see the [iOS deploy](ios-deploy.md) doc for more information).
|
||||
|
||||
### Testing using Xcode 8 (including iOS 10) with XCUITest
|
||||
|
||||
This functionality currently depends on logging based on `idevicesyslog`, and
|
||||
port forwarding based on `iProxy`, both of which are part of `libimobiledevice`.
|
||||
Install it with [Homebrew](http://brew.sh/),
|
||||
|
||||
```
|
||||
brew install libimobiledevice
|
||||
```
|
||||
|
||||
Alternatively, logging can be done using `deviceconsole`, which is available
|
||||
[here](https://github.com/rpetrich/deviceconsole). To choose between them, use
|
||||
the desired capability `realDeviceLogger`, passing in the path to the logging
|
||||
program.
|
||||
|
||||
|
||||
### Running your tests with Appium
|
||||
|
||||
Once your device and app are configured, you can run tests on that device by
|
||||
passing the `-U` or `--udid` flag to the server or the `udid` desired capability,
|
||||
and the bundle ID (if the app is installed on the device) or the path to the
|
||||
`.ipa` or `.apk` file via the `--app` flag or the `app` desired capability.
|
||||
|
||||
### Server Arguments
|
||||
|
||||
For example, if you are prelaunching your app and wish for Appium to force use
|
||||
a specific UDID, then you may use the below command:
|
||||
|
||||
```center
|
||||
appium -U <udid> --app <path or bundle>
|
||||
```
|
||||
|
||||
This will start Appium and have Appium use the device to test the app.
|
||||
|
||||
Refer to the [Appium server arguments](/docs/en/writing-running-appium/server-args.md) page for more detail on
|
||||
the arguments that you can use.
|
||||
|
||||
### Desired Capabilities
|
||||
|
||||
You can launch the app on a device by including the following desired
|
||||
capabilities in your tests:
|
||||
|
||||
* `app`
|
||||
* `udid`
|
||||
|
||||
Refer to the [Appium server capabilities](/docs/en/writing-running-appium/caps.md) page for more detail on
|
||||
the capabilities that you can use.
|
||||
|
||||
### Troubleshooting ideas
|
||||
|
||||
0. Make sure UDID is correct by checking it in Xcode Organizer or iTunes. It
|
||||
is a long string (20+ chars).
|
||||
0. Make sure that you can run your tests against the Simulator.
|
||||
0. Double check that you can invoke your automation from Instruments.
|
||||
0. Make sure Instruments is not already running.
|
||||
0. Make sure UI Automation is enabled on your device. Settings -> Developer -> Enable UI Automation
|
||||
|
||||
### Appium on real Android devices
|
||||
|
||||
Hooray! There's nothing extra to know about testing real Android devices: it
|
||||
works exactly the same as testing on emulators. Make sure that your device
|
||||
can connect to ADB and has Developer Mode enabled. For testing Chrome on a real
|
||||
device, you're responsible for ensuring that Chrome of an appropriate version
|
||||
is installed.
|
||||
|
||||
Also, you'll want to make sure that "Verify Apps" in settings is
|
||||
disabled/unchecked, otherwise it can prevent some of Appium's helper apps from
|
||||
launching and doing their job correctly.
|
||||
* For **Android** testing, see [android real device documentation](real-devices-android.md)
|
||||
* For **iOS** testing, see [iOS real device documentation](real-devices-ios.md)
|
||||
|
||||
@@ -4,14 +4,14 @@ Appium on OS X supports iOS and Android testing.
|
||||
|
||||
### System setup (iOS)
|
||||
|
||||
* Appium requires Mac OS X 10.7 or greater. We recommend OS X 10.10.
|
||||
* Appium requires Mac OS X 10.10 or greater.
|
||||
* Make sure you have Xcode and the iOS SDK(s) installed. Xcode version 7.1 is
|
||||
recommended as earlier versions of Xcode are limited in which versions of iOS
|
||||
they can test against. See the next section for more detail.
|
||||
* You need to authorize use of the iOS Simulator. See [below](#authorizing-ios-on-the-computer).
|
||||
* If you're on Xcode 7.x, Instruments Without Delay (IWD) does not work. You can
|
||||
enable IWD (which will significantly speed up your tests) using
|
||||
[this method](/docs/en/advanced-concepts/iwd_xcode7.md)
|
||||
* If you're on Xcode 7.x and up, Instruments Without Delay (IWD) does not work.
|
||||
You can enable IWD (which will significantly speed up your tests) using [this
|
||||
method](/docs/en/advanced-concepts/iwd_xcode7.md)
|
||||
* If you're on Xcode 6, you need to launch each simulator you intend to use
|
||||
with appium in advance, and change the default to actually show the soft
|
||||
keyboard if you want sendKeys to work. You can do this by clicking on any
|
||||
@@ -23,9 +23,9 @@ Appium on OS X supports iOS and Android testing.
|
||||
a platformVersion cap of "8.0", you need to make sure that there is exactly
|
||||
one device with the name "iPhone 5s" and the 8.0 sdk in your devices list.
|
||||
Otherwise, Appium won't know which one to use.
|
||||
* In iOS8, devices each have their own setting which enables or disables
|
||||
* In iOS 8, devices each have their own setting which enables or disables
|
||||
UIAutomation. It lives in a "Developer" view in the Settings app. You need to
|
||||
verify that UIAutomaion is enabled in this view before the simulator or
|
||||
verify that UIAutomation is enabled in this view before the simulator or
|
||||
device can be automated.
|
||||
|
||||
### Authorizing iOS on the computer
|
||||
@@ -66,8 +66,15 @@ manager:
|
||||
brew install carthage
|
||||
```
|
||||
|
||||
### Testing Mac apps
|
||||
|
||||
Currently, the Mac app driver for appium does not ship with the AppiumForMac binary, which means, in order to automate Mac apps you must manually install the AppiumForMac application and grant it the appropriate OS X Accessibility permissions.
|
||||
|
||||
To Install Appium for Mac:
|
||||
1. [Download a release](https://github.com/appium/appium-for-mac/releases/tag/0.2.0) and unzip the application into your `/Applications` folder
|
||||
2. Follow the [brief supplemental installation instructions](https://github.com/appium/appium-for-mac#installation) to enable appium to have access to OS X's Accessibility APIs
|
||||
|
||||
For more information on using Appium for mac, checkout the [docs](https://github.com/appium/appium-for-mac#appium-for-mac).
|
||||
|
||||
### System setup (Android)
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ own items in the SDK manager. Make sure you install the build-tools and platform
|
||||
* If Instruments is crashing when running against a physical device ("exited with code 253"), ensure Xcode has downloaded device symbols. Go to Window -> Devices, and it should start automatically. This is needed after iOS version upgrades.
|
||||
* If you see `iOS Simulator failed to install the application.` and the
|
||||
paths are correct, try restarting the computer.
|
||||
* Make sure your macOS keychain that holds the certificate(s) needed for building your app and the WebDriverAgent is unlocked. Especialy if you are using ssh. General symptom to look for is `codesign` failure.
|
||||
* If you have custom elements in your app, they will not be automatable by
|
||||
UIAutomation (and therefore Appium) by default. You need to set the
|
||||
accessibility status to 'enabled' on them. The way to do this in code is:
|
||||
@@ -139,11 +140,6 @@ own items in the SDK manager. Make sure you install the build-tools and platform
|
||||
* In a Safari session, if the logs indicate that the initial url cannot be entered, make sure that
|
||||
you have the software keyboard enabled. See this [discussion](https://github.com/appium/appium/issues/6440).
|
||||
|
||||
### FirefoxOS
|
||||
|
||||
* Make sure the Boot-to-Gecko simulator is up and running.
|
||||
* Make sure the simulator screen is alive and unlocked (might require restarting B2G).
|
||||
|
||||
### Let the community know
|
||||
|
||||
Once you've tried the above steps and your issue still isn't resolved,
|
||||
|
||||
@@ -81,10 +81,8 @@ have to modify your `/etc/authorization` file in one of two ways:
|
||||
`/etc/authorization` file for you:
|
||||
|
||||
```center
|
||||
sudo node_modules/.bin/authorize-ios.js
|
||||
|
||||
# alternatively
|
||||
sudo $(npm bin)/authorize-ios
|
||||
npm install -g authorize-ios
|
||||
sudo authorize-ios
|
||||
```
|
||||
|
||||
At this point, run:
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
- contains all available and supported CLI arguments
|
||||
- check for deprecation and mutual exclusion
|
||||
- put logging together
|
||||
- mixture out of npmlog, winston and appium-logger
|
||||
- mixture out of npmlog, winston and a custom logger
|
||||
- initiates AppiumDriver (extends Basedriver)
|
||||
- assigns iOS/Android/Selendroid/Fake driver to session
|
||||
- creates/deletes Appium session
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
* [instruments-without-delay](https://github.com/facebook/instruments-without-delay)
|
||||
* [deviceconsole](https://github.com/rpetrich/deviceconsole)
|
||||
* [WinAppDriver](http://github.com/Microsoft/WinAppDriver)
|
||||
* [WebDriverAgent](https://github.com/facebook/webdriveragent)
|
||||
|
||||
@@ -30,6 +30,37 @@ _development_ questions, not _usage_ questions or bug reports. Usage questions
|
||||
belong on [discuss.appium.io](https://discuss.appium.io). The GitHub issue
|
||||
tracker is for bug reports and feature requests only.
|
||||
|
||||
### Agile Development Workflow
|
||||
|
||||
The Appium team runs development according to a very lightweight version of
|
||||
SCRUM. Every two weeks we begin a new "sprint", or a period of time in which we
|
||||
have decided what we want to accomplish. Anyone familiar with the Appium
|
||||
codebase is welcome to attend our sprint planning and participate as a SCRUM
|
||||
team member for that sprint. No long-term commitments required! During the
|
||||
sprint, we update each other with daily progress in the `#standup` room in our
|
||||
[Appium Slack Group](https://appium.slack.com) (there are no real-time daily
|
||||
standups). At the end of the sprint, to celebrate our accomplishments and
|
||||
reflect on how things went, we hold a "retrospective", which might result in
|
||||
a list of things we can try differently or do better next time around.
|
||||
|
||||
Ultimately, the goal is to time an Appium release at the end of each sprint, so
|
||||
every two weeks. We're not quite there, but hopefully we will be soon.
|
||||
|
||||
Current meeting times:
|
||||
* Sprint Planning: every other Monday from 10:00 AM - 10:45 AM (Pacific Time)
|
||||
* Sprint Retrospective: every other _other_ Friday from 1:00 PM - 1:30 PM (Pacific Time)
|
||||
|
||||
We hold meetings using [Zoom](https://zoom.us) video chat.
|
||||
|
||||
For project management, we use the [ZenHub](http://zenhub.com) browser plugin,
|
||||
which adds various features like Kanban boards and Epics to the GitHub
|
||||
interface. To fully participate in Appium SCRUM, you'll need to have this
|
||||
browser plugin installed.
|
||||
|
||||
If you are interested in participating a sprint, ping `@jlipps` or `@isaac` in
|
||||
the Appium Slack Group, or DM `@jlipps` on Twitter, and we'll share how to join
|
||||
the video chat for the next sprint.
|
||||
|
||||
### Architecture
|
||||
|
||||
Appium is primarily a collection of [node.js](http://nodejs.org) packages that
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Appium gulp commands
|
||||
|
||||
[Gulp](http://gulpjs.com) is like make for Node.js! We use it to automate all
|
||||
[Gulp](http://gulpjs.com) is like `make` for Node.js! We use it to automate all
|
||||
kinds of appium dev tasks. Here's what you can do:
|
||||
|
||||
|Task|Description|
|
||||
|
||||
@@ -210,7 +210,7 @@ driver.open_notifications()
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
openNotifications
|
||||
open_notifications
|
||||
```
|
||||
|
||||
```csharp
|
||||
@@ -434,7 +434,7 @@ autoLaunch=false.
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
launch
|
||||
launch_app
|
||||
```
|
||||
|
||||
```python
|
||||
@@ -473,7 +473,7 @@ Reset the app.
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
reset
|
||||
driver.reset
|
||||
```
|
||||
|
||||
```python
|
||||
@@ -630,7 +630,7 @@ Get the app's strings.
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
strings = app_strings
|
||||
app_strings
|
||||
```
|
||||
|
||||
```python
|
||||
@@ -993,7 +993,7 @@ execute_script "mobile: scroll", direction: "down", element: element.ref
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.execute_script("mobile: scroll", {"direction": "down", element: element.id})
|
||||
driver.execute_script("mobile: scroll", {"direction": "down", "element": element.id})
|
||||
```
|
||||
|
||||
```java
|
||||
@@ -1107,19 +1107,22 @@ driver.PushFile("/data/local/tmp/file.txt", "some data for the file");
|
||||
|
||||
Here you will find sample code for getting/setting appium serverSetting.
|
||||
For more information on how they work, and which settings are supported, see
|
||||
[the settings docs][/docs/en/advanced-concepts/settings.md]
|
||||
[the settings docs](/docs/en/advanced-concepts/settings.md).
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
current_settings = get_settings
|
||||
update_settings someSetting: true
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
current_settings = driver.get_settings()
|
||||
driver.update_settings({"someSetting": true})
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
JsonObject settings = driver.getSettings()
|
||||
// java-client doesn't support setting arbitrary settings, just settings which are already provided by appium.
|
||||
// So for the 'ignoreUnimportantViews' setting, the following method exists:
|
||||
@@ -1127,16 +1130,19 @@ driver.ignoreUnimportantViews(true);
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var settings = driver.settings();
|
||||
browser.updateSettings({'someSetting': true});
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
$settings = $this->getSettings();
|
||||
$this->updateSettings(array('cyberdelia' => "open"));
|
||||
```
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
Dictionary<String, Object>settings = driver.GetSettings();
|
||||
// dotnet-driver doesn't support setting arbitrary settings, just settings which are already provided by appium.
|
||||
// So for the 'ignoreUnimportantViews' setting, the following method exists:
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
# Apple XCUITest
|
||||
|
||||
Xcode 7 introduces [new UI testing features](https://developer.apple.com/videos/play/wwdc2015/406/). Moving forward, [Appium iOS Driver](https://github.com/appium/appium-ios-driver) will leverage this framework, replacing UI Automation. While there are no official docs, @joemasilotti has created [some handy unofficial docs](http://masilotti.com/xctest-documentation/index.html) by pulling out comments from the header files.
|
||||
|
||||
## Launching the App (XCUIApplication)
|
||||
- ##### – launch
|
||||
|
||||
Launches the application. This call is synchronous and when it returns the application is launched
|
||||
and ready to handle user events. Any failure in the launch sequence is reported as a test failure
|
||||
and halts the test at this point. If the application is already running, this call will first
|
||||
terminate the existing instance to ensure clean state of the launched instance.
|
||||
|
||||
- ##### – terminate
|
||||
|
||||
Terminates any running instance of the application. If the application has an existing debug session
|
||||
via Xcode, the termination is implemented as a halt via that debug connection. Otherwise, a SIGKILL
|
||||
is sent to the process.
|
||||
|
||||
- ##### launchArguments
|
||||
|
||||
The arguments that will be passed to the application on launch. If not modified, these are the
|
||||
arguments that Xcode will pass on launch. Those arguments can be changed, added to, or removed.
|
||||
Unlike NSTask, it is legal to modify these arguments after the application has been launched. These
|
||||
changes will not affect the current launch session, but will take effect the next time the application
|
||||
is launched.
|
||||
|
||||
- ##### launchEnvironment
|
||||
|
||||
The environment that will be passed to the application on launch. If not modified, this is the
|
||||
environment that Xcode will pass on launch. Those variables can be changed, added to, or removed.
|
||||
Unlike NSTask, it is legal to modify the environment after the application has been launched. These
|
||||
changes will not affect the current launch session, but will take effect the next time the application
|
||||
is launched.
|
||||
|
||||
## Accessing the Device (XCUIDevice)
|
||||
- ##### + sharedDevice
|
||||
|
||||
The current device.
|
||||
|
||||
- ##### orientation
|
||||
|
||||
The orientation of the device.
|
||||
|
||||
- ##### – pressButton:
|
||||
|
||||
Simulates the user pressing a physical button.
|
||||
|
||||
## Querying for Elements (XCUIElementQuery)
|
||||
- ##### element
|
||||
|
||||
Returns an element that will use the query for resolution.
|
||||
|
||||
- ##### count
|
||||
|
||||
Evaluates the query at the time it is called and returns the number of matches found.
|
||||
|
||||
- ##### – elementAtIndex:
|
||||
|
||||
Returns an element that will resolve to the index into the query’s result set.
|
||||
|
||||
- ##### – elementBoundByIndex:
|
||||
|
||||
Returns an element that will use the index into the query’s results to determine which underlying accessibility element it is matched with.
|
||||
|
||||
- ##### – elementMatchingPredicate:
|
||||
|
||||
Returns an element that matches the predicate. The predicate will be evaluated against objects of type idXCUIElementAttributes.
|
||||
|
||||
- ##### – elementMatchingType:identifier:
|
||||
|
||||
Returns an element that matches the type and identifier.
|
||||
|
||||
- ##### – objectForKeyedSubscript:
|
||||
|
||||
Keyed subscripting is implemented as a shortcut for matching an identifier only. For example, app.descendants[“Foo”] -> XCUIElement.
|
||||
|
||||
- ##### allElementsBoundByAccessibilityElement
|
||||
|
||||
Immediately evaluates the query and returns an array of elements bound to the resulting accessibility elements.
|
||||
|
||||
- ##### allElementsBoundByIndex
|
||||
|
||||
Immediately evaluates the query and returns an array of elements bound by the index of each result.
|
||||
|
||||
- ##### – descendantsMatchingType:
|
||||
|
||||
Returns a new query that finds the descendants of all the elements found by the receiver.
|
||||
|
||||
- ##### – childrenMatchingType:
|
||||
|
||||
Returns a new query that finds the direct children of all the elements found by the receiver.
|
||||
|
||||
- ##### – matchingPredicate:
|
||||
|
||||
Returns a new query that applies the specified attributes or predicate to the receiver. The predicate will be evaluated against objects of type idXCUIElementAttributes.
|
||||
|
||||
- ##### – matchingType:identifier:
|
||||
|
||||
- ##### – matchingIdentifier:
|
||||
|
||||
- ##### – containingPredicate:
|
||||
|
||||
Returns a new query for finding elements that contain a descendant matching the specification. The predicate will be evaluated against objects of type idXCUIElementAttributes.
|
||||
|
||||
- ##### – containingType:identifier:
|
||||
|
||||
- ##### debugDescription
|
||||
|
||||
@discussion
|
||||
Provides debugging information about the query. The data in the string will vary based on the time
|
||||
at which it is captured, but it may include any of the following as well as additional data:
|
||||
• A description of each step of the query.
|
||||
• Information about the inputs and matched outputs of each step of the query.
|
||||
This data should be used for debugging only - depending on any of the data as part of a test is unsupported.
|
||||
|
||||
## Interacting with Elements (XCUIElement)
|
||||
### XCUIElementEventSynthesis Methods
|
||||
- ##### – typeText:
|
||||
|
||||
Types a string into the element. The element or a descendant must have keyboard focus; otherwise an
|
||||
error is raised.
|
||||
|
||||
- ##### – tap
|
||||
|
||||
Sends a tap event to a hittable point computed for the element.
|
||||
|
||||
- ##### – doubleTap
|
||||
|
||||
Sends a double tap event to a hittable point computed for the element.
|
||||
|
||||
- ##### – twoFingerTap
|
||||
|
||||
Sends a two finger tap event to a hittable point computed for the element.
|
||||
|
||||
- ##### – tapWithNumberOfTaps:numberOfTouches:
|
||||
|
||||
Sends one or more taps with one of more touch points.
|
||||
|
||||
- ##### – pressForDuration:
|
||||
|
||||
Sends a long press gesture to a hittable point computed for the element, holding for the specified duration.
|
||||
|
||||
- ##### – pressForDuration:thenDragToElement:
|
||||
|
||||
Initiates a press-and-hold gesture that then drags to another element, suitable for table cell reordering and similar operations.
|
||||
@param duration
|
||||
Duration of the initial press-and-hold.
|
||||
@param otherElement
|
||||
The element to finish the drag gesture over. In the example of table cell reordering, this would be the reorder element of the destination row.
|
||||
|
||||
- ##### – swipeUp
|
||||
|
||||
Sends a swipe-up gesture.
|
||||
|
||||
- ##### – swipeDown
|
||||
|
||||
Sends a swipe-down gesture.
|
||||
|
||||
- ##### – swipeLeft
|
||||
|
||||
Sends a swipe-left gesture.
|
||||
|
||||
- ##### – swipeRight
|
||||
|
||||
Sends a swipe-right gesture.
|
||||
|
||||
- ##### – pinchWithScale:velocity:
|
||||
|
||||
Sends a pinching gesture with two touches.
|
||||
|
||||
- ##### – rotate:withVelocity:
|
||||
|
||||
Sends a rotation gesture with two touches.
|
||||
|
||||
### XCUIElementTypeSlider Methods
|
||||
- ##### – adjustToNormalizedSliderPosition:
|
||||
|
||||
Manipulates the UI to change the displayed value of the slider to one based on a normalized position. 0 corresponds to the minimum value of the slider, 1 corresponds to its maximum value. The adjustment is a “best effort” to move the indicator to the desired position; absolute fidelity is not guaranteed.
|
||||
|
||||
- ##### normalizedSliderPosition
|
||||
|
||||
Returns the position of the slider’s indicator as a normalized value where 0 corresponds to the minimum value of the slider and 1 corresponds to its maximum value.
|
||||
|
||||
### XCUIElementTypePickerWheel Methods
|
||||
- ##### – adjustToPickerWheelValue:
|
||||
|
||||
Changes the displayed value for the picker wheel. Will generate a test failure if the specified value is not available.
|
||||
|
||||
### Other Methods
|
||||
- ##### exists
|
||||
|
||||
Test to determine if the element exists.
|
||||
|
||||
- ##### hittable
|
||||
|
||||
Whether or not a hit point can be computed for the element for the purpose of synthesizing events.
|
||||
|
||||
- ##### – descendantsMatchingType:
|
||||
|
||||
Returns a query for all descendants of the element matching the specified type.
|
||||
|
||||
- ##### – childrenMatchingType:
|
||||
|
||||
Returns a query for direct children of the element matching the specified type.
|
||||
|
||||
- ##### – coordinateWithNormalizedOffset:
|
||||
|
||||
Creates and returns a new coordinate that will compute its screen point by adding the offset multiplied by the size of the element’s frame to the origin of the element’s frame.
|
||||
|
||||
- ##### debugDescription
|
||||
|
||||
@discussion
|
||||
Provides debugging information about the element. The data in the string will vary based on the
|
||||
time at which it is captured, but it may include any of the following as well as additional data:
|
||||
• Values for the elements attributes.
|
||||
• The entire tree of descendants rooted at the element.
|
||||
• The element’s query.
|
||||
This data should be used for debugging only - depending on any of the data as part of a test is unsupported.
|
||||
|
||||
## Using Coordinates (XCUICoordinate)
|
||||
- ##### – init
|
||||
|
||||
Coordinates are never instantiated directly. Instead, they are created by elements or by other coordinates.
|
||||
|
||||
- ##### referencedElement
|
||||
|
||||
The element that the coordinate is based on, either directly or via the coordinate from which it was derived.
|
||||
|
||||
- ##### screenPoint
|
||||
|
||||
The dynamically computed value of the coordinate’s location on screen. Note that this value is dependent on the current frame of the referenced element; if the element’s frame changes, so will the value returned by this property. If the referenced element does exist when this is called, it will fail the test; check the referenced element’s exists property if the element may not be present.
|
||||
|
||||
- ##### – coordinateWithOffset:
|
||||
|
||||
Creates a new coordinate with an absolute offset in points from the original coordinate.
|
||||
|
||||
- ##### – tap
|
||||
|
||||
- ##### – doubleTap
|
||||
|
||||
- ##### – pressForDuration:
|
||||
|
||||
- ##### – pressForDuration:thenDragToCoordinate:
|
||||
|
||||
- ##### – hover
|
||||
@@ -62,6 +62,7 @@
|
||||
|`recreateChromeDriverSessions`| Kill ChromeDriver session when moving to a non-ChromeDriver webview. Defaults to `false` | `true` or `false`|
|
||||
|`nativeWebScreenshot`| In a web context, use native (adb) method for taking a screenshot, rather than proxying to ChromeDriver. Defaults to `false` | `true` or `false`|
|
||||
|`androidScreenshotPath`| The name of the directory on the device in which the screenshot will be put. Defaults to `/data/local/tmp` |e.g. `/sdcard/screenshots/`|
|
||||
|`autoGrantPermissions`|Have Appium automatically determine which permissions your app requires and grant them to the app on install. Defaults to `false`|`true` or `false`|
|
||||
|
||||
### iOS Only
|
||||
|
||||
@@ -75,8 +76,8 @@
|
||||
|`launchTimeout`| Amount of time in ms to wait for instruments before assuming it hung and failing the session|e.g. `20000`|
|
||||
|`locationServicesEnabled`| (Sim-only) Force location services to be either on or off. Default is to keep current sim setting.|`true` or `false`|
|
||||
|`locationServicesAuthorized`| (Sim-only) Set location services to be authorized or not authorized for app via plist, so that location services alert doesn't pop up. Default is to keep current sim setting. Note that if you use this setting you MUST also use the `bundleId` capability to send in your app's bundle ID.|`true` or `false`|
|
||||
|`autoAcceptAlerts`| Accept all iOS alerts automatically if they pop up. This includes privacy access permission alerts (e.g., location, contacts, photos). Default is false.|`true` or `false`|
|
||||
|`autoDismissAlerts`| Dismiss all iOS alerts automatically if they pop up. This includes privacy access permission alerts (e.g., location, contacts, photos). Default is false.|`true` or `false`|
|
||||
|`autoAcceptAlerts`| Accept all iOS alerts automatically if they pop up. This includes privacy access permission alerts (e.g., location, contacts, photos). Default is false. Does not work on `XCUITest`-based tests.|`true` or `false`|
|
||||
|`autoDismissAlerts`| Dismiss all iOS alerts automatically if they pop up. This includes privacy access permission alerts (e.g., location, contacts, photos). Default is false. Does not work on `XCUITest`-based tests.|`true` or `false`|
|
||||
|`nativeInstrumentsLib`| Use native intruments lib (ie disable instruments-without-delay).|`true` or `false`|
|
||||
|`nativeWebTap`| (Sim-only) Enable "real", non-javascript-based web taps in Safari. Default: `false`. Warning: depending on viewport size/ratio this might not accurately tap an element|`true` or `false`|
|
||||
|`safariInitialUrl`| (Sim-only) (>= 8.1) Initial safari url, default is a local welcome page | e.g. `https://www.github.com` |
|
||||
@@ -93,6 +94,8 @@
|
||||
|`waitForAppScript`| The ios automation script used to determined if the app has been launched, by default the system wait for the page source not to be empty. The result must be a boolean |e.g. `true;`, `target.elements().length > 0;`, `$.delay(5000); true;` |
|
||||
|`webviewConnectRetries`| Number of times to send connection message to remote debugger, to get webview. Default: `8` |e.g., `12`|
|
||||
|`appName`| The display name of the application under test. Used to automate backgrounding the app in iOS 9+.|e.g., `UICatalog`|
|
||||
|`customSSLCert`|(Sim/Emu-only) Add an SSL certificate to simulator. | e.g. <br/>`-----BEGIN CERTIFICATE-----MIIFWjCCBEKg...`<br/>`-----END CERTIFICATE-----`|
|
||||
|
||||
|
||||
### iOS Only, using XCUITest
|
||||
|
||||
@@ -103,11 +106,17 @@
|
||||
|`processArguments`|Process arguments and environment which will be sent to the WebDriverAgent server.|`{ args: ["a", "b", "c"] , env: { "a": "b", "c": "d" } }` or `'{"args": ["a", "b", "c"], "env": { "a": "b", "c": "d" }}'`|
|
||||
|`wdaLocalPort`|This value if specified, will be used to forward traffic from Mac host to real ios devices over USB. Default value is same as port number used by WDA on device.|e.g., `8100`|
|
||||
|`showXcodeLog`|Whether to display the output of the Xcode command used to run the tests. If this is `true`, there will be **lots** of extra logging at startup. Defaults to `false`|e.g., `true`|
|
||||
|`realDeviceLogger`|Device logger for real devices. It could be path to `deviceconsole` (installed with `npm install deviceconsole`, a compiled binary named `deviceconsole` will be added to `./node_modules/deviceconsole/`) or `idevicesyslog` (comes with libimobiledevice). Defaults to `idevicesyslog`|`idevicesyslog`, `/abs/path/to/deviceconsole`|
|
||||
|`iosInstallPause`|Time in milliseconds to pause between installing the application and starting WebDriverAgent on the device. Used particularly for larger applications. Defaults to `0`|e.g., `8000`|
|
||||
|`xcodeConfigFile`|Full path to an optional Xcode configuration file that specifies the code signing identity and team for running the WebDriverAgent on the real device.|e.g., `/path/to/myconfig.xcconfig`|
|
||||
|`keychainPath`|Full path to the private development key exported from the system keychain. Used in conjunction with `keychainPassword` when testing on real devices.|e.g., `/path/to/MyPrivateKey.p12`|
|
||||
|`keychainPassword`|Password for unlocking keychain specified in `keychainPath`.|e.g., `super awesome password`|
|
||||
|`scaleFactor`|Simulator scale factor. This is useful to have if the default resolution of simulated device is greater than the actual display resolution. So you can scale the simulator to see the whole device screen without scrolling. |Acceptable values are: `'1.0', '0.75', '0.5', '0.33' and '0.25'`. The value should be a string.|
|
||||
|`preventWDAAttachments`|Sets read only permissons to Attachments subfolder of WebDriverAgent root inside Xcode's DerivedData. This is necessary to prevent XCTest framework from creating tons of unnecessary screenshots and logs, which are impossible to shutdown using programming interfaces provided by Apple.|Setting the capability to `true` will set Posix permissions of the folder to `555` and `false` will reset them back to `755`|
|
||||
|`webDriverAgentUrl`|If provided, Appium will connect to an existing WebDriverAgent instance at this URL instead of starting a new one.|e.g., `http://localhost:8100`|
|
||||
|`useNewWDA`|If `true`, forces uninstall of any existing WebDriverAgent app on device. This can provide stability in some situations. Defaults to `false`.|e.g., `true`|
|
||||
|`wdaLaunchTimeout`|Time, in ms, to wait for WebDriverAgewnt to be pingable. Defaults to 60000ms.|e.g., `30000`|
|
||||
|`calendarAccessAuthorized`|If truthy, enables calendar access on IOS Simulator with given bundleId. If `false`, disables
|
||||
calendar access on IOS Simulator with given bundleId. Otherwise, the calendar authorizationStatus remains unchanged.||
|
||||
|
||||
### You.i Engine Only
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## The --default-capabilities flag
|
||||
|
||||
Appium 1.5 does away with most CLI flags; the remainder can be converted into JSON and made part of the `--default-capabilities` flag. For example:
|
||||
Appium 1.5 does away with most CLI flags that existed previously; the remainder can be converted into JSON and made part of the `--default-capabilities` flag. For example:
|
||||
|
||||
```
|
||||
# raw JSON as an argument
|
||||
@@ -28,13 +28,13 @@ Appium 1.5 does away with most CLI flags; the remainder can be converted into JS
|
||||
| --udid | udid |
|
||||
| --orientation | orientation |
|
||||
| --no-reset | noReset |
|
||||
| --full-reset | rullReset |
|
||||
| --full-reset | fullReset |
|
||||
| --app-pkg | appPackage |
|
||||
| --app-activity | appActivity |
|
||||
| --app-wait-package | appWaitPackage |
|
||||
| --app-wait-activity | appWaitActivity |
|
||||
| --device-ready-timeout | deviceReadyTimeout |
|
||||
| --android-coverage | androidCoverage |
|
||||
| --android-coverage | androidCoverage |
|
||||
| --avd | avd |
|
||||
| --avd-args | avdArgs |
|
||||
| --use-keystore | useKeystore |
|
||||
|
||||
@@ -9,7 +9,7 @@ with certain constraints)
|
||||
Appium additionally supports some of the [Mobile JSON Wire Protocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) locator strategies
|
||||
|
||||
* `-ios uiautomation`: a string corresponding to a recursive element search
|
||||
using the [UIAutomation library](ios_predicate.md) (iOS-only)
|
||||
using the [UIAutomation library](ios_predicate.md) (iOS 9.3 and below only)
|
||||
* `-android uiautomator`: a string corresponding to a recursive element
|
||||
search using the [UiAutomator Api](uiautomator_uiselector.md) (Android-only)
|
||||
* `accessibility id`: a string corresponding to a recursive element search
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
## Automating Mobile Gestures For iOS With WebDriverAgent/XCTest Backend
|
||||
|
||||
Unfortunately Apple's XCTest framework does not natively support W3C standards for
|
||||
TouchAction interface implementation. Although, it provides rich set of gestures,
|
||||
inluding these, that are unique for iOS platform. It is possible to directly invoke these
|
||||
gestures in Appium starting from version 1.6.4-beta.
|
||||
|
||||
It is important to rememeber that XCTest and WDA are being constantly changed.
|
||||
This means all "mobile: *" commands can be also subject of change in Appium
|
||||
without any preliminary notice.
|
||||
|
||||
|
||||
### mobile: swipe
|
||||
|
||||
This gesture performs a simple "swipe" gesture on the particular screen element or
|
||||
on the application element, which is usually the whole screen. This method does not
|
||||
accept coordnates and siply emulates single swipe with one finger. It might be
|
||||
useful for such cases like album pagination, switching views, etc. More advanced
|
||||
cases may require to call "mobile: dragFromToForDuration", where one can supply
|
||||
coordinates and duration.
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _direction_: Either 'up', 'down', 'left' or 'right'. The parameter is mandatory
|
||||
* _element_: Element id to swipe on. Application element will be used instead if this
|
||||
parameter is not provided
|
||||
|
||||
#### Usage examples
|
||||
|
||||
```java
|
||||
// Java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, String> scrollObject = new HashMap<String, String>();
|
||||
scrollObject.put("direction", "down");
|
||||
scrollObject.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: swipe", scrollObject);
|
||||
```
|
||||
|
||||
|
||||
### mobile: scroll
|
||||
|
||||
Scrolls the element or the whole screen. Different scrolling strategies are supported.
|
||||
Arguments define the choosen strategy: either 'name', 'direction', 'predicateString' or
|
||||
'toVisible' in that order. All strategies are exclusive and only one strategy
|
||||
can be applied at a single moment of time. Use "mobile: scroll" to emulate precise
|
||||
scrolling in tables or collection views, where it is already known to which element
|
||||
the scrolling should be performed. Although, there is one known limitation there: in case
|
||||
it is necessary to perform too many scroll gestures on parent container to reach the
|
||||
necessary child element (tens of them) then the method call may fail.
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _element_: Element id to scroll. Application element will be used if this argument is not set
|
||||
* _name_: the accessibility id of the child element, to which scrolling is performed.
|
||||
The same result can be achieved by setting _predicateString_ argument to
|
||||
'name == accessibilityId'. Has no effect if _element_ is not a container
|
||||
* _direction_: Either 'up', 'down', 'left' or 'right'. The main difference from
|
||||
_swipe_ call with the same argument is that _scroll_ will try to move the current viewport
|
||||
exactly to the next/previous page (the term "page" means the content, which fits into
|
||||
a single device screen)
|
||||
* _predicateString_: the NSPredicate locator of the child element, to which
|
||||
the scrolling should be performed. Has no effect if _element_ is not a container
|
||||
* _toVisible_: Boolean parameter. If set to _true_ then asks to scroll to
|
||||
the first visible _element_ in the parent container. Has no effect if _element_ is
|
||||
not set
|
||||
|
||||
#### Usage examples
|
||||
|
||||
```python
|
||||
# Python
|
||||
driver.execute_script('mobile: scroll', {'direction': 'down'});
|
||||
```
|
||||
|
||||
|
||||
### mobile: pinch
|
||||
|
||||
Performs pinch gesture on the given element or on the application element.
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _element_: Element id to pinch on. Application element will be used instead if this
|
||||
parameter is not provided
|
||||
* _scale_: Pinch scale of type float. Use a scale between 0 and 1 to "pinch close" or
|
||||
zoom out and a scale greater than 1 to "pinch open" or zoom in. Mandatory parameter
|
||||
* _velocity_: The velocity of the pinch in scale factor per second (float value). Mandatory parameter
|
||||
|
||||
#### Usage examples
|
||||
|
||||
```ruby
|
||||
# Ruby
|
||||
execute_script 'mobile: pinch', scale: 0.5, velocity: 1.1
|
||||
```
|
||||
|
||||
|
||||
### mobile: doubleTap
|
||||
|
||||
Performs double tap gesture on the given element or on the screen.
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _element_: Element id to double tap on
|
||||
* _x_: Screen x tap coordinate of type float. Mandatory parameter only if _element_ is not set
|
||||
* _y_: Screen y tap coordinate of type float. Mandatory parameter only if _element_ is not set
|
||||
|
||||
#### Usage examples
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.execute('mobile: doubleTap', {element: element.value.ELEMENT});
|
||||
```
|
||||
|
||||
|
||||
### mobile: twoFingerTap
|
||||
|
||||
Performs two finger tap gesture on the given element or on the application element.
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _element_: Element id to double tap on. Application element will be used instead if this
|
||||
parameter is not provided
|
||||
|
||||
#### Usage examples
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
Dictionary<string, string> tfTap = new Dictionary<string, string>();
|
||||
tfTap.Add("element", <element_id>);
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: twoFingerTap", tfTap));
|
||||
```
|
||||
|
||||
|
||||
### mobile: tap
|
||||
|
||||
Performs tap gesture by coordinates on the given element or on the screen.
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _element_: Element id to long tap on. _x_ and _y_ tap coordinates
|
||||
will be calulated relatively to the current element position on the
|
||||
screen if this argument is provided. Otherwise they should be calculated
|
||||
relatively to screen borders.
|
||||
* _x_: x tap coordinate of type float. Mandatory parameter
|
||||
* _y_: y tap coordinate of type float. Mandatory parameter
|
||||
|
||||
#### Usage examples
|
||||
|
||||
```php
|
||||
// PHP
|
||||
$params = array(array('x' => 100.0, 'y' => 50.0, 'element' => element.GetAttribute("id")));
|
||||
$driver->executeScript("mobile: tap", $params);
|
||||
```
|
||||
|
||||
|
||||
### mobile: dragFromToForDuration
|
||||
|
||||
Performs drag and drop gesture by coordinates. This can be done either on an element or
|
||||
on the screen
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _element_: Element id to perform drag on. All the coordinates will be calculated
|
||||
relatively this this element position on the screen. Absolute screen coordinates
|
||||
are expected if this argument is not set
|
||||
* _duration_: Float number of seconds in range [0.5, 60]. How long the tap gesture at
|
||||
starting drag point should be before to start dragging. Mandatory parameter
|
||||
* _fromX_: The x coordinate of starting drag point (type float). Mandatory parameter
|
||||
* _fromY_: The y coordinate of starting drag point (type float). Mandatory parameter
|
||||
* _toX_: The x coordinate of ending drag point (type float). Mandatory parameter
|
||||
* _toY_: The y coordinate of ending drag point (type float). Mandatory parameter
|
||||
|
||||
#### Usage examples
|
||||
|
||||
```java
|
||||
// Java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, String> params = new HashMap<String, Object>();
|
||||
params.put("duration", 1.0);
|
||||
params.put("fromX", 100);
|
||||
params.put("fromY", 100);
|
||||
params.put("toX", 200);
|
||||
params.put("toY", 200);
|
||||
params.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: dragFromToForDuration", params);
|
||||
```
|
||||
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
Check [WDA Element Commands API](https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Commands/FBElementCommands.m)
|
||||
to get the information about the gestures implemented in Facebook WebDriverAgent.
|
||||
Check Apple XCTest documentation on [XCUIElement](https://developer.apple.com/reference/xctest/xcuielement) and
|
||||
[XCUICoordinate](https://developer.apple.com/reference/xctest/xcuicoordinate) methods list to get the information
|
||||
about all gestures available there.
|
||||
@@ -1,5 +1,7 @@
|
||||
## iOS Predicate
|
||||
|
||||
*NOTE*: iOS predicates are usable in iOS 9.3 and below using the `-ios uiautomation` locator strategy and they are usable in iOS 10 and above using the `-ios predicate string` locator strategy
|
||||
|
||||
It is worth looking at *'-ios uiautomation'* search strategy with **Predicates**.
|
||||
[UIAutomation JavaScript API](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/) has following methods which can are very useful.
|
||||
|
||||
@@ -11,11 +13,18 @@ It is worth looking at *'-ios uiautomation'* search strategy with **Predicates**
|
||||
Native JS search strategy (powered by Apple) provides much more flexibility and is like Xpath.
|
||||
**[Predicates](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html)** can be used to restrict an elements set to select only those ones for which some condition is true.
|
||||
|
||||
For example:
|
||||
'-ios uiautomation' example:
|
||||
|
||||
```java
|
||||
// java
|
||||
appiumDriver.findElementsByIosUIAutomation("collectionViews()[0].cells().withPredicate(\"ANY staticTexts.isVisible == TRUE\")")
|
||||
appiumDriver.findElementsByIosUIAutomation("collectionViews()[0].cells().withPredicate(\"ANY staticTexts.isVisible == TRUE\")");
|
||||
```
|
||||
|
||||
'-ios predicate string' example:
|
||||
|
||||
```java
|
||||
// java
|
||||
appiumDriver.findElementsByIosNsPredicate("isWDVisible == 1");
|
||||
```
|
||||
|
||||
\- will select only those ```UIACollectionCell``` elements that have visible ```UIAStaticText``` child elements, and themselves are childs of 1st ```UIACollectionView``` element that should be located under the main app window. Here ```staticTexts()``` and ```isVisible()``` are methods available in ```UIAElementArray``` and ```UIAElement``` classes respectively. **Note that ```UIAElementArray``` numbering begins with ```0``` unlike Xpath where indexes counting starts from ```1```**
|
||||
|
||||
@@ -60,15 +60,18 @@ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator")
|
||||
|
||||
### Mobile Safari on a Real iOS Device
|
||||
|
||||
We use the [SafariLauncher
|
||||
App](https://github.com/snevesbarros/SafariLauncher) to launch Safari and run
|
||||
tests against mobile Safari. Once Safari has been launched the Remote Debugger
|
||||
automatically connects using the
|
||||
[ios-webkit-debug-proxy](https://github.com/google/ios-webkit-debug-proxy). When
|
||||
working with ios-webkit-debug-proxy, you have to trust the machine before you can
|
||||
can run tests against your iOS device.
|
||||
For iOS 9.3 and below (pre-XCUITest), we use the [SafariLauncher
|
||||
App](https://github.com/snevesbarros/SafariLauncher) app to launch Safari and
|
||||
run tests against mobile Safari. This is because Safari is an app that is owned
|
||||
by Apple, and Instruments cannot launch it on real devices. Once Safari has
|
||||
been launched by SafariLauncher, the Remote Debugger automatically connects
|
||||
using the
|
||||
[ios-webkit-debug-proxy](https://github.com/google/ios-webkit-debug-proxy).
|
||||
When working with `ios-webkit-debug-proxy`, you have to trust the machine before
|
||||
you can can run tests against your iOS device.
|
||||
|
||||
For instruction on how to install and run ios-webkit-debugger-proxy see [iOS webKit debug proxy](/docs/en/advanced-concepts/ios-webkit-debug-proxy.md) documentation.
|
||||
For instruction on how to install and run ios-webkit-debugger-proxy see
|
||||
[iOS WebKit debug proxy](/docs/en/advanced-concepts/ios-webkit-debug-proxy.md) documentation.
|
||||
|
||||
### Setup
|
||||
|
||||
@@ -76,28 +79,8 @@ Before you can run your tests against Safari on a real device you will need to:
|
||||
|
||||
* Have the **ios-webkit-debug-proxy** installed, running and listening on port 27753 (see the
|
||||
[hybrid docs](/docs/en/advanced-concepts/hybrid.md#execution-against-a-real-ios-device) for instructions)
|
||||
* Turn on **web inspector** on iOS device (**settings > safari >
|
||||
advanced**)
|
||||
* Create a **provisioning profile** that can be used to deploy the SafariLauncherApp.
|
||||
|
||||
To create a profile for the launcher go into the **Apple Developers Member Center** and:
|
||||
|
||||
* **Step 1:** Create a **new App Id** and select the WildCard App ID option and set it to "*"
|
||||
* **Step 2:** Create a **new Development Profile** and for App Id select the one created in step 1.
|
||||
* **Step 3:** Select your **certificate(s) and device(s)** and click next.
|
||||
* **Step 4:** Set the profile name and **generate the profile**.
|
||||
* **Step 5:** Download the profile and open it with a text editor.
|
||||
* **Step 6:** Search for the **UUID** and the string for it is your **identity code**.
|
||||
|
||||
Now simply include your UDID and device name in your desired capabilities:
|
||||
|
||||
```center
|
||||
{
|
||||
"udid": '...',
|
||||
"deviceName": '...',
|
||||
"browserName": "Safari"
|
||||
}
|
||||
```
|
||||
* Turn on **web inspector** on iOS device (**settings > safari > advanced**)
|
||||
* Make sure that `SafariLauncher` will work (see the [SafariLauncher docs](safari-launcher.md) for instructions)
|
||||
|
||||
### Running your test
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
### Preparing your app for test (iOS)
|
||||
|
||||
Test apps run on the simulator have to be compiled specifically for the
|
||||
simulator, for example by executing the following command in the Xcode project:
|
||||
simulator, for example by executing the following command in the Xcode project (you can use `xcodebuild -showsdks` to see the list of available SDKs):
|
||||
|
||||
> xcodebuild -sdk iphonesimulator6.0
|
||||
|
||||
@@ -275,8 +275,6 @@ writing your scripts for older devices or hybrid apps.
|
||||
|
||||
### Running your test app with Appium (Windows)
|
||||
|
||||
Ensure that Appium is listening
|
||||
Simply ensure that Appium is listening, and run your test with your test runner of choice.
|
||||
|
||||
Deploy your test from your test runner of choice
|
||||
|
||||
See our [samples](https://github.com/Microsoft/WinAppDriver/tree/master/Samples) for details
|
||||
See our [samples](https://github.com/Microsoft/WinAppDriver/tree/master/Samples) for details.
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
## Mobile Web on iOS 9.3 and below Real Devices: SafariLauncher
|
||||
|
||||
Running mobile web tests on iOS real devices with iOS 9.3 or below, using Instruments,
|
||||
requires the introduction of a third-party app, [SafariLauncher](https://github.com/snevesbarros/SafariLauncher).
|
||||
This is necessary because with Instruments there is no way to start the Safari
|
||||
app on the device. The `SafariLauncher` app just launches, and then launches
|
||||
Safari. Simple!
|
||||
|
||||
In some configurations, Appium is able to automatically build, sign, and install
|
||||
`SafariLauncher` as it needs, and there is nothing else necessary to be done. If,
|
||||
however, this is not the case, as is more often so with later versions of
|
||||
[Xcode](https://developer.apple.com/xcode/), the following configuration needs to
|
||||
be done before Safari tests on real devices can be successfully run.
|
||||
|
||||
|
||||
### Automatic SafariLauncher configuration
|
||||
|
||||
The only thing needed for automatic `SafariLauncher` configuration is to create
|
||||
a **provisioning profile** that can be used to deploy the `SafariLauncher` App.
|
||||
This requires, in particular, a wildcard certificate, which is not possible if
|
||||
your Apple developer account is a free one. If that is the case, skip to the
|
||||
manual configuration below.
|
||||
|
||||
To create a profile for the launcher go into the **Apple Developers Member Center** and:
|
||||
|
||||
* **Step 1:** Create a **new App Id** and select the WildCard App ID option and set it to "*"
|
||||
* **Step 2:** Create a **new Development Profile** and for App Id select the one created in step 1.
|
||||
* **Step 3:** Select your **certificate(s) and device(s)** and click next.
|
||||
* **Step 4:** Set the profile name and **generate the profile**.
|
||||
* **Step 5:** Download the profile and open it with a text editor.
|
||||
* **Step 6:** Search for the **UUID** and the string for it is your **identity code**.
|
||||
|
||||
Now simply include your UDID and device name in your desired capabilities:
|
||||
```js
|
||||
{
|
||||
udid: '...',
|
||||
deviceName: '...',
|
||||
platformName: 'iOS',
|
||||
platformVersion: '9.3',
|
||||
browserName: 'Safari'
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Manual SafariLauncher configuration
|
||||
|
||||
**Note:** This procedure assumes you have [Xcode](https://developer.apple.com/xcode/) 7.3 or 7.3.1.
|
||||
|
||||
It is possible to use the version of [SafariLauncher](https://github.com/snevesbarros/SafariLauncher)
|
||||
that comes with the [appium-ios-driver](https://github.com/appium/appium-ios-driver),
|
||||
but if you do, each time you update Appium the procedure will have to be done again.
|
||||
|
||||
To get a local copy of `SafariLauncher`, first clone it from [GitHub](https://github.com/):
|
||||
```bash
|
||||
git clone https://github.com/snevesbarros/SafariLauncher.git
|
||||
```
|
||||
|
||||
Once you have a local copy of the source code for the `SafariLauncher` app, open
|
||||
[Xcode](https://developer.apple.com/xcode/) and then open the `SafariLauncher` project
|
||||
|
||||

|
||||
|
||||
In the `SafariLauncher` target pane you will see an error, saying that there needs
|
||||
to be a provisioning profile for this app
|
||||
|
||||

|
||||
|
||||
In order to fix this, you first need to enter a "Bundle Identifier" for the app. The default
|
||||
expected by Appium is `com.bytearc.SafariLauncher`, but this might not be available
|
||||
for you to build. In that case, choose something else, and make note of it. Then
|
||||
choose a "Team", and allow the provisioning profile to be created
|
||||
|
||||

|
||||
|
||||
Finally, make sure your device is connected to the computer, and choose it as the
|
||||
target
|
||||
|
||||

|
||||
|
||||
And run the build and install actions to compile the app and push it onto your
|
||||
device
|
||||
|
||||

|
||||
|
||||
Now you have a working `SafariLauncher` on your device. The app itself is a plain
|
||||
screen that will launch `Safari` at the click of a button
|
||||
|
||||

|
||||
|
||||
The last step is only necessary if you chose a bundle identifier for the app that
|
||||
is different from the default (`com.bytearc.SafariLauncher`). If you did, it is
|
||||
necessary to send that to Appium when creating a session, using the `bundleId`
|
||||
desired capability:
|
||||
```js
|
||||
{
|
||||
udid: '...',
|
||||
deviceName: '...',
|
||||
platformName: 'iOS',
|
||||
platformVersion: '9.3',
|
||||
browserName: 'Safari',
|
||||
bundleId: 'com.imurchie.SafariLauncher'
|
||||
}
|
||||
```
|
||||
|
After Width: | Height: | Size: 216 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -105,7 +105,7 @@ allows you to do what you wanted to do with one of these views, namely, scroll
|
||||
it!
|
||||
|
||||
|
||||
**Scrolling**
|
||||
**Scrolling<a name="scrolling">**
|
||||
|
||||
|
||||
To allow access to this special feature, we override the `execute` or
|
||||
@@ -117,7 +117,7 @@ To scroll, pass direction in which you intend to scroll as parameter.
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.execute("mobile: scroll", [{direction: 'down'}])
|
||||
driver.execute('mobile: scroll', {direction: 'down'})
|
||||
```
|
||||
|
||||
```java
|
||||
@@ -154,7 +154,7 @@ Sample to scroll using direction and element.
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.execute("mobile: scroll", [{direction: 'down', element: element.value}]);
|
||||
driver.execute('mobile: scroll', {direction: 'down', element: element.value.ELEMENT});
|
||||
```
|
||||
|
||||
```java
|
||||
@@ -189,6 +189,14 @@ $params = array(array('direction' => 'down', 'element' => element.GetAttribute("
|
||||
$driver->executeScript("mobile: scroll", $params);
|
||||
```
|
||||
|
||||
**Swiping**
|
||||
|
||||
This is an XCUITest driver specific method that is similar to scrolling (for reference, see
|
||||
https://developer.apple.com/reference/xctest/xcuielement).
|
||||
|
||||
This method has the same API as [Scrolling](#scrolling), just replace "mobile: scroll"
|
||||
with "mobile: swipe"
|
||||
|
||||
**Automating Sliders**
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ To test a UWP app, you can use any Selenium supported language and simply specif
|
||||
// Launch the AlarmClock app
|
||||
DesiredCapabilities appCapabilities = new DesiredCapabilities();
|
||||
appCapabilities.SetCapability("app", "Microsoft.WindowsAlarms_8wekyb3d8bbwe!App");
|
||||
AlarmClockSession = new IOSDriver<IOSElement>(new Uri("http://127.0.0.1:4723"), appCapabilities);
|
||||
AlarmClockSession = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), appCapabilities);
|
||||
// Control the AlarmClock app
|
||||
AlarmClockSession.FindElementByAccessibilityId("AddAlarmButton").Click();
|
||||
AlarmClockSession.FindElementByAccessibilityId("AlarmNameTextBox").Clear();
|
||||
@@ -38,7 +38,7 @@ To test a classic Windows app, you can also use any Selenium supported language
|
||||
// Launch Notepad
|
||||
DesiredCapabilities appCapabilities = new DesiredCapabilities();
|
||||
appCapabilities.SetCapability("app", @"C:\Windows\System32\notepad.exe");
|
||||
NotepadSession = new IOSDriver<IOSElement>(new Uri("http://127.0.0.1:4723"), appCapabilities);
|
||||
NotepadSession = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), appCapabilities);
|
||||
// Control the AlarmClock app
|
||||
NotepadSession.FindElementByClassName("Edit").SendKeys("This is some text");
|
||||
```
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint no-console:0 */
|
||||
/* eslint-disable promise/prefer-await-to-callbacks */
|
||||
"use strict";
|
||||
|
||||
// turn all logging on since we have tests that rely on npmlog logs actually
|
||||
@@ -32,10 +33,12 @@ gulp.task('fixShrinkwrap', function (done) {
|
||||
boilerplate({
|
||||
build: 'appium',
|
||||
jscs: false,
|
||||
jshint: false,
|
||||
test: {
|
||||
files: ['${testDir}/**/*-specs.js']
|
||||
},
|
||||
extraPrepublishTasks: ['fixShrinkwrap'],
|
||||
preCommitTasks: ['eslint', 'once'],
|
||||
});
|
||||
|
||||
// generates server arguments readme
|
||||
@@ -66,7 +69,7 @@ gulp.task('docs', ['transpile'], function () {
|
||||
}
|
||||
|
||||
// handle empty objects
|
||||
if (JSON.stringify(argOpts.defaultValue) === '{}'){
|
||||
if (JSON.stringify(argOpts.defaultValue) === '{}') {
|
||||
argOpts.defaultValue = '{}';
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { SelendroidDriver } from 'appium-selendroid-driver';
|
||||
import { XCUITestDriver } from 'appium-xcuitest-driver';
|
||||
import { YouiEngineDriver } from 'appium-youiengine-driver';
|
||||
import { WindowsDriver } from 'appium-windows-driver';
|
||||
import { MacDriver } from 'appium-mac-driver';
|
||||
import B from 'bluebird';
|
||||
import util from 'util';
|
||||
|
||||
@@ -86,6 +87,10 @@ class AppiumDriver extends BaseDriver {
|
||||
return WindowsDriver;
|
||||
}
|
||||
|
||||
if (caps.platformName.toLowerCase() === 'mac') {
|
||||
return MacDriver;
|
||||
}
|
||||
|
||||
let msg;
|
||||
if (caps.automationName) {
|
||||
msg = `Could not find a driver for automationName '${caps.automationName}' and platformName ` +
|
||||
@@ -96,6 +101,26 @@ class AppiumDriver extends BaseDriver {
|
||||
throw new Error(`${msg} Please check your desired capabilities.`);
|
||||
}
|
||||
|
||||
getDriverVersion (driver) {
|
||||
const NAME_DRIVER_MAP = {
|
||||
SelendroidDriver: 'appium-selendroid-driver',
|
||||
AndroidUiautomator2Driver: 'appium-uiautomator2-driver',
|
||||
XCUITestDriver: 'appium-xcuitest-driver',
|
||||
YouiEngineDriver: 'appium-youiengine-driver',
|
||||
FakeDriver: 'appium-fake-driver',
|
||||
AndroidDriver: 'appium-android-driver',
|
||||
IosDriver: 'appium-ios-driver',
|
||||
WindowsDriver: 'appium-windows-driver',
|
||||
MacDriver: 'appium-mac-driver',
|
||||
};
|
||||
if (!NAME_DRIVER_MAP[driver.name]) {
|
||||
log.warn(`Unable to get version of driver '${driver.name}'`);
|
||||
return;
|
||||
}
|
||||
let {version} = require(`${NAME_DRIVER_MAP[driver.name]}/package.json`);
|
||||
return version;
|
||||
}
|
||||
|
||||
async getStatus () {
|
||||
let config = await getAppiumConfig();
|
||||
let gitSha = config['git-sha'];
|
||||
@@ -114,16 +139,23 @@ class AppiumDriver extends BaseDriver {
|
||||
return sessions;
|
||||
}
|
||||
|
||||
async createSession (caps, reqCaps) {
|
||||
caps = _.defaults(_.clone(caps), this.args.defaultCapabilities);
|
||||
let InnerDriver = this.getDriverForCaps(caps);
|
||||
let curSessions;
|
||||
log.info(`Creating new ${InnerDriver.name} session`);
|
||||
printNewSessionAnnouncement (driver, caps) {
|
||||
let driverVersion = this.getDriverVersion(driver);
|
||||
let introString = driverVersion ?
|
||||
`Creating new ${driver.name} (v${driverVersion}) session` :
|
||||
`Creating new ${driver.name} session`;
|
||||
log.info(introString);
|
||||
log.info('Capabilities:');
|
||||
util.inspect(caps);
|
||||
for (let [cap, value] of _.toPairs(caps)) {
|
||||
log.info(` ${cap}: ${util.inspect(value)}`);
|
||||
}
|
||||
}
|
||||
|
||||
async createSession (caps, reqCaps) {
|
||||
caps = _.defaults(_.clone(caps), this.args.defaultCapabilities);
|
||||
let InnerDriver = this.getDriverForCaps(caps);
|
||||
this.printNewSessionAnnouncement(InnerDriver, caps);
|
||||
|
||||
// sessionOverride server flag check
|
||||
// this will need to be re-thought when we go to multiple session support
|
||||
@@ -140,6 +172,7 @@ class AppiumDriver extends BaseDriver {
|
||||
}
|
||||
}
|
||||
|
||||
let curSessions;
|
||||
try {
|
||||
curSessions = this.curSessionDataForDriver(InnerDriver);
|
||||
} catch (e) {
|
||||
@@ -150,18 +183,11 @@ class AppiumDriver extends BaseDriver {
|
||||
let [innerSessionId, dCaps] = await d.createSession(caps, reqCaps, curSessions);
|
||||
this.sessions[innerSessionId] = d;
|
||||
|
||||
// Remove the session on unexpected shutdown, so that we are in a position
|
||||
// to open another session later on.
|
||||
// TODO: this should be removed and replaced by a onShutdown callback.
|
||||
d.onUnexpectedShutdown
|
||||
.then(() => { throw new Error('Unexpected shutdown'); })
|
||||
.catch(B.CancellationError, () => {})
|
||||
.catch((err) => {
|
||||
log.warn(`Closing session, cause was '${err.message}'`);
|
||||
log.info(`Removing session ${innerSessionId} from our master session list`);
|
||||
delete this.sessions[innerSessionId];
|
||||
})
|
||||
.done();
|
||||
// this is an async function but we don't await it because it handles
|
||||
// an out-of-band promise which is fulfilled if the inner driver
|
||||
// unexpectedly shuts down
|
||||
this.attachUnexpectedShutdownHandler(d, innerSessionId);
|
||||
|
||||
|
||||
log.info(`New ${InnerDriver.name} session created successfully, session ` +
|
||||
`${innerSessionId} added to master session list`);
|
||||
@@ -172,6 +198,26 @@ class AppiumDriver extends BaseDriver {
|
||||
return [innerSessionId, dCaps];
|
||||
}
|
||||
|
||||
async attachUnexpectedShutdownHandler (driver, innerSessionId) {
|
||||
// Remove the session on unexpected shutdown, so that we are in a position
|
||||
// to open another session later on.
|
||||
// TODO: this should be removed and replaced by a onShutdown callback.
|
||||
try {
|
||||
await driver.onUnexpectedShutdown; // this is a cancellable promise
|
||||
// if we get here, we've had an unexpected shutdown, so error
|
||||
throw new Error('Unexpected shutdown');
|
||||
} catch (e) {
|
||||
if (e instanceof B.CancellationError) {
|
||||
// if we cancelled the unexpected shutdown promise, that means we
|
||||
// no longer care about it, and can safely ignore it
|
||||
return;
|
||||
}
|
||||
log.warn(`Closing session, cause was '${e.message}'`);
|
||||
log.info(`Removing session ${innerSessionId} from our master session list`);
|
||||
delete this.sessions[innerSessionId];
|
||||
}
|
||||
}
|
||||
|
||||
curSessionDataForDriver (InnerDriver) {
|
||||
let data = _.values(this.sessions)
|
||||
.filter((s) => s.constructor.name === InnerDriver.name)
|
||||
|
||||
@@ -42,6 +42,18 @@ async function postRequest (data, addr, port) {
|
||||
logger.errorAndThrow(`Syntax error in node configuration file: ${err.message}`);
|
||||
}
|
||||
|
||||
// Move Selenium 3 configuration properties to configuration object
|
||||
if (!jsonObject.hasOwnProperty('configuration')) {
|
||||
let configuration = {};
|
||||
for (var property in jsonObject) {
|
||||
if (jsonObject.hasOwnProperty(property) && property !== 'capabilities') {
|
||||
configuration[property] = jsonObject[property];
|
||||
delete jsonObject[property];
|
||||
}
|
||||
}
|
||||
jsonObject.configuration = configuration;
|
||||
}
|
||||
|
||||
// if the node config does not have the appium/webdriver url, host, and port,
|
||||
// automatically add it based on how appium was initialized
|
||||
// otherwise, we will take whatever the user setup
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getLogger } from 'appium-logger';
|
||||
import { logger } from 'appium-support';
|
||||
|
||||
let logger = getLogger('Appium');
|
||||
|
||||
export default logger;
|
||||
let log = logger.getLogger('Appium');
|
||||
|
||||
export default log;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import npmlog from 'npmlog';
|
||||
import { patchLogger } from 'appium-logger';
|
||||
import winston from 'winston';
|
||||
import { fs } from 'appium-support';
|
||||
import { fs, logger } from 'appium-support';
|
||||
import 'date-utils';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
// set up distributed logging before everything else
|
||||
patchLogger(npmlog);
|
||||
logger.patchLogger(npmlog);
|
||||
global._global_npmlog = npmlog;
|
||||
|
||||
// npmlog is used only for emitting, we use winston for output
|
||||
@@ -36,7 +35,7 @@ const npmToWinstonLevels = {
|
||||
error: 'error',
|
||||
};
|
||||
|
||||
let logger = null;
|
||||
let log = null;
|
||||
let timeZone = null;
|
||||
|
||||
function timestamp () {
|
||||
@@ -53,7 +52,7 @@ function timestamp () {
|
||||
// having to create 2 loggers.
|
||||
function applyStripColorPatch (transport) {
|
||||
let _log = transport.log.bind(transport);
|
||||
transport.log = function (level, msg, meta, callback) {
|
||||
transport.log = function (level, msg, meta, callback) { // eslint-disable-line promise/prefer-await-to-callbacks
|
||||
let code = /\u001b\[(\d+(;\d+)*)?m/g;
|
||||
msg = ('' + msg).replace(code, '');
|
||||
_log(level, msg, meta, callback);
|
||||
@@ -184,7 +183,7 @@ async function init (args) {
|
||||
// object
|
||||
clear();
|
||||
|
||||
logger = new (winston.Logger)({
|
||||
log = new (winston.Logger)({
|
||||
transports: await _createTransports(args)
|
||||
});
|
||||
|
||||
@@ -196,7 +195,7 @@ async function init (args) {
|
||||
let prefix = `[${logObj.prefix}]`;
|
||||
msg = `${prefix.magenta} ${msg}`;
|
||||
}
|
||||
logger[winstonLevel](msg);
|
||||
log[winstonLevel](msg);
|
||||
if (args.logHandler && typeof args.logHandler === "function") {
|
||||
args.logHandler(logObj.level, msg);
|
||||
}
|
||||
@@ -204,21 +203,21 @@ async function init (args) {
|
||||
});
|
||||
|
||||
|
||||
logger.setLevels(levels);
|
||||
log.setLevels(levels);
|
||||
|
||||
// 8/19/14 this is a hack to force Winston to print debug messages to stdout rather than stderr.
|
||||
// TODO: remove this if winston provides an API for directing streams.
|
||||
if (levels[logger.transports.console.level] === levels.debug) {
|
||||
logger.debug = function (msg) {
|
||||
logger.info('[debug] ' + msg);
|
||||
if (levels[log.transports.console.level] === levels.debug) {
|
||||
log.debug = function (msg) {
|
||||
log.info('[debug] ' + msg);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function clear () {
|
||||
if (logger) {
|
||||
for (let transport of _.keys(logger.transports)) {
|
||||
logger.remove(transport);
|
||||
if (log) {
|
||||
for (let transport of _.keys(log.transports)) {
|
||||
log.remove(transport);
|
||||
}
|
||||
}
|
||||
npmlog.removeAllListeners('log');
|
||||
|
||||
@@ -48,9 +48,32 @@ function logDeprecationWarning (deprecatedArgs) {
|
||||
}
|
||||
|
||||
function logNonDefaultArgsWarning (args) {
|
||||
// cleanly print out the default arguments, allowing for prefix and timestamp
|
||||
function getValueArray (obj, indent = ' ') {
|
||||
if (!_.isObject(obj)) {
|
||||
return [obj];
|
||||
}
|
||||
|
||||
let strArr = ['{'];
|
||||
for (let [arg, value] of _.toPairs(obj)) {
|
||||
if (!_.isObject(value)) {
|
||||
strArr.push(`${indent} ${arg}: ${value}`);
|
||||
} else {
|
||||
value = getValueArray(value, `${indent} `);
|
||||
strArr.push(`${indent} ${arg}: ${value.shift()}`);
|
||||
strArr.push(...value);
|
||||
}
|
||||
}
|
||||
strArr.push(`${indent}}`);
|
||||
return strArr;
|
||||
}
|
||||
logger.info('Non-default server args:');
|
||||
for (let [arg, value] of _.toPairs(args)) {
|
||||
logger.info(` ${arg}: ${util.inspect(value)}`);
|
||||
value = getValueArray(value);
|
||||
logger.info(` ${arg}: ${value.shift()}`);
|
||||
for (let val of value) {
|
||||
logger.info(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +155,17 @@ async function main (args = null) {
|
||||
await server.close();
|
||||
throw err;
|
||||
}
|
||||
|
||||
process.once('SIGINT', async function () {
|
||||
logger.info(`Received SIGINT - shutting down`);
|
||||
await server.close();
|
||||
});
|
||||
|
||||
process.once('SIGTERM', async function () {
|
||||
logger.info(`Received SIGTERM - shutting down`);
|
||||
await server.close();
|
||||
});
|
||||
|
||||
logServerPort(args.address, args.port);
|
||||
|
||||
return server;
|
||||
|
||||
@@ -326,7 +326,7 @@ const args = [
|
||||
}],
|
||||
|
||||
[['--suppress-adb-kill-server'], {
|
||||
dest: 'suppressAdbKillServer',
|
||||
dest: 'suppressKillServer',
|
||||
defaultValue: false,
|
||||
action: 'storeTrue',
|
||||
required: false,
|
||||
@@ -782,7 +782,8 @@ function getParser () {
|
||||
let parser = new ArgumentParser({
|
||||
version: pkgObj.version,
|
||||
addHelp: true,
|
||||
description: 'A webdriver-compatible server for use with native and hybrid iOS and Android applications.'
|
||||
description: 'A webdriver-compatible server for use with native and hybrid iOS and Android applications.',
|
||||
prog: process.argv[1] || 'Appium'
|
||||
});
|
||||
let allArgs = _.union(args, deprecatedArgs);
|
||||
parser.rawArgs = allArgs;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"firefoxos",
|
||||
"testing"
|
||||
],
|
||||
"version": "1.6.0-beta3",
|
||||
"version": "1.6.4-beta.2",
|
||||
"author": "https://github.com/appium",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
@@ -34,29 +34,29 @@
|
||||
"doc": "./docs"
|
||||
},
|
||||
"dependencies": {
|
||||
"appium-android-driver": "^1.10.27",
|
||||
"appium-base-driver": "^2.0.19",
|
||||
"appium-fake-driver": "^0.1.10",
|
||||
"appium-ios-driver": "^1.12.27",
|
||||
"appium-logger": "^2.1.0",
|
||||
"appium-selendroid-driver": "^1.3.4",
|
||||
"appium-support": "^2.3.3",
|
||||
"appium-uiautomator2-driver": "^0.x",
|
||||
"appium-xcuitest-driver": "^2.0.25",
|
||||
"appium-youiengine-driver": "^1.0.6",
|
||||
"appium-windows-driver": "^0.x",
|
||||
"argparse": "^1.0.7",
|
||||
"asyncbox": "^2.3.1",
|
||||
"appium-android-driver": "1.x",
|
||||
"appium-base-driver": "2.x",
|
||||
"appium-fake-driver": "0.x",
|
||||
"appium-ios-driver": "1.x",
|
||||
"appium-mac-driver": "1.x",
|
||||
"appium-selendroid-driver": "1.x",
|
||||
"appium-support": "2.x",
|
||||
"appium-uiautomator2-driver": "0.x",
|
||||
"appium-xcuitest-driver": "2.x",
|
||||
"appium-youiengine-driver": "1.x",
|
||||
"appium-windows-driver": "0.x",
|
||||
"argparse": "1.x",
|
||||
"asyncbox": "2.x",
|
||||
"babel-runtime": "=5.8.24",
|
||||
"bluebird": "^2.10.2",
|
||||
"continuation-local-storage": "^3.1.7",
|
||||
"date-utils": "^1.2.21",
|
||||
"lodash": "^4.13.1",
|
||||
"npmlog": "^2.0.4",
|
||||
"request-promise": "^1.0.2",
|
||||
"source-map-support": "^0.4.0",
|
||||
"teen_process": "^1.7.1",
|
||||
"winston": "^2.2.0"
|
||||
"bluebird": "2.x",
|
||||
"continuation-local-storage": "3.x",
|
||||
"date-utils": "1.x",
|
||||
"lodash": "4.x",
|
||||
"npmlog": "2.x",
|
||||
"request-promise": "1.x",
|
||||
"source-map-support": "0.x",
|
||||
"teen_process": "1.x",
|
||||
"winston": "2.x"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "gulp prepublish",
|
||||
@@ -71,22 +71,23 @@
|
||||
"test"
|
||||
],
|
||||
"devDependencies": {
|
||||
"appium-gulp-plugins": "^1.4.5",
|
||||
"babel-eslint": "^6.1.0",
|
||||
"chai": "^3.5.0",
|
||||
"chai-as-promised": "^5.3.0",
|
||||
"eslint": "^2.13.1",
|
||||
"eslint-config-appium": "^0.0.8",
|
||||
"eslint-plugin-babel": "^3.3.0",
|
||||
"eslint-plugin-import": "^1.9.2",
|
||||
"eslint-plugin-mocha": "^3.0.0",
|
||||
"gulp": "^3.9.1",
|
||||
"mocha": "^2.5.3",
|
||||
"pre-commit": "^1.1.3",
|
||||
"sinon": "^1.17.4",
|
||||
"wd": "~0.4.0"
|
||||
"appium-gulp-plugins": "1.x",
|
||||
"babel-eslint": "6.x",
|
||||
"chai": "3.x",
|
||||
"chai-as-promised": "5.x",
|
||||
"eslint": "2.x",
|
||||
"eslint-config-appium": "0.x",
|
||||
"eslint-plugin-babel": "3.x",
|
||||
"eslint-plugin-import": "1.x",
|
||||
"eslint-plugin-mocha": "3.x",
|
||||
"eslint-plugin-promise": "3.x",
|
||||
"gulp": "3.x",
|
||||
"mocha": "2.x",
|
||||
"pre-commit": "1.x",
|
||||
"sinon": "1.x",
|
||||
"wd": "1.x"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "^1.0.12"
|
||||
"fsevents": "1.x"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"appium-unlock",
|
||||
"appium-webdriveragent-driver",
|
||||
"appium-xcode",
|
||||
"appium-xcuitest-driver",
|
||||
"authorize-ios",
|
||||
"io.appium.settings",
|
||||
"jsonwp-status",
|
||||
@@ -42,7 +43,6 @@
|
||||
"appium-ci",
|
||||
"appium-ci-standalone-tools",
|
||||
"appium-gulp-plugins",
|
||||
"appium-package-master",
|
||||
"appium-transpile-runtime",
|
||||
"appium-jenkins",
|
||||
"teen_process",
|
||||
@@ -70,35 +70,23 @@
|
||||
"appium-core": [
|
||||
"imurchie",
|
||||
"jlipps",
|
||||
"jonahss",
|
||||
"moizjv",
|
||||
"scottdixon",
|
||||
"sebv"
|
||||
"dangraham"
|
||||
],
|
||||
"appium-contrib": [
|
||||
"imurchie",
|
||||
"jlipps",
|
||||
"jonahss",
|
||||
"moizjv",
|
||||
"scottdixon",
|
||||
"sebv",
|
||||
"bootstraponline"
|
||||
"bootstraponline",
|
||||
"dangraham"
|
||||
],
|
||||
"appium-tools": [
|
||||
"imurchie",
|
||||
"jlipps",
|
||||
"jonahss",
|
||||
"moizjv",
|
||||
"scottdixon",
|
||||
"sebv"
|
||||
"dangraham"
|
||||
],
|
||||
"appium-apps": [
|
||||
"imurchie",
|
||||
"jlipps",
|
||||
"jonahss",
|
||||
"moizjv",
|
||||
"sebv",
|
||||
"scottdixon",
|
||||
"dangraham",
|
||||
"bootstraponline"
|
||||
],
|
||||
"extra-jlipps": [
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"trailing": true,
|
||||
"node": true,
|
||||
"eqeqeq": true,
|
||||
"trailing": true,
|
||||
"expr": true,
|
||||
"white": true,
|
||||
"indent": 2,
|
||||
|
||||
@@ -194,6 +194,30 @@ describe('Config', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('parsing args with empty argv[1]', () => {
|
||||
let argv1;
|
||||
|
||||
before(() => {
|
||||
argv1 = process.argv[1];
|
||||
});
|
||||
|
||||
after(() => {
|
||||
process.argv[1] = argv1;
|
||||
});
|
||||
|
||||
it('should not fail if process.argv[1] is undefined', () => {
|
||||
process.argv[1] = undefined;
|
||||
let args = getParser();
|
||||
args.prog.should.be.equal('Appium');
|
||||
});
|
||||
|
||||
it('should set "prog" to process.argv[1]', () => {
|
||||
process.argv[1] = 'Hello World';
|
||||
let args = getParser();
|
||||
args.prog.should.be.equal('Hello World');
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateServerArgs', () => {
|
||||
let parser = getParser();
|
||||
parser.debug = true; // throw instead of exit on error; pass as option instead?
|
||||
|
||||
@@ -9,11 +9,13 @@ import chai from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import { XCUITestDriver } from 'appium-xcuitest-driver';
|
||||
import { IosDriver } from 'appium-ios-driver';
|
||||
import { sleep } from 'asyncbox';
|
||||
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
const BASE_CAPS = {platformName: 'Fake', deviceName: 'Fake', app: TEST_FAKE_APP};
|
||||
const SESSION_ID = 1;
|
||||
|
||||
describe('AppiumDriver', () => {
|
||||
describe('getAppiumRouter', () => {
|
||||
@@ -36,20 +38,20 @@ describe('AppiumDriver', () => {
|
||||
return [appium, mockFakeDriver];
|
||||
}
|
||||
describe('createSession', () => {
|
||||
let appium
|
||||
, mockFakeDriver;
|
||||
let appium;
|
||||
let mockFakeDriver;
|
||||
beforeEach(() => {
|
||||
[appium, mockFakeDriver] = getDriverAndFakeDriver();
|
||||
});
|
||||
afterEach(() => {
|
||||
afterEach(async () => {
|
||||
mockFakeDriver.restore();
|
||||
appium.args.defaultCapabilities = {};
|
||||
await appium.deleteSession(SESSION_ID);
|
||||
});
|
||||
|
||||
it('should call inner driver\'s createSession with desired capabilities', async () => {
|
||||
mockFakeDriver.expects("createSession")
|
||||
.once().withExactArgs(BASE_CAPS, undefined, [])
|
||||
.returns([1, BASE_CAPS]);
|
||||
.returns([SESSION_ID, BASE_CAPS]);
|
||||
await appium.createSession(BASE_CAPS);
|
||||
mockFakeDriver.verify();
|
||||
});
|
||||
@@ -59,7 +61,7 @@ describe('AppiumDriver', () => {
|
||||
appium.args.defaultCapabilities = defaultCaps;
|
||||
mockFakeDriver.expects("createSession")
|
||||
.once().withArgs(allCaps)
|
||||
.returns([1, allCaps]);
|
||||
.returns([SESSION_ID, allCaps]);
|
||||
await appium.createSession(BASE_CAPS);
|
||||
mockFakeDriver.verify();
|
||||
});
|
||||
@@ -70,7 +72,7 @@ describe('AppiumDriver', () => {
|
||||
appium.args.defaultCapabilities = defaultCaps;
|
||||
mockFakeDriver.expects("createSession")
|
||||
.once().withArgs(BASE_CAPS)
|
||||
.returns([1, BASE_CAPS]);
|
||||
.returns([SESSION_ID, BASE_CAPS]);
|
||||
await appium.createSession(BASE_CAPS);
|
||||
mockFakeDriver.verify();
|
||||
});
|
||||
@@ -98,7 +100,7 @@ describe('AppiumDriver', () => {
|
||||
|
||||
mockFakeDriver.expects("createSession")
|
||||
.once().withExactArgs(BASE_CAPS, undefined, [])
|
||||
.returns([1, BASE_CAPS]);
|
||||
.returns([SESSION_ID, BASE_CAPS]);
|
||||
await appium.createSession(BASE_CAPS);
|
||||
|
||||
sessions = await appium.getSessions();
|
||||
@@ -111,14 +113,13 @@ describe('AppiumDriver', () => {
|
||||
});
|
||||
});
|
||||
describe('deleteSession', () => {
|
||||
let appium
|
||||
, mockFakeDriver;
|
||||
let appium;
|
||||
let mockFakeDriver;
|
||||
beforeEach(() => {
|
||||
[appium, mockFakeDriver] = getDriverAndFakeDriver();
|
||||
});
|
||||
afterEach(() => {
|
||||
mockFakeDriver.restore();
|
||||
appium.args.defaultCapabilities = {};
|
||||
});
|
||||
it('should remove the session if it is found', async () => {
|
||||
let [sessionId] = await appium.createSession(BASE_CAPS);
|
||||
@@ -135,22 +136,32 @@ describe('AppiumDriver', () => {
|
||||
.returns();
|
||||
await appium.deleteSession(sessionId);
|
||||
mockFakeDriver.verify();
|
||||
|
||||
// cleanup, since we faked the delete session call
|
||||
await mockFakeDriver.object.deleteSession();
|
||||
});
|
||||
});
|
||||
describe('getSessions', () => {
|
||||
let appium;
|
||||
let sessions;
|
||||
before(() => {
|
||||
appium = new AppiumDriver({});
|
||||
});
|
||||
afterEach(async () => {
|
||||
for (let session of sessions) {
|
||||
await appium.deleteSession(session.id);
|
||||
}
|
||||
});
|
||||
it('should return an empty array of sessions', async () => {
|
||||
let sessions = await appium.getSessions();
|
||||
sessions = await appium.getSessions();
|
||||
sessions.should.be.an.array;
|
||||
sessions.should.be.empty;
|
||||
});
|
||||
it('should return sessions created', async () => {
|
||||
let session1 = await appium.createSession(_.extend(_.clone(BASE_CAPS), {cap: 'value'}));
|
||||
let session2 = await appium.createSession(_.extend(_.clone(BASE_CAPS), {cap: 'other value'}));
|
||||
let sessions = await appium.getSessions();
|
||||
|
||||
sessions = await appium.getSessions();
|
||||
sessions.should.be.an.array;
|
||||
sessions.should.have.length(2);
|
||||
sessions[0].id.should.equal(session1[0]);
|
||||
@@ -158,20 +169,57 @@ describe('AppiumDriver', () => {
|
||||
sessions[1].id.should.equal(session2[0]);
|
||||
sessions[1].capabilities.should.eql(session2[1]);
|
||||
});
|
||||
describe('getStatus', () => {
|
||||
let appium;
|
||||
before(() => {
|
||||
appium = new AppiumDriver({});
|
||||
});
|
||||
it('should return a status', async () => {
|
||||
let status = await appium.getStatus();
|
||||
status.build.should.exist;
|
||||
status.build.version.should.exist;
|
||||
});
|
||||
});
|
||||
describe('getStatus', () => {
|
||||
let appium;
|
||||
before(() => {
|
||||
appium = new AppiumDriver({});
|
||||
});
|
||||
it('should return a status', async () => {
|
||||
let status = await appium.getStatus();
|
||||
status.build.should.exist;
|
||||
status.build.version.should.exist;
|
||||
});
|
||||
});
|
||||
describe('sessionExists', () => {
|
||||
});
|
||||
describe('attachUnexpectedShutdownHandler', () => {
|
||||
let appium
|
||||
, mockFakeDriver;
|
||||
beforeEach(() => {
|
||||
[appium, mockFakeDriver] = getDriverAndFakeDriver();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await mockFakeDriver.object.deleteSession();
|
||||
mockFakeDriver.restore();
|
||||
appium.args.defaultCapabilities = {};
|
||||
});
|
||||
|
||||
it('should remove session if inner driver unexpectedly exits with an error', async () => {
|
||||
let [sessionId,] = await appium.createSession(_.clone(BASE_CAPS)); // eslint-disable-line comma-spacing
|
||||
_.keys(appium.sessions).should.contain(sessionId);
|
||||
appium.sessions[sessionId].unexpectedShutdownDeferred.reject(new Error("Oops"));
|
||||
// let event loop spin so rejection is handled
|
||||
await sleep(1);
|
||||
_.keys(appium.sessions).should.not.contain(sessionId);
|
||||
});
|
||||
it('should remove session if inner driver unexpectedly exits with no error', async () => {
|
||||
let [sessionId,] = await appium.createSession(_.clone(BASE_CAPS)); // eslint-disable-line comma-spacing
|
||||
_.keys(appium.sessions).should.contain(sessionId);
|
||||
appium.sessions[sessionId].unexpectedShutdownDeferred.resolve();
|
||||
// let event loop spin so rejection is handled
|
||||
await sleep(1);
|
||||
_.keys(appium.sessions).should.not.contain(sessionId);
|
||||
});
|
||||
it('should not remove session if inner driver cancels unexpected exit', async () => {
|
||||
let [sessionId,] = await appium.createSession(_.clone(BASE_CAPS)); // eslint-disable-line comma-spacing
|
||||
_.keys(appium.sessions).should.contain(sessionId);
|
||||
appium.sessions[sessionId].onUnexpectedShutdown.cancel();
|
||||
// let event loop spin so rejection is handled
|
||||
await sleep(1);
|
||||
_.keys(appium.sessions).should.contain(sessionId);
|
||||
});
|
||||
});
|
||||
describe('getDriverForCaps', () => {
|
||||
it('should not blow up if user does not provide platformName', () => {
|
||||
let appium = new AppiumDriver({});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import path from 'path';
|
||||
import wd from 'wd';
|
||||
import B from 'bluebird';
|
||||
|
||||
const TEST_HOST = 'localhost';
|
||||
const TEST_PORT = 4723;
|
||||
@@ -18,7 +19,7 @@ function initSession (caps) {
|
||||
after(async () => {
|
||||
await driver.quit();
|
||||
});
|
||||
return new Promise((_resolve) => {
|
||||
return new B((_resolve) => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
import { init as logsinkInit, clear as logsinkClear } from '../lib/logsink';
|
||||
import sinon from 'sinon';
|
||||
import { getLogger } from 'appium-logger';
|
||||
import { logger } from 'appium-support';
|
||||
|
||||
|
||||
// temporarily turn on logging to stdio, so we can catch and query
|
||||
let forceLogs = process.env._FORCE_LOGS;
|
||||
process.env._FORCE_LOGS = 1;
|
||||
let logger = getLogger('Appium');
|
||||
let log = logger.getLogger('Appium');
|
||||
|
||||
describe('Logger', () => {
|
||||
describe('logging', () => {
|
||||
let stderrSpy;
|
||||
let stdoutSpy;
|
||||
beforeEach(() => {
|
||||
@@ -31,9 +31,9 @@ describe('Logger', () => {
|
||||
const debugMsg = 'some debug';
|
||||
|
||||
function doLogging () {
|
||||
logger.error(errorMsg);
|
||||
logger.warn(warnMsg);
|
||||
logger.debug(debugMsg);
|
||||
log.error(errorMsg);
|
||||
log.warn(warnMsg);
|
||||
log.debug(debugMsg);
|
||||
}
|
||||
|
||||
it('should send error, info and debug when loglevel is debug', async () => {
|
||||
|
||||