Compare commits

...
Author SHA1 Message Date
Jonathan Lipps edf2593e17 chore: publish
- appium@2.11.3
 - @appium/base-driver@9.11.3
 - @appium/base-plugin@2.2.43
 - @appium/doctor@2.1.10
 - @appium/docutils@1.0.19
 - @appium/driver-test-support@0.6.7
 - @appium/execute-driver-plugin@3.0.33
 - @appium/fake-plugin@3.1.47
 - @appium/images-plugin@3.0.18
 - @appium/logger@1.6.1
 - @appium/plugin-test-support@0.3.41
 - @appium/support@5.1.3
 - @appium/test-support@3.0.47
 - @appium/types@0.21.2
 - @appium/universal-xml-plugin@1.0.21
2024-08-07 11:20:04 -07:00
Jonathan Lipps 7a14f9f929 fix(types): commit type gen update (#20445) 2024-08-07 11:18:25 -07:00
renovate[bot] b4612e0c7a fix(execute-driver-plugin): update dependency webdriverio to v8.40.0 (#20442)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-06 08:21:52 +02:00
kkb912002 8a307a078b fix(support): Allow temp dir which do not have a parent folder (#20440) 2024-08-05 10:30:25 +02:00
zhangxh075 0ffca811ce docs: translate some documents into Chinese (#20439)
* Translate part of the document in intro/appium.md

* Translate part of the document in intro/drivers.md

* Translate the 'Interface Implementations' section in the 'intro/drivers.md' file
2024-08-04 21:36:23 -07:00
Mykola Mokhnach 89f2e25a6c chore(appium): Replace fancy-log dependency with appium logger (#20434) 2024-08-02 20:00:08 +02:00
renovate[bot] 7aac098d60 chore(docutils): update dependency mkdocs-material to v9.5.31 2024-08-02 15:27:56 +00:00
renovate[bot] 32f57500e8 chore(deps): update dependency @types/node to v20.14.14 2024-08-02 12:41:29 +00:00
renovate[bot] 1ca77c6ded fix(support): update dependency axios to v1.7.3 2024-08-02 09:38:44 +00:00
renovate[bot] 92b32f8524 chore(deps): update dependency rimraf to v5.0.10 2024-08-01 12:01:09 +00:00
renovate[bot] c1c3957cb7 chore(deps): update dependency @types/chai to v4.3.17 2024-08-01 10:38:12 +00:00
Mykola Mokhnach 885570e7ca fix(support): Print an empty string if no arguments are provided to a logging function (#20424) 2024-07-31 08:23:33 +02:00
renovate[bot] 8413ccb4fa chore(deps): update eslint-related packages to v7.18.0 2024-07-30 12:16:54 +00:00
renovate[bot] 82b7515867 fix(doctor): update dependency appium-adb to v12.5.1 2024-07-30 09:33:23 +00:00
renovate[bot] 2957b8344b chore(deps): update dependency eslint-plugin-mocha to v10.5.0 2024-07-29 13:25:14 +00:00
renovate[bot] ea86eff938 chore(deps): update dependency json-schema-to-typescript to v15 (#20401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-29 13:04:19 +02:00
renovate[bot] b98dc4f46f chore(deps): update definitelytyped (#20418)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-29 13:03:57 +02:00
renovate[bot] 61276f2e7c fix(universal-xml-plugin): update dependency fast-xml-parser to v4.4.1 2024-07-28 10:03:00 +00:00
zhangxh075 9625052d05 docs: translate some documents into Chinese (#20404)
* fixed the errors in the zh/intro/index.md file

* Translate the file located at zh\intro\appium.md

* Improve the missing menu items

* Supplement the missing documentation

* update zh/index.md file

* Keep the content of build-drivers.md

* Translate part of the document in intro/appium.md
2024-07-25 19:48:56 +03:00
renovate[bot] 0c755f503c fix(docutils): update dependency yaml to v2.5.0 2024-07-24 17:47:41 +00:00
renovate[bot] a2294fa716 chore(docutils): update dependency mkdocs-material to v9.5.30 2024-07-24 14:01:24 +00:00
renovate[bot] 32fae41c03 chore(deps): update dependency @types/node to v20.14.12 2024-07-24 11:03:31 +00:00
renovate[bot] 0e8e3c7144 fix(types): update dependency type-fest to v4.23.0 (#20396)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 10:55:19 +03:00
renovate[bot] 96b45a85cf chore(deps): update dependency mocha to v10.7.0 2024-07-23 16:44:58 +00:00
renovate[bot] e08e7ebec2 fix(docutils): update dependency typescript to v5.5.4 2024-07-23 12:02:25 +00:00
renovate[bot] a0be939031 chore(deps): update dependency lerna to v8.1.7 2024-07-23 03:47:59 +00:00
renovate[bot] bb26085f7e chore(deps): update eslint-related packages 2024-07-23 01:21:30 +00:00
Mykola Mokhnach 75e0788784 chore(appium): Remove debug logging from the manifest class (#20393) 2024-07-17 22:06:47 +02:00
Niklas 7b3f0b5dbb docs: correct URL for selenium and w3c (#20392) 2024-07-17 19:54:09 +02:00
Kazuaki Matsuo 9eb65f7ad4 fix(base-driver): change required to option for setWindowRect to follow w3c (#20391) 2024-07-17 08:49:26 -07:00
renovate[bot] 47405dda8a fix(types): update dependency type-fest to v4.22.0 (#20387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-17 16:36:53 +03:00
renovate[bot] 5a9ab97924 fix(support): update dependency semver to v7.6.3 2024-07-17 09:54:34 +00:00
renovate[bot] 4494fad3af chore(deps): update dependency @types/node to v20.14.11 2024-07-17 08:22:44 +00:00
Kazuaki Matsuo 6a97fe48ae fix(base-driver): calls startNewCommandTimeout before returning NotYetImplementedError (#20380) 2024-07-16 00:12:44 -07:00
renovate[bot] d35ed1c8ac chore(deps): update eslint-related packages to v7.16.1 (#20381)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-16 09:10:16 +02:00
renovate[bot] d5ef0f9c86 fix(driver-test-support): update dependency @types/lodash to v4.17.7 (#20382)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-16 09:09:48 +02:00
Mykola Mokhnach 139dbaeef6 fix(base-driver): Start command timeout even if the recent command has thrown an exception (#20379) 2024-07-16 08:59:44 +02:00
Kazuaki Matsuo 2d7b2c4b4c chore(): define docs:publish and remove generate-docs (#20374) 2024-07-15 18:49:52 -07:00
renovate[bot] 6488a0a4e1 fix(base-driver): update dependency path-to-regexp to v7.1.0 (#20376)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-15 14:54:41 +03:00
renovate[bot] 6b9d844998 chore(docutils): update dependency mkdocs-material to v9.5.29 2024-07-15 09:53:35 +00:00
renovate[bot] 8ee816d0cf chore(deps): update dependency prettier to v3.3.3 2024-07-14 09:40:25 +00:00
renovate[bot] b1b7c33edd fix(types): update dependency @types/ws to v8.5.11 2024-07-13 13:26:39 +00:00
Srinivasan Sekar 57dc6a045d chore(docs): Add AppiumConf info in website (#20373)
* Add AppiumConf in website header

* add appium conference as blog
2024-07-13 14:34:40 +05:30
renovate[bot] 75289711ee fix(appium): update dependency ajv to v8.17.1 2024-07-13 07:14:00 +00:00
renovate[bot] b7b97a24d6 fix(doctor): update dependency appium-adb to v12.5.0 2024-07-11 14:49:13 +00:00
renovate[bot] 715942845b fix(support): update dependency glob to v10.4.5 (#20365)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-11 11:27:39 +03:00
renovate[bot] 8d79467da8 fix(logger): update dependency lru-cache to v10.4.3 (#20364)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-11 11:16:03 +03:00
renovate[bot] dcfec17d1c fix(appium): update dependency winston to v3.13.1 2024-07-11 08:06:48 +00:00
Edgars Eglītis c38e639d52 docs(appium): add more AppiumTestDistribution plugins (#20361) 2024-07-10 23:26:51 +02:00
105 changed files with 6248 additions and 2241 deletions
+982 -1748
View File
File diff suppressed because it is too large Load Diff
+17 -19
View File
@@ -42,8 +42,8 @@
"dev:docs": "npm run -w packages/appium dev:docs",
"docs": "npm run -w packages/appium build:docs",
"docs:preview": "npm run -w packages/appium build:docs:preview",
"docs:publish": "npm run -w packages/appium publish:docs",
"doctor": "node ./packages/doctor",
"generate-docs": "npm run --workspace=packages/appium generate-docs",
"lint": "eslint .",
"lint:ci": "eslint --quiet .",
"lint:fix": "run-s \"lint -- --fix\"",
@@ -83,20 +83,20 @@
"devDependencies": {
"@colors/colors": "1.6.0",
"@tsconfig/node14": "14.1.2",
"@types/chai": "4.3.16",
"@types/chai": "4.3.17",
"@types/chai-as-promised": "7.1.8",
"@types/diff": "5.2.1",
"@types/mocha": "10.0.7",
"@types/node": "20.14.10",
"@types/node": "20.14.14",
"@types/semver": "7.5.8",
"@types/sinon": "17.0.3",
"@types/sinon-chai": "3.2.12",
"@types/source-map-support": "0.5.10",
"@types/teen_process": "2.0.4",
"@types/ws": "8.5.10",
"@types/ws": "8.5.12",
"@types/yargs": "17.0.32",
"@typescript-eslint/eslint-plugin": "7.16.0",
"@typescript-eslint/parser": "7.16.0",
"@typescript-eslint/eslint-plugin": "7.18.0",
"@typescript-eslint/parser": "7.18.0",
"asyncbox": "3.0.0",
"chai": "5.1.1",
"chai-as-promised": "8.0.0",
@@ -107,31 +107,29 @@
"eslint-find-rules": "4.1.0",
"eslint-import-resolver-typescript": "3.6.1",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-mocha": "10.4.3",
"eslint-plugin-promise": "6.4.0",
"fancy-log": "2.0.0",
"eslint-plugin-mocha": "10.5.0",
"eslint-plugin-promise": "6.6.0",
"finalhandler": "1.2.0",
"get-port": "5.1.1",
"json-schema-to-typescript": "14.1.0",
"lerna": "8.1.6",
"json-schema-to-typescript": "15.0.0",
"lerna": "8.1.7",
"log-symbols": "4.1.0",
"midnight-smoker": "8.0.0",
"mjpeg-consumer": "2.0.0",
"mjpeg-server": "0.3.1",
"mocha": "10.6.0",
"mocha": "10.7.0",
"npm-run-all2": "6.2.2",
"prettier": "3.3.2",
"prettier": "3.3.3",
"rewiremock": "3.14.5",
"rimraf": "5.0.9",
"rimraf": "5.0.10",
"serve-static": "1.15.0",
"sinon": "18.0.0",
"sync-monorepo-packages": "1.0.2",
"through2": "4.0.2",
"ts-node": "10.9.2",
"tsd": "0.31.1",
"typescript": "5.5.3",
"typescript": "5.5.4",
"validate.js": "0.13.1",
"webdriverio": "8.39.1",
"webdriverio": "8.40.0",
"ws": "8.18.0",
"yaml-js": "0.3.1"
},
@@ -144,10 +142,10 @@
},
"overrides": {
"@sidvind/better-ajv-errors": {
"ajv": "8.16.0"
"ajv": "8.17.1"
},
"ajv-formats": {
"ajv": "8.16.0"
"ajv": "8.17.1"
},
"http-cache-semantics": "4.1.1"
}
+17
View File
@@ -3,6 +3,23 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.11.3](https://github.com/appium/appium/compare/appium@2.11.2...appium@2.11.3) (2024-08-07)
### Bug Fixes
* **appium:** update dependency ajv to v8.17.1 ([7528971](https://github.com/appium/appium/commit/75289711ee344ac9a11a572f13ddb0471e2cbf79))
* **appium:** update dependency winston to v3.13.1 ([dcfec17](https://github.com/appium/appium/commit/dcfec17d1ceab90939b5f199854ba630829e3d1f))
* **docutils:** update dependency yaml to v2.5.0 ([0c755f5](https://github.com/appium/appium/commit/0c755f503c49e459315616e51be0c0776089b2bb))
* **execute-driver-plugin:** update dependency webdriverio to v8.40.0 ([#20442](https://github.com/appium/appium/issues/20442)) ([b4612e0](https://github.com/appium/appium/commit/b4612e0c7a21902a3cab658fbdc05f3b48c55d0d))
* **logger:** update dependency lru-cache to v10.4.3 ([#20364](https://github.com/appium/appium/issues/20364)) ([8d79467](https://github.com/appium/appium/commit/8d79467da8a0733ac3e49b9152bd6905989a57ca))
* **support:** update dependency axios to v1.7.3 ([1ca77c6](https://github.com/appium/appium/commit/1ca77c6dedbff4552aba9c97cf5406c7552d1a01))
* **support:** update dependency semver to v7.6.3 ([5a9ab97](https://github.com/appium/appium/commit/5a9ab9792402e31d3903fb1a3b08329a67b6a2a2))
* **types:** update dependency type-fest to v4.22.0 ([#20387](https://github.com/appium/appium/issues/20387)) ([47405dd](https://github.com/appium/appium/commit/47405dda8a5de17c72fb721b0c043e0dd4f6b35a))
* **types:** update dependency type-fest to v4.23.0 ([#20396](https://github.com/appium/appium/issues/20396)) ([0e8e3c7](https://github.com/appium/appium/commit/0e8e3c71441d02d22f015f08df5223909f5fbb93))
## [2.11.2](https://github.com/appium/appium/compare/appium@2.11.1...appium@2.11.2) (2024-07-10)
+17 -6
View File
@@ -1,8 +1,19 @@
authors:
jlipps:
name: "Jonathan Lipps"
description: "Appium project lead. Learn more about Jonathan at https://jlipps.com"
avatar: "https://gravatar.com/avatar/fdaadd825d92709bcf7fe76dffa12c40681c6108c67bcddf19478b2d00e3794b.jpg"
slug: "jlipps"
url: "https://jlipps.com"
name: 'Jonathan Lipps'
description: 'Appium project lead. Learn more about Jonathan at https://jlipps.com'
avatar: 'https://gravatar.com/avatar/fdaadd825d92709bcf7fe76dffa12c40681c6108c67bcddf19478b2d00e3794b.jpg'
slug: 'jlipps'
url: 'https://jlipps.com'
srini:
name: 'Srinivasan Sekar'
description: 'Appium Maintainer'
avatar: 'https://avatars.githubusercontent.com/u/8896549?v=4'
slug: 'srini'
url: 'https://srini.codes'
sai:
name: 'Sai krishna'
description: 'Appium Maintainer'
avatar: 'https://avatars.githubusercontent.com/u/4045041?v=4'
slug: 'sai'
url: 'https://saikrishna.tech'
@@ -0,0 +1,45 @@
---
authors:
- srini
- sai
date: 2024-07-13
---
# Appium Conf 2024: Call for Proposals Now Open!
We're thrilled to announce that Appium Conf is back and going online for 2024! This is the official Appium conference where you can learn all about what's new in Appium 2.0 and explore the latest in automating tests for devices, mobile apps, and desktop applications.
<!-- more -->
<div style="text-align:center;width:100%">
<a href="https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch">
<img id="image-36-42" alt="Appium Conf logo" src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" data-src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" decoding="async">
</a>
</div>
## Mark Your Calendars: September 13, 2024
Join us on September 13, 2024, for a full day of inspiring and practical talks from the Appium team and the world's top mobile testing and automation experts. With Appium 2.0 now well-established, this is your opportunity to dive deep and learn how to maximize its potential.
## Why Attend Appium Conf 2024?
1. **Gain Insights**: Hear interesting insights and inspiring case studies from global experts and the core Appium team.
2. **Improve Your Strategy**: Gain valuable knowledge to enhance your own automation strategy.
3. **Network**: Make connections with Appium users from around the globe.
4. **Learn from Specialists**: Benefit from Appium specialists' expertise on a variety of topics.
## Call for Proposals: Share Your Knowledge!
We're looking for a diverse range of speakers from around the globe who are eager to share innovative ideas and use-cases of mobile test automation. If you have experience with Appium and insights that could benefit the community of test practitioners, we want to hear from you!
Don't miss this chance to contribute to the Appium community and showcase your expertise on a global stage.
## How to Submit Your Proposal
Visit our website at [https://appiumconf.com/](https://appiumconf.com/) and [Submit a Proposal](https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch). We're excited to see your innovative ideas and experiences with Appium!
## Stay Tuned
Keep an eye on our website and social media channels for updates on the conference schedule, keynote speakers, and more exciting details about Appium Conf 2024.
Join us in shaping the future of mobile and device test automation. Submit your proposal today and be part of this exciting event!
+1 -1
View File
@@ -37,13 +37,13 @@ These drivers are not maintained by the Appium team and can be used to target ad
|Driver|Installation Key|Platform(s)|Mode(s)|Supported By|
|--|--|--|--|--|
|[Flutter](https://github.com/appium/appium-flutter-driver)|`--source=npm appium-flutter-driver`|iOS, Android|Native|Community|
|[Flutter Integration](https://github.com/AppiumTestDistribution/appium-flutter-integration-driver)|`--source=npm appium-flutter-integration-driver`|iOS, Android|Native|Community / `@AppiumTestDistribution`|
|[LG WebOS](https://github.com/headspinio/appium-lg-webos-driver)|`--source=npm appium-lg-webos-driver`|LG TV|Web|HeadSpin|
|[Linux](https://github.com/fantonglang/appium-linux-driver)|`--source=npm @stdspa/appium-linux-driver`|Linux|Native|`@fantonglang`|
|[Roku](https://github.com/headspinio/appium-roku-driver)|`--source=npm @headspinio/appium-roku-driver`|Roku|Native|HeadSpin|
|[Tizen](https://github.com/Samsung/appium-tizen-driver)|`--source=npm appium-tizen-driver`|Android|Native|Community / Samsung|
|[TizenTV](https://github.com/headspinio/appium-tizen-tv-driver)|`--source=npm appium-tizen-tv-driver`|Samsung TV|Web|HeadSpin|
|[Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver)|`--source=npm appium-youiengine-driver`|iOS, Android, macOS, Linux, tvOS|Native|Community / You.i|
|[Flutter Integration](https://github.com/AppiumTestDistribution/appium-flutter-integration-driver)|`--source=npm appium-flutter-integration-driver`|Android, iOS|Native|Community / AppiumTestDistribution|
!!! note
+5 -2
View File
@@ -32,9 +32,12 @@ These plugins are not maintained by the Appium team and can provide additional f
|<div style="width:6em">Plugin</div>|<div style="width:19em">Installation Key</div>|Description|<div style="width:13em">Supported By</div>|
|---|---|---|---|
|[AltUnity](https://github.com/headspinio/appium-altunity-plugin)|`--source=npm appium-altunity-plugin`|Target Unity games and apps for automation with a new context, via the AltUnityTester framework|HeadSpin|
|[Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)|`--source=npm appium-device-farm`|Manage and create driver session on connected android devices and iOS Simulators.|`@AppiumTestDistribution`|
|[Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)|`--source=npm appium-device-farm`|Manage and create driver sessions on connected Android devices and iOS simulators|`@AppiumTestDistribution`|
|[Gestures](https://github.com/AppiumTestDistribution/appium-gestures-plugin)|`--source=npm appium-gestures-plugin`|Perform basic gestures using W3C Actions|`@AppiumTestDistribution`|
|[Interceptor](https://github.com/AppiumTestDistribution/appium-interceptor-plugin)|`--source=npm appium-interceptor`|Intercept and mock API requests and responses|`@AppiumTestDistribution`|
|[OCR](https://github.com/jlipps/appium-ocr-plugin)|`--source=npm appium-ocr-plugin`|Find elements via OCR text|`@jlipps`|
|[Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)|`--source=npm appium-reporter-plugin`|Generates standalone consolidated html report with screenshots. Reports can be fetched from appium server, without worrying about heavy lifting such as screenshot capturing, report generation etc.|`@AppiumTestDistribution`|
|[Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)|`--source=npm appium-reporter-plugin`|Generate standalone consolidated HTML reports with screenshots|`@AppiumTestDistribution`|
|[Wait](https://github.com/AppiumTestDistribution/appium-wait-plugin)|`--source=npm appium-wait-plugin`|Manage global element wait timeouts|`@AppiumTestDistribution`|
!!! note
+6
View File
@@ -11,6 +11,12 @@ title: Welcome
display: none;
}
</style>
<div style="text-align:center;width:100%;background-color:#7f56c2" >
<h3>
Appium Conf 2024 is coming online, 13 September. Have you got something to share with the community? <a style="color:#fcba12" href="https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch" target="blank">Submit a proposal</a>
</h3>
</div>
<div style="text-align: center">
<img src="assets/images/appium-logo-horiz.png" style="max-width: 400px;" />
</div>
+2 -2
View File
@@ -40,12 +40,12 @@ but it is certainly a good one! So let's dive in.
## Appium's choice of API
Appium is very fortunate to have been preceded by a technology which has been a long-standing
pioneer in the field of UI automation, namely [Selenium](https://seleniumhq.org). The goal of the
pioneer in the field of UI automation, namely [Selenium](https://selenium.dev). The goal of the
Selenium project has been to support UI automation of web browsers, and in this way we can think of
it as occupying a subset of Appium's goals. Along the way, Selenium (and, after they merged,
another project called WebDriver) developed a relatively stable API for browser automation.
Over the years, Selenium worked with various web browser vendors and the [W3C](https://w3c.org)
Over the years, Selenium worked with various web browser vendors and the [W3C](https://w3.org)
standards group to turn its API into an official web browser standard, called the [WebDriver
specification](https://w3c.github.io/webdriver/). All the main browsers now
implement automation capabilities inline with the WebDriver spec, without the Selenium team having
+46 -24
View File
@@ -8,6 +8,7 @@ theme:
language: zh
nav:
- 首页: index.md
- 博客: blog/index.md
- 简介:
- intro/index.md
- 背景:
@@ -17,40 +18,61 @@ nav:
- intro/history.md
- 快速开始:
- quickstart/index.md
- quickstart/requirements.md
- quickstart/install.md
- quickstart/uiauto2-driver.md
- 编写测试:
- Write a Test:
- quickstart/test-js.md
- quickstart/test-py.md
- quickstart/test-java.md
- quickstart/test-rb.md
- quickstart/test-dotnet.md
- quickstart/next-steps.md
- 生态系统:
- ecosystem/index.md
- 开发 Appium 扩展:
- ecosystem/build-drivers.md
- ecosystem/build-plugins.md
- ecosystem/build-docs.md
- 命令行参考:
- ecosystem/drivers.md
- ecosystem/clients.md
- ecosystem/plugins.md
- ecosystem/tools.md
- CLI Reference:
- cli/index.md
- cli/args.md
- cli/env-vars.md
- cli/extensions.md
- cli/setup.md
- Command Reference:
- ../en/commands/base-driver.md
- ../en/commands/execute-driver-plugin.md
- ../en/commands/images-plugin.md
- ../en/commands/relaxed-caps-plugin.md
- ../en/commands/universal-xml-plugin.md
- commands/index.md
- commands/base-driver.md
- commands/execute-driver-plugin.md
- commands/images-plugin.md
- commands/relaxed-caps-plugin.md
- commands/universal-xml-plugin.md
- 指南:
- guides/migrating-1-to-2.md
- guides/managing-exts.md
- guides/config.md
- guides/security.md
- guides/caps.md
- guides/context.md
- guides/settings.md
- guides/execute-script-overload.md
- guides/event-timing.md
- guides/log-filters.md
- guides/grid.md
- 更多 Appium 资源: resources.md
- 贡献: contributing/index.md
- Migration:
- guides/migrating-1-to-2.md
- Server/Driver Configuration:
- guides/managing-exts.md
- guides/branch-testing.md
- guides/config.md
- guides/security.md
- guides/log-filters.md
- guides/grid.md
- guides/caching.md
- guides/tls.md
- Session Configuration:
- guides/caps.md
- guides/settings.md
- guides/execute-methods.md
- guides/context.md
- guides/event-timing.md
- 更多资源: resources.md
- 开发:
- developing/index.md
- developing/build-drivers.md
- developing/build-plugins.md
- developing/build-docs.md
- developing/build-doctor-checks.md
- 贡献:
- contributing/index.md
- contributing/develop.md
- contributing/config-system.md
+19
View File
@@ -0,0 +1,19 @@
authors:
jlipps:
name: 'Jonathan Lipps'
description: 'Appium project lead. Learn more about Jonathan at https://jlipps.com'
avatar: 'https://gravatar.com/avatar/fdaadd825d92709bcf7fe76dffa12c40681c6108c67bcddf19478b2d00e3794b.jpg'
slug: 'jlipps'
url: 'https://jlipps.com'
srini:
name: 'Srinivasan Sekar'
description: 'Appium Maintainer'
avatar: 'https://avatars.githubusercontent.com/u/8896549?v=4'
slug: 'srini'
url: 'https://srini.codes'
sai:
name: 'Sai krishna'
description: 'Appium Maintainer'
avatar: 'https://avatars.githubusercontent.com/u/4045041?v=4'
slug: 'sai'
url: 'https://saikrishna.tech'
+1 -1
View File
@@ -1,2 +1,2 @@
# Blog
# 博客
@@ -0,0 +1,45 @@
---
authors:
- srini
- sai
date: 2024-07-13
---
# Appium Conf 2024: Call for Proposals Now Open!
We're thrilled to announce that Appium Conf is back and going online for 2024! This is the official Appium conference where you can learn all about what's new in Appium 2.0 and explore the latest in automating tests for devices, mobile apps, and desktop applications.
<!-- more -->
<div style="text-align:center;width:100%">
<a href="https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch">
<img id="image-36-42" alt="Appium Conf logo" src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" data-src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" decoding="async">
</a>
</div>
## Mark Your Calendars: September 13, 2024
Join us on September 13, 2024, for a full day of inspiring and practical talks from the Appium team and the world's top mobile testing and automation experts. With Appium 2.0 now well-established, this is your opportunity to dive deep and learn how to maximize its potential.
## Why Attend Appium Conf 2024?
1. **Gain Insights**: Hear interesting insights and inspiring case studies from global experts and the core Appium team.
2. **Improve Your Strategy**: Gain valuable knowledge to enhance your own automation strategy.
3. **Network**: Make connections with Appium users from around the globe.
4. **Learn from Specialists**: Benefit from Appium specialists' expertise on a variety of topics.
## Call for Proposals: Share Your Knowledge!
We're looking for a diverse range of speakers from around the globe who are eager to share innovative ideas and use-cases of mobile test automation. If you have experience with Appium and insights that could benefit the community of test practitioners, we want to hear from you!
Don't miss this chance to contribute to the Appium community and showcase your expertise on a global stage.
## How to Submit Your Proposal
Visit our website at [https://appiumconf.com/](https://appiumconf.com/) and [Submit a Proposal](https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch). We're excited to see your innovative ideas and experiences with Appium!
## Stay Tuned
Keep an eye on our website and social media channels for updates on the conference schedule, keynote speakers, and more exciting details about Appium Conf 2024.
Join us in shaping the future of mobile and device test automation. Submit your proposal today and be part of this exciting event!
@@ -0,0 +1,46 @@
---
authors:
- jlipps
date: 2024-06-10
---
# Announcing BrowserStack as Appium's Strategic Partner
We have another exciting announcement for you! As part of our recently-announced [sponsorship and
contributor compensation
program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/),
we are obviously in need of significant funding to support giving back to our contributor
community. We are therefore extremely happy to announce one of our brand new exclusive Strategic Partners: <a
href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">BrowserStack</a>!
<!-- more -->
<div style="text-align:center;width:100%">
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
<img src="/docs/en/latest/assets/images/sponsor-logo-browserstack-dark.png#only-dark" width="300" />
<img src="/docs/en/latest/assets/images/sponsor-logo-browserstack-light.png#only-light" width="300" />
</a>
</div>
BrowserStack has long been recognized in the industry as having extensive support for Appium,
allowing you to run functional and visual regression tests for your native and hybrid apps at scale
across a variety of devices and platforms.
As a token of this collaboration, BrowserStack is extending a special premium access of
BrowserStack App Automate product to Appium users. Discover more about this special offer at
[browserstack.com](https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium&utm_term=partannouncement)
With the decision to come on board as Strategic Partner, BrowserStack is making a huge investment
in Appium and the Appium community. BrowserStack is very interested in supporting the development
of the Appium contributor base, and is proud to be a key part of our contributor compensation
scheme. Without Strategic Partners like BrowserStack, we would not be able to maintain such
a program! We welcome them with gratitude!
**About BrowserStack**
<em>BrowserStack is the world’s leading software testing platform powering over two million tests every
day across 19 global data centers. BrowserStack helps Tesco, Shell, NVIDIA, Discovery, Wells Fargo,
and over 50,000 customers deliver quality software at speed by moving testing to their Cloud.
BrowserStack’s platform provides instant access to 20,000+ real mobile devices on a highly reliable
cloud infrastructure that effortlessly scales as testing needs grow. With BrowserStack, Dev and QA
teams can move fast while delivering an amazing experience for every customer.</em>
@@ -0,0 +1,47 @@
---
authors:
- jlipps
date: 2024-06-06
---
# Announcing HeadSpin as Appium's Development Partner
Recently, we announced a new [sponsorship and contributor compensation program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/) for the Appium
project. As part of this program, we felt it was important to have a place to recognize those
companies who make an extremely valuable kind of contribution to the project: dedicated maintainer
time. Appium only survives because of the tireless efforts of the core maintainers, and some of us
are only able to do this work because it is donated on behalf of our day jobs. We're therefore very
excited to announce our first Development Partner: <a
href="https://www.headspin.io/solutions/appium-mobile-test-automation">HeadSpin</a>!
<!-- more -->
<div style="text-align:center;width:100%">
<a href="https://www.headspin.io/solutions/appium-mobile-test-automation"><img
src="/docs/en/latest/assets/images/sponsor-logo-headspin.png" style="width: 300px"/></a>
</div>
HeadSpin is a real device performance and UX analysis cloud, with full support for Appium. When you
run your Appium tests on HeadSpin, you get access to comprehensive performance reports about your
app, including potential network, system resource, or user experience issues. HeadSpin supports
a variety of complex testing modes, including hooking up your own devices to the cloud, injecting
and receiving video and audio to/from devices, working with media (streaming) platforms, and more.
HeadSpin has been one of the Appium project's biggest supporters for a long time, and currently
employs two of Appium's core maintainers, donating a significant portion of their time towards the
development, maintenance, support, and leadership of open source Appium repos. HeadSpin has also
worked hard towards Appium's vision of a robust Appium ecosystem, contributing several
HeadSpin-maintained Appium drivers and plugins to the community:
- A [Roku TV driver](https://github.com/headspinio/appium-roku-driver)
- A [Tizen TV driver](https://github.com/headspinio/appium-tizen-tv-driver/)
- A [LG webOS TV driver](https://github.com/headspinio/appium-lg-webos-driver/)
- A [Unity game automation plugin](https://github.com/headspinio/appium-altunity-plugin)
These are all free and open source Appium components that HeadSpin has donated to the community
with the goal of fostering collaboration in these areas of media app automation.
Looking to the future, HeadSpin plans to continue supporting Appium in significant ways, both as
a Development Partner and a significant contributor to the Appium ecosystem. The Appium project is
deeply indebted to HeadSpin for all of its support, and is proud to take this moment to recognize
HeadSpin as our first official Development Partner!
@@ -0,0 +1,36 @@
---
authors:
- jlipps
date: 2024-06-10
---
# Announcing Sauce Labs as Appium's Strategic Partner
The good news surrounding our new [sponsorship and contributor compensation
program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/)
just keeps coming! Effective immediately we are fortunate and excited to be able to welcome a new Strategic Partner to
the Appium project: <a href="https://saucelabs.com/resources/blog/appium-strategic-partner">Sauce Labs</a>!
<!-- more -->
<div style="text-align:center;width:100%">
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner"><img src="/docs/en/latest/assets/images/sponsor-logo-sauce.png" style="width: 300px"/></a>
</div>
Sauce Labs has a long history of support for the Appium project. In fact, Appium was initially
incubated at Sauce Labs under the direction of [@jlipps](https://github.com/jlipps), in the early
days of mobile automation. Sauce Labs always envisioned Appium as being a project for and by the
community, and cemented this perspective in 2016 with the donation of Appium to the JS Foundation
(now the [OpenJS Foundation](https://openjsf.org/)). To this day, developers associated with Sauce
Labs continue to help maintain various parts of the Appium project.
Now, Sauce Labs is making a further commitment to support Appium financially as a way to enable
our new contributor compensation program. We're very excited about this program as a vehicle for
getting more people involved in Appium's development and maintenance. With the help of Strategic
Partners like Sauce Labs, our project will be better able to meet the needs of our constantly
growing userbase, and attract new developers (like you?) to build the Appium ecosystem together.
Needless to say, we are extremely grateful for Sauce Labs's support!
**About Sauce Labs**
<em>Sauce Labs is the leader in continuous quality. Our Platform for Test helps organizations transform software testing from a chore to a competitive advantage. With decades of expertise and deep roots in the Selenium and Appium open source communities, high performing software teams use our platform to execute any testing workload across thousands of different devices, browsers, and operating systems—anywhere, any time, and at any scale. For more information, please visit [saucelabs.com](https://saucelabs.com).</em>
@@ -0,0 +1,48 @@
---
authors:
- jlipps
date: 2024-05-14
---
# Announcing Appium's Sponsorship Program
Over the last several months, the Appium team has been working on a sponsorship program that is
designed to help give back to Appium's contributors as well as to recognize important partner
individuals or companies in the industry. This program is now officially launching! Let's dive into
some of the details.
<!-- more -->
First of all, the details and fine print will always be available at Appium's [Governance
document](https://github.com/appium/appium/blob/master/GOVERNANCE.md), which outlines how the
project is run, who makes project decisions, etc... This document will be kept up to date with the
latest details of the program, so that's the place to bookmark for reference!
As of now, Appium has opened up sponsorship opportunities via our [OpenCollective
page](https://opencollective.com/appium). OpenCollective is a service which allows people to donate
to open source groups. We've defined a number of giving tiers for donations, within a very wide
range, and welcome any financial amount with gratitude! Based on the donation tier, sponsorship
comes with a variety of benefits, including recognition at different places in the Appium repo,
docs, and website. In addition to financial sponsorship, the project has decided to recognize
significant donations of project leadership and maintenance efforts from companies who have
invested heavily into Appium with their employees' time (we call these "Development Partners").
What will the project do with the funds raised through this sponsorship program? We aim to give it
all back to the Appium community! With the details again available at our [Governance document](https://github.com/appium/appium/blob/master/GOVERNANCE.md),
we have implemented a scheme very much inspired by our friends at [WebdriverIO](https://webdriver.io/blog/2024/02/15/new-contributor-stipend-program) (thanks WDIO
friends!) There are three groups of contributors to Appium that this scheme supports: (1) project
maintainers (those who devote consistent time to leading the project), (2) project contributors
(anyone in the wider community that contributes code or documentation), and (3) upstream projects
(other open source projects Appium relies heavily on to work well). Each month, the funds raised
via sponsorship will be distributed in different amounts to each of these groups. So if you
make a valuable contribution to Appium moving forward, you'll be eligible to get some cash as
a thank-you! (You'll need to have your own OpenCollective account in good standing to receive
funds).
We're very excited about this new program, and hope that it helps existing and new contributors to
feel even better about donating their time to making Appium better. And of course, none of this
would be possible without the amazing Partners and Sponsors we hope to attract! On that note, stay
tuned over the next few weeks as we unveil some of our initial program launch Partners! And if you
or your company would like to participate by supporting Appium financially, you are most welcome.
Just head over to our OpenCollective page and choose the tier that reflects your desired
contribution level.
@@ -0,0 +1,15 @@
---
authors:
- jlipps
date: 2024-03-07
---
# Hello World!
This is the first post in the Appium blog. There's not much to see here yet. We're creating this
space so we can make announcements or post other news, or information about events, that don't
really fit inside the documentation itself.
<!-- more -->
Stay tuned for more!
+66 -2
View File
@@ -1,5 +1,69 @@
---
title: Server CLI Args
hide:
- toc
title: Server Command-Line Arguments
---
TODO
To start the Appium server, you may either run `appium` or `appium server`. The `server` subcommand
is considered to be the default, so if you omit it, Appium will interpret this as your request to
run the Appium server.
The invocation of `appium` (or `appium server`) can take a number of arguments, which are detailed
below.
!!! note
All of these arguments can be set via a [Configuration File](../guides/config.md) instead if
you want. Any arguments set on the command line will override any arguments found in
a configuration file.
|<div style="width:12em">Argument</div>|Description|Type|<div style="width:8em">Default</div>|Aliases|
|--|--|--|--|--|
|`--address`|IP address to listen on|string|`0.0.0.0`|`-a`|
|`--allow-cors`|Whether the Appium server should allow web browser connections from any host|boolean|`false`||
|`--allow-insecure`|Set which insecure features are allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Note that features defined via `--deny-insecure` will be disabled, even if also listed here. If string, a path to a text file containing policy or a comma-delimited list.|array<string>|`[]`||
|`--base-path`|Base path to use as the prefix for all webdriver routes running on the server|string|`""`|`-pa`|
|`--callback-address`|Callback IP address (default: same as `--address`)|string||`-ca`|
|`--callback-port`|Callback port (default: same as `--port`) (Value must be between `1` and `65535`)|integer|`4723`|`-cp`|
|`--config`|Path to an [Appium configuration JSON file](../guides/config.md)|string|||
|`--debug-log-spacing`|Add exaggerated spacing in logs to help with visual inspection|boolean|`false`||
|`--default-capabilities`|Set the default desired capabilities, which will be set on each session unless overridden by received capabilities. If a string, a path to a JSON file containing the capabilities, or raw JSON.|object||`-dc`|
|`--deny-insecure`|Set which insecure features are not allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Features listed here will not be enabled even if also listed in `--allow-insecure`, and even if `--relaxed-security` is enabled. If string, a path to a text file containing policy or a comma-delimited list.|array<string>|`[]`||
|`--driver`|Driver-specific configuration. Keys should correspond to driver package names|object|||
|`--drivers-import-chunk-size`|The maximum amount of drivers that could be imported in parallel on server startup|number|`3`||
|`--keep-alive-timeout`|Number of seconds the Appium server should apply as both the keep-alive timeout and the connection timeout for all requests. Setting this to `0` disables the timeout.|integer|`600`|`-ka`|
|`--local-timezone`|Use local timezone for timestamps|boolean|`false`||
|`--log`|Also send log output to this file|string||`-g`|
|`--log-filters`|One or more log filtering rules|array|||
|`--log-level`|Log level (console[:file]) (Value must be one of: `info`, `info:debug`, `info:info`, `info:warn`, `info:error`, `warn`, `warn:debug`, `warn:info`, `warn:warn`, `warn:error`, `error`, `error:debug`, `error:info`, `error:warn`, `error:error`, `debug`, `debug:debug`, `debug:info`, `debug:warn`, `debug:error`)|string|`debug`||
|`--log-format`|Log format (Value must be to one of: `text`, `json`, `pretty_json`). If logs are printed as JSON then the text coloring is always disabled.|string|`text`||
|`--log-no-colors`|Do not use color in console output|boolean|`false`||
|`--log-timestamp`|Show timestamps in console output|boolean|`false`||
|`--long-stacktrace`|Add long stack traces to log entries. Recommended for debugging only.|boolean|`false`||
|`--no-perms-check`|Skip various permission checks on the server startup|boolean|`false`||
|`--nodeconfig`|Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself|string|||
|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object|||
|`--plugins-import-chunk-size`|The maximum amount of plugins that could be imported in parallel on server startup|number|`7`||
|`--port`|Port to listen on (Value must be between `1` and `65535`)|integer|`4723`|`-p`|
|`--relaxed-security`|Disable additional security checks, so it is possible to use some advanced features, provided by drivers supporting this option. Only enable it if all the clients are in the trusted network and it's not the case if a client could potentially break out of the session sandbox. Specific features can be overridden by using `--deny-insecure`|boolean|`false`||
|`--session-override`|Enables session override (clobbering)|boolean|`false`||
|`--ssl-cert-path`|Absolute path to the `.cert` file if TLS is used. Must be provided together with `--ssl-key-path`. See the [SSL/TLS/SPDY Support guide](../guides/tls.md) for details|string|||
|`--ssl-key-path`|Absolute path to the `.key` file if TLS is used. Must be provided together with `--ssl-cert-path`. See the [SSL/TLS/SPDY Support guide](../guides/tls.md) for details|string|||
|`--strict-caps`|Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device|boolean|`false`||
|`--tmp`|Absolute path to directory Appium can use to manage temp files|string|Windows: `C:\Windows\Temp`<br>Others: `/tmp`||
|`--trace-dir`|Absolute path to directory Appium can use to save iOS instrument traces|string|`<tmp>/appium-instruments`||
|`--use-drivers`|A list of drivers to activate. By default, all installed drivers will be activated.|array<string>|`[]`||
|`--use-plugins`|A list of plugins to activate. To activate all plugins, the value should be an array with a single item `"all"`.|array<string>|`[]`||
|`--webhook`|Also send log output to this http listener|string||`-G`|
The following arguments are used for information retrieval, after which the server will automatically exit. They are therefore meant for reference or debug purposes.
|<div style="width:10em">Argument</div>|Description|Alias|
|--|--|--|
|`--help`|Print instructions on using the Appium command-line. This argument can also be used for any Appium subcommands.|`-h`|
|`--show-build-info`|Print detailed information on the Appium server version||
|`--show-config`|Print the current Appium server configuration details||
|`--show-debug-info`|Print information on the current environment: details about the operating system, Node.js, and Appium itself||
|`--version`|Print the Appium server version|`-v`|
+26
View File
@@ -0,0 +1,26 @@
---
hide:
- toc
title: Server Environment Variables
---
The primary way of configuring the Appium server is via [Command-Line Arguments](./args.md). However, some more
advanced features are toggled or configured via environment variables. To set environment
variables, refer to the documentation for your operating system and terminal. These are the
environment variables that the Appium server understands:
|Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|Description|
|--------|-----------|
|`APPIUM_HOME`|By default, Appium creates a directory called `.appium` in the home directory for your system user. You can adjust the directory with this variable, as detailed in the [Managing Extensions](../guides/managing-exts.md) guide.|
|`APPIUM_TMP_DIR`|By default, Appium uses a random temporary directory for many of its operations. If you wish to use a specific directory, you may do so by including an absolute path as the value of this variable. The behaviour is equivalent to using the `--tmp` CLI arg.|
|`APPIUM_PREFER_SYSTEM_UNZIP`|Set to `0` or `false` to request that Appium not use the `unzip` binary included on your system for unzipping downloaded apps or other artifacts. Instead it will use a JS-based unzip library. This could help on some systems with non-existent or non-standard `unzip` commands. Note that if unzipping fails using the system library, the fallback library will be attempted in any case, so setting this env var merely saves time in the event you know the system unzip will fail.|
|`APPIUM_HOST`|Same as the `--address` CLI arg|
|`APPIUM_PORT`|Same as the `--port` CLI arg|
|`APPIUM_RELOAD_EXTENSIONS`|Set to `1` to cause Appium to re-require extensions when new sessions are created. This is mostly useful for [building extensions](../developing/build-drivers.md)|
|`APPIUM_OMIT_PEER_DEPS`|Adds `--omit=peer` to all the NPM commands run internally by Appium. Mostly an internal feature.|
|`APPIUM_APPS_CACHE_MAX_AGE`|Allows to set the maximum age (in minutes) for [cached applications](../guides/caching.md). The default value is `60 * 24` (24 hours). Do not set it to a lower number than the duration of a single session startup.|
|`APPIUM_APPS_CACHE_MAX_ITEMS`|Allows to set the maximum amount of [cached applications](../guides/caching.md). The default value is `1024`. Do not set it to a lower number than the amount of apps in all parallel sessions per process.|
|`APPIUM_APPS_CACHE_IGNORE_URL_QUERY`| If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys. See the corresponding
[feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713)
for more details. Disabled by default.|
+223 -2
View File
@@ -1,5 +1,226 @@
---
title: The Extension CLI
title: Extension Command-Line Usage
---
TODO
Appium allows for the flexible installation and management of various _extensions_, such as _drivers_
(which provide Appium with the capability to automate a given platform) and _plugins_ (which can
augment or alter the way individual Appium commands work). For a conceptual understanding of these
entities, please review the [Introduction](../intro/index.md).
Management of drivers and plugins is handled by Appium's Extension CLI (command-line interface).
!!! note
This reference uses placeholders to refer to various options. Anywhere you see one of these
placeholders in the reference, ensure you replace it with the correct type of actual content.
|Placeholder|Meaning|
|--|--|
|`<ext-type>`|"Extension type". It should be either `driver` or `plugin`. All the Extension CLI commands can be used with either drivers or plugins, so you must specify which type of extension will be used|
|`<ext-name>`|"Extension name". This is the short name of the extension found in a call to `appium <ext-type> list`. This is distinct from the NPM package name of the extension or, in general, the "install spec" of the extension.|
|`<install-spec>`|"Install specification". This refers to the string used to indicate what extension Appium should install.|
|`<install-source>`|This refers to the method that Appium should use to install an extension.|
## Commands
All Extension CLI commands begin with `appium <ext-type>`, i.e., either `appium driver` or `appium
plugin`.
All Extension CLI commands can take an optional `--json` argument, which will return the result of
the command as a machine-readable JSON string rather than the standard output, which is colourized
and tuned for human consumption.
### `doctor`
Run doctor checks for the given extension, which validate whether the extension has its prerequisites
configured correctly. Note that not all extensions include doctor checks. See the
[Building Doctor Checks](../developing/build-doctor-checks.md) tutorial for more details on
how to create them.
Usage:
```
appium <ext-type> doctor <ext-name>
```
Required arguments:
- `<ext-type>`: must be `driver` or `plugin`
- `<ext-name>`: the name of the extension whose doctor checks you want to run
Optional arguments:
- `--json`: return the result in JSON format
Example (run doctor checks for the UiAutomator2 driver):
```
appium driver doctor uiautomator2
```
### `install`
Install an extension. If successful, respond with the short name of the extension which can be used
in other invocations of the Extension CLI. If the extension is a driver, also note which platforms
may be used with the driver.
Usage:
```
appium <ext-type> install <install-spec> [--source=<install-source>] [--package=<package-name>] [--json]
```
Required arguments:
- `<ext-type>`: must be `driver` or `plugin`
- `<install-spec>`: this is the name, location, and/or version of the extension you want to
install. Its possible values are dependent on the `<install-source>` (see below).
Optional arguments:
- `--source`: this directs Appium where to find your extension. See below for a table of possible
source types and corresponding install specification.
- `--package`: when `<install-source>` is `git` or `github`, `--package` is required. It should be
the Node.js package name of the extension. Without this information, Appium will not be able to
find the installed package.
- `--json`: return the result in JSON format
|Install source type|Behaviour|
|--|--|
|None|This is the default behaviour when no `--source` is used. In this case, Appium will look at `<install-spec>` and match it against the name of extensions available when running `appium <ext-type> list`, i.e., against the officially recognized extension names. If found, it will install that extension at the latest version via NPM|
|`npm`|Install an extension based on its NPM package name. Here, `<install-spec>` must be the NPM package name with any additional NPM installation modifiers, like version (see below)|
|`github`|Install an extension via a GitHub spec of the form `<org>/<repo>`|
|`git`|Install an extension via a Git URL (e.g., `git+ssh://git-host.com/repo.git`)|
|`local`|Install an extension via a local path. This must be a path to the directory where the Node.js package information for the driver is located.|
#### NPM-based `<install-spec>`
When Appium is installing an extension via NPM (as is the case when `--source` is either omitted or
set to `npm`), the `<install-spec>` can be complex, and can include any kind of information allowed
by `npm install`:
- `[@scope]/<name>`
- `[@scope]/<name>@<version>`
- `[@scope]/<name>@<tag>`
- `[@scope]/<name>@<version range>`
#### Examples
- Install the latest XCUITest driver:
```
appium driver install xcuitest
```
- Install the XCUITest driver at version 4.11.1:
```
appium driver install xcuitest@4.11.1
```
- Install the `beta` version of the `@appium/fake-driver` from NPM:
```
appium driver install --source=npm @appium/fake-driver@beta
```
- Install a locally-developed plugin:
```
appium plugin install --source=local /path/to/my/plugin
```
### `list`
List installed and available extensions. "Available" extensions include those which are officially
recognized by the Appium team, but you are not limited to installing only the extensions displayed
in this list.
Usage:
```
appium <ext-type> list [--installed] [--updates] [--json]
```
Required arguments:
- `<ext-type>`: must be `driver` or `plugin`
Optional arguments:
- `--installed`: show only installed extensions, not installed plus available extensions
- `--updates`: for extensions installed via NPM, display a message if there are any updates
- `--json`: return the result in JSON format
### `run`
Run a script included in an extension package. Extension authors can include runnable scripts that
assist with setup or perform other tasks. These scripts are given names (called the `<script-name>`
in this reference) by extension authors and will generally be documented in extension
documentation.
Usage:
```
appium <ext-type> run <ext-name> [--json] <script-name> [script-args]
```
Required arguments:
- `<ext-type>`: must be `driver` or `plugin`
- `<ext-name>`: the name of the extension whose script you want to run
- `<script-name>`: the name of the script the extension has published
Optional arguments:
- `script-args`: any arguments that Appium does not interpret as belonging to its own set of
arguments will be passed along to the extension script
- `--json`: return the result in JSON format
Example (run the `reset` script included with the UiAutomator2 driver):
```
appium driver run uiautomator2 reset
```
### `update`
Update one or more extensions that have been installed via NPM. By default, Appium will not
automatically update any extension past a major version boundary, so as to prevent
unintended breaking changes.
Usage:
```
appium <ext-type> update <ext-name> [--unsafe] [--json]
```
Required arguments:
- `<ext-type>`: must be `driver` or `plugin`
- `<ext-name>`: the name of the extension to update, or the string `installed` (which will update
all installed extensions)
Optional arguments:
- `--unsafe`: direct Appium to go ahead and update past a major version boundary
- `--json`: return the result in JSON format
### `uninstall`
Remove an installed extension.
Usage:
```
appium <ext-type> uninstall <ext-name> [--json]
```
Required arguments:
- `<ext-type>`: must be `driver` or `plugin`
- `<ext-name>`: the name of the extension to uninstall
Optional arguments:
- `--json`: return the result in JSON format
+23 -2
View File
@@ -1,5 +1,26 @@
---
title: 命令行介绍
hide:
- toc
title: Command-Line Overview
---
TODO
Appium provides a command-line executable (`appium`), which will likely be your main way of interacting with
the Appium server. This section of the Appium documentation describes how to use this executable.
To start off, you can run `appium -v` or `appium --version` to return the installed version,
or run `appium -h` or `appium --help` to return the help message.
The main `appium` executable provides the following subcommands:
1. `appium server` (or simply `appium`) - launch an Appium server
- [See here for accepted arguments](./args.md)
- For advanced features, [see here for accepted environment variables](./env-vars.md)
2. `appium driver` - manage Appium drivers
- [See here for details](./extensions.md)
3. `appium plugin` - manage Appium plugins
- [See here for details](./extensions.md)
4. `appium setup` - batch install a preset of drivers and plugins
- [See here for details](./setup.md)
Like the main command, you can also run each subcommand with the `-h` or `--help` flag to learn more about it.
+28
View File
@@ -0,0 +1,28 @@
---
hide:
- toc
title: Setup Command-Line Usage
---
The `setup` command aims to simplify the initial procedure of setting up Appium. It allows to install
multiple extensions (drivers/plugins) in one go, without the need to run
`appium <ext-name> install <ext-name>` multiple times.
The command has several presets that can be used to install different sets of extensions.
The presets are as follows:
|Preset|Installation Command|Included Drivers|Included Plugins|
|--|--|--|--|
|Mobile|`appium setup mobile` or `appium setup`|`uiautomator2`, `xcuitest`[^1], `espresso`|`images`|
|Desktop application|`appium setup desktop`|`mac2`[^1], `windows`[^2]|`images`|
|Desktop browser|`appium setup browser`|`safari`[^1], `gecko`, `chromium`|`images`|
Attempting to install a preset while already having one or more of its included extensions installed
will only install the missing extensions.
Refer to the [Ecosystem documentation](../ecosystem/index.md) to learn more about the extensions
listed above.
[^1]: Only installed if the host machine is running macOS.
[^2]: Only installed if the host machine is running Windows.
@@ -0,0 +1,542 @@
# Driver: base-driver
### `createSession`
`POST` **`/session`**
Historically the first two arguments were reserved for JSONWP capabilities.
Appium 2 has dropped the support of these, so now we only accept capability
objects in W3C format and thus allow any of the three arguments to represent
the latter.
**`See`**
[https://w3c.github.io/webdriver/#new-session](https://w3c.github.io/webdriver/#new-session)
<!-- comment source: multiple -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `desiredCapabilities?` | `W3CDriverCaps`<`C`\> | the new session capabilities |
| `requiredCapabilities?` | `W3CDriverCaps`<`C`\> | another place the new session capabilities could be sent (typically left undefined) |
| `capabilities?` | `W3CDriverCaps`<`C`\> | another place the new session capabilities could be sent (typically left undefined) |
#### Response
`CreateResult`
The capabilities object representing the created session
### `deleteSession`
`DELETE` **`/session/:sessionId`**
Returns capabilities for the session and event history (if applicable)
<!-- comment source: method-signature -->
#### Response
`SingularSessionData`<`C`, `SessionData`\>
A session data object
### `getSession`
`GET` **`/session/:sessionId`**
Returns capabilities for the session and event history (if applicable)
<!-- comment source: multiple -->
#### Response
`SingularSessionData`<`C`, `SessionData`\>
A session data object
### `findElement`
`POST` **`/session/:sessionId/element`**
Find a UI element given a locator strategy and a selector, erroring if it can't be found
**`See`**
[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `string` | the locator strategy |
| `value` | `string` | the selector to combine with the strategy to find the specific element |
#### Response
`Element`<`string`\>
The element object encoding the element id which can be used in element-related
commands
### `findElementFromElement`
`POST` **`/session/:sessionId/element/:elementId/element`**
Find a UI element given a locator strategy and a selector, erroring if it can't be found. Only
look for elements among the set of descendants of a given element
**`See`**
[https://w3c.github.io/webdriver/#find-element-from-element](https://w3c.github.io/webdriver/#find-element-from-element)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `string` | the locator strategy |
| `value` | `string` | the selector to combine with the strategy to find the specific element |
#### Response
`Element`<`string`\>
The element object encoding the element id which can be used in element-related
commands
### `findElementFromShadowRoot`
`POST` **`/session/:sessionId/shadow/:shadowId/element`**
Find an element from a shadow root
**`See`**
[https://w3c.github.io/webdriver/#find-element-from-shadow-root](https://w3c.github.io/webdriver/#find-element-from-shadow-root)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `string` | the locator strategy |
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
#### Response
`Element`<`string`\>
The element inside the shadow root matching the selector
### `findElements`
`POST` **`/session/:sessionId/elements`**
Find a a list of all UI elements matching a given a locator strategy and a selector
**`See`**
[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `string` | the locator strategy |
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
#### Response
`Element`<`string`\>[]
A possibly-empty list of element objects
### `findElementsFromElement`
`POST` **`/session/:sessionId/element/:elementId/elements`**
Find a a list of all UI elements matching a given a locator strategy and a selector. Only
look for elements among the set of descendants of a given element
**`See`**
[https://w3c.github.io/webdriver/#find-elements-from-element](https://w3c.github.io/webdriver/#find-elements-from-element)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `string` | the locator strategy |
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
#### Response
`Element`<`string`\>[]
A possibly-empty list of element objects
### `findElementsFromShadowRoot`
`POST` **`/session/:sessionId/shadow/:shadowId/elements`**
Find elements from a shadow root
**`See`**
[https://w3c.github.io/webdriver/#find-element-from-shadow-root](https://w3c.github.io/webdriver/#find-element-from-shadow-root)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `string` | the locator strategy |
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
#### Response
`Element`<`string`\>[]
A possibly empty list of elements inside the shadow root matching the selector
### `getLog`
`POST` **`/session/:sessionId/log`**
Get the log for a given log type.
!!! warning "Deprecated"
Please use the `/session/:sessionId/se/log` endpoint instead
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `type` | `string` | Name/key of log type as defined in ILogCommands.supportedLogTypes. |
#### Response
`any`
### `getLog`
`POST` **`/session/:sessionId/se/log`**
Get the log for a given log type.
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `type` | `string` | Name/key of log type as defined in ILogCommands.supportedLogTypes. |
#### Response
`any`
### `getLogEvents`
`POST` **`/session/:sessionId/appium/events`**
Get a list of events that have occurred in the current session
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `type?` | `string` \| `string`[] | filter the returned events by including one or more types |
#### Response
`EventHistory` \| `Record`<`string`, `number`\>
The event history for the session
### `getLogTypes`
`GET` **`/session/:sessionId/log/types`**
Get available log types as a list of strings
!!! warning "Deprecated"
Please use the `/session/:sessionId/se/log/types` endpoint instead
<!-- comment source: method-signature -->
#### Response
`string`[]
### `getLogTypes`
`GET` **`/session/:sessionId/se/log/types`**
Get available log types as a list of strings
<!-- comment source: method-signature -->
#### Response
`string`[]
### `getPageSource`
`GET` **`/session/:sessionId/source`**
Get the current page/app source as HTML/XML
**`See`**
[https://w3c.github.io/webdriver/#get-page-source](https://w3c.github.io/webdriver/#get-page-source)
<!-- comment source: method-signature -->
#### Response
`string`
The UI hierarchy in a platform-appropriate format (e.g., HTML for a web page)
### `getSessions`
`GET` **`/sessions`**
Get data for all sessions running on an Appium server
<!-- comment source: method-signature -->
#### Response
A list of session data objects.
Each session data object will be returned with `id` and the session's capabilities as `capabilities` keys like an example below:
```json
[
{
"id":"ba30c6da-c266-4734-8ddb-c16f5bb53e16",
"capabilities":{ "platformName":"ios","browserName":"safari","automationName":"xcuitest","platformVersion":"17.2","deviceName":"iPhone 15" }
},
{
"id":"1441110c-1ece-4e45-abbf-ebf404f45f0a",
"capabilities":{ "platformName":"ios","browserName":"safari","automationName":"xcuitest","platformVersion":"17.0","deviceName":"iPhone 14" }
},
...
]
```
### `getSettings`
`GET` **`/session/:sessionId/appium/settings`**
Update the session's settings dictionary with a new settings object
<!-- comment source: method-signature -->
#### Response
``null``
### `updateSettings`
`POST` **`/session/:sessionId/appium/settings`**
Update the session's settings dictionary with a new settings object
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `settings` | `Settings` | A key-value map of setting names to values. Settings not named in the map will not have their value adjusted. |
#### Response
``null``
### `getStatus`
`GET` **`/status`**
**`Summary`**
Retrieve the server's current status.
**`Description`**
Returns information about whether a remote end is in a state in which it can create new sessions and can additionally include arbitrary meta information that is specific to the implementation.
The readiness state is represented by the ready property of the body, which is false if an attempt to create a session at the current time would fail. However, the value true does not guarantee that a New Session command will succeed.
Implementations may optionally include additional meta information as part of the body, but the top-level properties ready and message are reserved and must not be overwritten.
<!-- comment source: builtin-interface -->
#### Examples
<!-- BEGIN:EXAMPLES -->
##### JavaScript
<!-- BEGIN:EXAMPLE lang=JavaScript -->
```js
// webdriver.io example
await driver.status();
```
<!-- END:EXAMPLE -->
##### Python
<!-- BEGIN:EXAMPLE lang=Python -->
```python
driver.get_status()
```
<!-- END:EXAMPLE -->
##### Java
<!-- BEGIN:EXAMPLE lang=Java -->
```java
driver.getStatus();
```
<!-- END:EXAMPLE -->
##### Ruby
<!-- BEGIN:EXAMPLE lang=Ruby -->
```ruby
# ruby_lib example
remote_status
# ruby_lib_core example
@driver.remote_status
```
<!-- END:EXAMPLE -->
<!-- END:EXAMPLES -->
#### Response
`Object`
### `getTimeouts`
`GET` **`/session/:sessionId/timeouts`**
Set the various timeouts associated with a session
**`See`**
[https://w3c.github.io/webdriver/#set-timeouts](https://w3c.github.io/webdriver/#set-timeouts)
<!-- comment source: method-signature -->
#### Response
``null``
### `timeouts`
`POST` **`/session/:sessionId/timeouts`**
Set the various timeouts associated with a session
**`See`**
[https://w3c.github.io/webdriver/#set-timeouts](https://w3c.github.io/webdriver/#set-timeouts)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `type?` | `string` | used only for the old (JSONWP) command, the type of the timeout |
| `ms?` | `string` \| `number` | used only for the old (JSONWP) command, the ms for the timeout |
| `script?` | `number` | the number in ms for the script timeout, used for the W3C command |
| `pageLoad?` | `number` | the number in ms for the pageLoad timeout, used for the W3C command |
| `implicit?` | `string` \| `number` | the number in ms for the implicit wait timeout, used for the W3C command |
#### Response
``null``
### `implicitWait`
`POST` **`/session/:sessionId/timeouts/implicit_wait`**
Set the implicit wait timeout
!!! warning "Deprecated"
Please use the `/session/:sessionId/timeouts` endpoint instead
Use `timeouts` instead
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `ms` | `string` \| `number` | the timeout in ms |
#### Response
``null``
### `logCustomEvent`
`POST` **`/session/:sessionId/appium/log_event`**
Add a custom-named event to the Appium event log
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `vendor` | `string` | the name of the vendor or tool the event belongs to, to namespace the event |
| `event` | `string` | the name of the event itself |
#### Response
``null``
### `reset`
`POST` **`/session/:sessionId/appium/app/reset`**
Reset the current session (run the delete session and create session subroutines)
!!! warning "Deprecated"
Please use each driver's launch, activate, terminate or cleanup method.
Use explicit session management commands instead
<!-- comment source: method-signature -->
#### Response
``null``
@@ -0,0 +1,22 @@
# Plugin: execute-driver
### `executeDriverScript`
`POST` **`/session/:sessionId/appium/execute_driver`**
Implementation of a command within a plugin
At minimum, `D` must be `ExternalDriver`, but a plugin can be more narrow about which drivers it supports.
<!-- comment source: method-signature -->
#### Parameters
| Name | Type |
| :------ | :------ |
| `script` | [script: string, scriptType: string, timeoutMs: number] |
| `type?` | [script: string, scriptType: string, timeoutMs: number] |
#### Response
`unknown`
@@ -0,0 +1,67 @@
# Plugin: images
### `compareImages`
`POST` **`/session/:sessionId/appium/compare_images`**
#### Parameters
| Name | Type |
| :------ | :------ |
| `mode` | `any`[] |
| `options?` | `any`[] |
#### Response
`ComparisonResult`
### `findElement`
`POST` **`/session/:sessionId/element`**
Find a UI element given a locator strategy and a selector, erroring if it can't be found
**`See`**
[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `any` | the locator strategy |
| `value` | `any` | the selector to combine with the strategy to find the specific element |
#### Response
`any`
The element object encoding the element id which can be used in element-related
commands
### `findElements`
`POST` **`/session/:sessionId/elements`**
Find a a list of all UI elements matching a given a locator strategy and a selector
**`See`**
[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `any` | the locator strategy |
| `value` | `any` | the selector to combine with the strategy to find the specific elements |
#### Response
`any`
A possibly-empty list of element objects
+24
View File
@@ -0,0 +1,24 @@
---
hide:
- toc
title: Intro to Commands
---
Here you can find various commands exposed by the main Appium module through its base driver, as
well as the commands available in several plugins.
!!! note
The Appium base driver only exposes a few commands, as it is not meant to be used on its own.
Please refer to the documentation of your [Appium driver](../ecosystem/drivers.md) to learn
about the commands it exposes, and then check your [Appium client](../ecosystem/clients.md)
documentation for the exact syntax of that command.
The command listings can be found here:
* [Base Driver](./base-driver.md)
* [Execute Driver Plugin](./execute-driver-plugin.md)
* [Images Plugin](./images-plugin.md)
* [Relaxed Caps Plugin](./relaxed-caps-plugin.md)
* [Universal XML Plugin](./universal-xml-plugin.md)
@@ -0,0 +1,27 @@
# Plugin: relaxed-caps
### `createSession`
`POST` **`/session`**
Start a new automation session
**`See`**
[https://w3c.github.io/webdriver/#new-session](https://w3c.github.io/webdriver/#new-session)
<!-- comment source: multiple -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `desiredCapabilities?` | `any` | the new session capabilities |
| `requiredCapabilities?` | `any` | another place the new session capabilities could be sent (typically left undefined) |
| `capabilities?` | `any` | another place the new session capabilities could be sent (typically left undefined) |
#### Response
`any`
The capabilities object representing the created session
@@ -0,0 +1,68 @@
# Plugin: universal-xml
### `findElement`
`POST` **`/session/:sessionId/element`**
Find a UI element given a locator strategy and a selector, erroring if it can't be found
**`See`**
[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `any`[] | the locator strategy |
#### Response
`any`
The element object encoding the element id which can be used in element-related
commands
### `findElements`
`POST` **`/session/:sessionId/elements`**
Find a a list of all UI elements matching a given a locator strategy and a selector
**`See`**
[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements)
<!-- comment source: method-signature -->
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `using` | `any`[] | the locator strategy |
#### Response
`any`
A possibly-empty list of element objects
### `getPageSource`
`GET` **`/session/:sessionId/source`**
Get the current page/app source as HTML/XML
**`See`**
[https://w3c.github.io/webdriver/#get-page-source](https://w3c.github.io/webdriver/#get-page-source)
<!-- comment source: method-signature -->
#### Response
`string`
The UI hierarchy in a platform-appropriate format (e.g., HTML for a web page)
@@ -0,0 +1,451 @@
---
title: Appium's Config System
---
Appium 2 supports [configuration files](../guides/config.md). A configuration file is intended to
have (nearly) 1:1 parity with command-line arguments. An end user can supply Appium 2 with
a configuration file, CLI args, or both (the args have precedence over the config file).
This document will be a technical overview of how the configuration system works. It is intended
for Appium contributors, but will also explain the system's fundamental features.
## Reading a Config File
A config file is a JSON, JavaScript, or YAML file which can be validated against a schema. By
default, this file will be named `.appiumrc.{json,js,yaml,yml}` and should be in the root of the
project which depends upon `appium`. Other filenames and locations are supported via the `--config
<file>` flag. For obvious reasons, the `config` argument is disallowed within config files.
In lieu of a separate file, configuration can be embedded in a project's `package.json` using the
`appiumConfig` property, e.g.,:
```json
{
"appiumConfig": {
"server": {
"port": 12345
}
}
}
```
When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`
will call into `lib/config-file.js` to load and/or search for a configuration file and in
`package.json`.
!!! note
It is not an error if configuration isn't found!
The [`lilconfig`](https://npm.im/lilconfig) package provides the search & load functionality; refer
to its documentation for more information about the search paths. Additionally, Appium provides
support for config files written in YAML via the package [`yaml`](https://npm.im/yaml).
If a config file is found and successfully [validated](#validation), the result will be merged with
a set of defaults and any additionall CLI arguments. CLI arguments have precedence over config
files, and config files have precedence over defaults.
## Validation
The same system is used for _both_ validation of config files _and_ command-line arguments.
The package [`ajv`](https://npm.im/ajv) provides validation. Of course, to make `ajv` validate
anything, it must be provided a _schema_.
The _base_ schema is a [JSON Schema
Draft-7](https://json-schema.org/draft/2020-12/json-schema-core.html)-compliant object exported by
`lib/schema/appium-config-schema.js`. This schema defines configuration _native to Appium_, and
only concerns its behavior as a _server_; it does not define configuration for any other
functionality (e.g., the `plugin` or `driver` subcommands).
!!! warning
Note that this file is the _base_ schema; this will become painfully relevant.
This file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
especially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files.
It is more straightforward to explain how config files are validated, so we'll start there.
### Validating Config Files
When a config file is found (`lib/config-file.js`), it will call the `validate` function exported
from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to
validate the data against the schema that Appium has provided it.
If the config file is invalid, errors will be generated to be displayed to the user. Finally, the
`init` function will detect these errors, display them, and the process will exit.
I hope that made sense, because this is the easy part.
### Validating CLI Arguments
As mentioned earlier, the same system is used for validating both config files and CLI arguments.
Totally not judging, but Appium uses [`argparse`](https://npm.im/argparse) for its CLI argument
parsing. This package, and others like it, provides an API to define the arguments a command-line
Node.js script accepts, and will ultimately return an object representation of the user-supplied
arguments.
Just as the schema defines what's allowed in a config file, it also defines what's allowed on the
command-line.
#### Defining CLI Arguments via Schema
CLI arguments must be _defined_ before their values can be validated.
A JSON schema isn't a natural fit for defining CLI args--it needs some grease to make it work--but
it's close enough that we can do so with an adapter and some custom metadata.
In `lib/cli/parser.js`, there's a wrapper around `argparse`'s `ArgumentParser`; it's called (wait
for it)... `ArgParser`. The wrapper exists because we're doing some custom things with `argparse`,
but is has nothing to do with the schema directly.
An `ArgParser` instance is created and its `parseArgs()` method is called with the raw CLI
arguments. The definition of the accepted arguments comes from `lib/cli/args.js` in part--here, all
of the arguments _not_ intended for use with the `server` subcommand are hard-coded (e.g., the
`driver` subcommand and _its_ subcommands). `args.js` also contains a function `getServerArgs()`,
which in turn calls into `toParserArgs` in `lib/schema/cli-args.js`. `lib/schema/cli-args.js` can
be considered the "adapter" layer between `argparse` and the schema.
`toParserArgs` uses the `flattenSchema` function exported by `lib/schema/schema.js`, which
"squashes" the schema into a key/value representation. Then, `toParserArgs` iterates over each
key/value pair and "converts" it into a suitable `ArgumentOption` object for final handoff to
`ArgParser`.
This adapter (`cli-args.js`) is where most of the mess is hidden; let's explore this rat's nest
a bit further.
##### CLI & Schema Incongruities
The conversion algorithm (see function `subSchemaToArgDef` in `lib/schema/cli-args.js`) is mostly
just hacks and special cases neatly packed into a function. Things that don't cleanly map from
`argparse` to a JSON schema include, but are not limited to:
- A schema cannot natively express "store the value of `--foo=<value>` in a property called `bar`" in a schema (this corresponds to the `ArgumentOption['dest']` prop).
- A schema cannot natively express aliases; e.g., `--verbose` can also be `-v`
- A schema `enum` is not restricted to multiple types, but `argparse`'s equivalent `ArgumentOption['choices']` prop _is_
- A schema does not know about `argparse`'s concept of "actions" (note that Appium is not currently using custom actions--though it did, and it could again).
- `argparse` has no native type for `email`, `hostname`, `ipv4`, `uri` etc., and the schema does
- Schema validation only _validates_, it does not perform translation, transformation, or coercion (mostly). `argparse` allows this.
- Schemas allow the `null` type, for whatever reason. Ever pass `null` on the CLI?
- `argparse` does not understand anything other than primitives; no objects, arrays, etc., and certainly not arrays of a particular type.
All of the above cases and others are handled by the adapter.
!!! warning
Some decisions made in the adapter were arrived at via coin toss. If you are curious about why
something is the way it is, it's likely that it had to do _something_.
Let's look more closely at handling types.
#### Argument Types via `ajv`
While `argparse` allows consumers, via its API, to define the _type_ of various arguments (e.g.,
a string, number, boolean flag, etc.), Appium mostly avoids these built-in types. _Why is that?_
Well:
1. We already know the type of an argument, because we've defined it in a schema.
2. `ajv` provides validation against a schema.
3. A schema allows for greater expression of types, allowed values, etc., than `argparse` can provide natively.
4. The expressiveness of a schema allows for better error messaging.
To that end, the adapter eschews `argparse`'s built-in types (see allowed string values of
`ArgumentOption['type']`) and instead abuses the ability to provide a _function_ as a `type`. The
exception is _boolean_ flags, which do not have a `type`, but rather `action: 'store_true'`. The
world may never know why.
##### Types as Functions
When a `type` is a function, the function performs both validation _and_ coercion (if necessary).
So what are these functions?
> Note: `type` is _omitted_ (and thus _not_ a function) from the `ArgumentOption` if the property
> type is `boolean`, and is instead provided an `action` property of `store_true`. Yes, this is
> weird. No, I don't know why.
Well... it depends upon the schema. But generally speaking, we create a _pipeline_ of functions,
each corresponding to a keyword in the schema. Let's take the example of the `port` argument. In
lieu of asking the OS which ports the `appium`-running user can bind to, this argument is expected
to be an integer between 1 and 65535. This turns out to be two functions which we combine into
a pipeline:
1. Convert the value to an integer, if possible. Because _every value in `process.argv` is a string_, we must coerce if we want a number.
2. Use `ajv` to validate the integer against the schema for `port`. A schema lets us define a range via the `minimum` and `maximum` keywords. Read more about how this works in
Much like the config file validation, if errors are detected, Appium nicely tells the end-user and
the process exits w/ some help text.
For other arguments which are naturally of non-primitive types, things are not so straightforward.
##### Transformers
Remember how `argparse` doesn't understand arrays? What if the most ergonomic way to express
a value is, in fact, an array?
Well, Appium can't accept an array on the CLI, even though it can accept one in the config file.
But Appium _can_ accept a comma-delimited string (a CSV "line"). Or a string filepath referring to
a file which _contains_ a delimited list. Either way: by the time the value gets out of the
argument parser, it should be an array.
And as mentioned above, the native facilities of a JSON schema cannot express this. However, it's
possible to define a _custom keyword_ which Appium can then detect and handle accordingly. So
that's what Appium does.
In this case, a custom keyword `appiumCliTransformer` is registered with `ajv`. The value of
`appiumCliTransformer` (at the time of this writing) can be `csv` or `json`. In the base schema
file, `appium-config-schema.js`, Appium uses `appiumCliTransformer: 'csv'` if this behavior is
desired.
!!! note
Any property defined in the schema having type `array` will _automatically_ uses the `csv`
transformer. Likewise, a property having type `object` will use the `json` transformer. It's
conceivable that `array` may want to use the `json` transformer, but otherwise, the presence of
the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not stricly
necessary.
The adapter (remember the adapter?) creates a pipeline function including a special "CSV
transformer" (transformers are defined in `lib/schema/cli-transformers.js`), and uses this function
as the `type` property of the `ArgumentOption` passed into `argparse`. In this case, the `type:
'array'` in the schema is ignored.
!!! note
The config file doesn't _need_ to perform any complex transformation of values, because it
naturally allows Appium to define exactly what it expects. So Appium does no post-processing of
config file values.
Properties that do not need this special treatment use `ajv` directly for validation. How this
works requires some explanation, so that's next.
#### Validation of Individual Arguments via `ajv`
When we think of a JSON schema, we tend to think, "I have this JSON file and I want to validate it
against the schema". That's valid, and in fact Appium does just that with config files! However,
Appium does not do this when validating arguments.
!!! note
During implementation, I was tempted to mash all of the arguments together into
a config-file-like data structure and then validate it all at once. I think that would have
been _possible_, but since an object full of CLI arguments is a flat key/value structure and
the schema is not, this seemed like trouble.
Instead, Appium validates a value against a specific property _within_ the schema. To do this, it
maintains a mapping between a CLI argument definition and its corresponding property. The mapping
itself is a `Map` with a unique identifier for the argument as the key, and an `ArgSpec`
(`lib/schema/arg-spec.js`) object as the value.
An `ArgSpec` object stores the following metadata:
| Property Name | Description |
| --------------- | ------------------------------------------------------------------------------------- |
| `name` | Canonical name of the argument, corresponding to the property name in the schema. |
| `extType?` | `driver` or `plugin`, if appropriate |
| `extName?` | Extension name, if appropriate |
| `ref` | Computed `$id` of the property in the schema |
| `arg` | Argument as accepted on CLI, without leading dashes |
| `dest` | Property name in parsed arguments object (as returned by `argparse`'s `parse_args()`) |
| `defaultValue?` | Value of the `default` keyword in schema, if appropriate |
When a schema is [finalized](#schema-finalization), the `Map` is populated with `ArgSpec` objects
for all known arguments.
So when the adapter is creating the pipeline of functions for the argument's `type`, it already has
an `ArgSpec` for the argument. It creates a function which calls `validate(value, ref)` (in
`lib/schema/schema.js`) where `value` is whatever the user provided, and `ref` is the `ref`
property of the `ArgSpec`. The concept is that `ajv` can validate using _any_ `ref` it knows about;
each property in a schema can be referenced by this `ref` whether it's defined or not. To help
visualize, if a schema is:
```json
{
"$id": "my-schema.json",
"type": "object",
"properties": {
"foo": {
"type": "number"
}
}
}
```
The `ref` of `foo` would be `my-schema.json#/properties/foo`. Assuming our `Ajv` instance knows
about this `my-schema.json`, then we can call its `getSchema(ref)` method (which has a `schema`
property, but is a misnomer nonetheless) to get a validation function; `validate(value, ref)` in
`schema.js` calls this validation function.
!!! note
The schema spec says a schema author can supply an explicit `$id` keyword to override this;
it's unsupported by Appium at this time. If needed, extension authors must carefully use `$ref`
without custom `$id`s. It's highly unlikely an extension would have a schema so complicated as
to need this, however; Appium itself doesn't even use `$ref` to define its own properties!
Next, let's take a look at how Appium loads schemas. This actually happens _before_ any argument
validation.
## Schema Loading
Let's ignore extensions for a moment, and start with the base schema.
When something first imports the `lib/schema/schema.js` module, an instance of an `AppiumSchema` is
created. This is a singleton, and its methods are exported from the module (all of which are bound
to the instance).
The constructor does very little; it instantiates an `Ajv` instance and configures it with Appium's
[custom keywords](#custom-keyword-reference) and adds support for the `format` keyword via the
[ajv-formats](https://npm.im/ajv-formats) module.
Otherwise, the `AppiumSchema` instance does not interact with the `Ajv` instance until its
`finalize()` method (exported as `finalizeSchema()`) is called. When this method is called, we're
saying "we are not going to add any more schemas; go ahead and create `ArgSpec` objects and
register schemas with `ajv`".
When does finalization happen? Well:
1. When the `appium` executable begins, it _checks for and configures extensions_ (hand-wave) in `APPIUM_HOME`.
2. Only then does it start to think about arguments--it instantiates an `ArgParser`, which (as you'll recall) runs the adapter to convert the schema to arguments.
3. _Finalization happens here_--when creating the parser. Appium need the schema(s) to be registered with `ajv` in order to create validation functions for arguments.
4. Thereafter, Appium parses the arguments with the `ArgParser`.
5. Finally, decides what to do with the returned object.
Without extensions, `finalize()` still knows about the Appium base schema
(`appium-config-schema.js`), and just registers that. However, step 1. above is doing a _lot of
work_, so let's look at how extensions come into play.
## Extension Support
One of the design goals of this system is the following:
_An extension should be able to register custom CLI arguments with the Appium, and a user should be
able to use them like any other argument_.
Previously, Appium 2 accepted arguments in this manner (via `--driverArgs`), but validation was
hand-rolled and required extension implementors to use a custom API. It also required the user to
awkwardly pass a JSON string as the configuration on the command-line. Further, no contextual help
(via `--help`) existed for these arguments.
Now, by providing a schema for its options, a driver or plugin can register CLI arguments and
config file schemas with Appium.
To register a schema, an extension must provide the `appium.schema` property in its `package.json`.
The value may be a schema or a path to a schema. If the latter, the schema should be JSON or
a CommonJS module (ESM not supported at this time, nor is YAML).
For any property in this schema, the property will appear as a CLI argument of the form
`--<extension-type>-<extension-name>-<property-name>`. For example, if the `fake` driver provides
a property `foo`, the argument will be `--driver-fake-foo`, and will show in `appium server --help`
like any other CLI argument.
The corresponding property in a config file would be
`server.<extension-type>.<extension-name>.<property-name>`, e.g.:
```json
{
"server": {
"driver": {
"fake": {
"foo": "bar"
}
}
}
}
```
The naming convention described above avoids problems of one extension type having a name conflict
with a different extension type.
!!! note
While an extension can provide aliases via `appiumCliAliases`, "short" flags are disallowed,
since all arguments from extensions are prefixed with `--<extension-type>-<extension-name>-`.
The extension name and argument name will be kebab-cased for the CLI, according to [Lodash's
rules](https://lodash.com/docs/4.17.15#kebabCase) around kebab-casing.
The schema object will look much like Appium's base schema, but it will only have top-level
properties (nested properties are currently unsupported). Example:
```json
{
"title": "my rad schema for the cowabunga driver",
"type": "object",
"properties": {
"fizz": {
"type": "string",
"default": "buzz",
"$comment": "corresponds to CLI --driver-cowabunga-fizz"
}
}
}
```
As written in a user's config file, this would be the `server.driver.cowabunga.fizz` property.
When extensions are loaded, the `schema` property is verified and the schema is registered with the
`AppiumSchema` (it is _not_ registered with `Ajv` until `finalize()` is called).
During finalization, each registered schema is added to the `Ajv` instance. The schema is assigned
an `$id` based on the extension type and name (which overrides whatever the extension provides, if
anything). Schemas are also forced to disallowed unknown arguments via the `additionalProperties:
false` keyword.
Behind the scenes, the base schema has `driver` and `plugin` properties which are objects. When
finalized, a property is added to each--corresponding to an extension name--and the value of this
property is a reference to the `$id` of a property in the extension schema. For example, the
`server.driver` property will look like this:
```json
{
"driver": {
"cowabunga": {
"$ref": "driver-cowabunga.json"
}
}
}
```
This is why we call it the "base" schema--it is _mutated_ when extensions provide schemas. The
extension schemas are kept separately, but the _references_ are added to the schema before it's
ultimately added to `ajv`. This works because an `Ajv` instance understands references _from_ any
schema it knows about _to_ any schema it knows about.
!!! note
This makes it impossible to provide a complete static schema for Appium _and_ the installed
extensions (as of Nov 5 2021). A static `.json` schema _is_ generated from the base (via a Gulp
task), but it does not contain any extension schemas. The static schema also has uses beyond
Appium; e.g., IDEs can provide contextual error-checking of config files this way. Let's solve
this?
Just like how we look up the reference ID of a particular argument in the base schema, validation
of arguments from extensions happens the exact same way. If the `cowabunga` driver has the schema
ID `driver-cowabunga.json`, then the `fizz` property can be referenced from any schema registered
with `ajv` via `driver-cowabunga.json#/properties/fizz`. "Base" schema arguments begin with
`appium.json#properties/` instead.
## Development Environment Support
During the flow of development, a couple extra tasks have been automated to maintain the base
schema:
- As a post-transpilation step, a `lib/appium-config.schema.json` gets generated from
- `lib/schema/appium-config-schema.js` (in addition to its CJS counterpart generated by Babel).
- This file is under version control. It ends up being _copied_ to
- `build/lib/appium-config.schema.json` in this step. A pre-commit hook (see
- `scripts/generate-schema-declarations.js` in the root monorepo) generates
- a `types/appium-config-schema.d.ts` from the above JSON file. The types in `types/types.d.ts`
- depend upon this file. This file is under version control.
## Custom Keyword Reference
Keywords are defined in `lib/schema/keywords.js`.
- `appiumCliAliases`: allows a schema to express aliases (e.g., a CLI argument can be `--verbose` or `-v`). This is an array of strings. Strings shorter than three (3) characters will begin with a single dash (`-`) instead of a double-dash (`--`). Note that any argument provided by an extension will begin with a double-dash, because these are required to have the `--<extension-type>-<extension-name>-` prefix.
- `appiumCliDest`: allows a schema to specify a custom property name in the post-`argprase` arguments objects. If not set, this becomes a camelCased string.
- `appiumCliDescription`: allows a schema to override the description of the argument when displayed on the command-line. This is useful paired with `appiumCliTransformer` (or `array`/`object`-typed properties), since there's a substantial difference between what a CLI-using user can provide vs. what a config-file-using user can provide.
- `appiumCliTransformer`: currently a choice between `csv` and `json`. These are custom functions which post-process a value. They are not used when loading & validating config files, but the idea should be that they result in the same object you'd get if you used whatever the config file wanted (e.g., an array of strings). `csv` is for comma-delimited strings and CSV files; `json` is for raw JSON strings and `.json` files.
- `appiumCliIgnore`: If `true`, do not support this property on the CLI.
- `appiumDeprecated`: If `true`, the property is considered "deprecated", and will be displayed as such to the user (e.g., in the `--help` output). Note the JSON Schema draft-2019-09 introduces a new keyword `deprecated` which we should use instead if upgrading to this metaschema. When doing so, `appiumDeprecated` should itself be marked as `deprecated`.
@@ -0,0 +1,90 @@
---
title: Contributing Code
---
To contribute to the Appium code base make sure to check out the Git repository.
!!! info
If you are VS Code user you can easily check out the project using [Runme](https://runme.dev/api/runme?repository=https%3A%2F%2Fgithub.com%2Fappium%2Fappium.git&fileToOpen=packages%2Fappium%2Fdocs%2Fen%2Fcontributing%2Findex.md).
It is advised to [fork](https://github.com/appium/appium/fork) before cloning it to your system.
```sh
export GITHUB_USERNAME=<your-username>
git clone git@github.com:$GITHUB_USERNAME/appium.git
```
After cloning you can go ahead and install the project dependencies:
```sh
npm install
```
From here on there are several things you can do.
### Watch Files
When developing Appium code we have to watch all JavaScript and TypeScript files to re-compile them after every change. You can run this watch process via:
```sh
npm run dev
```
### Start Appium in Dev-Mode
To test your changes you can run Appium in dev mode via:
```sh
npm start
```
### Run Tests
The project maintains a set of different test variations you can run to verify the quality of the code.
#### Linting
Appium uses [`eslint`](https://eslint.org/) for static code analysis and linting. You can run these checks via:
```sh
npm run lint
```
#### Unit
```sh
npm run test:unit
```
You can also run tests for specific workspaces, e.g.:
```sh
export APPIUM_WORKSPACE=@appium/doctor
npm run test:unit -w $APPIUM_WORKSPACE
```
#### Smoke and E2E
```sh
npm run test:slow
```
### Deploy Docs Locally
Our documentation system uses [MKDocs](https://www.mkdocs.org/) and therefore requires [Python](https://www.python.org/) to be installed on your system. You can run the docs by:
```sh
# installing needed Python dependencies
pip install -r packages/docutils/requirements.txt
# build the project
npm run build
# run dev server
npm run dev:docs
```
You should be able to view the page at `http://127.0.0.1:8000/docs/en`:
```sh
open http://127.0.0.1:8000/docs/en
```
+35 -2
View File
@@ -1,5 +1,38 @@
---
title: 为Appium做贡献
hide:
- toc
title: Contributing to Appium
---
TODO
Appium is open source, available under an Apache 2.0 license. Appium's copyright is held by the
[OpenJS Foundation](https://openjsf.org), and Appium receives contributions from many companies
across several software industries, regardless of their competitive status. (3rd-party drivers and
plugins are available under the licenses provided by their authors.)
As such, we welcome contributions! The project moves forward in relation to the investment of
contributions of code, documentation, maintenance, and support from companies and volunteers.
This section of Appium's documentation is for those who are interested in contributing to Appium's
development. It contains developer overviews, guides, and notes. Use the navigation menu to find
a specific topic. All the information in these guides assumes in-depth familiarity with Appium
already.
!!! warning
Developer information may not be kept up to date as frequently as user-facing information, or
it may be most relevant in its current form on the online repository, not in this published
version. Always be sure to check the repo or discuss with maintainers. We're always happy to
help new contributors get started!
## Ways to Contribute
The project offers a variety of ways to contribute, e.g.:
- [contributing code](./develop.md)
- improving documentation
- creating educational content (blog posts, tutorials, videos, etc.)
- spreading the good word about the project (e.g. via Twitter)
- filing bugs if you discover them while using Appium
- making feature requests if you are missing something in the project or help triaging bugs
- supporting users in the [Appium forum](https://discuss.appium.io/)
@@ -0,0 +1,86 @@
---
title: Building Documentation
---
Once you've [built a driver](./build-drivers.md) or [built a plugin](./build-plugins.md) for Appium,
you will hopefully want to document how that extension works for your users. The most basic way of
doing this is to write up a quick `README.md` and keep it in the root of your project's repository.
However, this can involve a lot of effort.
The Appium project has built tools to help with this, and we've packaged up these tools so our
ecosystem developers building drivers and plugins can _also_ use them. The best way to get going
with these tools is probably to look at an existing Appium driver repo to see how it's done, for
example the [XCUITest driver repo](https://github.com/appium/appium-xcuitest-driver). But this guide
will outline the basic approach.
### Conceptual architecture
Appium settled on [MkDocs](https://www.mkdocs.org/) as a Markdown-based documentation site
generator. It uses a Python toolchain (and not Node.js), but it turned out to be the best option
for our purposes. You can adjust this, but by default Appium's utilities also assume that you'll be
using the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) theme/extension for
MkDocs.
In order to make different versions of your docs available (one for each minor release of your
extension, typically), we also bundle [Mike](https://github.com/jimporter/mike).
From here, building a basic docs site is as easy as collecting your Markdown files together and
defining how you want them to be organized.
### Prerequisites
To take advantage of Appium's documentation utilities, you'll need to install:
- [Python v3+](https://www.python.org/downloads/)
- [pip](https://pip.pypa.io/en/stable/installation/) (this may be installed automatically with Python)
- The `@appium/docutils` package:
```bash
npm install --save-dev @appium/docutils
```
### Initializing an Extension for Building Docs
To prepare your extension for generating documentation, run the following command:
```bash
npx appium-docs init
```
This will:
1. Create a `tsconfig.json` if one does not already exist. This is necessary even if your extension
is not written in TypeScript.
2. Create a `mkdocs.yml` with the necessary configuration for MkDocs.
### Documenting Your Extension
At this point, you can begin documenting your extension. By default, MkDocs will look for Markdown
files in the `docs` directory. You can therefore create your Markdown documentation files, place
them in `docs`, and add links to these files in `mkdocs.yml`.
Refer to the [MkDocs documentation](https://www.mkdocs.org/user-guide/writing-your-docs/) for
information on how to organize and structure your documentation.
### Building the Docs
At this point, you can use the `appium-docs` CLI tool. Run this tool with no arguments to get the
full help output and see all the available subcommands and parameters. Here are a few usage
examples:
```bash
# Generate reference and build the mkdocs site into the site dir
npx appium-docs build
# Same as build, but host the docs on a local dev server
# and watch for changes and rebuild when files change
npx appium-docs build --serve
# Build the docs and deploy them with mike versioning to the docs-site branch
# using the included commit message.
# This is particularly useful for pushing content to a GitHub pages branch!
npx appium-docs build \
--deploy \
-b docs-site \
-m 'docs: auto-build docs for appium-xcuitest-driver@%s'
```
@@ -0,0 +1,141 @@
---
title: Building Doctor Checks
---
The idea of Appium Doctor is to assist users with driver or plugin preconditions setup. Sometimes such
preconditions might be quite complicated and require non-trivial technical knowledge. Doctor checks,
which are vanilla Node.js class instances written by extension authors, simplify
the setup process by automating diagnostics and possible fixes for the found issues. These checks
might also be interactive to ensure better usage experience.
This tutorial is supposed to be used by plugin or driver authors that would like to help their users
to deal with complicated setup or configuration steps.
## Adding Doctor Checks
### Typing Requirements
The term `Doctor Check` literally describes a single javascript class instance that implements the
[IDoctorCheck interface](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts).
The interface defines the following methods and properties:
- `diagnose(): Promise<DoctorCheckResult>`: Contains the code to diagnose a possible issue
- `fix(): Promise<string|null>`: Either fixes the actual problem if `hasAutofix()` returns true or
returns a string description for possible manual fixes. If this method throws an exception named
`FixSkippedError` and `hasAutofix()` returns true then the result of the method invocation
is going to be ignored.
- `hasAutofix(): boolean`: Whether calling `fix()` would resolve the found issue
- `isOptional(): boolean`: Whether the found issue can be ignored and is not a showstopper
- `log: AppiumLogger`: May be used for logging. This property may be assigned
by the instance itself or by the Appium server if it is left unassigned.
The `DoctorCheckResult` object returned by the `diagnose()` method must contain the following properties:
- `ok: boolean`: Whether the diagnosis found no issues
- `optional: boolean`: Whether the diagnosed issue is safe to ignore
- `message: string`: The text message describing the diagnostic result
### Manifest Requirements
A single extension may export multiple Doctor checks to Appium. In order for these checks to be properly
picked up by the server CLI after the corresponding extension is installed they might be listed in the
package .json manifest under the `appium.doctor.checks` section similar to the definition below:
```json
// ...
"appium": {
"driverName": "fake",
"automationName": "Fake",
"platformNames": [
"Fake"
],
"mainClass": "FakeDriver",
"schema": "./build/lib/fake-driver-schema.js",
"scripts": {
"fake-error": "./build/lib/scripts/fake-error.js",
"fake-success": "./build/lib/scripts/fake-success.js",
"fake-stdin": "./build/lib/scripts/fake-stdin.js"
},
"doctor": {
"checks": [
"./doctor/fake1.js",
"./doctor/fake2.js"
// ...
]
}
},
// ...
```
Also, it makes sense to include the [@appium/types](https://www.npmjs.com/package/@appium/types) import
to the package dev dependencies.
### Implementation Example
The below example is a "raw" Node.JS implementation that does not use any transpilation:
```js
const {fs, doctor} = require('@appium/support');
/** @satisfies {import('@appium/types').IDoctorCheck} */
class EnvVarAndPathCheck {
/**
* @param {string} varName
*/
constructor(varName) {
this.varName = varName;
}
async diagnose() {
const varValue = process.env[this.varName];
if (typeof varValue === 'undefined') {
return doctor.nok(`${this.varName} environment variable is NOT set!`);
}
if (await fs.exists(varValue)) {
return doctor.ok(`${this.varName} is set to: ${varValue}`);
}
return doctor.nok(`${this.varName} is set to '${varValue}' but this is NOT a valid path!`);
}
async fix() {
return (
`Make sure the environment variable ${this.varName} is properly configured for the Appium server process`
);
}
hasAutofix() {
return false;
}
isOptional() {
return false;
}
}
const androidHomeCheck = new EnvVarAndPathCheck('ANDROID_HOME');
module.exports = {androidHomeCheck};
/**
* @typedef {import('@appium/types').DoctorCheckResult} CheckResult
*/
```
This file could be saved as `doctor/android-home-check.js` and then added to the package.json manifest
as
```json
// ...
"appium": {
// ...
"doctor": {
"checks": [
"./doctor/android-home-check.js",
]
}
// ...
},
// ...
```
@@ -0,0 +1,460 @@
---
title: Building Plugins
---
This is a high-level guide for developing Appium plugins, which is not something most Appium users
need to know or care about. If you are not familiar with Appium plugins yet from a user
perspective, check out the [list of plugins](../ecosystem/plugins.md) to play around with some and get
an idea of the sorts of things that plugins can do. Plugins are a powerful system for augmenting
Appium's functionality or changing the way Appium works. They can be distributed to other Appium
users and can extend Appium's ecosystem in all kinds of interesting ways! (There is also
a significant amount of overlap here with developing Appium drivers, so you may also want to check
out the [building drivers](./build-drivers.md) guide for further inspiration.)
## Before you create your plugin
Before creating your plugin, it's good to have a general idea of what you want your plugin to
accomplish and whether it will be possible to implement it given the restrictions of the Appium
platform. Reading through this guide will help you understand what's possible. In general, Appium's
plugin system is extremely powerful and no attempts have been made to artificially limit what's
possible with them (which is a main reason that all plugins are opt-in by the system administrator
responsible for starting the Appium server---plugins are powerful and should only be used when
explicitly trusted!).
## Other plugins to reference
There are a wide variety of open source Appium plugins available for perusal. It's definitely
recommended to explore the code for some other plugins before embarking on writing your own. The
Appium team maintains a set of official plugins in the [Appium GitHub
repo](https://github.com/appium/appium). Links to other open source plugins can be found in the
[Plugin list](../ecosystem/plugins.md)
## Basic requirements for plugins
These are the things your plugin *must* do (or be), if you want it to be a valid Appium plugin.
### Node.js package with Appium extension metadata
All Appium plugins are fundamentally Node.js packages, and therefore must have a valid
`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in
Node.js so it can be loaded by Appium.
Your `package.json` must include `appium` as a `peerDependency`. The requirements for the
dependency versions should be as loose as possible (unless you happen to know your plugin will only
work with certain versions of Appium). For Appium 2, for example, this would look something like
`^2.0.0`, declaring that your plugin works with any version of Appium that starts with 2.x.
Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension
metadata'):
```json
{
...,
"appium": {
"pluginName": "fake",
"mainClass": "FakePlugin"
},
...
}
```
The required subfields are:
* `pluginName`: this should be a short name for your plugin.
* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
class which extends Appium's `BasePlugin` (see below).
### Extend Appium's `BasePlugin` class
Ultimately, your plugin is much easier to write because most of the hard work of defining patterns
for overriding commands is done for you. This is
all encoded up as a class which Appium exports for you to use, called `BasePlugin`. It is exported
from `appium/plugin`, so you can use one of these styles to import it and create your *own* class
that extends it:
```js
import {BasePlugin} from 'appium/plugin';
// or: const {BasePlugin} = require('appium/plugin');
export class MyPlugin extends BasePlugin {
// class methods here
}
```
!!! note
In all the code samples below, whenever we reference an example method, it is assumed
that it is defined _within_ the class, though this is not explicitly written, for the sake of
clarity and space.
### Make your plugin available
That's basically it! With a Node.js package exporting a plugin class and with correct Appium
extension metadata, you've got yourself an Appium plugin! Now it doesn't *do* anything, but you can
load it up in Appium, activate it, etc...
To make it available to users, you could publish it via NPM. When you do so, your plugin will be
installable via the Appium CLI:
```
appium plugin install --source=npm <plugin-package-on-npm>
```
It's a good idea to test your plugin first, of course. One way to see how it works within Appium is
to install it locally first:
```
appium plugin install --source=local /path/to/your/plugin
```
And of course, plugins must be "activated" during Appium server start, so make sure you direct your
users to do so:
```
appium --use-plugins=plugin-name
```
### Developing your plugin
How you develop your plugin is up to you. It is convenient, however, to run it from within Appium
without having to do lots of publishing and installing. The most straightforward way to do this is
to include the most recent version of Appium as a `devDependency` (although its being already
included as a `peerDependency` is sufficient in newer versions of NPM), and then also your own plugin,
like this:
```json
{
"devDependencies": {
...,
"appium": "^2.0.0",
"your-plugin": "file:.",
...
}
}
```
Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your plugin is
listed as a dependency alongside it, it will be automatically "installed" and available. You can
design your e2e tests this way, or if you're writing them in Node.js, you can simply import
Appium's start server methods to handle starting and stopping the Appium server in Node.
Of course, you can always install it locally as described above as well.
Anytime you make changes to your plugin code, you'll need to restart the Appium server to make sure
it picks up the latest code. As with drivers, you can set the `APPIUM_RELOAD_EXTENSIONS`
environment variable if you wish Appium to try to re-require your plugin module when a new session
starts.
## Standard plugin implementation ideas
These are things you will probably find yourself wanting to do when creating a plugin.
### Set up state in a constructor
If you define your own constructor, you'll need to call `super` to make sure all the standard state
is set up correctly:
```js
constructor(...args) {
super(...args);
// now do your own thing
}
```
The `args` parameter here is the object containing all the CLI args used to start the Appium
server.
### Intercept and handle specific Appium commands
This is the most normal behavior for Appium plugins -- to modify or replace the execution of one or
more commands that would normally be handled by the active driver. To override the default command
handling, you need to implement `async` methods in your class with the same name as the Appium
commands to be handled (just exactly how [drivers themselves are
implemented](./build-drivers.md#implement-webdriver-commands)). Curious what command names there
are? They are defined in the Appium base driver's
[routes.js](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js) file,
and of course you can add more as defined in the next section.
Each command method is sent the following arguments:
1. `next`: This is a reference to an `async` function which encapsulates the chain of behaviors which would take place if this plugin were not handling the command. You can choose to call the next behavior in the chain at any point in your logic (by making sure to include `await next()` somewhere), or not. If you don't, it means the default behavior (or any plugins registered after this one) won't be run.
1. `driver`: This is the object representing the driver handling the current session. You have access to it for any work you need to do, for example calling other driver methods, checking capabilities or settings, etc...
1. `...args`: A spread array with any arguments that have been applied to the command by the user.
For example, if we wanted to override the `setUrl` command to simply add some extra logging on top,
we would implement as follows:
```js
async setUrl(next, driver, url) {
this.log(`Let's get the page source for some reason before navigating to '${url}'!`);
await driver.getPageSource();
const result = await next();
this.log(`We can also log after the original behaviour`);
return result;
}
```
### Intercept and handle _all_ Appium commands
You might find yourself in a position where you want to handle *all* commands, in order to inspect
payloads to determine whether or not to act in some way. If so, you can implement `async handle`,
and any command that is not handled by one of your named methods will be handled by this method
instead. It takes the following parameters (with all the same semantics as above):
1. `next`
1. `driver`
1. `cmdName` - string representing the command being run
1. `...args`
For example, let's say we want to log timing for all Appium commands as part of a plugin. We could
do this by implementing `handle` in our plugin class as follows:
```js
async handle(next, driver, cmdName, ...args) {
const start = Date.now();
try {
const result = await next();
} finally {
const elapsedMs = Date.now() - start;
this.log(`Command '${cmdName}' took ${elapsedMs}`);
}
return result;
}
```
### Work around driver proxies
There is a bit of a gotcha with handling Appium commands. Appium drivers have the ability to turn
on a special 'proxy' mode, wherein the Appium server process takes a look at incoming URLs, and
decides whether to forward them on to some upstream WebDriver server. It could happen that
a command which a plugin wants to handle is designated as a command which is being proxied to an
upstream server. In this case, we run into a problem, because the plugin never gets a chance to
handle that command! For this reason, plugins can implement a special member function called
`shouldAvoidProxy`, which takes the following parameters:
1. `method` - string denoting HTTP method (`GET`, `POST`, etc...)
2. `route` - string denoting the requested resource, for example `/session/8b3d9aa8-a0ca-47b9-9ab7-446e818ec4fc/source`
3. `body` - optional value of any type representing the WebDriver request body
These parameters define an incoming request. If you want to handle a command in your plugin which
would normally be proxied directly through a driver, you could disable or 'avoid' proxying the
request, and instead have the request fall into the typical Appium command execution flow (and
thereby your own command function). To avoid proxying a request, just return `true` from
`shouldAvoidProxy`. Some examples of how this method is used are in the [Universal XML
plugin](https://github.com/appium/appium/blob/master/packages/universal-xml/lib/plugin.js) (where
we want to avoid proxying the `getPageSource` command, or in the [Images
plugin](https://github.com/appium/appium/blob/master/packages/images-plugin/lib/plugin.js) (where
we want to conditionally avoid proxying any command if it looks like it contains an image element).
### Throw WebDriver-specific errors
The WebDriver spec defines a [set of error
codes](https://github.com/jlipps/simple-wd-spec#error-codes) to accompany command responses if an
error occurred. Appium has created error classes for each of these codes, so you can throw the
appropriate error from inside a command, and it will do the right thing in terms of the protocol
response to the user. To get access to these error classes, import them from `appium/driver`:
```js
import {errors} from 'appium/driver';
throw new errors.NoSuchElementError();
```
### Log messages to the Appium log
You can always use `console.log`, of course, but Appium provides a nice logger for you as
`this.logger` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log
levels). If you want to create an Appium logger outside of a plugin context (say in a script or
helper file), you can always construct your own too:
```js
import {logging} from 'appium/support';
const log = logging.getLogger('MyPlugin');
```
## Further possibilities for Appium plugins
These are things your plugin *can* do to take advantage of extra plugin features or do its job more
conveniently.
### Add a schema for custom command line arguments
You can add custom CLI args if you want your plugin to receive data from the command line when the
Appium server is started (for example, ports that a server administrator should set that should not
be passed in as capabilities).
This works largely the same for plugins as it does for drivers, so for more details have a look at
[the equivalent section in the building drivers
doc](./build-drivers.md#add-a-schema-for-custom-command-line-arguments).
The only difference is that to construct the CLI argument name, you prefix it with
`--plugin-<name>`. So for example, if you have a plugin named `pluggo` and a CLI arg defined with
the name `electro-port`, you can set it when starting Appium via `--plugin-pluggo-electro-port`.
Setting args via a configuration file is also supported, as it is for drivers, but under the
`plugin` field instead. For example:
```json
{
"server": {
"plugin": {
"pluggo": {
"electro-port": 1234
}
}
}
}
```
### Add plugin scripts
Sometimes you might want users of your plugin to be able to run scripts outside the context of
a session (for example, to run a script that pre-builds aspects of your plugin). To support this,
you can add a map of script names and JS files to the `scripts` field within your Appium extension
metadata. So let's say you've created a script in your project that lives in a `scripts` directory
in your project, named `plugin-prebuild.js`. Then you could add a `scripts` field like this:
```json
{
"scripts": {
"prebuild": "./scripts/plugin-prebuild.js"
}
}
```
Now, assuming your plugin is named `myplugin`, users of your plugin can run `appium plugin run
myplugin prebuild`, and your script will execute.
### Add new Appium commands
If you want to offer functionality that doesn't map to any of the existing commands supported by
drivers, you can create new commands in one of two ways, just as is possible for drivers:
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
1. Overloading the Execute Script command by defining [Execute
Methods](../guides/execute-methods.md)
If you want to follow the first path, you can direct Appium to recognize new methods and add them
to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`
static variable in your driver class to an object of the same form as Appium's `routes.js` object.
For example, here is part of the `newMethodMap` for the `FakePlugin` example driver:
```js
static newMethodMap = {
'/session/:sessionId/fake_data': {
GET: {command: 'getFakeSessionData', neverProxy: true},
POST: {
command: 'setFakeSessionData',
payloadParams: {required: ['data']},
neverProxy: true,
},
},
'/session/:sessionId/fakepluginargs': {
GET: {command: 'getFakePluginArgs', neverProxy: true},
},
};
```
!!! note
If you're using TypeScript, static member objects like these should be defined `as const`.
In this example we're adding a few new routes and a total of 3 new commands. For more examples of
how to define commands in this way, it's best to have a look through `routes.js`. Now all you need
to do is implement the command handlers in the same way you'd implement any other Appium command.
Note also the special `neverProxy` key for commands; this is generally a good idea to set to `true`
for plugins, since your plugin might be active for a driver that is put into proxy mode but hasn't
bothered to decline proxying for these (new and therefore unknown) commands. Setting `neverProxy`
to `true` here will cause Appium to never proxy these routes and therefore ensure your plugin
handles them, even if a driver is in proxy mode.
The downside of adding new commands via `newMethodMap` is that people using the standard Appium
clients won't have nice client-side functions designed to target these endpoints. So you would need
to create and release client-side plugins for each language you want to support (directions or
examples can be found at the relevant client docs).
An alternative to this way of doing things is to overload a command which all WebDriver clients
have access to already: Execute Script. Make sure to read the section on [adding new
commands](./build-drivers.md#extend-the-existing-protocol-with-new-commands) in
the Building Drivers guide to understand the way this works in general. The way it works with
plugins is only slightly different. Let's look at an example taken from Appium's `fake-plugin`:
```js
static executeMethodMap = {
'fake: plugMeIn': {
command: 'plugMeIn',
params: {required: ['socket']},
},
};
async plugMeIn(next, driver, socket) {
return `Plugged in to ${socket}`;
}
async execute(next, driver, script, args) {
return await this.executeMethod(next, driver, script, args);
}
```
We have three important components shown here which make this system work, all of which are defined
inside the plugin class:
1. The `executeMethodMap`, defined in just the same way as for drivers
1. The implementation of the command method as defined in `executeMethodMap` (in this case,
`plugMeIn`)
1. The overriding/handling of the `execute` command. Just like any plugin command handlers, the
first two arguments are `next` and `driver`, followed by the script name and args. `BasePlugin`
implements a helper method which we can simply call with all of these arguments.
Overriding Execute Methods from drivers works as you'd expect: if your plugin defines an Execute
Method with the same name as that of a driver, your command (in this case `plugMeIn`) will be
called first. You can choose to run the driver's original behaviour via `next` if you want.
### Build Appium Doctor checks
Your users can run `appium plugin doctor <pluginName>` to run installation and health checks. Visit
the [Building Doctor Checks](./build-doctor-checks.md) guide for more information on this
capability.
### Update the Appium server object
You probably don't normally need to update the Appium server object (which is an
[Express](https://expressjs.com/) server having already been
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)
in a variety of ways). But, for example, you could add new Express middleware to the server to
support your plugin's requirements. To update the server you must implement the `static async
updateServer` method in your class. This method takes three parameters:
* `expressApp`: the Express app object
* `httpServer`: the Node HTTP server object
* `cliArgs`: a map of the CLI args used to start the Appium server
You can do whatever you want with them inside the `updateServer` method. You might want to
reference how these objects are created and worked with in the BaseDriver code, so that you know
you're not undoing or overriding anything standard and important. But if you insist, you can, with
results you'll need to test! Warning: this should be considered an advanced feature and requires
knowledge of Express, as well as the care not to do anything that could affect the operation of
other parts of the Appium server!
### Handle unexpected session shutdown
When developing a plugin you may want to add some cleanup logic for when a session ends. You would
naturally do this by adding a handler for `deleteSession`. This works in most cases, except when
the session does not finish cleanly. Appium sometimes determines that a session has finished
unexpectedly, and in these situations, Appium will look for a method called `onUnexpectedShutdown`
in your plugin class, which will be called (passing the current session driver as the first
parameter, and the error object representing the cause of the shutdown as the second), giving you
an opportunity to take any steps that might be necessary to clean up from the session. For example,
keeping in mind that the function is not `await`ed you could implement something like this:
```js
async onUnexpectedShutdown(driver, cause) {
try {
// do some cleanup
} catch (e) {
// log any errors; don't allow anything to be thrown as they will be unhandled rejections
}
}
```
@@ -0,0 +1,18 @@
---
hide:
- toc
title: Intro to Development
---
Appium 2 is built with a modular structure, which means that Appium extensions (drivers and plugins)
are decoupled from the main Appium module, and you only need to install the extensions that you
want to use. This modular structure also unlocks the ability to develop entirely new extensions!
This section of the Appium documentation is intended to help aspiring developers with creating their
own Appium extension:
* For creating a driver, see the [Build Drivers](./build-drivers.md) page
* For creating a plugin, take a look at the [Build Plugins](build-plugins.md) page
* Drivers and plugins both need documentation, so check out the [Build Documentation](./build-docs.md) page
* For creating a doctor check, see the [Building Doctor Checks](./build-doctor-checks.md) page
@@ -1,5 +0,0 @@
---
title: Building Docs for Appium Extensions
---
TODO
@@ -1,5 +0,0 @@
---
title: Building Appium Plugins
---
TODO
@@ -0,0 +1,42 @@
---
hide:
- toc
title: Appium Clients
---
You need a client to write and run Appium scripts. You'll want to become very
familiar with your client documentation (as well as the documentation of any Selenium client that
the Appium client depends on) since that will be your primary interface to Appium.
To learn more about clients, read our [Client Intro](../intro/clients.md).
### Official Clients
These clients are currently maintained by the Appium team:
|Client|Language|
|-|-|
|[Appium Java client](https://github.com/appium/java-client)|Java|
|[Appium Python client](https://github.com/appium/python-client)|Python|
|[Appium Ruby Core client](https://github.com/appium/ruby_lib_core) (Recommended)<br>[Appium Ruby client](https://github.com/appium/ruby_lib)|Ruby|
|[Appium .NET client](https://github.com/appium/dotnet-client)|C#|
### Other Clients
These clients are not maintained by the Appium team and can be used with other languages:
|Client|Language|
|-|-|
|[WebdriverIO](https://webdriver.io/docs/appium)|Node.js|
|[Nightwatch.js](https://nightwatchjs.org/guide/mobile-app-testing/introduction.html)|Node.js|
|[RobotFramework](https://github.com/serhatbolsu/robotframework-appiumlibrary)|DSL|
|[multicatch's appium-client](https://github.com/multicatch/appium-client)|Rust|
In general, any W3C WebDriver spec-compatible client will also integrate well with Appium, though
some Appium-specific commands may not be implemented in other clients.
!!! note
If you maintain an Appium client that you would like to be listed in the Appium docs, feel free
to make a PR to add it to this section with a link to the documentation for the client.
@@ -0,0 +1,51 @@
---
hide:
- toc
title: Appium Drivers
---
You can't use Appium without at least one driver! Click on the link for each driver to see the
specific installation instructions and documentation for that driver.
Generally, drivers can be installed using their listed installation key, with the following command:
```
appium driver install <installation key>
```
To learn more about drivers, check out the [Driver Intro](../intro/drivers.md).
### Official Drivers
These drivers are currently maintained by the Appium team:
|Driver|Installation Key|Platform(s)|Mode(s)|
|--|--|--|--|
|[Chromium](https://github.com/appium/appium-chromium-driver)|`chromium`|macOS, Windows, Linux|Web|
|[Espresso](https://github.com/appium/appium-espresso-driver)|`espresso`|Android|Native|
|[Gecko](https://github.com/appium/appium-geckodriver)|`gecko`|macOS, Windows, Linux, Android|Web|
|[Mac2](https://github.com/appium/appium-mac2-driver)|`mac2`|macOS|Native|
|[Safari](https://github.com/appium/appium-safari-driver)|`safari`|macOS, iOS|Web|
|[UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)|`uiautomator2`|Android|Native, Hybrid, Web|
|[Windows](https://github.com/appium/appium-windows-driver)|`windows`|Windows|Native|
|[XCUITest](https://github.com/appium/appium-xcuitest-driver)|`xcuitest`|iOS|Native, Hybrid, Web|
### Other Drivers
These drivers are not maintained by the Appium team and can be used to target additional platforms:
|Driver|Installation Key|Platform(s)|Mode(s)|Supported By|
|--|--|--|--|--|
|[Flutter](https://github.com/appium/appium-flutter-driver)|`--source=npm appium-flutter-driver`|iOS, Android|Native|Community|
|[Flutter Integration](https://github.com/AppiumTestDistribution/appium-flutter-integration-driver)|`--source=npm appium-flutter-integration-driver`|iOS, Android|Native|Community / `@AppiumTestDistribution`|
|[LG WebOS](https://github.com/headspinio/appium-lg-webos-driver)|`--source=npm appium-lg-webos-driver`|LG TV|Web|HeadSpin|
|[Linux](https://github.com/fantonglang/appium-linux-driver)|`--source=npm @stdspa/appium-linux-driver`|Linux|Native|`@fantonglang`|
|[Roku](https://github.com/headspinio/appium-roku-driver)|`--source=npm @headspinio/appium-roku-driver`|Roku|Native|HeadSpin|
|[Tizen](https://github.com/Samsung/appium-tizen-driver)|`--source=npm appium-tizen-driver`|Android|Native|Community / Samsung|
|[TizenTV](https://github.com/headspinio/appium-tizen-tv-driver)|`--source=npm appium-tizen-tv-driver`|Samsung TV|Web|HeadSpin|
|[Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver)|`--source=npm appium-youiengine-driver`|iOS, Android, macOS, Linux, tvOS|Native|Community / You.i|
!!! note
If you maintain an Appium driver that you would like to be listed in the Appium docs, feel free
to make a PR to add it to this section with a link to the driver documentation.
+41 -2
View File
@@ -1,6 +1,45 @@
---
title: Appium生态系统
hide:
- toc
title: Ecosystem Overview
---
Appium has a wide ecosystem of related software and tools. This section of the Appium documentation
aims to compile a listing of various officially-supported and community-supported Appium projects:
TODO
<div class="grid cards" markdown>
- :material-car: __Drivers__
---
Link Appium to your test device
[:octicons-arrow-right-24: View all drivers](./drivers.md)
- :octicons-code-16: __Clients__
---
Link Appium to your automation code
[:octicons-arrow-right-24: View all clients](./clients.md)
- :fontawesome-solid-plug: __Plugins__
---
Modify and extend Appium functionality
[:octicons-arrow-right-24: View all plugins](./plugins.md)
- :material-wrench: __Tools__
---
Interact with Appium in other ways
[:octicons-arrow-right-24: View all tools](./tools.md)
</div>
@@ -0,0 +1,45 @@
---
hide:
- toc
title: Appium Plugins
---
Plugins offer various ways to extend or modify Appium's behaviour. They are _completely optional_
and are not needed for standard automation functionality, but you may find them to be useful
for more specialised automation workflows.
Generally, plugins can be installed using their listed installation key, with the following command:
```
appium plugin install <installation key>
```
### Official Plugins
These plugins are are currently maintained by the Appium team:
|<div style="width:7em">Plugin</div>|<div style="width:8em">Installation Key</div>|Description|
|---|---|---|
|[Execute Driver](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin)|`execute-driver`|Run entire batches of commands in a single call to the Appium server|
|[Images](https://github.com/appium/appium/tree/master/packages/images-plugin)|`images`|Image matching and comparison features|
|[Relaxed Caps](https://github.com/appium/appium/tree/master/packages/relaxed-caps-plugin)|`relaxed-caps`|Relax Appium's requirement for vendor prefixes on capabilities|
|[Universal XML](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin)|`universal-xml`|Instead of the standard XML format for iOS and Android, use an XML definition that is the same across both platforms|
### Other Plugins
These plugins are not maintained by the Appium team and can provide additional functionality:
|<div style="width:6em">Plugin</div>|<div style="width:19em">Installation Key</div>|Description|<div style="width:13em">Supported By</div>|
|---|---|---|---|
|[AltUnity](https://github.com/headspinio/appium-altunity-plugin)|`--source=npm appium-altunity-plugin`|Target Unity games and apps for automation with a new context, via the AltUnityTester framework|HeadSpin|
|[Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)|`--source=npm appium-device-farm`|Manage and create driver sessions on connected Android devices and iOS simulators|`@AppiumTestDistribution`|
|[Gestures](https://github.com/AppiumTestDistribution/appium-gestures-plugin)|`--source=npm appium-gestures-plugin`|Perform basic gestures using W3C Actions|`@AppiumTestDistribution`|
|[Interceptor](https://github.com/AppiumTestDistribution/appium-interceptor-plugin)|`--source=npm appium-interceptor`|Intercept and mock API requests and responses|`@AppiumTestDistribution`|
|[OCR](https://github.com/jlipps/appium-ocr-plugin)|`--source=npm appium-ocr-plugin`|Find elements via OCR text|`@jlipps`|
|[Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)|`--source=npm appium-reporter-plugin`|Generate standalone consolidated HTML reports with screenshots|`@AppiumTestDistribution`|
|[Wait](https://github.com/AppiumTestDistribution/appium-wait-plugin)|`--source=npm appium-wait-plugin`|Manage global element wait timeouts|`@AppiumTestDistribution`|
!!! note
If you maintain an Appium plugin that you would like to be listed in the Appium docs, feel free
to make a PR to add it to this section with a link to the documentation for the plugin.
@@ -0,0 +1,42 @@
---
hide:
- toc
title: Appium-Related Tools
---
There are several Appium tools that have been created to to assist with things not directly related
to testing, such as Appium installation, test development, and more.
### [Appium Inspector](https://appium.github.io/appium-inspector/latest/)
Appium has a graphical client which can be used to inspect application screenshots, view the
application hierarchy, run Appium commands, record app interactions, and more. It is very useful
for Appium test development.
Find downloads and more information on its GitHub page: [Appium Inspector](https://github.com/appium/appium-inspector)
### Appium Doctor
Appium Doctor is a command-line tool built into Appium drivers and plugins.
The command is expected to be used to validate whether a driver or plugin has all of its prerequisites and other environment details set up correctly
if the driver/plugin author implemented the `doctor` command.
For example, `uiautomator2` driver provides the `doctor` command below.
```
appium driver doctor uiautomator2
```
It shows no result if the driver/plugin author did not implement them.
More information on this command can be found in the [Command-Line Usage documentation](../cli/extensions.md#doctor).
For driver/plugin developers, please read [Building Doctor Checks](../developing/build-doctor-checks.md).
### Other Tools
These tools are not maintained by the Appium team and can be used to assist with other problems:
|Name|Description|Supported By|
|---|---|---|
|[appium-installer](https://github.com/AppiumTestDistribution/appium-installer)|Help set up an Appium environment for Android and iOS|`@AppiumTestDistribution`|
@@ -0,0 +1,57 @@
---
title: Local Validation Of Extension PRs
---
Sometimes it might be necessary to validate if a remote driver or a plugin PR works for the particular local
environment before it is merged or published. This tutorial describes how to achieve that.
## Requirements
- Recent LTS version of NodeJS. Check [Node.js main page](https://nodejs.org) for the download link.
- Recent version of the Appium server. Use the following commands to ensure you have
the latest version installed: `npm uninstall appium` and `npm install -g appium`.
- [Git](https://git-scm.com/) should be available locally.
## Installation
- [Check out]((https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally)) the PR locally.
There is also an option (although it is less flexible, because you won't be able to easily fetch
any changes to this PR later) to simply [download](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives) and unzip the sources
locally. If you choose the later option then no `git` tool would be necessary.
- Navigate to the local driver or plugin folder and run `npm i` from that folder.
- Make sure you don't have the given driver or plugin already installed. Use the `appium driver uninstall <driver_name>`
or `appium plugin uninstall <plugin_name>` CLI in order to delete any leftovers. The value of
`<driver_name>`/`<plugin_name>` depends on the actual driver or plugin name the PR has been prepared for.
If you are not sure which name you need to use then check the content of the `package.json` manifest,
which must be always located under the root folder of the fetched sources. You should be looking for
the `"appium" -> "driverName"` entry value there.
- Change the current folder to the one, which is NOT the driver/plugin folder root or its subfolder.
Also, make sure your current working folder does not contain any extra `package.json` file. If
it does then simply navigate to any other folder that does not.
- Run the following command in order to link the driver/plugin sources to the Appium server:
`appium driver install --source=local <full_path_to_driver_folder_with_fetched_sources>` or
`appium plugin install --source=local <full_path_to_plugin_folder_with_fetched_sources>`.
- Stop the Appium server if it is running and start it again (`appium server --use-drivers=<driver_name>`)
to check the list of loaded drivers. If the linking succeeded then you must see the driver name and the path to its
parent folder in the server logs. In case of a plugin it is required to explicitly request
this plugin to be loaded upon server startup: `appium server --use-plugins=<plugin_name>`.
## Update
After you have tested the PR and there are issues it might be necessary to update the local branch with
the recent changes from Git. Follow the next steps for that:
- Navigate to the parent folder of your local driver/plugin and run `git pull`.
- Stop Appium server if it is running.
- Run `npm i` in the parent folder of your local driver/plugin to rebuild it and update any dependencies if necessary.
- Start Appium server again similarly to how this is done in the corresponding [Installation](#installation) step above.
## Switching Back To a Stable Release
After the PR is merged there is no need to use the local plugin/driver deployment anymore, and it makes sense
to switch back to the package managed by NPM. Follow the next steps for that:
- Unlink the installed driver/plugin from the server by running `appium driver uninstall <driver_name>` or
`appium plugin uninstall <driver_name>`.
- Delete the local source folder (`rm -rf <full_path_to_plugin_or_driver_folder_with_fetched_sources>`).
- Install the driver or the plugin from NPM. Check the component README in order to find a proper command for that.
+76
View File
@@ -0,0 +1,76 @@
---
title: Caching of Application Bundles
---
Appium's base driver provides a feature which enables caching of application builds provided, for example,
as `app` capability value or to endpoints similar to the `installApp` one. This article explains common caching
principles, so you could create more performant and efficient test suite execution strategies.
## Why Caching Is Necessary
Mobile application bundles could reach hundreds of megabytes is size. This could become a serious
performance issue if a test suite is executed, and it is necessary to fetch/extract the same application
bundle for each test.
## What Is Cached
Caching could be applied to application bundles generated by
[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.js#L107) helper call.
Inherited drivers can customize their caching logic by providing own `onPostProcess`
(or both `inDownload` and `onPostProcess`) property definition, but the general
rule of thumb is that we need to cache locally all application bundles need to be downloaded and/or extracted
first before they could be actually installed on the device under test. On iOS, for example, these are `.ipa` or
`.zip` compressed application bundles, or .`aab` on Android.
## Caching of Remote Application Bundles
In order to validate whether an app bundle downloaded from the given URL could be (re)used from the cache the following
steps are applied:
1. The script checks if the given URL is already present in the cache.
If yes then it tries to fetch previously remembered
[Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified)
or [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) header values for it.
2. If `ETag` value is present then it is put into
[If-None-Match request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match).
Else if `Last-Modified` header value is present then it is put into
[If-Modified-Since request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since).
Otherwise, no caching is applied.
3. If the response status is equal to `304` then the previously cached binary is used,
otherwise the cached entry is reset and refreshed.
## Caching of Local Application Bundles
It only makes sense to cache application bundles if they need some preprocessing before being installed on the device under test.
For example, on iOS `.ipa` bundles must be unzipped, because the system installer only works with `.app` folders.
1. The script verifies if the given bundle path is already present in the cache. If the bundle was not in the cache yet
then it gets preprocessed and added there.
2. The script validates the hashsum of the bundle and compares it to the previously stored one. If hash sums don't match
then the cached item gets deleted and the preprocessing of the bundle repeats.
## How The Cache File System Is Configured
The cache where the base driver keeps all application bundles is located in the system temp folder. It is configured
on per-process basis, so each test session initialized in scope of the same Appium server process takes advantages
of it. It is a [LRU Cache](https://www.npmjs.com/package/lru-cache) with the following limitations:
- Max items: 1024. You may customize it by providing a new value to
the [APPIUM_APPS_CACHE_MAX_ITEMS](../cli/env-vars.md) environment variable.
Do not set it to a lower number than the amount of apps in all parallel sessions per process.
- Max time to live (TTL) for each entry: 24 hours.
You may customize it by providing a new value to the
[APPIUM_APPS_CACHE_MAX_AGE](../cli/env-vars.md) environment variable.
Do not set it to a lower number than the duration of a single session startup.
- TTL is refreshed for each entry upon access
- By default the full application URL is used as cache key. You may change this behavior
by enabling the [APPIUM_APPS_CACHE_IGNORE_URL_QUERY](../cli/env-vars.md) environment variable.
If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys.
See the corresponding [feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713)
for more details.
!!! warning
Note: The cache root folder is set up for automatic deletion on Appium process termination. This would only
work if Appium server is killed with `SIGINT` or `SIGTERM`. If `SIGKILL` is used then no cache cleanup
would be performed.
+262 -2
View File
@@ -1,5 +1,265 @@
---
title: Capabilities
title: Session Capabilities
---
TODO
"Capabilities" is the name given to the set of parameters used to start an Appium session. The
information in the set describes what sort of "capabilities" you want your session to have, for
example, a certain mobile operating system or a certain version of a device. Capabilities are
represented as key-value pairs, with values allowed to be any valid JSON type, including
other objects.
The W3C WebDriver spec's [section on Capabilities](https://w3c.github.io/webdriver/#capabilities)
identifies a small set of 10 standard capabilities, including the following:
| Capability Name | Type | Description |
|------------------|----------|------------------------------------------------|
| `browserName` | `string` | The name of the browser to launch and automate |
| `browserVersion` | `string` | The specific version of the browser |
| `platformName` | `string` | The type of platform hosting the browser |
## Common Appium Capabilities
Appium understands these browser-focused capabilities, but introduces a number of additional
capabilities. According to the WebDriver spec, any
non-standard "extension capabilities" must include a namespace prefix (signifying the vendor
introducing the capability), ending in a `:`. Appium's vendor prefix is
`appium:`, and so any Appium-specific capabilities must include this prefix. Depending on which
client you are using, the prefix may be added automatically or in conjunction with certain
interfaces, but it is always a good practice to explicitly include it for clarity.
Here is a list of all the globally-recognized Appium capabilities:
!!! info
Individual drivers and plugins can support other capabilities, so refer to their documentation
for lists ofspecific capability names. Some drivers may also not support all of these capabilities
| <div style="width:12em">Capability</div> | Type | Required? | Description |
|--------------------------------------------|-----------|-----------|----------------------------|
| `platformName` | `string` | yes | The type of platform hosting the app or browser |
| `appium:automationName` | `string` | yes | The name of the Appium driver to use |
| `browserName` | `string` | no | The name of the browser to launch and automate, if the driver supports web browsers as a special case |
| `appium:app` | `string` | no | The path to an installable application |
| `appium:deviceName` | `string` | no | The name of a particular device to automate, e.g., `iPhone 14` (currently only actually useful for specifying iOS simulators, since in other situations it's typically recommended to use a specific device id via the `appium:udid` capability). |
| `appium:platformVersion` | `string` | no | The version of a platform, e.g., for iOS, `16.0` |
| `appium:newCommandTimeout` | `number` | no | The number of seconds the Appium server should wait for clients to send commands before deciding that the client has gone away and the session should shut down |
| `appium:noReset` | `boolean` | no | If true, instruct an Appium driver to avoid its usual reset logic during session start and cleanup (default `false`) |
| `appium:fullReset` | `boolean` | no | If true, instruct an Appium driver to augment its usual reset logic with additional steps to ensure maximum environmental reproducibility (default `false`) |
| `appium:eventTimings` | `boolean` | no | If true, instruct an Appium driver to collect [Event Timings](./event-timing.md) (default `false`) |
| `appium:printPageSourceOnFindFailure` | `boolean` | no | If true, collect the page source and print it to the Appium log whenever a request to find an element fails (default `false`) |
Some drivers place more complex constraints on capabilities as a group. For example, while the
`appium:app` and `browserName` capabilities are listed above as optional, if you want to launch
a session with a specific app, the XCUITest driver requires that at least one of `appium:app`,
`browserName`, or `appium:bundleId` are included in the capabilities (otherwise it will not know
what app to install and/or launch and will simply open a session on the home screen). Each driver
will document how it interprets these capabilities and any other platform-specific requirements.
!!! note
Capabilities are like parameters used when starting a session. After the capabilities are sent
and the session is started, they cannot be changed. If a driver supports updating aspects of
its behaviour in the course of a session, it will provide a [Setting](./settings.md) for this
purpose instead of, or in addition to, a capability.
Each Appium client has its own way of constructing capabilities and starting a session. For
examples of doing this in each client library, head to the [Ecosystem](../ecosystem/index.md) page
and click through to the appropriate client documentation.
## Using `appium:options` to Group Capabilities
If you use a lot of `appium:` capabilities in your tests, it can get a little repetitive. You can
combine all capabilities as an object value of a single `appium:options` capability instead, in
which case you don't need to use prefixes on the capabilities inside the object. For example:
```json
{
"platformName": "iOS",
"appium:options": {
"automationName": "XCUITest",
"platformVersion": "16.0",
"app": "/path/to/your.app",
"deviceName": "iPhone 12",
"noReset": true
}
}
```
Note that constructing a capability value which is itself an object differs by language; refer to
your client documentation for further examples on how to achieve this.
!!! warning
If you include the same capabilities both inside and outside of `appium:options`, the values
inside of `appium:options` take precedence.
## Always-Match and First-Match Capabilities
The W3C spec allows clients to give the Appium server some flexibility in the kind of session it
creates in response to a new session request. This is through the concept of "always-match" and
"first-match" capabilities:
- Always-match capabilities consist of a single set of capabilities, every member of which must
be satisfied by the server in order for the new session request to proceed.
- First-match capabilities consist of an array of capability sets. Each set is merged with the
always-match capabilities, and the first set that the server knows how to handle will be the set
that is used to start the session.
!!! note
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or
a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for
a more in-depth description of how capabilities are processed.
In practice, use of first-match capabilities is not necessary or recommended for use with Appium.
Instead, we recommend that you define the explicit set of capabilities you want the Appium
server to handle. These will be encoded as the always-match capabilities, and the array of
first-match capabilities will be empty.
That being said, Appium _does_ understand always-match and first-match capabilities as
defined in the W3C spec, so if you use these features, Appium will work as expected. The process of
defining always-match and first-match capabilities is unique to each client library, so refer to
the documentation for your client library to see examples of how it works.
## Special Notes for Cloud Providers
!!! warning
This section is not intended for end-users of Appium; it is intended for developers building
Appium-compatible cloud services.
When managing an Appium cloud, your users may wish to target various independent versions of Appium
drivers and plugins. It is of course up to each service provider how they wish to implement the
discovery, installation, and availability of any official or third party drivers or plugins. But
the Appium team does provide several suggestions, for consistency across the industry. _These are
recommendations only,_ and not a standard, but adopting it will help users to navigate the increased
complexity that working with Appium 2 in a cloud environment may bring.
### Suggested capabilities
In addition to the standard `platformName`, `appium:deviceName`, `appium:automationName`, and
`appium:platformVersion`, we recommend adopting the capability `$cloud:appiumOptions`, where the
label `$cloud` is not meant to be interpreted literally but instead should be replaced by your
vendor prefix (so for HeadSpin it would be `headspin`, Sauce Labs it would be `sauce`, and
BrowserStack it would be `browserstack`, to name just a few examples). The `$cloud:appiumOptions`
capability would itself be a JSON object, with the following internal keys:
| <div style="width:10em">Capability</div> | Usage | Example |
| ---------------------------------------- | ------ | ------- |
| `version` | The version of the Appium server that is used to host and manage drivers. If omitted, the behavior is left up to the provider, but the recommendation would be to provide the latest official version. | `2.0.0` |
| `automationVersion` | The version of the driver (as specified by `appium:automationName`) that should be used. | `1.55.2` |
| `automation` | The name of a custom driver to use (see below for more info). This would override `appium:automationName` and `$cloud:automationVersion`. | `{"name": "@org/custom-driver", "source": "github", "package": "custom-driver"}` |
| `plugins` | The list of plugins (and potentially versions of plugins) that should be activated (see below for more info). | `["images", "universal-xml"]` |
### Basic example
Appium extensions (drivers and plugins) have a set of properties that specify where they can be
installed from. Cloud providers are obviously under no obligation to provide support for
arbitrarily specified extensions, seeing as these may represent untrusted code running in a managed
environment. In the case where arbitrary extensions are not supported, the `appium:automationName`,
`$cloud:automationVersion`, and `$cloud:appiumPlugins` capabilities should be sufficient. See the
following JSON object representing capabilities for a session:
```json
{
"platformName": "iOS",
"appium:platformVersion": "14.4",
"appium:deviceName": "iPhone 11",
"appium:app": "Some-App.app.zip",
"appium:automationName": "XCUITest",
"$cloud:appiumOptions": {
"version": "2.0.0",
"automationVersion": "3.52.0",
"plugins": ["images"]
}
}
```
This set of capabilities requests an Appium 2+ server supporting the XCUITest driver at version
`3.52.0`, and the `images` plugin active. This set is easy for a cloud provider to verify. The
cloud provider can obviously do anything it wants in response to these capabilities, including
downloading Appium and driver and plugin packages on the fly, or erroring out if the versions
requested are not in a supported set, or if the plugin is not supported, etc...
### Basic example with `appium:options`
The previous example still looks a bit disorganized, so of course we also recommend that cloud
providers support the `appium:options` capability as detailed above, which could turn the previous
set of capabilities into the following:
```json
{
"platformName": "iOS",
"appium:options": {
"platformVersion": "14.4",
"deviceName": "iPhone 11",
"app": "Some-App.app.zip",
"automationName": "XCUITest"
},
"$cloud:appiumOptions": {
"version": "2.0.0",
"automationVersion": "3.52.0",
"plugins": ["images"]
}
}
```
### Extension objects
Some service providers may wish to dynamically allow access to all of the features of the Appium
2 CLI, including downloading arbitrary drivers and plugins. To represent these extensions, we can
define special JSON "extension objects", with the following keys:
- `name`: the name of the extension. This would be an `npm` package name (if downloading from `npm`),
or a `git` or GitHub spec (if downloading from a `git` server or GitHub).
- `version`: the version of the extension, e.g., the `npm` package version or `git` SHA.
- (optional) `source`: a denotation of where the extension can be downloaded from. It is recommended
to support the following values: `appium`, `npm`, `git`, `github`. Here, `appium` means "Appium's
own official list", and should be the default value if this key is not included.
- (optional) `package`: when downloading extensions from `git` or GitHub, the `npm` package name of
the extension must also be provided. This is optional for non-`git` sources.
Since each session is handled by a single driver, the `$cloud:appiumOptions`/`$automation`
capability could be used with an extension object value to denote this driver, for example:
```json
{
"$cloud:appiumOptions": {
"automation": {
"name": "git+https://some-git-host.com/custom-driver-project.git",
"version": "some-git-sha",
"source": "git",
"package": "driver-npm-package-name"
}
}
}
```
And since sessions can handle multiple plugins, each value in the list of `$cloud:appiumPlugins`
could also be an extension object rather than a string, so that specific versions could be
requested:
```json
{
"$cloud:appiumOptions": {
"plugins": [{
"name": "images",
"version": "1.1.0"
}, {
"name": "my-github-org/my-custom-plugin",
"version": "a83f2e",
"source": "github",
"package": "custom-plugin"
}]
}
}
```
These serve as illustrative examples for the recommendations here. Of course, it is up to the
service providers to implement the handling of these capabilities at their front end / load
balancer, to perform any error checking, or to actually run any of the `appium driver` or `appium
plugin` CLI commands that support the end user's request. This section is merely a suggestion as to
how service providers might design their user-facing capabilities API in a way which in principle
supports all of the capabilities that Appium itself would provide to the end user if they were
running Appium on their own.
+94 -1
View File
@@ -2,4 +2,97 @@
title: The Appium Config File
---
TODO
Instead of passing arguments on the command line to Appium, you may add them to a special config
file. Appium will read values from this config file when it runs. (Please note that CLI arguments
have _precedence_ over configuration files; if a value is set in a config file _and_ via CLI
argument, the CLI argument is preferred.)
## Supported Config File Formats
You can store your config data in the following kinds of files:
- JSON
- YAML
- JS (a JavaScript file exporting a JS object)
- CJS (the same as above; the extension is for common JS)
!!! warning
Note: Configuration files in ESM format are not currently supported.
## Supported Config File Locations
Configuration files can be named anything, but the following filenames will be automatically
discovered and loaded by Appium:
- `.appiumrc.json` (recommended)
- `.appiumrc.yaml`
- `.appiumrc.yml`
- `.appiumrc.js`
- `.appiumrc.cjs`
- `appium.config.js`
- `appium.config.cjs`
- `.appiumrc` (which is considered to be JSON)
Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium`
property in your `package.json` and it will be automatically discovered.
### Config File Search
Appium will search _up_ the directory tree from the current working directory for one of these
files. If it reaches the current user's home directory or filesystem root, it will stop looking.
To specify a _custom_ location for your config file, use `appium --config-file /path/to/config/file`.
#### Configuration File Format
First, you might want to look at some examples:
- [Appium Configuration - JSON](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.json)
- [Appium Configuration - YAML](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.yaml)
- [Appium Configuration - JS](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.js)
A description of the format is available, as well:
- [Appium Configuration File JSON Schema](https://github.com/appium/appium/blob/master/packages/schema/lib/appium-config.schema.json)
- [TypeScript declarations for Appium Configuration](https://github.com/appium/appium/blob/master/packages/types/lib/config.ts)
To describe in words, the config file will have a root `server` property, and all arguments are
child properties. For certain properties which must be supplied on the command-line as
comma-delimited lists, JSON strings, and/or external filepaths, these instead will be of their
"native" type. For example, `--use-plugins <value>` needs `<value>` to be comma-delimited string
or path to a delimited file. However, the config file just wants an array, e.g.,:
```json
{
"server": {
"use-plugins": ["my-plugin", "some-other-plugin"]
}
}
```
## Configuring extensions (drivers and plugins)
For `driver`-and-`plugin`-specific configuration, these live under the `server.driver` and
`server.plugin` properties, respectively. Each driver or plugin will have its own named property,
and the values of any specific configuration it provides are under this. For example:
```json
{
"server": {
"driver": {
"xcuitest": {
"webkit-debug-proxy-port": 5400
}
}
}
}
```
!!! note
The above configuration corresponds to the `--driver-xcuitest-webkit-debug-proxy-port` CLI argument.
All properties are case-sensitive and will be in
[kebab-case](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Delimiter-separated_words).
For example, `callback-port` is allowed, but `callbackPort` is not.
+41 -2
View File
@@ -1,5 +1,44 @@
---
title: The Context API
hide:
- toc
title: Managing Contexts
---
TODO
A common feature of many app platforms is the ability for developers to embed web content inside of
the platform-native app frame. This allows developers to leverage web technologies or existing web
content for some or all of the app functionality. However, the additional complexity of mixing
"modes" within a single application can make it difficult for automation tools that are designed to
target the "native" elements and behaviours.
Appium provides a set of APIs for working with different app modes, called "contexts", that Appium
drivers can implement if they support automation commands in these different modes. There are three
basic commands that Appium has added to the W3C WebDriver spec for this purpose:
| Command Name | Method/Route | Params | Description | Returns |
|-----------------------|-----------------------------|-------------------|-----------------------------------------------|-----------------|
| `Get Contexts` | `GET /session/:id/contexts` | | Get a list of the available contexts | `array<string>` |
| `Get Current Context` | `GET /session/:id/context` | | Get the name of the active context | `string` |
| `Set Context` | `POST /session/:id/context` | `name` (`string`) | Switch into the context with the given `name` | `null` |
This API is flexible enough to handle a variety of semantic interpretations on the part of the
driver. For example, the XCUITest driver includes two kinds of contexts: the native app context and
any active webviews, as one context per webview. A call to `Get Contexts` will return the list of
names, which you as a test author can sift through and use to switch into the appropriate context.
As another example, the [Appium Altunity
Plugin](https://github.com/headspinio/appium-altunity-plugin) introduces the concept of a `UNITY`
context, which encapsulates all the plugin's specific behaviour to ensure that when outside of the
`UNITY` context, the active driver's usual command implementations are used.
It is important to note that a call to `Get Contexts` will always contain at least one context,
conventionally but not necessarily named `NATIVE_APP`. This is the default active context.
Depending on the type of context you're in, the operation of the driver might change. The XCUITest
driver, when targeting a webview context, will not run its typical routines for finding and
interacting with elements. Instead, it will run a different set of routines appropriate to web
elements. This might have a variety of consequences, like supporting a different set of locator
strategies.
The command names in the table above are generic references to the commands and not code examples.
For examples of how to access the Context API in the language-specific client libraries, please
visit the documentation for a given library.
+71 -2
View File
@@ -1,5 +1,74 @@
---
title: The Event Timing API
hide:
- toc
title: Retrieving Event Timings
---
TODO
Appium comes with the ability to retrieve timing information about startup
information and command length. This is an advanced feature that is controlled
by the use of the `appium:eventTimings` capability (set it to `true` to log event
timings).
With this capability turned on, the `GET /session/:id` response (i.e., the
response to `driver.getSessionDetails()` or similar, depending on client) will
be decorated with an `events` property. This is the structure of that `events`
property:
```
{
"<event_type>": [<occurence_timestamp_1>, ...],
"commands": [
{
"cmd": "<command_name>",
"startTime": <js_timestamp>,
"endTime": <js_timestamp>
},
...
]
}
```
In other words, the `events` property has 2 kinds of properties of its own:
* Properties which are the names of event types
* The `commands` property
Properties which are names of event types correspond to an array of timestamps
when that event happened. It's an array because events might happen multiple
times in the course of a session. Examples of event types include:
* `newSessionRequested`
* `newSessionStarted`
(Individual drivers will define their own event types, so we do not have an
exhaustive list to share here. It's best to actually get one of these responses
from a real session to inspect the possible event types.)
The `commands` property is an array of objects. Each object has the name of the
Appium-internal command (for example `click`), as well as the time the command
started processing and the time it finished processing.
With this data, you can calculate the time between events, or a strict timeline
of events, or statistical information about average length of a certain type of
command, and so on.
You can only receive data about events that have happened when you make the
call to `/session/:id`, so the best time to get data about an entire session is
right before quitting it.
The Appium team maintains an event timings parser tool that can be used to
generate various kinds of reports from event timings output:
[appium/appium-event-parser](https://github.com/appium/appium-event-parser).
## Add a custom event
!!! warning "TODO"
The links to the commands in the following paragraph do not yet work since these docs are under
construction.
You can add custom events that will show up in the event timings data. You can send a custom event
name to the Appium server using the [Log Event API](#TODO), and the server will store the
timestamp. The [Get Events](#TODO) command can be used to retrieve named events' timestamps later
on.
@@ -0,0 +1,122 @@
---
hide:
- toc
title: Execute Methods
---
Because the scope of commands implemented in Appium drivers is broader than the scope of commands
defined by the W3C WebDriver spec, Appium needs a way for these "extended" commands to be accessible
by client libraries. There are two main strategies for this:
1. Appium drivers define new W3C-compatible API routes, and Appium clients are updated to include
support for those new routes.
2. Appium drivers define so-called "Execute Methods" which provide new functionality by
overloading the existing `Execute Script` command which is already available in any WebDriver-
based client library (including all Selenium and Appium clients).
There are pros and cons for each strategy, but it is ultimately up to the extension author to
decide how they wish implement new commands.
This guide is designed to specifically help you understand the "Execute Method" strategy. This
pattern is commonly used in official Appium drivers and other third-party extensions.
Here's an example of how the `Execute Script` command is designed to work in the world of WebDriver
and browser automation:
=== "JS (WebDriverIO)"
```js
await driver.executeScript('return arguments[0] + arguments[1]', [3, 4])
```
=== "Java"
```java
JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
jsDriver.executeScript("return arguments[0] + arguments[1]", 3, 4);
```
=== "Python"
```py
driver.execute_script('return arguments[0] + arguments[1]', 3, 4)
```
=== "Ruby"
```rb
driver.execute_script 'return arguments[0] + arguments[1]', 3, 4
```
=== "C#"
```dotnet
((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0] + arguments[1]", 3, 4);
```
What's happening here is that we are defining a snippet of Javascript (technically,
a function body) to be executed within the web browser. The client can send arguments which are
serialized, sent over HTTP, and finally provided to the function as parameters. In this example,
we are essentially defining an addition function. The return value of the `Execute Script` command
is whatever the return value of the Javascript snippet is! In the case of this example, that value
would be the number `7` (`3` + `4`).
Each client library has its own way of calling the command and providing any arguments to the script
function, but the function itself—the snippet—is always a string and is the same across all languages.
In the world of Appium, we are usually not automating a web browser, which means this command is
not particularly useful. But it *is* useful as a way to encode the name of an arbitrary command and
to provide parameters. For example, the [XCUITest
Driver](https://github.com/appium/appium-xcuitest-driver) has implemented a command that lets a client
terminate a running application if you know the ID (the `bundleId`) of the app. The way that the
driver makes this command available is via the Execute Method `mobile: terminateApp`. Instead of
providing a JavaScript function to the "Execute Script" command, the user provides a _known string_
as defined by the driver. The only other thing a client needs to know is the set of
parameters for the method, which are documented by the driver. In this case, we have a parameter
named `bundleId`, whose value should be a string encoding the ID of the app to terminate. Here is
how this Execute Method would be called:
=== "JS (WebDriverIO)"
```js
await driver.executeScript('mobile: terminateApp', [{bundleId: 'com.my.app'}])
```
=== "Java"
```java
JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
jsDriver.executeScript("mobile: terminateApp", ImmutableMap.of("bundleId", "com.my.app"));
```
=== "Python"
```py
driver.execute_script('mobile: terminateApp', {'bundleId': 'com.my.app'})
```
=== "Ruby"
```rb
driver.execute_script 'mobile: terminateApp', { bundleId: 'com.my.app' }
```
=== "C#"
```dotnet
((IJavaScriptExecutor)driver).ExecuteScript("mobile: terminateApp",
new Dictionary<string, string> { { "bundleId", "com.my.app" } });
```
There are two important differences in using Appium Execute Methods from vanilla Selenium
Javascript execution:
1. The script string is just a command name; it will be provided by the driver documentation
1. The standard way to provide parameters is as a *single* object with keys representing parameter
names and values representing parameter values. So in this case, we had to specify both the
parameter name (`bundleId`) as the key of the parameters object, and the parameter value
(`com.my.app`) as the value for that key. A driver can define parameters as _required_ or _optional_.
Of course, always refer to the documentation for the particular Execute Method in case the author
has made any alterations to the standard access method.
@@ -1,5 +0,0 @@
---
title: Execute Script Overloads
---
TODO
+162 -1
View File
@@ -2,4 +2,165 @@
title: Appium and Selenium Grid
---
TODO
## Using Selenium Grid 4+
The
[relay](https://www.selenium.dev/documentation/grid/configuration/toml_options/#relaying-commands-to-a-service-endpoint-that-supports-webdriver)
feature in Grid 4 allows you to proxy Appium requests to an Appium server instance. Here is
an example walkthrough of how you would connect two different Appium instances to a Selenium Grid.
### Define the Appium configs
Each Appium instance should have a config file that can be easily updated. It should contain any
information which needs to be unique to that particular server (e.g., ports its drivers should use
that others should not). We are going to have 2 Appium servers, so we will need 2 config files:
```yaml
# appium1.yml
server:
port: 4723
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8100
mjpegServerPort: 9100
mjpegScreenshotUrl: "http://localhost:9100"
```
In the above YAML config file, we specify the Appium server port, the driver used, and parameters
for the driver that will be sent in as default capabilities. Our goal is to ensure that any other
drivers running on this host will not compete with system ports or other resources. The second
config file could look like the following, where we simply adjust a few ports to prevent clashes:
```yaml
# appium2.yml
server:
port: 4733
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8110
mjpegServerPort: 9110
mjpegScreenshotUrl: "http://localhost:9110"
```
### Define the Grid node configs
We will be launching one Grid "node" per Appium server, to manage relaying commands and determining
capacity and online status, etc... So we should have one config file per Grid node as well. Each
node config should include the address of the Appium server it will target, as well as a list of
capability "configs" it should accept to relay a session request to Appium. Here is what the config
could look like for the two nodes:
```toml
# node1.toml
[server]
port = 5555
[node]
detect-drivers = false
[relay]
url = "http://localhost:4723"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 13\", \"appium:automationName\": \"XCUITest\"}"
]
```
```toml
# node2.toml
[server]
port = 5565
[node]
detect-drivers = false
[relay]
url = "http://localhost:4733"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 12\", \"appium:automationName\": \"XCUITest\"}"
]
```
Note that each node config also specifies a different port itself for the node to run on.
### Putting it together
The Grid nodes aren't enough--you'll also want a Grid "hub" that acts as a load balancer and
manager for all the nodes. So in the end we'll have 5 processes running at once: 2 Appium servers,
2 Grid nodes, and 1 Grid hub. It's best to run each of these in a separate terminal window to avoid
confusion of logs. Here is how you'd start each process:
0. `appium --config appium1.yml`
0. `appium --config appium2.yml`
0. `java -jar /path/to/selenium.jar node --config node1.toml`
0. `java -jar /path/to/selenium.jar node --config node2.toml`
0. `java -jar /path/to/selenium.jar hub`
Once you wait a few moments for the nodes to detect their Appium servers, and to register with the
hub, you'll be able to send all your Appium traffic via the single hub endpoint (defaulting to
`http://localhost:4444`).
And of course, you're able to link up Appium servers and nodes running on different machines in
your network to form a larger grid.
## Using Selenium Grid 3
It is possible to register your Appium server with a local [Selenium Grid 3](https://www.selenium.dev/documentation/legacy/selenium_3/grid_3/)
([setup docs](https://www.selenium.dev/documentation/legacy/grid_3/setting_up_your_own_grid/)) instance by using the
`--nodeconfig` server argument.
```bash
appium server --nodeconfig /path/to/nodeconfig.json --base-path=/wd/hub
```
In the referenced config file you have to define the `browserName`, `version` and `platform`
capabilities and based on these parameters the grid will re-direct your test to the right device.
You will also need to configure your host details and the Selenium Grid details. For a full list of
all parameters and descriptions see
[here](https://www.selenium.dev/documentation/legacy/selenium_3/grid_setup/).
Once you start the Appium server it will register with the grid, and you will see your device on
the grid console page:
`http://**\<grid-ip-adress\>**:**\<grid-port\>**/grid/console`
### Example Grid Node Configuration JSON
```json
{
"capabilities":
[
{
"browserName": "<e.g._iPhone5_or_iPad4>",
"version":"<version_of_iOS_e.g._7.1>",
"maxInstances": 1,
"platform":"<platform_e.g._MAC_or_ANDROID>"
}
],
"configuration":
{
"cleanUpCycle":2000,
"timeout":30000,
"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
"url":"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub",
"host": "<host_name_appium_server_or_ip-address_appium_server>",
"port": <appium_port>,
"maxSession": 1,
"register": true,
"registerCycle": 5000,
"hubPort": <grid_port>,
"hubHost": "<Grid_host_name_or_grid_ip-address>",
"hubProtocol": "<Protocol_of_Grid_defaults_to_http>"
}
}
```
If `url`, `host`, and `port` are not given, the config will be auto updated to point to
`localhost:<appium-port>`.
If your Appium server is running on a different machine to your Selenium Grid server, make sure you
use an external name/IP address in your `host` and `url` configuration; `localhost` and `127.0.0.1`
will prevent Selenium Grid from connecting correctly.
+83 -2
View File
@@ -1,5 +1,86 @@
---
title: Log Filtering
title: Filtering the Appium Log
---
TODO
Sometimes it might be necessary to hide sensitive information, like passwords, device identifiers,
hashes, etc..., from the server log. Appium makes it possible to ensure such information is
redacted in logs via the `--log-filters` command line argument. This argument allows you to provide
the path to a special config file, containing one or more log obfuscation rules.
## Config Format
The filtering config must be one of:
- a path to a valid JSON file containing an array of filtering rules
- a `log-filters` entry in an [Appium Config](./config.md) file, with the rules array inline
Each rule is an object with a set of predefined properties. The following rule properties are
supported:
- `pattern`: A valid Javascript RegExp pattern to replace. Must be a valid non-empty pattern.
- `text`: A simple non-empty exact text match to replace. Either this property or the above one must
be provided. `pattern` has priority over `text` if both are provided.
- `flags`: Regular expression flags for the given pattern. Supported flags are the same as for the
standard JavaScript [RegExp constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2).
Note that the `g` (global matching) flag is always enabled.
- `replacer`: The replacer value to use. By default it is `**SECURE**`. Empty values are allowed.
### Config Examples
Replace all occurrences of `my.magic.app` string with the default replacer:
```json
[
{
"text": "my.magic.app"
}
]
```
Replace all occurrences of `my.magic.<any char>` string with a custom replacer (case insensitive):
```json
[
{
"pattern": "my\\.magic\\.\\w",
"flags": "i",
"replacer": "***"
}
]
```
Replace all occurrences of `my.magic.<any chars>` and/or `your.magic` strings with a custom
replacer (case insensitive):
```json
[
{
"pattern": "my\\.magic\\.\\w+",
"flags": "i",
"replacer": "***"
},
{
"pattern": "your\\.magic",
"flags": "i",
"replacer": "***"
}
]
```
Truncate all log lines to max 15 chars (advanced):
```json
[
{
"pattern": "(.{1,15}).*",
"flags": "s",
"replacer": "$1"
}
]
```
### Config Errors Handling
If any of the config rules contains invalid items (such as empty/invalid pattern, empty rule, etc.)
then Appium will print the detailed report about collected errors and will fail to start until
these errors are addressed.
@@ -1,5 +1,87 @@
---
title: Managing Appium Drivers and Plugins
title: Managing Drivers and Plugins
---
TODO
To do anything useful with Appium, you need to have at least one [Driver](../intro/drivers.md)
installed, otherwise Appium won't know how to automate anything. There is an entire
[Ecosystem](../ecosystem/index.md) of drivers and plugins out there!
This guide helps explain how to manage these drivers and plugins. There are
two basic strategies: using Appium's extension CLI interface, or managing extensions yourself in an
`npm`-based project.
!!! note
Other package managers are not currently supported.
## Using Appium's Extension CLI
With Appium's [Extension CLI](../cli/extensions.md), you let Appium manage drivers and plugins for
you. You will use CLI commands to tell Appium which extensions you would like to install, update,
or remove. Here's an example of how you might install a driver using the CLI:
```bash
appium driver install xcuitest
```
This command will install the latest version of the
[XCUITest Driver](https://github.com/appium/appium-xcuitest-driver). The Extension CLI comes with a variety
of commands and parameters; see the documentation for that command for all the specifics.
The all-important question when Appium is managing your extensions for you is: where are they installed?
Appium manages extensions in a directory specified by the `APPIUM_HOME` environment variable. You
can set that variable to anything you like, and Appium will manage its extensions there. You can
therefore also use the `APPIUM_HOME` environment variable to manage different sets of extensions,
for example if you want to have the same driver installed at conflicting versions:
```bash
APPIUM_HOME=/path/to/home1 appium driver install xcuitest@4.11.1
APPIUM_HOME=/path/to/home2 appium driver install xcuitest@4.11.2
```
Running these commands will result in two separate `APPIUM_HOME` directories being created and
populated with the corresponding version of the XCUITest driver. You can then use the same
environment variables to direct Appium which version to use on launch:
```bash
APPIUM_HOME=/path/to/home1 appium # use xcuitest driver 4.11.1
APPIUM_HOME=/path/to/home2 appium # use xcuitest driver 4.11.2
```
You don't need to set `APPIUM_HOME` if you don't want to! By default, Appium will set `APPIUM_HOME`
to the directory `.appium` in your user home directory.
These installed packages will be managed by `extensions.yaml` in `$APPIUM_HOME/node_modules/.cache/appium/extensions.yaml`.
## Do-It-Yourself with `npm`
Because Appium and Appium drivers are Node.js programs, if you are integrating your Appium scripts
into your own Node.js project, there is an alternative way to manage drivers and plugins: via `npm`,
like any other dependency. Basically, whenever you run Appium, if you have not explicitly set
`APPIUM_HOME`, it will:
1. Try to determine whether the _current directory_ is inside an `npm` package.
1. If so, it will check whether `appium` is a dependency (dev, prod, or peer) in the project's
`package.json`
1. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will ignore load
drivers and plugins defined in that `package.json` file instead.
This means you are freely able to add Appium drivers and plugins as regular package dependencies or
dev dependencies. For example, if your project has a `package.json` which includes the following:
```json
{
"devDependencies": {
"appium": "^2.0.0",
"appium-xcuitest-driver": "^4.11.1"
}
}
```
Then, if you run `npx appium` inside your project, Appium will detect that it is a dependency of
the project, and will load the XCUITest driver which is also listed as a dev dependency for the
project.
This strategy is *only* recommended if you are already using `npm` for your project.
Otherwise, it is recommended that you use Appium's Extension CLI and, if necessary, adjust
`APPIUM_HOME` to change the location of stored extensions.
+235 -234
View File
@@ -1,198 +1,208 @@
---
title: 自 Appium 1.x 迁移到 Appium 2.x
title: Migrating to Appium 2
---
本文档是针对使用 Appium 1.x 并希望迁移到 Appium 2.x 的用户的指南.
其包含重大更改的列表, 以及如何迁移您的环境或测试套件以确保与Appium 2.0的兼容性.
## Appium 2.0 概述
This document is a guide for those who are using Appium 1 and wish to migrate to Appium 2. It
contains a list of breaking changes and how to migrate your environments or test suites to ensure
compatibility with Appium 2.
Appium 2.0 是Appium近5年来最重要的新版本.
Appium 2.0 中的更改主要与特定平台的自动化行为更改 _无_ 关.
相反, Appium 2.0将Appium重新定义为一个 _平台_,
其可以轻松创建和共享"驱动程序" (引入对给定平台自动化的支持的代码项目)
和"插件" (允许覆盖, 更改, 扩展或向Appium添加行为的代码项目) .
## Overview of Appium 2
与此同时, Appium项目正在借此机会删除许多陈旧以及作废的功能.
Appium 2 is the most major new release of Appium in over 5 years. The changes in Appium 2 are _not_
primarily related to changes in automation behaviors for specific platforms. Instead, Appium 2
reenvisions Appium as a _platform_ where "drivers" (code projects that introduce support for
automation of a given platform) and "plugins" (code projects that allow for overriding, altering,
extending, or adding behaviors to Appium) can be easily created and shared.
借此机会介绍一些重大变更, 包括如何安装Appium、
如何管理驱动程序和各种功能、以及协议支持等.
以下为详细介绍.
At the same time, the Appium project is taking the opportunity to remove many old and deprecated
bits of functionality.
## 重大变更
Together these do introduce a few breaking changes to how Appium is installed, how drivers and
various features are managed, and protocol support. These are detailed below.
查看 [Appium 2.0 发行说明](https://github.com/appium/appium/releases) 以获取最全面的变更列表.
在此, 我们指出重大变更以及您需要为它们执行的操作.
## Breaking Changes
### :bangbang: 在安装过程中安装驱动程序
### :bangbang: Default server base path
当您安装Appium 1.x时, 所有可用的驱动程序将与主Appium Server同时安装.
现在情况已不再如此. 简单地安装Appium 2.0 (例如, 通过 `npm install -g appium` ) ,
将只安装Appium Server, 但没有驱动程序.
要安装驱动程序, 您必须改用新的 [Appium 扩展 CLI](../cli/extensions.md).
例如, 为了获取最新版本的XCUITest和UiAutomator2驱动程序,
您可以在安装Appium后, 运行以下命令:
With Appium 1, the server would accept commands by default on `http://localhost:4723/wd/hub`. The
`/wd/hub` base path was a legacy convention from the days of migrating from Selenium 1 to Selenium
2, and is no longer relevant. As such the default base path for the server is now `/`. If you want
to retain the old behaviour, you can set the base path via a command line argument as follows:
```
appium driver install xcuitest
appium driver install uiautomator2
appium --base-path=/wd/hub
```
至此, 您的驱动程序已安装并准备就绪.
您可以使用此CLI做更多的事情, 因此请务必查看其文档.
如果您在持续集成环境中运行, 或者想要在一步到位地安装 Appium 和一些驱动程序,
则可以在安装过程中使用一些特殊标志来执行此操作, 例如:
You can also set server arguments as [Config file](./config.md) properties.
```
npm install --global appium --drivers=xcuitest,uiautomator2
### :bangbang: Installing drivers during setup
When you installed Appium 1, all available drivers would be installed at the same time as the main
Appium server. This is no longer the case. Simply installing Appium 2 (e.g., by `npm i -g appium`),
will install the Appium server only, but no drivers. To install drivers, you must instead use the
new [Appium extension CLI](../cli/extensions.md). For example, to install the latest versions of the
XCUITest and UiAutomator2 drivers, after installing Appium you would run the following commands:
```bash
appium driver install uiautomator2 # installs the latest driver version
appium driver install xcuitest@4.12.2 # installs a specific driver version
```
这将一次性为您安装Appium和两种驱动程序.
At this point, your drivers are installed and ready. There's a lot more you can do with the Appium 2
command line, so be sure to check out [its documentation](../cli/index.md). If you're running in a CI
environment or want to install Appium along with some drivers all in one step, you can do so using
some special flags during install, for example:
### :bangbang: 驱动安装路径
```bash
npm i -g appium --drivers=xcuitest,uiautomator2
```
当您安装 Appium 1.x 时,
所有可用的驱动程序将与主 Appium 服务器同时安装.
路径是 `/path/to/appium/node_modules`.
例如, 手动构建WebDriverAgent的`appium-webdriveragent`
是 `/path/to/appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`.
This will install Appium and the two drivers for you in one go. Please uninstall any existing Appium 1
`npm` packages (with `npm uninstall -g appium`) if you get an installation or startup error.
Appium 2.0 在 `APPIUM_HOME` 环境变量中安装此类依赖项.
默认路径为 `~/.appium`.
因此,安装 XCUITest 驱动程序包后,
`appium-webdriveragent` 的路径可能是 `$APPIUM_HOME/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent` .
### :bangbang: Drivers installation path
### :bangbang: Chromedriver安装标志
When you installed Appium 1, all available drivers would be installed at the same time as the main
Appium server, at `/path/to/appium/node_modules`. For example, `appium-webdriveragent` was located
at `/path/to/appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`.
在Appium 1.x中, 可以使用以下命令行标志自定义Chromedriver的安装方式
(例如作为UiAutomator2驱动程序的一部分) :
Appium 2 installs such dependencies in the path defined by the `APPIUM_HOME` environment variable.
The default path is `~/.appium`. So, `appium-webdriveragent` would now be located at
`$APPIUM_HOME/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`.
### :bangbang: Chromedriver installation flags
In Appium 1, it was possible to customize the way Chromedriver was installed (as part of the
UiAutomator2 driver for example), using the following command line flags:
* `--chromedriver-skip-install`
* `--chromedriver-version`
* `--chromedriver-cdnurl`
由于现在通过 Appium 2.0 为您安装驱动程序, 并且这些标志是作为 NPM 配置标志实现的,
因此它们将不再有效. 相反地, 请在驱动程序安装过程中使用以下环境变量:
Because Appium 2 now installs drivers for you, and because these flags were implemented as `npm`
config flags, they will no longer work. Instead, use the following environment variables during
driver installation:
* `APPIUM_SKIP_CHROMEDRIVER_INSTALL`
* `CHROMEDRIVER_VERSION`
* `CHROMEDRIVER_CDNURL`
例如:
For example:
```
```bash
APPIUM_SKIP_CHROMEDRIVER_INSTALL=1 appium driver install uiautomator2
```
### :bangbang: 特定于驱动程序的命令行选项
### :bangbang: Driver-specific command line options
在 Appium 1.x 中, 针对特定驱动程序的命令行选项都托管在主 Appium 服务器上.
因此, 您可以与Appium一起使用诸如
'--chromedriver-executable' 这样的CLI参数,
来设置特定Chromedriver版本的位置,
UiAutomator2同理.
With Appium 1, command-line options specific to particular drivers were all hosted on the main
Appium server. So, for example, `--chromedriver-executable` was a CLI parameter you could use with
Appium to set the location of a specific Chromedriver version for use with, say, the UiAutomator2 driver.
With Appium 2, all driver- and platform-specific CLI params have been moved to the drivers themselves.
To access the corresponding functionality, you'll need to refer to the driver/plugin documentation.
In some cases, the extension will continue to expose CLI parameters. For example, the XCUITest driver
used to expose a parameter `--webdriveragent-port`. Now, to access this parameter, it should be
prefixed with `driver-xcuitest`, to differentiate it from parameters other drivers might also expose.
To use this parameter, you thus need to start Appium with something like:
在 Appium 2.x 中,
所有特定于驱动程序和平台的 CLI 参数都已移至驱动程序本身.
要访问它们, 您现在需要在参数前面附加扩展类型 ( `driver` 或 `plugin`) 以及扩展名的名称.
例如, `--chromedriver-executable`变为`--driver-uiautomator2-chromedriver-executable`.
```bash
appium --driver-xcuitest-webdriveragent-port=5000
```
Some drivers have done away with CLI args entirely in favour of default capabilities. With the
above-mentioned `--chromedriver-executable` parameter for example, you now need to take advantage
of the `appium:chromedriverExecutable` capability supported by the UiAutomator2 driver. To set this
capability from the command line, do the following:
### :bangbang: 特定于驱动程序的自动化命令
```bash
appium --default-capabilities '{"appium:chromedriverExecutable": "/path/to/chromedriver"}'
```
仅与特定驱动程序相关的某些命令的定义已移至这些驱动程序内实现.
例如, `pressKeyCode` 特定作用于 UiAutomator2 驱动程序,
并且现在只有该驱动程序才能识别.
在实践中, 这里唯一的重大变更是未安装驱动程序的那种错误.
之前, 如果使用未实现命令的驱动程序, 则会收到 `501 Not Yet Implemented` 错误.
现在, 您将获得`404 Not Found`错误,
因为如果不知道该命令的驱动程序是否有效,
主 Appium Server将不会定义与命令对应的路由.
### :bangbang: Driver-specific automation commands
The definition of certain commands that pertain only to specific drivers has been moved to those
drivers' implementations. For example, `pressKeyCode` is specific to the UiAutomator2 driver and is
now understood only by that driver. In practice, the only breaking change here is the kind of error
you would encounter if the appropriate driver is not installed. Previously, you would get a `501
Not Yet Implemented` error if using a driver that didn't implement the command. Now, you will get
a `404 Not Found` error because if a driver that doesn't know about the command is not active, the
main Appium server will not define the route corresponding to the command.
### :bangbang: 驱动程序更新
在过去, 要获取iOS或Android驱动程序的更新,
您只需等待新版本的Appium包含这些升级,
然后更新您的Appium版本即可.
在 Appium 2.x 中, Appium Server和 Appium 驱动程序是分开进行版本控制和发布的.
这意味着驱动程序可以按照自己的节奏进行发布,
并且可以在发生驱动程序更新时获得驱动程序更新,
而不是等待新的Appium Server发布.
检查驱动程序更新的方法是使用 CLI:
### :bangbang: Driver updates
In the past, to get updates to your iOS or Android drivers, you'd simply wait for those updates to
be rolled into a new release of Appium, and then update your Appium version. With Appium 2, the
Appium server and the Appium drivers are versioned and released separately. This means that drivers
can be on their own release cadence, and you can get the latest driver version right away, rather
than waiting for a new Appium server release. The way to check for driver updates is with the CLI:
```bash
appium driver list --updates
```
如果有任何更新可用,
则可以针对任何给定的驱动程序运行 `update` 命令:
If any updates are available, you can then run the `update` command for any given driver:
```bash
appium driver update xcuitest
```
要更新Appium Server本身, 您需要执行与过去一致的操作: `npm install -g appium`.
现在, 安装新版本的Appium Server将无关于其他驱动程序, 因此整个过程将更加快速.
(For a complete description of the update command, check out the
[Extension CLI](../cli/extensions.md#update) documentation)
To update the Appium server itself, you do the same thing as in the past: `npm install -g appium`.
Now, installing new versions of the Appium server will leave your drivers intact, so the whole
process will be much more quick.
### :bangbang: 协议变更
If you would like to update to a specific driver version, not the latest, please uninstall the driver
and install the desired version using the `install` subcommand instead of `update`.
Appium的API基于[W3C WebDriver协议](https://www.w3.org/TR/webdriver/),
并且已经支持该协议多年.
在W3C WebDriver协议被设计为Web标准之前,
还有其他几种协议用于Selenium和Appium.
这些协议是 "JSONWP" (JSON Wire Protocol) 以及 "MJSONWP" (Mobile JSON Wire Protocol).
W3C协议与(M)JSONWP协议在某些方面略有差异.
```bash
appium driver uninstall xcuitest
appium driver install xcuitest@4.11.1
```
### :bangbang: Protocol changes
在Appium 2.0之前, Appium支持这两种协议,
因此之前的Selenium / Appium客户端仍然可以与较新的Appium服务器进行通信.
长期来看, Appium将删除对遗留协议的支持.
Appium's API is based on the [W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/), and it has
supported this protocol for years. Before the W3C WebDriver Protocol was designed as a web standard,
several other protocols were used for both Selenium and Appium. These protocols were the "JSONWP"
(JSON Wire Protocol) and "MJSONWP" (Mobile JSON Wire Protocol). The W3C Protocol differs from the
(M)JSONWP protocols in a few small ways.
Up until Appium 2, Appium supported both protocols, so that older Selenium/Appium clients could
still communicate with newer Appium servers. Appium 2 removes support for older protocols and is
now only compatible with the W3C WebDriver Protocol.
### :bangbang: _Capabilities_
### :bangbang: Capabilities must use vendor prefix
新旧协议之间的一个显着差异在于capabilities的格式.
以前称为"desired capabilities", 现在简称为"capabilities",
现在要求在任何非标准capabilities上使用所谓的"供应商前缀".
标准capabilities列表在 [WebDriver 协议规范](https://www.w3.org/TR/webdriver/#capabilities)中给出,
其中包括一些常用capabilities, 如`browserName` 以及 `platformName`.
这些标准capabilities继续按原样使用.
所有其他capabilities的名称中必须包含"供应商前缀".
供应商前缀是后跟冒号的字符串, 例如 `appium:`.
Appium 的大多数capabilities都超出了标准的 W3C capabilities,
因此必须包含供应商前缀 (我们建议您使用 `appium:` , 除非文档另有说明) . 例如:
One significant difference between old and new protocols is in the format of capabilities.
Previously called "desired capabilities", and now called simply "capabilities", there is now a
requirement for a so-called "vendor prefix" on any non-standard capabilities. The list of standard
capabilities is given in the [WebDriver Protocol spec](https://www.w3.org/TR/webdriver/#capabilities),
and includes a few commonly used capabilities such as `browserName` and `platformName`.
These standard capabilities continue to be used as-is. All other capabilities must include a
"vendor prefix" in their name. A vendor prefix is a string followed by a colon, such as `appium:`.
Most of Appium's capabilities go beyond the standard W3C capabilities and must therefore include
vendor prefixes (we recommend that you use `appium:` unless directed otherwise by documentation).
For example:
- `appium:app`
- `appium:noReset`
- `appium:deviceName`
面向 Appium 2.0 时,
此要求对于您的测试套件来说, 可能是也可能不是重大更改.
如果您使用的是更新过的Appium客户端,
客户端将在所有必要的功能上为您添加 `appium:` 前缀.
新版本的Appium Inspector工具也将这样做.
基于云的Appium提供商也可以这样做.
因此, 只需注意, 如果您收到任何提示,
表明您的功能缺少供应商前缀, 这便是如何您解决问题的方法.
在相关的说明中,
将无法再使用不支持 W3C 协议的 WebDriver 客户端
启动 Appium 会话 (有关 WD 库的针对此效果的注释, 请参阅下文) .
为了让大家更轻松一些,
我们还引入了将所有与 Appium 相关的capabilities
打包到一个capabilities对象`appium:options`中的选项.
您可以将通常用于 `appium:` 前缀上的任何内容绑定到此capabilities中.
下面是一个示例 (以原始 JSON 格式) ,
说明如何使用`appium:options`在 Safari 浏览器上启动 iOS 会话:
This requirement may or may not be a breaking change for your test suites when targeting Appium 2.
If you're using an updated Appium client (at least one maintained by the Appium team), the client
will add the `appium:` prefix for you on all necessary capabilities automatically. New versions of
[Appium Inspector](https://github.com/appium/appium-inspector) will also do this. Cloud-based Appium
providers may also do this. So simply be aware that if you get any messages to the effect that your
capabilities lack a vendor prefix, this is how you solve that problem.
To make everyone's lives a bit easier, we've also introduced the option of grouping up all
Appium-related capabilities into one object capability, `appium:options`. You can bundle together
anything that you would normally put an `appium:` prefix on into this one capability. Here's an
example (in raw JSON) of how you might start an iOS session on the Safari browser using `appium:options`:
```json
{
@@ -206,154 +216,145 @@ Appium 的大多数capabilities都超出了标准的 W3C capabilities,
}
```
(当然, 每个客户端都会有不同的方法来创建结构化capabilities,
诸如 `appium:options` 或其他你可能见过的capabilities, 如 `goog:chromeOptions`) .
注意:显示在 `appium:options` 中的capabilities将覆盖显示在对象顶层的同名capabilities.
(Of course, each client will have a different way of creating structured capabilities like
`appium:options` or other ones that you might have seen such as `goog:chromeOptions`).
有关capabilities的更多信息, 请查看[Capabilities指南](caps.md).
!!! note
### :bangbang: _删除的命令_
Capabilities included in the `appium:options` object will overwrite capabilities of the same
name that are used outside of this object. (The `appium:options` syntax support by cloud
providers may vary.)
除了已移至驱动程序实现的命令外,
作为W3C协议外的旧的JSON Wire协议命令将不再可用:
For more information on capabilities, have a look at the [Capabilities Guide](./caps.md).
- TODO (这些命令正在被区分和删除, 完成后将在此处更新)
### :bangbang: Removed Commands
如果您使用现代Appium或Selenium客户端,
则无论如何都不应再使用遗留命令,
因此任何重大变更都应首先作用于客户端方面.
In addition to commands which have been moved to driver implementations, commands which were a part
of the old JSON Wire Protocol and not a part of the W3C Protocol are no longer available:
- TODO (these commands are being identified and removed and will be updated here when complete)
### :bangbang: 图像分析功能移至插件
If you use a modern Appium or Selenium client, you should no longer have access to these anyway,
so any breaking changes should appear on the client side first and foremost.
Appium 2.0 的设计目标之一是
将非核心功能迁移到名为 [plugins](../ecosystem/plugins.md)的特殊扩展中.
这允许人们选择使用额外时间来下载或扩展系统设置的功能.
Appium的各种图像相关功能 (图像比较, 按图像查找元素等) 已被移动到一个名为 [images](https://github.com/appium/appium/tree/master/packages/images-plugin)的官方支持的插件中.
### :bangbang: Image analysis features moved to plugin
如果您使用这些与图像相关的方法,
要继续使用它们, 您需要执行两项操作.
One of the design goals for Appium 2 is to migrate non-core features into special extensions called
[plugins](../ecosystem/plugins.md). This allows people to opt into features which require extra time
to download or extra system setup. The various image-related features of Appium (image comparison,
finding elements by image, etc...) have been moved into an officially supported plugin called
[images](https://github.com/appium/appium/tree/master/packages/images-plugin).
1. 安装插件: `appium plugin install images`
2. 确保您启动 Appium Server时具备访问运行插件的权限, 方法是将其包含在命令行上指定的插件列表中, 例如 `appium --use-plugins=images`
If you use these image-related methods, to continue accessing them you will need to do two things:
与图像相关的命令也将在客户端被删除,
这意味着您需要按照插件README上的说明安装客户端插件来使用这些功能.
1. Install the plugin: `appium plugin install images`
2. Ensure you start the Appium server with access to run the plugin by including it in the list of
plugins designated on the command line, e.g., `appium --use-plugins=images`
Image-related commands will also be removed on the client side of things, which means you will need
to follow the instructions on the plugin README for installing client-side plugins to access these features.
### :bangbang: 执行驱动程序脚本命令移至插件
### :bangbang: Execute Driver Script command moved to plugin
如果您使用高级执行驱动程序脚本功能
(它允许您发送WebdriverIO脚本以使其完全在服务器上执行,
而不是从客户端逐个命令执行) ,
则此功能已移至插件.
以下是继续使用它的方法:
If you use the advanced Execute Driver Script feature (which allows you to send in a WebdriverIO
script to have it executed completely on the server instead of command-by-command from the client),
this functionality has been moved to a plugin. Here's what to do to keep using it:
1. Install the plugin: `appium plugin install execute-driver`
2. Ensure you start the Appium server with access to run the plugin by including it in the list of
plugins designated on the command line, e.g., `appium --use-plugins=execute-driver`
1. 安装插件: `appium plugin install execute-driver`
2. 确保您启动 Appium Server时具备访问运行插件的权限, 方法是将其包含在命令行上指定的插件列表中, 例如 `appium --use-plugins=execute-driver`
### :bangbang: External Files No Longer Supported for `--nodeconfig`, `--default-capabilities`, `--allow-insecure` and `--deny-insecure`
### :bangbang: 不再支持外部文件 `--nodeconfig`, `--default-capabilities`, `--allow-insecure` 以及 `--deny-insecure`
These options can be provided as strings on the command line (a JSON string for `--nodeconfig` and
a comma-separated list of strings for `--allow-insecure` and `--deny-insecure`). Arguments provided
on the command line will likely need to be quoted or escaped.
这些选项可以在命令行上以字符串形式提供
( `--nodeconfig` 的JSON字符串以及
用于`--allow-insecure`和`--deny-insecure`的逗号分隔字符串列表) .
命令行上提供的参数可能需要用引号括起或转义.
The recommended method to provide these options is through a [configuration file](./config.md).
现在, 提供这些选项的推荐方法是通过 [配置文件](#tada-configuration-files).
In summary, if you are using a JSON Appium config file, you can simply cut-and-paste the contents
of your "nodeconfig" JSON file into the value of the `server.nodeconfig` property. Any CSV-like
files you had previously provided for `--allow-insecure` and `--deny-insecure` become the values
of the `server.allow-insecure` and `server.deny-insecure` properties in the Appium config files
(respectively); both are arrays of strings.
总之, 如果您使用的是 JSON Appium 配置文件,
则只需将"nodeconfig"JSON 文件的内容剪切并粘贴到 `server.nodeconfig` 属性的值中即可.
您之前为 `--allow-insecure` 和 `--deny-insecure` 提供的任何类似CSV的文件
分别成为Appium配置文件中 `server.allow-insecure` 和 `server.deny-insecure` 属性的值;
两者都是字符串数组.
### :bangbang: Old drivers removed
The old iOS and Android (UiAutomator 1) drivers and related tools (e.g., `authorize-ios`) have been
removed. They haven't been relevant for many years anyway.
### :bangbang: 删除的旧驱动
### :bangbang: Server can no longer be started with `--port 0`
旧的iOS和Android (UiAutomator 1) 驱动程序
和相关工具 (例如, `authorize-ios`) 已被删除.
无论如何, 它们已经很多年都没有关联了.
In Appium 1, it was possible to specify `--port 0` during server startup. This had the effect of
starting Appium on a random free port. In Appium 2, port values must be `1` or higher. The random
port assignment was never an intentional feature of Appium 1, but a consequence of how Node's
HTTP servers work and the fact that there was no port input validation in Appium 1. If you want
to find a random free port to start Appium on, you must now take care of this on your own prior to
starting Appium. Starting Appium on an explicit and known port is the correct practice moving
forward.
### :warning: 内部包已重命名
### :warning: Internal packages renamed
一些Appium内部的NPM软件包已被重命名
(例如, `appium-base-driver` 现在是 `@appium/base-driver`) .
对于Appium用户来说, 这并非是重大变更,
仅仅针对那些已经构建了直接包含Appium代码的软件的人来说.
Some Appium-internal NPM packages have been renamed (for example, `appium-base-driver` is now
`@appium/base-driver`). This is not a breaking change for Appium users, only for people who have
built software that directly incorporates Appium's code.
### :warning: 不再支持"WD"JavaScript 客户端库
### :warning: `wd` JavaScript client library no longer supported
多年来, Appium的一些作者一直维护着[WD](https://github.com/admc/wd) 客户端库.
此库已被弃用, 并且尚未更新W3C WebDriver协议.
因此, 如果您正在使用此库, 则需要迁移到更现代的库.
我们推荐 [WebdriverIO](https://webdriver.io).
For many years, some of Appium's authors maintained the [WD](https://github.com/admc/wd) client
library. This library has been deprecated and has not been updated for use with the W3C WebDriver
protocol. As such, if you're using this library you'll need to move to a more modern one. We
recommend [WebdriverIO](https://webdriver.io).
### :warning: Appium Desktop replaced with Appium Inspector
### :warning: Appium Inspector 从 Appium Desktop 中分离出来
The inspector functionality of Appium Desktop has been moved to its own app:
[Appium Inspector](https://github.com/appium/appium-inspector). It is fully compatible with
standalone Appium 2 servers, but also works with later versions of Appium 1 servers. Appium Desktop
itself has been deprecated and is not compatible with Appium 2.
Appium Desktop的Inspector部分已移至其自己的应用程序Appium Inspector:
[github.com/appium/appium-inspector](https://github.com/appium/appium-inspector).
其与Appium 2.0 Server完全兼容.
只需下载它并自行运行即可.
您不再需要GUI Appium桌面服务器来检查应用程序.
Appium Desktop Server将继续在其原始站点
[github.com/appium/appium-desktop](https://github.com/appium/appium-desktop) 上受支持.
它不再将Inspector与其捆绑在一起.
In addition to the app, Appium Inspector also has a browser version, accessible at
[inspector.appiumpro.com](https://inspector.appiumpro.com). Note that in order to use the
browser version with a local Appium server, you'll need to first start the server with the
`--allow-cors` flag.
您现在还可以通过访问[Web版本的Appium Inspector](https://inspector.appiumpro.com)
来使用Appium Inspector而无需下载任何内容.
请注意, 要针对本地服务器进行测试, 您需要使用"--allow-cors"启动服务器,
以便基于浏览器版本的Appium Inspector可以访问您的Appium Server以启动会话.
## Major New Features
Apart from the breaking changes mentioned above, in this section is a list of some of the major new
features you may wish to take advantage of with Appium 2.
## 主要新功能
### Plugins
除了上面提到的重大变更之外,
本节中还列出了您可能希望在 Appium 2.0 中利用的一些主要新功能.
#### :tada: Server Plugins
### 插件
Appium extension authors can now develop their own server plugins, which can intercept and modify
any Appium command, or even adjust the way the underlying Appium HTTP server itself works. To learn
more about plugins, read the new [Appium Introduction](../intro/index.md). Interested in building
a plugin? Check out the [Building Plugins](../developing/build-plugins.md) guide.
#### :tada: _服务器插件_
### :tada: Install drivers and plugins from anywhere
Appium 扩展作者现在可以开发自己的服务器插件,
可以拦截和修改任何Appium命令,
甚至调整底层 Appium HTTP 服务器本身的工作方式.
了解有关插件的更多信息,
查询新的 [Appium 介绍](../intro/index.md).
有兴趣构建插件?
请查阅 [构建插件](../ecosystem/build-plugins.md) 指南.
You're no longer limited to the drivers that come with Appium, or that the Appium team even knows
about! Appium extension authors can now develop custom drivers, which can be downloaded or
installed via Appium's [Extension CLI](../cli/extensions.md) from `npm`, `git`, GitHub, or even the
local filesystem. Interested in building a driver? Check out the [Building
Drivers](../developing/build-drivers.md) guide.
### :tada: Configuration Files
#### :tada: _客户端插件_
Appium now supports _configuration files_ in addition to command-line arguments. In a nutshell,
nearly all arguments which Appium 1 required to be provided on the CLI are now able to be expressed
via a configuration file. Configuration files may be in JSON, JS, or YAML format. See the
[Config Guide](./config.md) for a full explanation.
TODO
## Special Notes for Cloud Providers
### :tada: 从任何地方安装驱动程序和插件
The rest of this document has applied to Appium generally, but some of the architectural changes in
Appium 2 will constitute breaking changes for Appium-related service providers, whether a
cloud-based Appium host or an internal service. At the end of the day, the maintainer of the Appium
server is responsible for installing and making available the various Appium drivers and plugins
that end users may wish to use.
您不再局限于 Appium 附带的驱动程序,
或者通过Appium团队知晓!
Appium 扩展作者现在可以开发自定义驱动程序,
可以通过Appium的[扩展 CLI](../cli/extensions.md)
从NPM, Git, GitHub 乃至本地的文件系统下载或安装.
有兴趣构建驱动程序?
请查阅 [构建驱动](../ecosystem/build-drivers.md) 指南.
### :tada: 配置文件
Appium 现在除了命令行参数外,
还支持 _配置文件_ .
简而言之, Appium 1.x需要在CLI上提供的几乎所有参数现在都可以通过配置文件来表达.
配置文件可以是 JSON、JS 或 YAML 格式.
有关完整说明, 请参阅 [配置指南](config.md) .
## 云供应商特别说明
本文档的其余部分已普遍适用于 Appium,
但 Appium 2.0 中的一些架构更改将构成 Appium 相关服务供应商的重大变更,
无论是基于云的 Appium 主机还是内部服务.
在一天结束时, Appium Server的维护者负责安装和提供最终用户可能希望使用的各种Appium驱动程序和插件.
我们鼓励云供应商彻底阅读并理解我们的 [针对云供应商的建议](caps.md#special-notes-for-cloud-providers),
以行业兼容的方式支持用户!
We encourage cloud providers to thoroughly read and understand our [recommendation for cloud
provider capabilities](./caps.md#special-notes-for-cloud-providers) in order to support user needs in
an industry-compatible way!
+61 -1
View File
@@ -2,4 +2,64 @@
title: Appium Server Security
---
TODO
The Appium team makes every effort to ensure the security of the Appium server. This is especially
important when Appium is run in a multitenant environment, or when multiple users are running
sessions on the same Appium server. In general, you can only safely enable all Appium's features if
all the following are true:
- You're running your own Appium server locally or within a protected internal network
- You're not sharing it with any untrusted parties
- You don't expose Appium's port(s) to the wider internet
But because many Appium users might not be able to guarantee such a safe environment, the Appium
team puts many features behind a security protection mechanism which forces system admins (the
people that are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
(Third-party driver and plugin authors can also [hide behaviour behind security
flags](../developing/build-drivers.md).)
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities;
this is the responsibility of the server admin who configures and launches the Appium server.
## Security Server Args
The [Server CLI Args](../cli/args.md) doc outlines three relevant arguments which may be passed to
Appium when starting it from the command line:
|<div style="width:10em">Parameter</div>|Description|
|---------------------------------------|-----------|
|`--relaxed-security` |Setting this flag turns on _all_ insecure features (unless blocked by `--deny-insecure`; see below)|
|`--allow-insecure` |Setting this flag to a comma-separated list of feature names or a path to a file containing a feature list (each name on a separate line) will allow _only_ the features listed. For example, `--allow-insecure=adb_shell` will cause _only_ the ADB shell execution feature to be enabled. This is true _unless_ `--relaxed-security` is also used, in which case all features will still be enabled. It makes no sense to combine this flag with `--relaxed-security`.|
|`--deny-insecure` |This flag can likewise be set to a comma-separated list of feature names, or a path to a feature file. Any features listed here will be _disabled_, regardless of whether `--relaxed-security` is set and regardless of whether the names are also listed with `--allow-insecure`.|
## Insecure Features
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
you should read through the documentation for a particular driver to know which feature names it
might use. Here is an incomplete list of examples from some of Appium's official drivers:
|<div style="width:12em">Feature Name</div>|Description|Supported Extension(s)|
|------------|-----------|-------|
|`get_server_logs`|Allows retrieving of Appium server logs via the Webdriver log interface|IOS, XCUITest, Android, UiAutomator2, Espresso|
|`adb_shell`|Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command|Android, UiAutomator2, Espresso|
|`record_audio`|Allow recording of host machine audio inputs|XCUITest|
|`execute_driver_script`| Allows to send a request which has multiple Appium commands.|Execute Driver Plugin|
## Examples
To turn on the `get_server_logs` feature for my Appium server, I could start it like this:
```bash
appium --allow-insecure=get_server_logs
```
To turn on multiple features:
```bash
appium --allow-insecure=get_server_logs,record_audio
```
To allow all features except one:
```bash
appium --relaxed-security --deny-insecure=adb_shell
```
+65 -2
View File
@@ -1,5 +1,68 @@
---
title: The Settings API
hide:
- toc
title: Session Settings
---
TODO
Appium has a set of extension APIs that allow you to adjust parameters for a given session during
the session itself. Called "Settings", these parameters are similar to [Capabilities](./caps.md),
but while Capabilities _cannot be adjusted_ once a session has started, Settings _can be adjusted any
number of times_ during the course of a session.
There are 3 important points to the concept of Settings:
- Settings are mutable; they can be changed during a session using the Settings API
- Settings are only relevant during the session in which they are set. They are typically reset for
each new session, though depending on the driver, some settings may persist between sessions
- Settings only adjust the way the Appium server behaves during test automation. They do not affect
the device or app under test
An example of a setting would be the `ignoreUnimportantViews` setting recognized by the UiAutomator2
driver. The driver can be instructed to ignore elements in the view hierarchy which it deems
irrelevant. Changing this setting to `true` can cause tests to run faster. But if later in the same
session you _want_ to access elements which would be ignored under this setting, you can always
change it back to `false`.
Settings are implemented via the following API endpoints:
| Command | <div style="width:18em">Method/Route</div> | Params | Description | Returns |
|-------------------|---------------------------------------------|------------------------------------|------------------------------------|------------------------------------|
| `Update Settings` | `POST /session/:id/appium/settings` | `settings` (`Record<string, any>`) | Update the provided setting values | `null` |
| `Get Settings` | `GET /session/:id/appium/settings` | | Return the current settings | `settings` (`Record<string, any>`) |
The `settings` object must be a set of keys and values, where the key is the setting name, and the
value is any documented valid value for that setting.
!!! info
Settings are driver-specific, so refer to your driver's documentation for a list of supported settings
## Initializing Settings via Capabilities
If you want to start an Appium session with a setting in a non-default state, you can do so by
including a capability of the form `appium:settings[<name>]` with the appropriate value. So to turn
on the `ignoreUnimportantViews` setting mentioned above from the very beginning of a session, you
would construct a set of capabilities that includes the following in its JSON representation:
```json
{
"appium:settings[ignoreUnimportantViews]": true
}
```
Also, since Appium 2.1, there is a possibility to provide multiple settings in a single
`appium:settings` capability value:
```json
{
"appium:settings": {
"ignoreUnimportantViews": true,
"allowInvisibleElements": true
}
}
```
Of course, initializing a setting via capabilities doesn't prevent you from changing it later on
via the Settings API. To learn more about how to use the Settings API in the context of your
specific client library, visit the documentation for that client.
+42
View File
@@ -0,0 +1,42 @@
---
hide:
- toc
title: SSL/TLS/SPDY Support
---
Appium 2.2 introduces the option to start the Appium server with SSL/TLS support.
## Command Line Arguments
In order to enable secure connections to the server, you need to provide the following command
line arguments:
```bash
appium server --ssl-cert-path=/path/to/cert.pem --ssl-key-path=/path/to/key.pem
```
Both arguments must be provided and should contain paths to a valid
[X509 PEM](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/)
certificate and its corresponding private key.
After the server is started use the `https` protocol and a client supporting SSL/TLS or
[SPDY](https://en.wikipedia.org/wiki/SPDY) to communicate to it.
### Supported Features
Once a secure server socket is established it supports the following protocols:
`['h2', 'spdy/3.1', 'spdy/3', 'spdy/2', 'http/1.1', 'http/1.0']`. See
[the SPDY node module documentation](https://www.npmjs.com/package/spdy) to get more details about
its features. All insecure client connections will be rejected by the server.
### Self-Signed Certificates
Use the following command in order to generate a self-signed certificate/key pair:
```bash
openssl req -nodes -new -x509 -keyout key.pem -out cert.pem -subj "/C=US/ST=State/L=City/O=company/OU=Com/CN=www.testserver.local"
```
Feel free to change the value of `-subj` in the command above with your matching details. The server
should work just fine with a self-signed certificate, although you need to take care about a proper
client setup, e.g. make sure it does not reject unauthorized certificates.
+35 -13
View File
@@ -6,7 +6,8 @@ hide:
title: 欢迎
---
<style>
.md-typeset h1 {
.md-typeset h1,
.appium-sponsor-thanks {
display: none;
}
</style>
@@ -14,23 +15,44 @@ title: 欢迎
<img src="assets/images/appium-logo-horiz.png" style="max-width: 400px;" />
</div>
欢迎访问 Appium 文档!Appium 是一个开源项目和相关软件的生态系统。
软件,旨在促进许多应用程序平台的用户界面自动化,包括移动平台(iOS、
Android、Tizen)、浏览器(Chrome、Firefox、Safari)、桌面(macOS、Windows)、电视(Roku、tvOS、
Android TV、三星)等!
欢迎来到Appium文档!Appium是一个开源项目和相关软件生态系统,旨在促进许多应用程序平台的UI自动化,包括移动端(iOS、Android、Tizen)、浏览器端(Chrome、Firefox、Safari)、桌面端(macOS、Windows)、电视端(Roku、tvOS、Android TV、三星)等!
<div style="text-align: center; margin-top: 2rem; font-style: italic;">
Appium非常感谢主要合作伙伴的支持!(了解更多关于我们的赞助计划和贡献者补偿计划信息请<a
href="https://github.com/appium/appium/blob/master/GOVERNANCE.md#sponsorship">点击此处</a>)
<div class="homepageSponsors">
<div class="homepageSponsor">
<a href="https://www.headspin.io/solutions/appium-mobile-test-automation">
<img src="assets/images/sponsor-logo-headspin.png" style="width: 200px;" />
</a>
</div>
<div class="homepageSponsor">
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
<img src="assets/images/sponsor-logo-browserstack-dark.png#only-dark" style="width: 220px;" />
<img src="assets/images/sponsor-logo-browserstack-light.png#only-light" style="width: 220px;" />
</a>
</div>
<div class="homepageSponsor">
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner">
<img src="assets/images/sponsor-logo-sauce.png" style="width: 200px;" />
</a>
</div>
</div>
</div>
## 探索文档
<div class="grid cards" markdown>
- 查看 [__介绍__](./intro/index.md) 确保您理解关键概念
- 查看 [__简介__](./intro/index.md) 以确保您了解关键概念
- 通过 [__快速入门__](./quickstart/index.md) 来进行设置并运行基本的 Android 测试
- 访问 [__生态系统__](./ecosystem/index.md) 页面,查看您可能需要使用的驱动程序、客户端和插件列表
- 参考 [__CLI 参考__](./cli/index.md) 用于从命令行使用 Appium
- 查看 [__命令说明__](./commands/index.md) Appium 和插件公开的命令列表
- 阅读不同的 [__指南__](./guides/migrating-1-to-2.md) 来获取各种说明、技巧和窍门
- 查阅各种第三方的 [__资源__](./resources.md) 来探索网上的Appium运用
- 为了创建您自己的Appium拓展, 请查看 [__开发者__](./developing/index.md) 文档
- 对 Appium 自身的贡献,请查阅 [__贡献__](./contributing/index.md) 页面
- 访问 [__生态系统__](./ecosystem/index.md) 页面,获取您可能想要使用的驱动程序、客户端和插件列表
- 参考 [__CLI Reference__](./cli/index.md) 以了解如何从命令行使用Appium
- 参考 [__Command Reference__](./commands/index.md) 以了解有关Appium和插件的命令列表
- 阅读不同的 [__指南__](./guides/migrating-1-to-2.md),了解各种说明、提示和技巧
- 查看各种第三方 [__资源__](./resources.md) 以探索网络上的Appium
- 要创建自己的Appium扩展,请参阅 [__开发者__](./developing/index.md) 文档
- 有关对Appium本身的贡献,请查阅 [__贡献__](./contributing/index.md) 页面
</div>
+90
View File
@@ -0,0 +1,90 @@
---
title: Appium如何工作?
---
正如主页上提到的那样,Appium是一个开源项目和相关软件生态系统,旨在促进许多应用程序平台的UI自动化。随着Appium 2的发布,Appium的主要目标如下:[^1]
- 在跨平台、标准API下提供特定于平台的自动化功能
- 允许从任何编程语言轻松访问此API
- 提供工具以方便社区开发Appium扩展
[^1]:
为了实现这些主要目标,我们还制定了一套次要目标或方法论原则,我们也鼓励Appium扩展开发人员这样做:
- 尽可能依赖(并贡献)开源技术
- 尽可能依赖供应商为给定平台提供的工具
- 尽可能依赖允许不修改应用程序就能实现自动化的工具(不要让用户构建额外的SDK或软件,从而导致应用程序的测试版本和生产版本之间存在差异)
- 尽可能依赖现有标准而不是创建新标准
因此,请选择您所知道的任何应用程序平台,例如iOS或Android。Appium希望有一种方法让开发人员和测试人员根据单一、统一的API为该平台编写UI自动化代码。根据Appium的目标,我们有很多问题需要回答才能使这一切顺利进行:
- “单一、统一”API应该是哪个API?
- 我们如何将该API映射到特定平台的自动化行为?
- 我们如何通过多种流行编程语言访问该API?
考虑到除了iOS和Android之外还有更多的应用程序平台,这里还隐藏着另一个更大的问题:
- 我们如何实现所有平台的自动化?
探索Appium对这些问题的答案可能不是了解Appium是什么的最快方法,但它肯定是一个很好的方法!那么让我们深入研究吧。
## Appium对API的选择
Appium非常幸运,它先于UI自动化领域的长期先驱技术 [Selenium](https://selenium.dev) 。Selenium项目的目标是支持网络浏览器的UI自动化,通过这种方式,我们可以将其视为占据Appium目标的一个子集。一路走来,Selenium(以及合并后的另一个名为WebDriver的项目)开发了一个相对稳定的浏览器自动化API。
多年来,Selenium与多家网络浏览器供应商和 [W3C](https://w3.org) 标准小组合作,将其API转变为官方网络浏览器标准,称为 [WebDriver规范](https://w3c.github.io/webdriver/)。所有主要浏览器现在都实现了符合WebDriver规范的自动化功能,Selenium团队无需维护任何执行实际自动化的软件;胜利的标准!
Appium的最初目标是为移动应用程序(iOS和Android)开发自动化标准。我们本可以创造一些新的东西,但要本着团结一致和保持标准的精神,好吧,标准,我们决定采用WebDriver规范作为Appium的API。[^2]虽然网站和移动原生应用程序中的用户交互并不完全相同(例如,一旦我们开始考虑由简单遥控器控制的电视平台,差异就会更大),实际上大多数软件UI几乎相同。这意味着WebDriver规范提供自动化API基元(查找元素、与元素交互、加载页面或屏幕等)或多或少映射到任何平台。
[^2]: 从技术上讲,当Appium第一次编写时,我们正在处理比WebDriver规范更早的东西,称为JSON Wire Protocol。从那时起,Appium继续随着W3C规范发展,并且完全符合W3C。
当然,Appium希望支持用户交互从网页到移动设备或从网页到电视的不同情况,因此Appium还利用了WebDriver规范的内置可扩展性。结果是,无论您想要实现哪个平台自动化,当您使用Appium时,您都将使用标准的WebDriver规范来执行,但有两个警告:
- 我们可能无法在给定的平台上支持特定的WebDriver API命令,因此某些命令可能不受支持(例如,在原生移动应用程序自动化中,获取或设置cookie是不可能的)。
- 我们可能支持超出WebDriver API命令列表中可用范围的自动化行为,尽管任何此类命令都是WebDriver API的有效且符合规范的扩展。
您实际上如何使用WebDriver API,特别是在Appium的环境中?我们将在[下面](#universal-programming-language-access)关于Appium如何提供通用编程语言访问的部分中讨论这一点。目前您需要知道的是,Appium引入通用UI自动化界面的方式是通过实现WebDriver协议。
## 平台自动化行为
下一个问题是,Appium如何将该协议映射到广泛平台上的自动化行为?严格来说,Appium没有这样做!它将这一责任留给了一种名为Appium驱动程序的软件模块。接下来您可以阅读完整的[驱动程序简介](./drivers.md),因此我们目前不会详细介绍它们的工作原理。
目前需要了解的重要一点是,驱动程序有点像Appium的可插入模块,它使Appium能够自动化特定平台(或一组平台,具体取决于驱动程序的目标)。归根结底,驱动程序的责任只是简单地实现代表WebDriver协议的Appium内部接口。它如何实现这个接口完全取决于驱动程序,基于其在特定平台上实现自动化的策略。通常,由于细节上的复杂性和困难性要大得多,驱动程序通过依赖于平台特定的自动化技术来做到这一点。例如,苹果维护一项名为[XCUITest](https://developer.apple.com/documentation/xctest/user_interface_tests)的iOS自动化技术。支持iOS应用自动化的Appium驱动程序被称为[XCUITest
Driver](https://github.com/appium/appium-xcuitest-driver),因为它最终的作用是将WebDriver协议转换为XCUITest库调用。
驱动程序是独立的可插入模块,这样做的原因之一是因为它们的工作方式完全不同。构建和使用不同平台驱动程序的工具和需求也是完全不同的。因此,Appium允许您仅使用自动化任务所需的驱动程序。选择驱动程序并安装它们,以便您可以将它们与Appium实例一起使用,这是非常重要的,因此Appium拥有自己的[CLI来管理驱动程序](../cli/extensions.md)。
因此,为了回答我们最初的问题,Appium为给定平台提供自动化功能访问的方式是,Appium团队(或其他任何人[^3])为该平台编写驱动程序,根据需要实现尽可能多或尽可能少的WebDriver协议。然后任何使用Appium的人都可以安装该驱动程序。
[^3]:您可以构建和共享自己的驱动程序!查看[构建驱动程序](../developing/build-drivers.md),了解更多关于如何在Node.js中开发可与Appium一起使用的驱动程序的信息。
## 通用编程语言访问
但使用Appium到底是什么意思,或者看起来是什么样子呢?由于Appium最终是一个Node.js程序,因此看起来就像将Appium及其驱动程序作为库导入到您自己的Node.js程序中。但这无法满足Appium为使用任何流行编程语言的人们提供自动化功能的目标。
幸运的是,Appium搭上了Selenium的顺风车,这意味着我们从第一天起就有了解决这个问题的办法。你看,WebDriver规范实际上是一个基于HTTP的协议,这意味着它被设计为在网络上使用,而不是在单个程序的内存中使用。
这种“客户端-服务器”架构的主要好处之一是,它允许自动化实现者(执行自动化的东西,这里指服务器端)与自动化运行者(定义自动化应该执行什么、在哪些步骤中等,这里指客户端)完全不同。基本上,所有“硬东西”(实际上是弄清楚如何在给定的平台上实现自动化)都可以由服务器在一个地方处理,而“瘦”客户端库可以用任何编程语言编写,这些语言只需以适当的语言对服务器的HTTP请求进行编码。换句话说,如果存在高级的HTTP库,那么通过在那种语言中编写一个基本的HTTP客户端,就可以相对容易地将基本的Appium/WebDriver功能引入到新的编程语言中。
对于Appium用户来说,这里有几个重要的要点:
- Appium是一个HTTP服务器。只要您想将其用于自动化,它就必须在某台计算机上作为进程运行。它必须可以在网络上访问您想用来运行自动化的任何计算机(无论是同一台机器还是世界各地的机器)。
- 除非您想编写原始HTTP调用或使用cURL,否则使用Appium进行自动化需要使用您选择的语言的[Appium客户端](clients.md)。每个客户端的目标都是封装WebDriver协议,这样您就可以使用对您的语言来说习惯的对象和方法,而不用担心协议本身。
- Appium服务器和Appium客户端不需要在同一台计算机上运行。您只需要能够通过某种网络将HTTP请求从客户端发送到服务器即可。这极大地方便了Appium云提供商的使用,因为它们可以托管Appium服务器以及任何相关驱动程序和设备,并且您需要做的就是将您的客户端脚本指向其安全端点。
当然,这些都不是关于“测试”本身,而纯粹是关于使用Appium及其客户端库来实现自动化目的。如果你想以“测试”为目的进行自动化,你可能会希望获得测试运行者、测试框架等的帮助,这些都不需要与Appium相关;Appium的“通用可访问性”的好处之一是,它可以很好地与你认为对你的情况最有利的任何一组工具配合使用。
## Appium的广阔应用范围
Appium的愿景(在单个API下实现一切自动化)是巨大的!当然,这比开源项目的核心维护人员团队要大得多。那么Appium希望如何实现这个目标呢?基本上,通过授权社区在Appium作为平台的基础上开发功能。这就是我们所说的Appium“生态系统”。
Appium团队本身确实正式维护了一些驱动程序(例如,我们之前谈到的XCUITest驱动程序)。但不能指望他们拥有特定于平台的专业知识或为许多不同平台维护驱动程序的能力。但我们所做的,特别是从Appium 2开始,是提供工具来帮助社区加入我们的愿景:
- 任何人都可以通过创建一个符合约定的Node.js模块来创建驱动程序,并实现WebDriver协议的任何子集或超集。创建驱动程序通常需要最少的代码,因为WebDriver协议的细节被抽象出来,并且有许多辅助库可用——这些库也为Appium团队自己的驱动程序提供动力。
- 使用Appium驱动程序CLI可以轻松地与他人共享驱动程序。没有中央权力机构。任何人都可以公开或私下、免费或出售共享驱动程序。驱动程序可以是开源的,也可以是闭源的(尽管我们很欣赏开源!)。
Appium作为开发平台的愿景不仅限于支持所有应用平台的自动化。作为一种流行的自动化工具,Appium有很多机会与各种其他工具和服务集成。此外,对于Appium,无论是作为核心服务器还是通过各种驱动程序的实现,都有许多特性的想法,这些是核心团队永远没有时间来构建的。因此,在Appium 2中,Appium发布了一个插件系统,使任何人都可以构建和共享改变Appium工作方式的模块!
就像驱动程序可以通过Appium驱动程序CLI轻松共享和使用一样,插件也可以通过相似的[插件CLI](../cli/extensions.md)发布和使用。插件可以做各种各样的事情,例如为Appium添加根据模板图像查找屏幕区域并与屏幕区域交互的能力(如在[图像插件](https://github.com/appium/appium/tree/master/packages/images-plugin)中)。你可以用插件做什么几乎没有限制,所以你可能也有兴趣学习如何在Node.js中[构建](../developing/build-plugins.md)可以与Appium一起使用的插件。
这就是Appium:一个可扩展的通用界面,用于实现潜在一切的UI自动化!请继续阅读一些具体的介绍文档以获取更多详细信息,或查看各种指南以深入了解Appium的一些概念和功能。
+151 -2
View File
@@ -1,6 +1,155 @@
---
title: Intro to Appium Drivers
title: Appium驱动程序简介
---
正如[概述](./appium.md)所表明的那样,“驱动程序”基本上是Appium对“我们如何支持多个无关平台的自动化”这个问题的回答,在本文档中,我们将更详细地了解驱动程序的工作方式。驱动程序如何工作的具体细节对您来说可能并不太重要,除非您计划编写自己的驱动程序或为现有的驱动程序做出贡献(我们希望您这样做!)。
TODO
深入了解驱动程序的工作原理的主要好处是,当您在测试中不可避免地遇到问题时,了解典型的复杂性或典型的驱动程序架构将为您的调试过程提供信息。
## 接口实现
在最基本的层面上,驱动程序只是Node.js类,它扩展了Appium中包含的一个特殊类,称为`BaseDriver`。只需一些非常简单的代码,您就可以拥有一个接近可工作的驱动程序:
```js
import BaseDriver from '@appium/base-driver'
class MyNewDriver extends BaseDriver {
}
```
这个空驱动程序什么也不做,但您可以把它包装在一个Node.js模块中,在模块的清单(`package.json`)中添加一些与Appium相关的字段,然后使用`appium driver install`来安装它。
因此,从技术角度来看,Appium驱动程序只是继承自其他Appium代码的一段代码。就是这样!现在,从`BaseDriver`继承实际上给了我们很多东西,因为`BaseDriver`本质上是整个WebDriver协议的封装。因此,驱动程序需要做的有用的事情就是实现Node.js方法,其名称与WebDriver协议中定义的名称相对应。
假设我想用这个空驱动程序做一些事情;首先我必须决定我想实现哪个WebDriver命令。对于我们的示例,让我们实现[Navigate To](https://w3c.github.io/webdriver/#navigate-to)这个WebDriver命令。暂且不谈执行此命令时我想让驱动程序做什么。为了告诉Appium驱动程序可以处理该命令,我们所要做的就是在我们的驱动程序类中定义一个这样的方法:[^1]
```js
async setUrl(url) {
// 在这里做我们想做的事
}
```
[^1]: 您可能会注意到`setUrl`看起来一点也不像`Navigate To`,那么我们怎么知道应该使用它而不是其他随机字符串呢?Appium中WebDriver协议到方法名的映射是在`@appium/base-driver`包中名为[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js)的特殊文件中定义的。因此,如果您正在编写一个驱动程序,您可以在这里弄清楚要使用什么方法名以及需要什么参数。或者您可以查看任何主要的Appium驱动程序源代码!
就是这样!我们如何实际实现命令完全取决于我们,取决于我们想要支持的平台。以下是该命令针对不同平台的一些不同示例实现:
- 浏览器: 执行一些JavaScript去设置`window.location.href`
- iOS应用程序: 使用深度链接启动应用程序
- Android应用程序: 使用深度链接启动应用程序
- React应用程序: 加载特定路线
- Unity: 转到指定的场景
因此,您可以看到,驱动程序在不同平台上实现相同WebDriver命令的方式存在很大差异。[^2]不过,他们表达他们能够处理协议命令的方式是相同的。
[^2]: 当然,我们希望语义尽可能相似,但在iOS世界中,例如,通过深度链接(一个带有特定应用程序协议的URL)启动应用程序,这几乎是我们能够实现的最接近于导航到网页URL的方式。
我们要深入这么多细节(顺便说一下,您不需要记住这些),重点是要强调一个观点,即Appium驱动程序本质上并不是什么特别的东西,它不过是一段能够处理WebDriver协议命令的JavaScript代码。从那里开始,你能走多远就看你了,驱动程序的作者!
## 自动化映射
But *typically* what driver authors want to do is to provide automation behaviours for a given
platform(s) that are semantically very similar to the the WebDriver spec implementations for
browsers. When you want to find an element, you should get a reference to a UI element. When you
want to click or tap that element, the resulting behaviour should be the same as if a person were
to click or tap on the element. And so on.
So the real challenge for driver authors is not how to work with the WebDriver protocol (because
`BaseDriver` encapsulates all that for you), but how to make the actual automation happen on the
target platform. Every driver relies on its own set of underlying technologies here. As mentioned
in the [Overview](index.md), the iOS driver uses an Apple technology called
[XCUITest](https://developer.apple.com/documentation/xctest/xcuielement). These underlying
automation technologies usually have proprietary or idiosyncratic APIs of their own. Writing
a driver becomes the task of mapping the WebDriver protocol to this underlying API (or sometimes
a set of different underlying APIs--for example, the UiAutomator2 driver relies not only on the
[UiAutomator2](https://developer.android.com/training/testing/other-components/ui-automator)
technology from Google, but also functions only available through
[ADB](https://developer.android.com/tools/adb), as well as functions only available
via the Android SDK inside a helper app). Tying it all together into a single, usable, WebDriver
interface is the incredibly useful (but incredibly challenging) art of driver development!
## 多层架构
In practice, this often results in a pretty complex architecture. Let's take iOS for example again.
The XCUITest framework (the one used by the Appium driver) expects code that calls it to be written
in Objective-C or Swift. Furthermore, XCUITest code can only be run in a special mode triggered by
Xcode (and directly or indirectly, the Xcode command line tools). In other words, there's no
straightforward way to go from a Node.js function implementation (like `setUrl()` above) to
XCUITest API calls.
What the XCUITest driver authors have done is instead to split the driver into two parts: one part
written in Node.js (the part which is incorporated into Appium and which initially handles the
WebDriver commands), and the other part written in Objective-C (the part which actually gets run on
an iOS device and makes XCUITest API calls). This makes interfacing with XCUITest possible, but
introduces the new problem of coordination between the two parts.
The driver authors could have chosen any of a number of very different strategies to model the
communication between the Node.js side and the Objective-C side, but at the end of the day decided
to use ... the WebDriver protocol! That's right, the Objective-C side of the XCUITest driver is
itself a WebDriver implementation, called
[WebDriverAgent](https://github.com/appium/webdriveragent).[^3]
[^3]: You could in theory, therefore, point your WebDriver client straight to WebDriverAgent and
bypass Appium entirely. This is usually not convenient, however, for a few reasons:
- The Appium XCUITest driver builds and manages WebDriverAgent for you, which can be a pain and
involves the use of Xcode.
- The XCUITest driver does lots more than what can be done by WebDriverAgent, for example working
with simulators or devices, installing apps, and the like.
The moral of the story is that driver architectures can become quite complicated and multilayered,
due to the nature of the problem we're trying to solve. It also means it can be difficult sometimes
to tell where in this chain of technologies something has gone wrong, if you run into a problem
with a particular test. With the XCUITest world again, we have something like the following set of
technologies all in play at the same time:
- Your test code (in its programming language) - owned by you
- The Appium client library - owned by Appium
- The Selenium client library - owned by Selenium
- The network (local or Internet)
- The Appium server - owned by Appium
- The Appium XCUITest driver - owned by Appium
- WebDriverAgent - owned by Appium
- Xcode - owned by Apple
- XCUITest - owned by Apple
- iOS itself - owned by Apple
- macOS (where Xcode and iOS simulators run) - owned by Apple
It's a pretty deep stack!
## 代理模式
There's one other important architectural aspect of drivers to understand. It can be exemplified
again by the XCUITest driver. Recall that we just discussed how the two "halves" of the XCUITest
driver both speak the WebDriver protocol---the Node.js half clicks right into Appium's WebDriver
server, and the Objective-c half (WebDriverAgent) is its own WebDriver implementation.
This opens up the possibility of Appium taking a shortcut in certain cases. Let's imagine that the
XCUITest driver needs to implement the `Click Element` command. The internal code of this
implementation would look something like taking the appropriate parameters and constructing an HTTP
request to the WebDriverAgent server. In this case, we're basically just reconstructing the
client's original call to the Appium server![^4] So there's really no need to even write a function
implementing the `Click Element` command. Instead, the XCUITest driver can just let Appium know
that this command should be proxied directly to some other WebDriver server.
[^4]: It's not *exactly* the same call, because the Appium server and the WebDriverAgent server
will generate different session IDs, but these differences will be handled transparently.
If you're not familiar with the concept of "proxying," in this case it just means that the XCUITest
driver will not be involved at all in handling the command. Instead it will merely be repackaged
and forwarded to WebDriverAgent at the protocol level, and WebDriverAgent's response will likewise
be passed back directly to the client, without any XCUITest driver code seeing it or modifying it.
This architectural pattern provides a nice bonus for driver authors who choose to deal with the
WebDriver protocol everywhere, rather than constructing bespoke protocols. It also means that
Appium can create wrapper drivers for any other existing WebDriver implementation very easily. If
you look at the [Appium Safari driver](https://github.com/appium/appium-safari-driver) code, for
example, you'll see that it implements basically no standard commands, because all of these are
proxied directly to an underlying SafariDriver process.
It's important to understand that this proxying business is sometimes happening under the hood,
because if you're ever diving into some open source driver code trying to figure out where
a command is implemented, you might be surprised to find no implementation at all in the Node.js
driver code itself! In that case, you'll need to figure out where commands are being proxied to so
you can look there for the appropriate implementation.
OK, that's enough for this very detailed introduction to drivers!
+9 -8
View File
@@ -2,28 +2,29 @@
hide:
- toc
title: Appium in a Nutshell
title: Appium 简介
---
正如主页上提到的那样,Appium旨在支持许多不同平台(移动、网络、桌面等)的UI自动化。不仅如此,它还旨在支持用不同语言(JS、Java、Python等)编写的自动化代码。将所有这些功能结合到一个程序中是一项非常艰巨、甚至不可能的任务!
正如主页上提到的那样,Appium旨在支持许多不同平台(移动端、网页端、桌面端等)的UI自动化。不仅如此,它还旨在支持用不同语言(JS、Java、Python等)编写的自动化代码。将所有这些功能结合到一个程序中是一项非常艰巨、甚至不可能的任务!
为了实现这一目标,Appium实际上被分为四个部分:
<div class="grid cards" markdown>
- :material-image-filter-center-focus-strong: __Appium Core__ - 定义核心API
- :material-car: __Drivers__ - 实现与特定平台的连接
- :octicons-code-16: __Clients__ - 实现与特定平台的连接
- :octicons-code-16: __Clients__ - 用特定语言实现Appium的API
- :fontawesome-solid-plug: __Plugins__ - 更改或扩展Appium的核心功能
</div>
因此,为了开始使用Appium自动化某些内容,您需要:
因此,为了开始使用Appium自动化某些内容,你需要:
- 安装Appium本身
- 为您的目标平台安装驱动程序
- 为您的目标编程语言安装客户端库
- 为你的目标平台安装驱动程序
- 为你的目标编程语言安装客户端库
- (可选)安装一个或多个插件
这些都是基础!如果您准备好加入,请继续[快速入门](../quickstart/index.md)!
这些都是基础!如果你准备好加入,请继续[快速入门](../quickstart/index.md)!
如果您想了解有关其运作方式的更多详细信息,请参阅以下页面了解背景材料:
如果你想了解有关其运作方式的更多详细信息,请参阅以下页面了解背景材料:
- [Appium Core](./appium.md)
- [Appium Drivers](./drivers.md)
@@ -0,0 +1,29 @@
---
hide:
- toc
title: System Requirements
---
The basic requirements for the Appium server are:
* A macOS, Linux, or Windows operating system
* [Node.js](https://nodejs.org) version in the [SemVer](https://semver.org) range `^14.17.0 || ^16.13.0 || >=18.0.0`
* LTS is recommended
* [`npm`](https://npmjs.com) version `>=8` (`npm` is usually bundled with Node.js, but can be upgraded
independently)
By itself, Appium is relatively lightweight and doesn't have significant disk space or RAM
requirements. It can even be run in resource-constrained environments like Raspberry Pi, so long as
Node.js is available.
### Driver Requirements
Drivers for automating specific platforms will likely have other requirements. Refer to the
documentation of the [Appium driver(s)](../ecosystem/drivers.md) for that platform for additional
dependencies. It is almost universally the case that Appium drivers for a given platform will
require the developer toolchain and SDKs for that platform to be installed.
In order to assist with driver requirements, each (official) driver comes with the Appium Doctor tool,
which allows to verify if all requirements have been set up. Learn more about how to use this tool in
the [Command-Line Usage documentation](../cli/extensions.md#doctor).
@@ -0,0 +1,105 @@
---
hide:
- toc
title: Write a Test (.NET)
---
The [Appium .NET Client](https://github.com/appium/dotnet-client/) is
an official Appium client in C#. This driver is an extension of the Selenium C# client. It has all the functionalities of the regular driver, but add Appium-specific methods on top of this. The driver is available on the public NuGet Gallery as [Appium.WebDriver](https://www.nuget.org/packages/Appium.WebDriver/).
Now, we get inside the directory and create a new [NUnit](https://nunit.org/) project. We will also add the references to the Appium.Net driver, and other dependencies.
```bash
cd dotnet-client
dotnet new nunit --name appiumtest
cd appiumtest
# This will install the latest 5.x version
dotnet add package Appium.WebDriver --prerelease
dotnet add package Newtonsoft.Json --version 13.0.3
```
Once this is done, your project should have a placeholder file `UnitTest1.cs`. We will replace the code to include the OpenQA namespaces, an initialization of the driver, and the actual test.
```C# title="UnitTest1.cs"
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Android;
using OpenQA.Selenium.Appium.Enums;
namespace appiumtest;
public class Tests
{
private AndroidDriver _driver;
[OneTimeSetUp]
public void SetUp()
{
var serverUri = new Uri(Environment.GetEnvironmentVariable("APPIUM_HOST") ?? "http://127.0.0.1:4723/");
var driverOptions = new AppiumOptions() {
AutomationName = AutomationName.AndroidUIAutomator2,
PlatformName = "Android",
DeviceName = "Android Emulator",
};
driverOptions.AddAdditionalAppiumOption("appPackage", "com.android.settings");
driverOptions.AddAdditionalAppiumOption("appActivity", ".Settings");
// NoReset assumes the app com.google.android is preinstalled on the emulator
driverOptions.AddAdditionalAppiumOption("noReset", true);
_driver = new AndroidDriver(serverUri, driverOptions, TimeSpan.FromSeconds(180));
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
}
[OneTimeTearDown]
public void TearDown()
{
_driver.Dispose();
}
[Test]
public void TestBattery()
{
_driver.StartActivity("com.android.settings", ".Settings");
_driver.FindElement(By.XPath("//*[@text='Battery']")).Click();
}
}
```
!!! note
It's not within the scope of this guide to give a complete run-down on the dotnet client
library or everything that's happening here, so we'll leave the code itself unexplained in
detail for now. You may want to read up particularly on Appium
[Capabilities](../guides/caps.md) in addition to familiarizing yourself with the
[dotnet client driver documentation](https://github.com/appium/dotnet-client/) for a fuller explanation
of the various API commands you see and what their purpose is.
Basically, this code is doing the following:
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
kind of thing you want to automate. Some of these parameters can be overriden using environment variables.
1. Starting an Appium session on the built-in Android settings app.
1. Finding the "Battery" list item and clicking it.
1. Ending the Appium session.
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
running in another terminal session, otherwise you'll get an error about not being able to connect
to one. Then, you can execute the script:
```bash
dotnet test
# Example output:
# Starting test execution, please wait...
# A total of 1 test files matched the specified pattern.
# Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: 323 ms - appiumtest.dll (net7.0)
```
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view in the emulator before the app closes again.
Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.
@@ -0,0 +1,83 @@
---
hide:
- toc
title: Write a Test (Ruby)
---
The [AppiumLib](https://github.com/appium/ruby_lib) and the [AppiumLibCore](https://github.com/appium/ruby_lib_core) (**recommended**) are official Appium client libraries in Ruby, which are available via gem under the [appium_lib](https://rubygems.org/gems/appium_lib) and the [appium_lib_core](https://rubygems.org/gems/appium_lib_core) package names. The appium_lib_core inherits from the Selenium Ruby Binding, and the appium_lib inherits from the appium_lib_core, so installing these libraries include the selenium binding. We recommend `appium_lib_core` if you need a less complex client-side solution. The `appium_lib` has some useful methods the core does not have, but for the cost of greater complexity and historical methods which may not work in the latest environment.
As the first step, let's initialize a Gemfile to manage the dependency:
```bash
bundle init
```
Then, you could add Appium Ruby Client dependency as below:
```bash
bundle add appium_lib_core
# or
# bundle add appium_lib
```
Test code example below uses `test-unit` module, thus please run:
```bash
bundle add test-unit
```
Once these steps has done, your `Gemfile` file should include:
```ruby title="Gemfile"
--8<-- "./sample-code/quickstarts/rb/Gemfile"
```
The `appium_lib_core` is the main part as an Appium client.
`appium_lib` has various helper methods, but the driver instance was ordinary designed to be used as a global variable. It could causes an issue to handle the instance.
`appium_lib_core` does not have such a global variable.
This example is by the `appium_lib_core` with `test-unit` gem module.
Tes code in `appium_lib` should be similar.
```ruby title="test.rb"
--8<-- "./sample-code/quickstarts/rb/test.rb"
```
!!! note
It's not within the scope of this guide to give a complete run-down on the Ruby client
library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.
- You may want to read up particularly on Appium [Capabilities](../guides/caps.md).
- [functional test code](https://github.com/appium/ruby_lib_core/tree/master/test/functional) in the appium_lib_core GitHub repository should help to find more working example.
- Documentation [appium_lib_core](https://www.rubydoc.info/github/appium/ruby_lib_core) and [appium_lib](https://www.rubydoc.info/github/appium/ruby_lib) also helps to find available methods.
!!! note
The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/rb).
Basically, this code is doing the following:
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
kind of thing you want to automate.
1. Starting an Appium session on the built-in Android settings app.
1. Finding the "Battery" list item and clicking it.
1. Pausing for a moment purely for visual effect.
1. Ending the Appium session.
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
running in another terminal session, otherwise you'll get an error about not being able to connect
to one. Then, you can execute the script:
```bash
# Please run "bundle install" first if your environment has not run the installation command yet.
bundle exec ruby test.rb
```
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the
app closes again.
Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.
-25
View File
@@ -8,7 +8,6 @@ import _ from 'lodash';
import path from 'path';
import YAML from 'yaml';
import {CURRENT_SCHEMA_REV, DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
import log from '../logger';
import {INSTALL_TYPE_NPM, INSTALL_TYPE_DEV} from './extension-config';
import {packageDidChange} from './package-changed';
import {migrate} from './manifest-migrations';
@@ -177,22 +176,6 @@ export class Manifest {
try {
const pkg = JSON.parse(await fs.readFile(filepath, 'utf8'));
if (isExtension(pkg)) {
const extType = isDriver(pkg) ? DRIVER_TYPE : PLUGIN_TYPE;
/**
* this should only be 'unknown' if the extension's `package.json` is invalid
* @type {string}
*/
const name = isDriver(pkg)
? pkg.appium.driverName
: isPlugin(pkg)
? pkg.appium.pluginName
: '(unknown)';
if (
(isDriver(pkg) && !this.hasDriver(name)) ||
(isPlugin(pkg) && !this.hasPlugin(name))
) {
log.info(`Discovered installed ${extType} "${name}"`);
}
const installType = devType && hasAppiumDependency ? INSTALL_TYPE_DEV : INSTALL_TYPE_NPM;
const changed = this.addExtensionFromPackage(pkg, filepath, installType);
didChange = didChange || changed;
@@ -403,12 +386,8 @@ export class Manifest {
try {
const yaml = await fs.readFile(this.#manifestPath, 'utf8');
data = YAML.parse(yaml);
log.debug(
`Parsed manifest file at ${this.#manifestPath}: ${JSON.stringify(data, null, 2)}`
);
} catch (err) {
if (err.code === 'ENOENT') {
log.debug(`No manifest file found at ${this.#manifestPath}; creating`);
data = _.cloneDeep(INITIAL_MANIFEST_DATA);
shouldWrite = true;
} else {
@@ -434,9 +413,6 @@ export class Manifest {
* file will get the latest schema revision, so we can skip the migration.
*/
if (!shouldWrite && (data.schemaRev ?? 0) < CURRENT_SCHEMA_REV) {
log.debug(
`Updating manifest schema from rev ${data.schemaRev ?? '(none)'} to ${CURRENT_SCHEMA_REV}`
);
shouldWrite = await migrate(this);
}
@@ -454,7 +430,6 @@ export class Manifest {
* `APPIUM_HOME`, but we don't do that here.
*/
if (shouldWrite || (hasAppiumDependency && (await packageDidChange(this.appiumHome)))) {
log.debug('Discovering newly installed extensions...');
shouldWrite = (await this.syncWithInstalledExtensions(hasAppiumDependency)) || shouldWrite;
}
+14 -15
View File
@@ -1,6 +1,6 @@
{
"name": "appium",
"version": "2.11.2",
"version": "2.11.3",
"description": "Automation for Apps.",
"keywords": [
"automation",
@@ -59,42 +59,41 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/base-driver": "^9.11.2",
"@appium/base-plugin": "^2.2.42",
"@appium/docutils": "^1.0.18",
"@appium/logger": "^1.6.0",
"@appium/base-driver": "^9.11.3",
"@appium/base-plugin": "^2.2.43",
"@appium/docutils": "^1.0.19",
"@appium/logger": "^1.6.1",
"@appium/schema": "^0.6.1",
"@appium/support": "^5.1.2",
"@appium/types": "^0.21.1",
"@appium/support": "^5.1.3",
"@appium/types": "^0.21.2",
"@sidvind/better-ajv-errors": "2.1.3",
"@types/argparse": "2.0.16",
"@types/bluebird": "3.5.42",
"@types/fancy-log": "2.0.2",
"@types/semver": "7.5.8",
"@types/teen_process": "2.0.4",
"@types/wrap-ansi": "3.0.0",
"ajv": "8.16.0",
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"argparse": "2.0.1",
"async-lock": "1.4.1",
"asyncbox": "3.0.0",
"axios": "1.7.2",
"axios": "1.7.3",
"bluebird": "3.7.2",
"cross-env": "7.0.3",
"lilconfig": "3.1.2",
"lodash": "4.17.21",
"lru-cache": "10.3.0",
"lru-cache": "10.4.3",
"ora": "5.4.1",
"package-changed": "3.0.0",
"resolve-from": "5.0.0",
"semver": "7.6.2",
"semver": "7.6.3",
"source-map-support": "0.5.21",
"teen_process": "2.2.0",
"type-fest": "4.21.0",
"winston": "3.13.0",
"type-fest": "4.23.0",
"winston": "3.13.1",
"wrap-ansi": "7.0.0",
"ws": "8.18.0",
"yaml": "2.4.5"
"yaml": "2.5.0"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
@@ -1,5 +1,5 @@
{
"devDependencies": {
"webdriverio": "8.39.1"
"webdriverio": "8.40.0"
}
}
@@ -4,13 +4,14 @@
const path = require('path');
const yaml = require('yaml');
const {fs, util} = require('@appium/support');
const {fs, util, logger} = require('@appium/support');
const validate = require('validate.js');
const Handlebars = require('handlebars');
const _ = require('lodash');
const {asyncify} = require('asyncbox');
const url = require('url');
const log = require('fancy-log');
const log = logger.getLogger('YamlParser');
validate.validators.array = function array(value, options, key, attributes) {
if (attributes[key] && !validate.isArray(attributes[key])) {
@@ -276,7 +277,7 @@ async function generateCommands() {
await registerSpecUrlHelper();
const commands = path.resolve(YAML_DIR, 'commands/**/*.yml');
log('Traversing YML files', commands);
log.info('Traversing YML files', commands);
await fs.rimraf(path.resolve(rootFolder, 'docs', 'en', 'commands'));
// get the template from which the md files will be created
@@ -288,7 +289,7 @@ async function generateCommands() {
let fileCount = 0;
for (const filename of await fs.glob(commands)) {
const relativeFilename = path.relative(YAML_DIR, filename);
log(`Rendering file: ${filename} ${relativeFilename}`);
log.info(`Rendering file: ${filename} ${relativeFilename}`);
// Translate the YML specs to JSON
const inputYML = await fs.readFile(filename, 'utf8');
@@ -309,13 +310,13 @@ async function generateCommands() {
relativeFilename.length - ext.length
)}.md`;
const outfile = path.resolve(rootFolder, 'docs', 'en', markdownPath);
log(` Writing to: ${outfile}`);
log.info(` Writing to: ${outfile}`);
await fs.mkdirp(path.dirname(outfile));
await fs.writeFile(outfile, markdown, 'utf8');
fileCount++;
}
log(`Done writing ${fileCount} command documents`);
log.info(`Done writing ${fileCount} command documents`);
}
async function generateCommandIndex() {
@@ -351,7 +352,7 @@ async function generateCommandIndex() {
);
async function writeIndex(index, commands, indexPath) {
log(`Creating API index '${index}'`);
log.info(`Creating API index '${index}'`);
const commandMarkdown = commandTemplate({
commands,
path: indexPath,
@@ -361,7 +362,7 @@ async function generateCommandIndex() {
const apiIndex = path.resolve(rootFolder, 'docs', 'en', 'about-appium', 'api.md');
await writeIndex(apiIndex, commands);
log(`Done writing main API index`);
log.info(`Done writing main API index`);
async function writeIndividualIndexes(command) {
if (!util.hasValue(command.commands)) {
+17
View File
@@ -3,6 +3,23 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [9.11.3](https://github.com/appium/appium/compare/@appium/base-driver@9.11.2...@appium/base-driver@9.11.3) (2024-08-07)
### Bug Fixes
* **base-driver:** calls startNewCommandTimeout before returning NotYetImplementedError ([#20380](https://github.com/appium/appium/issues/20380)) ([6a97fe4](https://github.com/appium/appium/commit/6a97fe48aebb85424fa7e5be5de2eb5524cf0db6))
* **base-driver:** change required to option for setWindowRect to follow w3c ([#20391](https://github.com/appium/appium/issues/20391)) ([9eb65f7](https://github.com/appium/appium/commit/9eb65f7ad4efc89bbf5af89791bb9eb81fc2248f))
* **base-driver:** Start command timeout even if the recent command has thrown an exception ([#20379](https://github.com/appium/appium/issues/20379)) ([139dbae](https://github.com/appium/appium/commit/139dbaeef6963f79a1de38541181bae8953e00e1))
* **base-driver:** update dependency path-to-regexp to v7.1.0 ([#20376](https://github.com/appium/appium/issues/20376)) ([6488a0a](https://github.com/appium/appium/commit/6488a0a4e1dd08f4eda6e40e33a9b31d31edda1c))
* **driver-test-support:** update dependency @types/lodash to v4.17.7 ([#20382](https://github.com/appium/appium/issues/20382)) ([d5ef0f9](https://github.com/appium/appium/commit/d5ef0f9c8608ba545988c3016cefd0669f2400dc))
* **logger:** update dependency lru-cache to v10.4.3 ([#20364](https://github.com/appium/appium/issues/20364)) ([8d79467](https://github.com/appium/appium/commit/8d79467da8a0733ac3e49b9152bd6905989a57ca))
* **support:** update dependency axios to v1.7.3 ([1ca77c6](https://github.com/appium/appium/commit/1ca77c6dedbff4552aba9c97cf5406c7552d1a01))
* **types:** update dependency type-fest to v4.22.0 ([#20387](https://github.com/appium/appium/issues/20387)) ([47405dd](https://github.com/appium/appium/commit/47405dda8a5de17c72fb721b0c043e0dd4f6b35a))
* **types:** update dependency type-fest to v4.23.0 ([#20396](https://github.com/appium/appium/issues/20396)) ([0e8e3c7](https://github.com/appium/appium/commit/0e8e3c71441d02d22f015f08df5223909f5fbb93))
## [9.11.2](https://github.com/appium/appium/compare/@appium/base-driver@9.11.1...@appium/base-driver@9.11.2) (2024-07-10)
+43 -29
View File
@@ -98,41 +98,55 @@ export class BaseDriver<
// If we don't have this command, it must not be implemented
if (!this[cmd]) {
await this.startNewCommandTimeout();
throw new errors.NotYetImplementedError();
}
let unexpectedShutdownListener;
const commandExecutor = async () =>
await B.race([
this[cmd](...args),
new B((resolve, reject) => {
unexpectedShutdownListener = reject;
this.eventEmitter.on(ON_UNEXPECTED_SHUTDOWN_EVENT, unexpectedShutdownListener);
}),
]).finally(() => {
if (unexpectedShutdownListener) {
const runCommandPromise = async () => {
let unexpectedShutdownRejecter: ((error?: any) => void) | null = null;
let unexpectedShutdownResolver: ((x?: unknown) => void) | null = null;
let wasSessionShutdownUnexpectedly = false;
const onUnexpectedShutdown = (e: Error) => {
wasSessionShutdownUnexpectedly = true;
unexpectedShutdownRejecter?.(e);
};
try {
return await B.race([
this[cmd](...args),
// This promise is needed to monitor if the session has been
// shut down unexpectedly while the command was running
new B((resolve, reject) => {
unexpectedShutdownResolver = resolve;
unexpectedShutdownRejecter = reject;
this.eventEmitter.once(ON_UNEXPECTED_SHUTDOWN_EVENT, onUnexpectedShutdown);
})
]);
} finally {
if (unexpectedShutdownRejecter && unexpectedShutdownResolver) {
// This is needed to prevent memory leaks
this.eventEmitter.removeListener(
ON_UNEXPECTED_SHUTDOWN_EVENT,
unexpectedShutdownListener,
);
unexpectedShutdownListener = null;
this.eventEmitter.removeListener(ON_UNEXPECTED_SHUTDOWN_EVENT, onUnexpectedShutdown);
unexpectedShutdownRejecter = null;
// @ts-ignore typescript cannot understand this
unexpectedShutdownResolver?.();
unexpectedShutdownResolver = null;
}
});
const res = this.isCommandsQueueEnabled
? await this.commandsQueueGuard.acquire(BaseDriver.name, commandExecutor)
: await commandExecutor();
// if we have set a new command timeout (which is the default), start a
// timer once we've finished executing this command. If we don't clear
// the timer (which is done when a new command comes in), we will trigger
// automatic session deletion in this.onCommandTimeout. Of course we don't
// want to trigger the timer when the user is shutting down the session
// intentionally
if (this.isCommandsQueueEnabled && cmd !== DELETE_SESSION_COMMAND) {
// resetting existing timeout
await this.startNewCommandTimeout();
}
// if we have set a new command timeout (which is the default), start a
// timer once we've finished executing this command. If we don't clear
// the timer (which is done when a new command comes in), we will trigger
// automatic session deletion in this.onCommandTimeout. Of course we don't
// want to trigger the timer when the user is shutting down the session
// intentionally
if (!wasSessionShutdownUnexpectedly && this.isCommandsQueueEnabled && cmd !== DELETE_SESSION_COMMAND) {
// resetting existing timeout
await this.startNewCommandTimeout();
}
}
};
const res = this.isCommandsQueueEnabled
? await this.commandsQueueGuard.acquire(BaseDriver.name, runCommandPromise)
: await runCommandPromise();
// log timing information about this command
const endTime = Date.now();
+1 -1
View File
@@ -824,7 +824,7 @@ export const METHOD_MAP = /** @type {const} */ ({
GET: {command: 'getWindowRect'},
POST: {
command: 'setWindowRect',
payloadParams: {required: ['x', 'y', 'width', 'height']},
payloadParams: {optional: ['x', 'y', 'width', 'height']},
},
},
'/session/:sessionId/window/maximize': {
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/base-driver",
"version": "9.11.2",
"version": "9.11.3",
"description": "Base driver class for Appium drivers",
"keywords": [
"automation",
@@ -44,30 +44,30 @@
"test:types": "tsd"
},
"dependencies": {
"@appium/support": "^5.1.2",
"@appium/types": "^0.21.1",
"@appium/support": "^5.1.3",
"@appium/types": "^0.21.2",
"@colors/colors": "1.6.0",
"@types/async-lock": "1.4.2",
"@types/bluebird": "3.5.42",
"@types/express": "4.17.21",
"@types/lodash": "4.17.6",
"@types/lodash": "4.17.7",
"@types/method-override": "0.0.35",
"@types/serve-favicon": "2.5.7",
"async-lock": "1.4.1",
"asyncbox": "3.0.0",
"axios": "1.7.2",
"axios": "1.7.3",
"bluebird": "3.7.2",
"body-parser": "1.20.2",
"express": "4.19.2",
"http-status-codes": "2.3.0",
"lodash": "4.17.21",
"lru-cache": "10.3.0",
"lru-cache": "10.4.3",
"method-override": "3.0.0",
"morgan": "1.10.0",
"path-to-regexp": "7.0.0",
"path-to-regexp": "7.1.0",
"serve-favicon": "2.5.0",
"source-map-support": "0.5.21",
"type-fest": "4.21.0",
"type-fest": "4.23.0",
"validate.js": "0.13.1"
},
"optionalDependencies": {
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.43](https://github.com/appium/appium/compare/@appium/base-plugin@2.2.42...@appium/base-plugin@2.2.43) (2024-08-07)
**Note:** Version bump only for package @appium/base-plugin
## [2.2.42](https://github.com/appium/appium/compare/@appium/base-plugin@2.2.41...@appium/base-plugin@2.2.42) (2024-07-10)
**Note:** Version bump only for package @appium/base-plugin
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/base-plugin",
"version": "2.2.42",
"version": "2.2.43",
"description": "The base plugin used to create Appium 2.0 plugins",
"keywords": [
"automation",
@@ -40,8 +40,8 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/base-driver": "^9.11.2",
"@appium/support": "^5.1.2"
"@appium/base-driver": "^9.11.3",
"@appium/support": "^5.1.3"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.1.10](https://github.com/appium/appium/compare/@appium/doctor@2.1.9...@appium/doctor@2.1.10) (2024-08-07)
### Bug Fixes
* **doctor:** update dependency appium-adb to v12.5.0 ([b7b97a2](https://github.com/appium/appium/commit/b7b97a24d66e5c561b4c9559a4b0aea25503f39a))
* **doctor:** update dependency appium-adb to v12.5.1 ([82b7515](https://github.com/appium/appium/commit/82b7515867c10c20843dd02c37c7a2e9014c3703))
## [2.1.9](https://github.com/appium/appium/compare/@appium/doctor@2.1.8...@appium/doctor@2.1.9) (2024-07-10)
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/doctor",
"version": "2.1.9",
"version": "2.1.10",
"description": "Test environment for fitness to run Appium",
"keywords": [
"automation",
@@ -44,11 +44,11 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/support": "^5.1.2",
"@appium/support": "^5.1.3",
"@colors/colors": "1.6.0",
"@types/bluebird": "3.5.42",
"@types/teen_process": "2.0.4",
"appium-adb": "12.4.8",
"appium-adb": "12.5.1",
"bluebird": "3.7.2",
"inquirer": "9.2.12",
"lodash": "4.17.21",
+13
View File
@@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.19](https://github.com/appium/appium/compare/@appium/docutils@1.0.18...@appium/docutils@1.0.19) (2024-08-07)
### Bug Fixes
* **docutils:** update dependency typescript to v5.5.4 ([e08e7eb](https://github.com/appium/appium/commit/e08e7ebec24866611e0718f0d038e9566abd3dd6))
* **docutils:** update dependency yaml to v2.5.0 ([0c755f5](https://github.com/appium/appium/commit/0c755f503c49e459315616e51be0c0776089b2bb))
* **support:** update dependency semver to v7.6.3 ([5a9ab97](https://github.com/appium/appium/commit/5a9ab9792402e31d3903fb1a3b08329a67b6a2a2))
* **types:** update dependency type-fest to v4.22.0 ([#20387](https://github.com/appium/appium/issues/20387)) ([47405dd](https://github.com/appium/appium/commit/47405dda8a5de17c72fb721b0c043e0dd4f6b35a))
* **types:** update dependency type-fest to v4.23.0 ([#20396](https://github.com/appium/appium/issues/20396)) ([0e8e3c7](https://github.com/appium/appium/commit/0e8e3c71441d02d22f015f08df5223909f5fbb93))
## [1.0.18](https://github.com/appium/appium/compare/@appium/docutils@1.0.17...@appium/docutils@1.0.18) (2024-07-10)
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/docutils",
"version": "1.0.18",
"version": "1.0.19",
"description": "Documentation generation utilities for Appium and related projects",
"keywords": [
"automation",
@@ -48,7 +48,7 @@
"start": "node ./build/lib/cli/index.js"
},
"dependencies": {
"@appium/support": "^5.1.2",
"@appium/support": "^5.1.3",
"@appium/tsconfig": "^0.3.3",
"@sliphua/lilconfig-ts-loader": "3.2.2",
"@types/which": "3.0.4",
@@ -60,12 +60,12 @@
"lodash": "4.17.21",
"pkg-dir": "5.0.0",
"read-pkg": "5.2.0",
"semver": "7.6.2",
"semver": "7.6.3",
"source-map-support": "0.5.21",
"teen_process": "2.2.0",
"type-fest": "4.21.0",
"typescript": "5.5.3",
"yaml": "2.4.5",
"type-fest": "4.23.0",
"typescript": "5.5.4",
"yaml": "2.5.0",
"yargs": "17.7.2",
"yargs-parser": "21.1.1"
},
+1 -1
View File
@@ -1,5 +1,5 @@
mkdocs==1.6.0
mkdocs-git-revision-date-localized-plugin==1.2.6
mkdocs-material==9.5.28
mkdocs-material==9.5.31
mkdocs-redirects==1.2.1
mike==2.1.2
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.6.7](https://github.com/appium/appium/compare/@appium/driver-test-support@0.6.6...@appium/driver-test-support@0.6.7) (2024-08-07)
### Bug Fixes
* **driver-test-support:** update dependency @types/lodash to v4.17.7 ([#20382](https://github.com/appium/appium/issues/20382)) ([d5ef0f9](https://github.com/appium/appium/commit/d5ef0f9c8608ba545988c3016cefd0669f2400dc))
* **support:** update dependency axios to v1.7.3 ([1ca77c6](https://github.com/appium/appium/commit/1ca77c6dedbff4552aba9c97cf5406c7552d1a01))
* **types:** update dependency type-fest to v4.22.0 ([#20387](https://github.com/appium/appium/issues/20387)) ([47405dd](https://github.com/appium/appium/commit/47405dda8a5de17c72fb721b0c043e0dd4f6b35a))
* **types:** update dependency type-fest to v4.23.0 ([#20396](https://github.com/appium/appium/issues/20396)) ([0e8e3c7](https://github.com/appium/appium/commit/0e8e3c71441d02d22f015f08df5223909f5fbb93))
## [0.6.6](https://github.com/appium/appium/compare/@appium/driver-test-support@0.6.5...@appium/driver-test-support@0.6.6) (2024-07-10)
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/driver-test-support",
"version": "0.6.6",
"version": "0.6.7",
"description": "Test utilities for Appium drivers",
"keywords": [
"automation",
@@ -41,10 +41,10 @@
},
"types": "./build/lib/index.d.ts",
"dependencies": {
"@appium/types": "^0.21.1",
"@types/lodash": "4.17.6",
"@appium/types": "^0.21.2",
"@types/lodash": "4.17.7",
"@types/stoppable": "1.1.3",
"axios": "1.7.2",
"axios": "1.7.3",
"bluebird": "3.7.2",
"chai": "5.1.1",
"chai-as-promised": "8.0.0",
@@ -53,7 +53,7 @@
"sinon": "18.0.0",
"source-map-support": "0.5.21",
"stoppable": "1.1.0",
"type-fest": "4.21.0"
"type-fest": "4.23.0"
},
"peerDependencies": {
"appium": "^2.0.0-beta.43",
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.0.33](https://github.com/appium/appium/compare/@appium/execute-driver-plugin@3.0.32...@appium/execute-driver-plugin@3.0.33) (2024-08-07)
### Bug Fixes
* **execute-driver-plugin:** update dependency webdriverio to v8.40.0 ([#20442](https://github.com/appium/appium/issues/20442)) ([b4612e0](https://github.com/appium/appium/commit/b4612e0c7a21902a3cab658fbdc05f3b48c55d0d))
## [3.0.32](https://github.com/appium/appium/compare/@appium/execute-driver-plugin@3.0.31...@appium/execute-driver-plugin@3.0.32) (2024-07-10)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/execute-driver-plugin",
"version": "3.0.32",
"version": "3.0.33",
"description": "Plugin for batching and executing driver commands with Appiums",
"keywords": [
"automation",
@@ -43,7 +43,7 @@
"lodash": "4.17.21",
"source-map-support": "0.5.21",
"vm2": "3.9.19",
"webdriverio": "8.39.1"
"webdriverio": "8.40.0"
},
"peerDependencies": {
"appium": "^2.0.0-beta.35"
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.1.47](https://github.com/appium/appium/compare/@appium/fake-plugin@3.1.46...@appium/fake-plugin@3.1.47) (2024-08-07)
**Note:** Version bump only for package @appium/fake-plugin
## [3.1.46](https://github.com/appium/appium/compare/@appium/fake-plugin@3.1.45...@appium/fake-plugin@3.1.46) (2024-07-10)
**Note:** Version bump only for package @appium/fake-plugin
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/fake-plugin",
"version": "3.1.46",
"version": "3.1.47",
"description": "A fake Appium 2.0 plugin",
"keywords": [
"automation",
@@ -39,8 +39,8 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/base-plugin": "^2.2.42",
"@appium/support": "^5.1.2",
"@appium/base-plugin": "^2.2.43",
"@appium/support": "^5.1.3",
"@types/bluebird": "3.5.42",
"bluebird": "3.7.2",
"lodash": "4.17.21",
+9
View File
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.0.18](https://github.com/appium/appium/compare/@appium/images-plugin@3.0.17...@appium/images-plugin@3.0.18) (2024-08-07)
### Bug Fixes
* **logger:** update dependency lru-cache to v10.4.3 ([#20364](https://github.com/appium/appium/issues/20364)) ([8d79467](https://github.com/appium/appium/commit/8d79467da8a0733ac3e49b9152bd6905989a57ca))
## [3.0.17](https://github.com/appium/appium/compare/@appium/images-plugin@3.0.16...@appium/images-plugin@3.0.17) (2024-07-10)
**Note:** Version bump only for package @appium/images-plugin
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/images-plugin",
"version": "3.0.17",
"version": "3.0.18",
"description": "Plugin for working with images and image elements in Appium",
"keywords": [
"automation",
@@ -40,9 +40,9 @@
},
"dependencies": {
"@appium/opencv": "^3.0.5",
"@appium/support": "^5.1.2",
"@appium/support": "^5.1.3",
"lodash": "4.17.21",
"lru-cache": "10.3.0",
"lru-cache": "10.4.3",
"sharp": "0.33.4",
"source-map-support": "0.5.21"
},
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.6.1](https://github.com/appium/appium/compare/@appium/logger@1.6.0...@appium/logger@1.6.1) (2024-08-07)
### Bug Fixes
* **logger:** update dependency lru-cache to v10.4.3 ([#20364](https://github.com/appium/appium/issues/20364)) ([8d79467](https://github.com/appium/appium/commit/8d79467da8a0733ac3e49b9152bd6905989a57ca))
* **support:** Print an empty string if no arguments are provided to a logging function ([#20424](https://github.com/appium/appium/issues/20424)) ([885570e](https://github.com/appium/appium/commit/885570e7caec486765c1baa67131f0b3adf1daf7))
## [1.6.0](https://github.com/appium/appium/compare/@appium/logger@1.5.0...@appium/logger@1.6.0) (2024-07-10)
+1 -3
View File
@@ -245,9 +245,7 @@ export class Log extends EventEmitter implements Logger {
if (stack) {
messageArguments.unshift(`${stack}\n`);
}
const formattedMessage: string = messageArguments.length
? util.format(...messageArguments)
: '';
const formattedMessage = util.format(...messageArguments);
const m: MessageObject = {
id: this._id++,
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/logger",
"version": "1.6.0",
"version": "1.6.1",
"author": "https://github.com/appium",
"description": "A Universal Logger For The Appium Ecosystem",
"repository": {
@@ -29,7 +29,7 @@
"dependencies": {
"console-control-strings": "1.1.0",
"lodash": "4.17.21",
"lru-cache": "10.3.0",
"lru-cache": "10.4.3",
"set-blocking": "2.0.0"
},
"license": "ISC",
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.3.41](https://github.com/appium/appium/compare/@appium/plugin-test-support@0.3.40...@appium/plugin-test-support@0.3.41) (2024-08-07)
**Note:** Version bump only for package @appium/plugin-test-support
## [0.3.40](https://github.com/appium/appium/compare/@appium/plugin-test-support@0.3.39...@appium/plugin-test-support@0.3.40) (2024-07-10)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/plugin-test-support",
"version": "0.3.40",
"version": "0.3.41",
"description": "Testing utilities for Appium plugins",
"keywords": [
"automation",
@@ -41,7 +41,7 @@
"test:unit": "exit 0"
},
"dependencies": {
"@appium/types": "^0.21.1",
"@appium/types": "^0.21.2",
"get-port": "5.1.1",
"log-symbols": "4.1.0",
"source-map-support": "0.5.21",
+15
View File
@@ -3,6 +3,21 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.1.3](https://github.com/appium/appium/compare/@appium/support@5.1.2...@appium/support@5.1.3) (2024-08-07)
### Bug Fixes
* **support:** Allow temp dir which do not have a parent folder ([#20440](https://github.com/appium/appium/issues/20440)) ([8a307a0](https://github.com/appium/appium/commit/8a307a078b48176dfd7cf7013cd5ca405fc6d870))
* **support:** Print an empty string if no arguments are provided to a logging function ([#20424](https://github.com/appium/appium/issues/20424)) ([885570e](https://github.com/appium/appium/commit/885570e7caec486765c1baa67131f0b3adf1daf7))
* **support:** update dependency axios to v1.7.3 ([1ca77c6](https://github.com/appium/appium/commit/1ca77c6dedbff4552aba9c97cf5406c7552d1a01))
* **support:** update dependency glob to v10.4.5 ([#20365](https://github.com/appium/appium/issues/20365)) ([7159428](https://github.com/appium/appium/commit/715942845b8375f96dcd6c21f0273b2a386b19a3))
* **support:** update dependency semver to v7.6.3 ([5a9ab97](https://github.com/appium/appium/commit/5a9ab9792402e31d3903fb1a3b08329a67b6a2a2))
* **types:** update dependency type-fest to v4.22.0 ([#20387](https://github.com/appium/appium/issues/20387)) ([47405dd](https://github.com/appium/appium/commit/47405dda8a5de17c72fb721b0c043e0dd4f6b35a))
* **types:** update dependency type-fest to v4.23.0 ([#20396](https://github.com/appium/appium/issues/20396)) ([0e8e3c7](https://github.com/appium/appium/commit/0e8e3c71441d02d22f015f08df5223909f5fbb93))
## [5.1.2](https://github.com/appium/appium/compare/@appium/support@5.1.1...@appium/support@5.1.2) (2024-07-10)
+6 -2
View File
@@ -67,8 +67,12 @@ export function getLogger(prefix = null) {
for (const level of LEVELS) {
wrappedLogger[level] = /** @param {any[]} args */ function (...args) {
const finalPrefix = getFinalPrefix(this.prefix, isDebugTimestampLoggingEnabled);
// @ts-ignore This is OK
logger[level](finalPrefix, ...args);
if (args.length) {
// @ts-ignore This is OK
logger[level](finalPrefix, ...args);
} else {
logger[level](finalPrefix, '');
}
};
}
if (!usingGlobalLog) {
+1 -1
View File
@@ -31,7 +31,7 @@ async function tempDir() {
);
// creates a temp directory using the date and a random string
await fs.mkdir(filePath);
await fs.mkdir(filePath, {recursive: true});
return filePath;
}
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/support",
"version": "5.1.2",
"version": "5.1.3",
"description": "Support libs used across appium packages",
"keywords": [
"automation",
@@ -41,9 +41,9 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/logger": "^1.6.0",
"@appium/logger": "^1.6.1",
"@appium/tsconfig": "^0.3.3",
"@appium/types": "^0.21.1",
"@appium/types": "^0.21.2",
"@colors/colors": "1.6.0",
"@types/archiver": "6.0.2",
"@types/base64-stream": "1.0.5",
@@ -61,14 +61,14 @@
"@types/uuid": "10.0.0",
"@types/which": "3.0.4",
"archiver": "7.0.1",
"axios": "1.7.2",
"axios": "1.7.3",
"base64-stream": "1.0.0",
"bluebird": "3.7.2",
"bplist-creator": "0.1.1",
"bplist-parser": "0.3.2",
"form-data": "4.0.0",
"get-stream": "6.0.1",
"glob": "10.4.2",
"glob": "10.4.5",
"jsftp": "2.1.3",
"klaw": "4.1.0",
"lockfile": "1.0.4",
@@ -84,12 +84,12 @@
"read-pkg": "5.2.0",
"resolve-from": "5.0.0",
"sanitize-filename": "1.6.3",
"semver": "7.6.2",
"semver": "7.6.3",
"shell-quote": "1.8.1",
"source-map-support": "0.5.21",
"supports-color": "8.1.1",
"teen_process": "2.2.0",
"type-fest": "4.21.0",
"type-fest": "4.23.0",
"uuid": "10.0.0",
"which": "4.0.0",
"yauzl": "3.1.3"
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.0.47](https://github.com/appium/appium/compare/@appium/test-support@3.0.46...@appium/test-support@3.0.47) (2024-08-07)
**Note:** Version bump only for package @appium/test-support
## [3.0.46](https://github.com/appium/appium/compare/@appium/test-support@3.0.45...@appium/test-support@3.0.46) (2024-07-10)
**Note:** Version bump only for package @appium/test-support
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/test-support",
"version": "3.0.46",
"version": "3.0.47",
"description": "A collection of test utilities used across Appium packages",
"keywords": [
"automation",
@@ -45,7 +45,7 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/support": "^5.1.2",
"@appium/support": "^5.1.3",
"@colors/colors": "1.6.0",
"bluebird": "3.7.2",
"lodash": "4.17.21",

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