Compare commits

..
Author SHA1 Message Date
Jonathan Lipps 9004554879 chore: publish
- appium@3.1.2
 - @appium/base-driver@10.1.2
 - @appium/base-plugin@3.0.5
 - @appium/docutils@2.2.0
 - @appium/driver-test-support@1.0.5
 - @appium/eslint-config-appium-ts@2.0.5
 - @appium/execute-driver-plugin@5.0.3
 - @appium/fake-plugin@4.0.5
 - @appium/images-plugin@4.0.4
 - @appium/logger@2.0.3
 - @appium/plugin-test-support@1.0.4
 - @appium/storage-plugin@1.0.4
 - @appium/support@7.0.4
 - @appium/test-support@4.0.4
 - @appium/tsconfig@1.1.1
 - @appium/types@1.1.2
 - @appium/universal-xml-plugin@2.0.3
2025-12-04 14:58:53 -08:00
Edgars Eglītis 86d84b8c6a feat(docutils): add 3 Material for MkDocs features (#21784) 2025-12-04 16:38:40 +02:00
renovate[bot] 24b54f4e89 chore(support): update dependency teen_process to v3.0.4 (#21778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 20:55:29 +00:00
renovate[bot] 65bacd51db chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.48.1 (#21777)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 19:10:07 +00:00
renovate[bot] 5c1b043ddd chore(types): update dependency type-fest to v5.3.0 (#21780)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 16:54:21 +01:00
renovate[bot] 2676dd64f0 chore(deps): update dependency prettier to v3.7.4 (#21776)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 12:32:36 +00:00
renovate[bot] a5c786fe84 chore(deps): update dependency finalhandler to v2.1.1 (#21775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 11:01:49 +00:00
renovate[bot] e20ace541f chore(deps): update dependency @types/express to v5.0.6 (#21773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-02 17:53:14 +00:00
renovate[bot] 9a0cb698bd chore(base-driver): update dependency express to v5.2.1 (#21772)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-02 13:33:26 +00:00
github-actions[bot]andmykola-mokhnach 7e8cc784c8 docs(appium): Update documentation translations (#21771)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-12-01 20:35:21 -08:00
renovate[bot] 69756995c2 chore(base-driver): update dependency express to v5.2.0 [security] (#21769)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 21:20:50 +00:00
renovate[bot] 49f8f8a073 chore(execute-driver-plugin): update dependency webdriverio to v9.21.0 (#21768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 20:38:46 +00:00
Sai KrishnaandSrinivasanTarget 83e1cc4e1d docs(appium): Update blog with LT as development partner (#21752)
Co-authored-by: SrinivasanTarget <srinivasan.sekar1990@gmail.com>
2025-12-01 10:20:35 -08:00
renovate[bot] 65bd6faa4a chore(storage-plugin): update dependency lru-cache to v11.2.4 (#21767)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 14:56:10 +00:00
renovate[bot] 901e71049c chore(docutils): update dependency yaml to v2.8.2 (#21765)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 00:58:00 +00:00
Mykola Mokhnach ecbc7c4879 ci: Use shared workflows (#21766) 2025-11-30 23:13:29 +01:00
renovate[bot] d1eb6856ba chore(deps): update dependency prettier to v3.7.3 (#21764)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 13:49:57 +00:00
renovate[bot] d81e682243 chore(deps): update dependency prettier to v3.7.2 (#21763)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 14:02:15 +00:00
renovate[bot] 991b4baee2 chore(deps): update dependency lerna to v9.0.3 (#21762)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 09:14:10 +00:00
renovate[bot] 54e8ef7764 chore(deps): update dependency prettier to v3.7.1 (#21761)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 18:46:33 +00:00
github-actions[bot]andmykola-mokhnach af2701ac4d docs(appium): Update documentation translations (#21760)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-11-26 18:09:16 -08:00
renovate[bot] 2235689d93 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.48.0 (#21751)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 19:30:01 +00:00
renovate[bot] c4c895cbdd chore(deps): update dependency @types/lodash to v4.17.21 (#21747)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 12:32:36 +00:00
renovate[bot] 18674037bc chore(appium): update dependency @sidvind/better-ajv-errors to v4.0.1 (#21746)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 08:50:46 +00:00
github-actions[bot]andmykola-mokhnach 8d0f9017c4 docs(appium): Update documentation translations (#21755)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-11-26 08:32:34 +02:00
renovate[bot] aa6a8531e6 chore(base-driver): update dependency body-parser to v2.2.1 [security] (#21754)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 04:45:35 +00:00
Dor Blayzer 65a17a1b59 docs: Refine security documentation for clarity (#21749)
* Refine security documentation for clarity

Corrected formatting and phrasing for clarity and consistency throughout the document. Adjusted security feature descriptions and command examples.

* Fix typos in security documentation

* Update security.md for multiple insecure features

Clarified section on enabling multiple insecure features for drivers.

* Update security.md to remove insecure feature examples

Removed examples of insecure feature commands.

* Remove section on multiple insecure features

Removed the section on enabling multiple insecure features for specific drivers.

* Fix formatting of appium command examples in security.md
2025-11-26 00:07:36 +02:00
renovate[bot] c23e45b09d chore(workflows): update peter-evans/create-pull-request action to v7.0.9 (#21748)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-23 14:02:53 +00:00
Mykola Mokhnach 82536ae9d5 ci: Do not presist credentials while doing checkout (#21745) 2025-11-22 08:08:28 +01:00
renovate[bot]andMykola Mokhnach 1034b02925 chore(support): update dependency glob to v13 (#21739)
* chore(support): update dependency glob to v13

* Update lockfile

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Mykola Mokhnach <mokhnach@gmail.com>
2025-11-21 22:35:43 +01:00
renovate[bot] 2fd9cfb6d5 chore(workflows): update actions/checkout action to v6 (#21743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-21 09:36:23 +02:00
github-actions[bot]andmykola-mokhnach edceebe78d docs(appium): Update documentation translations (#21742)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-11-20 20:10:28 -08:00
renovate[bot]andMykola Mokhnach 73cff7dd31 chore(storage-plugin): update dependency rimraf to v6.1.2 (#21738)
* chore(storage-plugin): update dependency rimraf to v6.1.2

* update lock

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Mykola Mokhnach <mokhnach@gmail.com>
2025-11-20 19:44:11 +01:00
Edgars Eglītis f12fc21dcb chore(deps): fix some npm audit issues (#21737) 2025-11-19 21:58:29 +02:00
renovate[bot] 4658cf60ce chore(execute-driver-plugin): update dependency webdriverio to v9.20.1 (#21735)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-19 12:50:01 +00:00
renovate[bot] 18089f70e4 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.47.0 (#21734)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 19:25:17 +01:00
renovate[bot] a7d19f481f chore(tsconfig): update dependency @tsconfig/node20 to v20.1.8 (#21733)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 15:04:39 +00:00
renovate[bot] 9decd8b00c chore(support): update dependency glob to v11.1.0 [security] (#21732)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 08:16:01 +00:00
renovate[bot] 968460c1a9 chore(deps): update dependency @types/sinon to v21 (#21730)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-17 12:47:16 +01:00
renovate[bot] 39cca27784 chore(support): update dependency form-data to v4.0.5 (#21729)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-17 12:47:02 +01:00
renovate[bot] 1c0a07c19f chore(support): update dependency teen_process to v3.0.3 (#21725)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-16 14:28:43 +00:00
renovate[bot] 2ceb39df06 chore(eslint-config-appium-ts): update dependency @eslint/compat to v2 (#21718)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 21:18:44 +02:00
Edgars Eglītis cabe2e53bc fix(eslint-config-appium-ts): update eslint-plugin-mocha to v11 (#21722) 2025-11-15 20:02:34 +02:00
Kazuaki Matsuo 9c43921ac9 ci: modify contribution post format (#21719)
* chore: modify contribution post format

* modify comment
2025-11-15 09:47:19 -08:00
Mykola Mokhnach 795181ffc2 test(docutils): Add e2e tests (#21721) 2025-11-15 18:23:54 +01:00
renovate[bot]andMykola Mokhnach f01b6fb054 chore(tsconfig): update dependency @tsconfig/node20 to v20.1.7 (#21713)
* chore(tsconfig): update dependency @tsconfig/node20 to v20.1.7

* fix: linter errors

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Mykola Mokhnach <mokhnach@gmail.com>
2025-11-15 13:36:18 +01:00
renovate[bot] a09c85e59e chore(support): update dependency which to v6 (#21720)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 12:49:37 +02:00
renovate[bot] 050bad8f12 chore(deps): update dependency @types/yargs to v17.0.35 (#21717)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 08:37:55 +00:00
renovate[bot] 38c918711a chore(universal-xml-plugin): update dependency fast-xml-parser to v5.3.2 (#21716)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 00:44:07 +00:00
renovate[bot] 982d33e318 chore(deps): update dependency lerna to v9.0.1 (#21715)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 18:30:00 +00:00
renovate[bot] 46bd0512d7 chore(deps): update dependency @types/sinon to v20 (#21714)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 08:42:26 +02:00
renovate[bot] 4d8189d68a chore(driver-test-support): update dependency chai to v6.2.1 (#21712)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-13 00:43:36 +00:00
renovate[bot] e357a55ebc chore(deps): update dependency @types/node to v24.10.1 (#21711)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 18:07:03 +00:00
renovate[bot] 1dff1300e6 chore(docutils): update dependency mkdocs-material to v9.7.0 (#21710)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 04:33:06 +00:00
Jonathan Lipps 6fec1bfbeb chore: publish
- appium@3.1.1
 - @appium/base-driver@10.1.1
 - @appium/base-plugin@3.0.4
 - @appium/docutils@2.1.2
 - @appium/driver-test-support@1.0.4
 - @appium/eslint-config-appium-ts@2.0.4
 - @appium/fake-plugin@4.0.4
 - @appium/images-plugin@4.0.3
 - @appium/opencv@4.0.3
 - @appium/plugin-test-support@1.0.3
 - @appium/storage-plugin@1.0.3
 - @appium/support@7.0.3
 - @appium/test-support@4.0.3
 - @appium/types@1.1.1
 - @appium/universal-xml-plugin@2.0.2
2025-11-11 16:03:19 -08:00
Mykola Mokhnach fc273da0ef fix(base-driver): Use shouldUpgradeCallback for proper upgrades processing (#21706) 2025-11-11 21:42:43 +01:00
renovate[bot] f9ecc32a20 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.46.4 (#21709)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-11 16:37:46 +00:00
renovate[bot] b64862c705 chore(support): update dependency sharp to v0.34.5 (#21707)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-07 10:09:33 +02:00
renovate[bot] 85f86c562a chore(support): update dependency axios to v1.13.2 (#21704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 12:10:30 +00:00
github-actions[bot]andmykola-mokhnach 81b90b6918 docs(appium): Update documentation translations (#21702)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-11-05 19:12:39 +02:00
renovate[bot] 304e4c4a8b chore(deps): update dependency mocha to v11.7.5 (#21703)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:07:20 +00:00
Theo King 4591151515 docs(appium): Update Selenium Grid guide to address breaking changes to 4.35 relay behaviour (#21701) 2025-11-04 21:16:07 +02:00
renovate[bot] f31d2cd5d6 chore(types): update dependency type-fest to v5.2.0 (#21700)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 14:04:39 +01:00
renovate[bot] 32ace79b7f chore(eslint-config-appium-ts): update eslint-related packages (#21699)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 14:04:21 +01:00
renovate[bot] 54bfa8fc99 chore(deps): update dependency @types/node to v24.10.0 (#21697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 19:47:55 +00:00
renovate[bot] 9188336c20 chore(universal-xml-plugin): update dependency fast-xml-parser to v5.3.1 (#21696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 08:55:59 +00:00
renovate[bot] 7e5ac594d7 chore(docutils): update dependency mkdocs-material to v9.6.23 (#21695)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-02 09:50:35 +00:00
renovate[bot] 46e5dd1b62 chore(docutils): update dependency mkdocs-git-revision-date-localized-plugin to v1.5.0 (#21692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-01 12:32:16 +00:00
Mykola Mokhnach 8fdb16b3e9 ci: Sort Github stats by PR author first (#21694) 2025-11-01 12:24:14 +01:00
renovate[bot] 5650d04672 chore(eslint-config-appium-ts): update eslint-related packages to v9.39.0 (#21693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-01 09:20:58 +01:00
renovate[bot] 1d70d08d2b chore(storage-plugin): update dependency rimraf to v6.1.0 (#21690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 08:35:46 +01:00
Kazuaki Matsuo ce219fba33 docs: update a few more in payout.md
Added examples for contribution types and payment details.
2025-10-31 00:09:18 -07:00
Kazuaki Matsuo 1796cbe737 docs: update payout steps by following the new Web UI design 2025-10-30 23:54:45 -07:00
Mykola Mokhnach e72804878d ci: Tune PRs sorting logic in the Slack message (#21689) 2025-10-30 17:07:33 +01:00
Mykola Mokhnach ce68d14087 ci: Only run e2e tests for pull requests (#21688) 2025-10-30 09:24:44 +01:00
renovate[bot] 855fe5c31a chore(deps): update definitelytyped (#21676)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 09:21:47 +01:00
renovate[bot] 5f3e697ff6 chore(eslint-config-appium-ts): update dependency @eslint/compat to v1.4.1 (#21687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 09:12:24 +01:00
renovate[bot] 1f621cc190 chore(deps): update dependency @types/node to v22.18.13 (#21678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 09:12:10 +01:00
renovate[bot] e790ad7607 chore(support): update dependency axios to v1.13.1 (#21679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 09:11:52 +01:00
Mykola Mokhnach 0d5ba222d1 test: Update integration tests for compatibility with Node24 (#21685) 2025-10-30 08:59:17 +01:00
Edgars Eglītis b12a47349a fix(driver-test-support): fix test failures due to invalid syntax (#21683) 2025-10-29 15:31:59 +01:00
Mykola Mokhnach 3cac6a77e9 ci: Simplify slack table format (#21686) 2025-10-29 14:10:46 +01:00
Mykola Mokhnach fd156243a2 ci: Tune slack table formatting (#21684) 2025-10-29 13:50:24 +01:00
Mykola Mokhnach 579f1029aa ci: Fix sending messages to Slack (#21682) 2025-10-29 13:20:44 +01:00
renovate[bot] f1e747853e chore(workflows): update slackapi/slack-github-action action to v2.1.1 (#21680)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:38:09 +02:00
renovate[bot] 0888b14afd chore(workflows): update actions/setup-node action to v6 (#21681)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:35:32 +02:00
Mykola Mokhnach ac539b0d29 ci: Fail on slack errors 2025-10-29 07:34:23 +01:00
Mykola Mokhnach 6553207df6 ci: Automate Github PRs statistics retrieval (#21677) 2025-10-29 07:22:59 +01:00
Mykola Mokhnach 139a983f25 ci: Report Crowdin translation stats for each month automatically to Slack (#21649) 2025-10-28 20:50:55 +01:00
renovate[bot] b1cef7cb2d chore(support): update dependency axios to v1.13.0 (#21674)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-28 18:36:38 +00:00
renovate[bot] 25ca047314 chore(deps): update dependency @types/express to v5.0.5 (#21673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-28 11:54:48 +00:00
Mykola Mokhnach 5d62688e8b fix(support): Properly handle moving to another volume (#21672) 2025-10-26 14:30:46 +01:00
renovate[bot] 54ba877943 chore(deps): update definitelytyped (#21670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-24 12:02:04 +00:00
github-actions[bot]andmykola-mokhnach d27413081a docs(appium): Update documentation translations (#21669)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-10-23 14:43:44 +09:00
Edgars Eglītis 00db7d3325 docs: add Jarvis Appium to ecosystem docs (#21668) 2025-10-22 20:20:41 +03:00
renovate[bot] 2e5c05b404 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.46.2 (#21667)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-22 07:04:09 +00:00
renovate[bot] c6a061926a chore(deps): update definitelytyped (#21666)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-21 17:48:18 +00:00
Mykola Mokhnach 8f5aac3722 fix(appium): Inject symlinks for all installed extensions (#21664) 2025-10-20 17:36:30 +02:00
renovate[bot] d12a6a53cf chore(eslint-config-appium-ts): update eslint-related packages to v9.38.0 (#21663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-18 08:46:55 +00:00
renovate[bot] bc192cd6be chore(support): update dependency teen_process to v3.0.2 (#21661)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-17 13:28:55 +00:00
renovate[bot] 55ed37f185 chore(deps): update dependency @types/node to v22.18.11 (#21660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-17 09:06:22 +00:00
renovate[bot] d77abf141f chore(docutils): update dependency mkdocs-material to v9.6.22 (#21658)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-16 15:59:53 +00:00
renovate[bot] 791e2679c4 chore(workflows): update actions/setup-node action to v6 (#21655)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 16:22:20 +03:00
renovate[bot] 0a68b5be52 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.46.1 (#21654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 09:10:55 +00:00
renovate[bot] e075875ee3 chore(types): update dependency type-fest to v5.1.0 (#21651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 13:57:16 +00:00
renovate[bot] e6b4018866 chore(deps): update dependency @types/node to v22.18.10 (#21650)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-12 13:33:58 +00:00
renovate[bot] ce9f5cd2e2 chore(deps): update dependency @types/node to v22.18.9 (#21648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-10 09:38:26 +00:00
Jonathan Lipps c00cbfa1fb chore: publish
- appium@3.1.0
 - @appium/base-driver@10.1.0
 - @appium/base-plugin@3.0.3
 - @appium/docutils@2.1.1
 - @appium/driver-test-support@1.0.3
 - @appium/eslint-config-appium-ts@2.0.3
 - @appium/execute-driver-plugin@5.0.2
 - @appium/fake-driver@6.0.1
 - @appium/fake-plugin@4.0.3
 - @appium/images-plugin@4.0.2
 - @appium/logger@2.0.2
 - @appium/opencv@4.0.2
 - @appium/plugin-test-support@1.0.2
 - @appium/relaxed-caps-plugin@2.0.1
 - @appium/storage-plugin@1.0.2
 - @appium/support@7.0.2
 - @appium/test-support@4.0.2
 - @appium/types@1.1.0
 - @appium/universal-xml-plugin@2.0.1
2025-10-08 14:02:07 -07:00
renovate[bot] 3d57d047f3 chore(support): update dependency semver to v7.7.3 (#21645)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-08 10:43:30 +00:00
github-actions[bot]andmykola-mokhnach 27d7d9c29a docs(appium): Update documentation translations (#21644)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-10-08 00:21:35 -07:00
Edgars Eglītis e6635b737d fix(base-driver,relaxed-caps-plugin,types): add missing W3C caps (#21642)
* fix(base-driver,relaxed-caps-plugin,types): add missing W3C standard caps

* docs: add links to webdriver caps
2025-10-07 19:35:54 +03:00
renovate[bot] cb9b3736ac chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.46.0 (#21640)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-07 09:35:05 +00:00
Edgars Eglītis e8835c80fd chore(deps): remove @types/uuid (#21641) 2025-10-07 09:30:52 +03:00
Edgars Eglītis cb386cef85 chore(deps): remove vulnerable axios versions from lockfile (#21639) 2025-10-07 09:12:40 +03:00
Edgars Eglītis 7ccb6c2aec chore(appium): update dependency winston to v3.18.3 (#21638) 2025-10-07 09:06:17 +03:00
renovate[bot] efbdc34689 chore(universal-xml-plugin): update dependency fast-xml-parser to v5.3.0 (#21633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-05 13:41:06 +00:00
renovate[bot] 0919cad18d chore(eslint-config-appium-ts): update eslint-related packages to v9.37.0 (#21632)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-04 08:43:54 +00:00
renovate[bot] 0049513230 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.45.0 (#21629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-03 16:52:16 +00:00
renovate[bot] 9ce33f70c6 chore(deps): update dependency cross-env to v10.1.0 (#21628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-03 12:26:16 +00:00
renovate[bot] debf2ef757 chore(docutils): update dependency mkdocs-material to v9.6.21 (#21627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-02 18:35:49 +00:00
renovate[bot] 012525cd18 chore(deps): update dependency typescript to v5.9.3 (#21626)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-02 13:12:46 +00:00
renovate[bot] 6f9effcd5a chore(deps): update dependency mocha to v11.7.4 (#21623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-02 04:49:49 +00:00
github-actions[bot]andmykola-mokhnach 60aaf8019c docs(appium): Update documentation translations (#21625)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-10-01 18:41:44 -07:00
renovate[bot] f1bfcb3002 chore(deps): update dependency @types/node to v22.18.8 (#21622)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 21:01:34 +00:00
dependabot[bot] b836010d06 chore(deps): bump tar-fs in the npm_and_yarn group across 1 directory (#21608)
Bumps the npm_and_yarn group with 1 update in the / directory: [tar-fs](https://github.com/mafintosh/tar-fs).


Updates `tar-fs` from 3.0.9 to 3.1.1
- [Commits](https://github.com/mafintosh/tar-fs/compare/v3.0.9...v3.1.1)

---
updated-dependencies:
- dependency-name: tar-fs
  dependency-version: 3.1.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-01 12:47:39 +03:00
github-actions[bot]andmykola-mokhnach 5568749990 docs(appium): Update documentation translations (#21621)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-10-01 12:46:15 +03:00
renovate[bot]andKazuaki Matsuo dd01c57da6 chore(deps): update dependency lerna to v9 (#21603)
* chore(deps): update dependency lerna to v9

* run lerna repair

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Kazuaki Matsuo <fly.49.89.over@gmail.com>
2025-09-30 19:14:52 -07:00
renovate[bot] 3096f47fd0 chore(deps): update dependency @types/node to v22.18.7 (#21618)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-30 12:28:36 +00:00
github-actions[bot]andmykola-mokhnach 938b1088b2 docs(appium): Update documentation translations (#21617)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-09-29 21:42:42 -07:00
renovate[bot] 1c7e36c297 chore(execute-driver-plugin): update dependency webdriverio to v9.20.0 (#21615)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-28 12:30:25 +00:00
renovate[bot] 5f45defd7a chore(driver-test-support): update dependency chai to v6.2.0 (#21614)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-28 09:27:23 +00:00
Kazuaki Matsuo dad07575c9 fix(appium): fix base path handling in bidi (#21611)
* fix bidi with base path

* run test with custom base path
2025-09-27 00:04:32 -07:00
renovate[bot] c403768a41 chore(storage-plugin): update dependency lru-cache to v11.2.2 (#21606)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-24 14:14:17 +02:00
renovate[bot] 3a9739365b chore(eslint-config-appium-ts): update eslint-related packages (#21602)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-23 10:12:28 +00:00
renovate[bot] 280e2ec792 chore(eslint-config-appium-ts): update eslint-related packages to v9.36.0 (#21601)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-20 08:09:13 +02:00
renovate[bot] 2f069ae351 chore(types): update dependency type-fest to v5.0.1 (#21600)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-19 13:31:35 +00:00
renovate[bot] 4ef43e8348 chore(deps): update dependency @types/uuid to v11 (#21599)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-18 16:04:09 +02:00
renovate[bot]andMykola Mokhnach 3624635393 chore(types): update dependency type-fest to v5 (#21587)
* chore(types): update dependency type-fest to v5

* update types

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Mykola Mokhnach <mokhnach@gmail.com>
2025-09-18 08:44:17 +02:00
renovate[bot] 560ddce517 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.44.0 (#21598)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-18 08:21:24 +02:00
renovate[bot] f0b2cbfaf2 chore(support): update dependency sharp to v0.34.4 (#21597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-18 08:21:11 +02:00
renovate[bot] dd96fc9e5b chore(docutils): update dependency mkdocs-material to v9.6.20 (#21596)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-18 06:08:37 +00:00
renovate[bot] 218bbaeea4 chore(deps): update dependency @types/node to v22.18.6 (#21595)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-18 08:05:46 +02:00
renovate[bot] bfe008671f chore(deps): update dependency lerna to v8.2.4 (#21593)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 17:40:03 +00:00
renovate[bot] 0f40a20517 chore(deps): update dependency @types/node to v22.18.5 (#21592)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 13:11:48 +00:00
🚀 Erdinç Yılmaz 24bd9eeb1f chore(appium,fake-driver,support): updates tests and docstring (#21541)
* fix: remove trailing comma in tsconfig.json

* docs: enhance JSDoc documentation and clean up outdated TODO comments

* chore: tweak the type

* chore: keep the version comparison
2025-09-16 21:22:37 -07:00
renovate[bot] 1c3891b3d6 chore(support): update dependency axios to v1.12.2 (#21588)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 19:46:29 +00:00
renovate[bot] 1cc1619c79 chore(deps): update dependency @types/node to v22.18.3 (#21586)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-14 14:00:33 +00:00
Noritaka Kobayashi 9f8b55e7ab chore: fix typos (#21585) 2025-09-13 17:14:42 -07:00
renovate[bot] 34665dbe77 chore(support): update dependency axios to v1.12.1 (#21580)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-13 15:55:01 +03:00
github-actions[bot]andmykola-mokhnach 1fc22d25f9 docs(appium): Update documentation translations (#21583)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-09-12 21:50:10 -07:00
Edgars Eglītis 7f906fcf9a feat: add 21 WebDriver extension endpoints (#21577)
* chore: add reference links to extensions

* feat: add permissions and reporting API endpoints

* feat: add device posture API endpoints

* feat: add generic sensor API endpoints

* docs: fix protocol order

* feat: add custom handlers API endpoint

* feat: add SPC API endpoint

* feat: add compute pressure API endpoints

* feat: add FedCM API endpoints

* chore: formatting & test hash fix

* docs: add protocol-enabling capabilities where possible

* docs: adjust wording + fix anchors

* docs: fix FedCM HTTP methods
2025-09-12 08:40:10 +03:00
github-actions[bot]andmykola-mokhnach c1ef362a89 docs(appium): Update documentation translations (#21579)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2025-09-11 19:08:57 -07:00
Edgars Eglītis 1753dcd5e9 feat: add inspector to plugins installed via appium setup (#21578) 2025-09-11 18:54:37 +03:00
Edgars Eglītis cbea4f2e97 feat: add W3C printPage endpoint (#21576) 2025-09-11 08:49:07 +03:00
Edgars Eglītis e2d076c5dc chore: reorder routes.js to match docs (#21568) 2025-09-10 20:21:46 +03:00
171 changed files with 11763 additions and 5830 deletions
+41
View File
@@ -0,0 +1,41 @@
name: Setup Node, Install, Build
description: |
Common setup for Appium CI jobs: checkout, setup Node, install deps, optional build, optional V8 cache clear.
inputs:
node-version:
description: Node.js version to setup
required: true
install-command:
description: npm install command
required: false
default: npm ci --foreground-scripts
run-build:
description: Whether to run npm run build
required: false
default: 'true'
runs:
using: composite
steps:
- name: Use Node.js ${{ inputs.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node-version }}
cache: npm
- name: SocketDev Security Check
uses: SocketDev/action@v1
with:
mode: firewall-free
- name: Install dependencies
shell: bash
run: |
# Replace npm with sfw npm in the install command
install_cmd="${{ inputs.install-command }}"
install_cmd="${install_cmd//npm /sfw npm }"
$install_cmd
- name: Build packages
if: ${{ inputs.run-build == 'true' }}
shell: bash
run: npm run build
+122 -30
View File
@@ -3,7 +3,6 @@ on:
push:
branches:
- master
- appium3
# this list of paths could potentially impact the build
paths:
- '**/tsconfig*.json'
@@ -25,7 +24,6 @@ on:
pull_request:
branches:
- master
- appium3
paths:
- '**/tsconfig*.json'
- 'packages/base-driver/static/**/*'
@@ -52,56 +50,150 @@ permissions:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
prepare_matrix:
uses: appium/appium-workflows/.github/workflows/node-lts-matrix.yml@main
prepare_e2e_packages:
runs-on: ubuntu-latest
outputs:
versions: ${{ steps.generate-matrix.outputs.lts }}
packages: ${{ steps.discover-packages.outputs.packages }}
steps:
- name: Select all current LTS versions of Node.js
id: generate-matrix
uses: msimerson/node-lts-versions@v1
- uses: actions/checkout@v6
- name: Discover packages with e2e tests
id: discover-packages
run: |
packages=()
for package_dir in packages/*/; do
package_json="${package_dir}package.json"
if [[ -f "$package_json" ]]; then
# Check if package.json has test:e2e script and it's not a no-op
has_e2e=$(node -e "
try {
const pkg = require('./$package_json');
const script = pkg.scripts && pkg.scripts['test:e2e'];
if (script && !script.includes('echo') && !script.includes('No e2e tests')) {
console.log('true');
}
} catch(e) {
// Ignore errors
}
")
if [[ "$has_e2e" == "true" ]]; then
# Use the directory path without packages/ prefix (remove trailing slash)
package_name="${package_dir%/}"
package_name="${package_name#packages/}"
packages+=("$package_name")
fi
fi
done
# Convert array to JSON array for GitHub Actions matrix
if [[ ${#packages[@]} -eq 0 ]]; then
echo "No packages with e2e tests found"
packages_json="[]"
else
# Use jq to create a compact single-line JSON array
packages_json=$(printf '%s\n' "${packages[@]}" | jq -R '.' | jq -s '.' | jq -c '.')
fi
echo "packages=$packages_json" >> $GITHUB_OUTPUT
echo "Found packages with e2e tests:"
echo "$packages_json" | jq -r '.[]' | sed 's/^/ - /'
test:
test-smoke:
needs:
- prepare_matrix
name: Tests
name: Smoke Tests
strategy:
matrix:
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
os:
- ubuntu-latest
# TODO: Windows is not stable and slow to run
# - windows-latest
# TODO: Enable below envs after all tests have been verified green
# - macos-latest
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v5
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
uses: bahmutov/npm-install@v1
with:
useRollingCache: true
install-command: npm ci --foreground-scripts
- name: Run smoke, unit & E2E tests
run: npm run test:ci
run-build: 'true'
- name: Run smoke tests
run: npm run test:smoke
test-unit:
needs:
- prepare_matrix
name: Unit Tests
strategy:
matrix:
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
install-command: npm ci --foreground-scripts
run-build: 'true'
- name: Run unit tests
run: npm run test:unit
test-types:
needs:
- prepare_matrix
name: Type Tests
strategy:
matrix:
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
install-command: npm ci --foreground-scripts
run-build: 'true'
- name: Run type tests
run: npm run test:types
test-e2e:
needs:
- prepare_matrix
- prepare_e2e_packages
name: E2E Tests - ${{ matrix.package_dir }} (Node ${{ matrix.node-version }})
if: ${{ github.event_name == 'pull_request' }}
strategy:
fail-fast: false
matrix:
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
package_dir: ${{ fromJSON(needs.prepare_e2e_packages.outputs.packages) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
install-command: npm ci --foreground-scripts
run-build: 'true'
- name: Run E2E tests for ${{ matrix.package_dir }}
run: |
set -o pipefail
cd "packages/${{ matrix.package_dir }}"
npm run test:e2e
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install dependencies
uses: bahmutov/npm-install@v1
- uses: actions/checkout@v6
- name: Setup and install (no build)
uses: ./.github/actions/setup-build
with:
useRollingCache: true
node-version: lts/*
install-command: npm ci
run-build: 'false'
- name: ESLint
run: npm run lint:ci
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Cleanup
run: |
+44
View File
@@ -0,0 +1,44 @@
# Collects translation statistics from Crowdin for the last calendar month
# and posts them to Slack grouped by project, language, and translator
name: Crowdin Translation Statistics
on:
workflow_dispatch:
schedule:
# Run on the first day of each month at 9:00 AM UTC
- cron: 0 9 1 * *
jobs:
collect-stats:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- project_id_var: CROWDIN_DOCS_PROJECT_ID
project_name: appium-documentation
- project_id_var: CROWDIN_INSPECTOR_PROJECT_ID
project_name: appium-inspector
steps:
- uses: actions/checkout@v6
- name: Use Node.js LTS
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Collect Crowdin Stats for ${{ matrix.project_name }}
id: crowdin-stats
run: node ./scripts/crowdin-stats.mjs > crowdin-stats-${{ matrix.project_name }}.json
env:
CROWDIN_PROJECT_ID: ${{ vars[matrix.project_id_var] }}
CROWDIN_TOKEN: ${{ secrets.CROWDIN_DOCS_TOKEN }}
- name: Post to Slack for ${{ matrix.project_name }}
uses: slackapi/slack-github-action@v2.1.1
with:
errors: true
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload-file-path: crowdin-stats-${{ matrix.project_name }}.json
@@ -12,9 +12,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Use Node.js LTS
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: 'npm'
@@ -27,7 +29,7 @@ jobs:
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_DOCS_PROJECT_ID }}
CROWDIN_TOKEN: ${{ secrets.CROWDIN_DOCS_TOKEN }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7.0.8
uses: peter-evans/create-pull-request@v7.0.9
with:
token: ${{ github.token }}
commit-message: 'docs(appium): Update documentation translations'
@@ -15,9 +15,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Use Node.js LTS
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: 'npm'
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install Appium
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
name: Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install dependencies (Node.js)
uses: bahmutov/npm-install@v1
with:
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
env:
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
ref: master
- name: Install dependencies
@@ -0,0 +1,37 @@
# Collects GitHub contribution statistics from the Appium organization for the last calendar month
# and posts it to Slack
name: GitHub Contribution Statistics
on:
workflow_dispatch:
schedule:
# Run on the first day of each month at 09:00 AM UTC
- cron: 0 9 1 * *
jobs:
collect-contrib-stats:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Use Node.js LTS
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Collect GitHub Contribution Stats
id: github-stats
run: node ./scripts/github-contrib-stats.mjs > github-contrib-stats.json
env:
# GITHUB_TOKEN is optional - if not provided, uses unauthenticated requests (rate limited)
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Post to Slack
uses: slackapi/slack-github-action@v2.1.1
with:
errors: true
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload-file-path: github-contrib-stats.json
+4 -9
View File
@@ -4,12 +4,7 @@ on:
types: [opened, edited, synchronize, reopened]
jobs:
conventional:
name: PR Title
runs-on: ubuntu-latest
steps:
- uses: beemojs/conventional-pr-action@v3
with:
config-preset: angular
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
lint:
uses: appium/appium-workflows/.github/workflows/pr-title.yml@main
with:
config-preset: angular
+2 -2
View File
@@ -17,12 +17,12 @@ jobs:
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: |
git config user.name github-actions
git config user.email github-actions@github.com
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies (Node.js)
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
name: Check Renovate Configs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Validate Renovate Config
uses: rinchsan/renovate-config-validator@v0.2.0
with:
+2
View File
@@ -11,3 +11,5 @@ package.json
# generated
packages/types/lib/appium-config.ts
**/*.hbs
/.nx/workspace-data
+27 -20
View File
@@ -4,25 +4,32 @@ This documentation is a note for the opencollective payout.
<img width="200" alt="Screenshot 2024-09-17 at 11 04 32 PM" src="https://github.com/user-attachments/assets/5d598a46-8aa3-41e0-aadc-ce3f34b10f6b">
2. Select `Invoice`
3. Type proper account name in `Who is being paid for this expense?`
- The form depends on the target user
4. Select `Next`
5. Input expense info and complete the form. Then, the user will receive the expense info.
2. Select `Appium` in `Who is paying`
3. Select `Invite someone` and fill in a user name to pay payouts for
4. Select `Invoice` for `Select the type of expense`
5. Check the `I have read and understood the instructions and conditions` agreement
6. Select `No, generate an invoice for me`
- Keep blank for the `Additional invoice information (optional)`
8. Fill in the description in the `Item Description`, date and amount for `Expense Items`
- for TCs:
- `<year-month> contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`
- i.e. `2024-07 contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`
- for individuals
- `PR contribution: <PRs>` for PRs. `Community contribution in Q&A forum at https://discuss.appium.io/` for appium forums
- E.g.
- `PR contribution: https://github.com/appium/dotnet-client/pull/810, https://github.com/appium/dotnet-client/pull/808`
- `PR contribution: https://github.com/appium/java-client/pull/2206, https://github.com/appium/java-client/pull/2203 and a few PRs`
- `Community contribution in Q&A forum at https://discuss.appium.io/`
- Translations
- e.g.
- `Translation contributions for https://crowdin.com/project/appium-documentation`
- For Date
- today
- For Amount
- Put the payment amount in USD
9. Fill in title in `Title` in `Additional details`
- Expense title: `<year-month> contribution payout`
- e.g. `2024-07 contribution payout`
- Description in "Set invoice details"
- for TCs:
- `<year-month> contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`
- i.e. `2024-07 contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`
- for individuals
- `PR contribution: <PRs>` for PRs. `Community contribution in Q&A forum at https://discuss.appium.io/` for appium forums
- E.g.
- `PR contribution: https://github.com/appium/dotnet-client/pull/810, https://github.com/appium/dotnet-client/pull/808`
- `PR contribution: https://github.com/appium/java-client/pull/2206, https://github.com/appium/java-client/pull/2203 and a few PRs`
- `Community contribution in Q&A forum at https://discuss.appium.io/`
- Amount
- Type the amount in `USD`
6. Approve each expense after getting response for each expense
<img width="500" alt="Screenshot 2024-09-11 at 8 40 35 PM" src="https://github.com/user-attachments/assets/462cda69-1ce7-458c-b319-dda87cf10d65">
10. Submit expense
11. Update the expense url in our payout sheet
12. Approve each expense after getting a response for each expense
+6475 -4167
View File
File diff suppressed because it is too large Load Diff
+22 -23
View File
@@ -85,75 +85,74 @@
},
"devDependencies": {
"@colors/colors": "1.6.0",
"@eslint/js": "9.35.0",
"@tsconfig/node20": "20.1.6",
"@eslint/js": "9.39.1",
"@tsconfig/node20": "20.1.8",
"@types/argparse": "2.0.17",
"@types/archiver": "6.0.3",
"@types/archiver": "7.0.0",
"@types/async-lock": "1.4.2",
"@types/base64-stream": "1.0.5",
"@types/bluebird": "3.5.42",
"@types/chai": "5.2.2",
"@types/chai": "5.2.3",
"@types/chai-as-promised": "8.0.2",
"@types/express": "5.0.3",
"@types/express": "5.0.6",
"@types/jsftp": "2.1.5",
"@types/json-schema": "7.0.15",
"@types/klaw": "3.0.7",
"@types/lockfile": "1.0.4",
"@types/lodash": "4.17.20",
"@types/lodash": "4.17.21",
"@types/method-override": "3.0.0",
"@types/mocha": "10.0.10",
"@types/mv": "2.1.4",
"@types/ncp": "2.0.8",
"@types/node": "22.18.1",
"@types/node": "24.10.1",
"@types/pluralize": "0.0.33",
"@types/semver": "7.7.1",
"@types/serve-favicon": "2.5.7",
"@types/shell-quote": "1.7.5",
"@types/sinon": "17.0.4",
"@types/sinon": "21.0.0",
"@types/sinon-chai": "4.0.0",
"@types/source-map-support": "0.5.10",
"@types/supports-color": "8.1.3",
"@types/teen_process": "2.0.4",
"@types/uuid": "10.0.0",
"@types/which": "3.0.4",
"@types/wrap-ansi": "3.0.0",
"@types/ws": "8.18.1",
"@types/xmldom": "0.1.34",
"@types/yargs": "17.0.33",
"@types/yargs": "17.0.35",
"asyncbox": "3.0.0",
"chai": "6.0.1",
"chai": "6.2.1",
"chai-as-promised": "8.0.2",
"conventional-changelog-conventionalcommits": "7.0.2",
"cpy-cli": "6.0.0",
"cross-env": "10.0.0",
"eslint": "9.35.0",
"cross-env": "10.1.0",
"eslint": "9.39.1",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-typescript": "4.4.4",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-mocha": "10.5.0",
"eslint-plugin-mocha": "11.2.0",
"eslint-plugin-promise": "7.2.1",
"finalhandler": "2.1.0",
"finalhandler": "2.1.1",
"get-port": "5.1.1",
"json-schema-to-typescript": "15.0.4",
"lerna": "8.2.3",
"lerna": "9.0.3",
"log-symbols": "4.1.0",
"midnight-smoker": "8.0.0",
"mjpeg-consumer": "2.0.0",
"mjpeg-server": "0.3.1",
"mocha": "11.7.2",
"mocha": "11.7.5",
"npm-run-all2": "8.0.4",
"prettier": "3.6.2",
"prettier": "3.7.4",
"rewiremock": "3.14.6",
"rimraf": "6.0.1",
"rimraf": "6.1.2",
"serve-static": "2.2.0",
"sinon": "21.0.0",
"sync-monorepo-packages": "1.0.2",
"teen_process": "3.0.1",
"teen_process": "3.0.4",
"ts-node": "10.9.2",
"tsd": "0.33.0",
"typescript": "5.9.2",
"typescript-eslint": "8.43.0",
"webdriverio": "9.19.2",
"typescript": "5.9.3",
"typescript-eslint": "8.48.1",
"webdriverio": "9.21.0",
"ws": "8.18.3",
"yaml-js": "0.3.1"
},
+33
View File
@@ -3,6 +3,39 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.1.2](https://github.com/appium/appium/compare/appium@3.1.1...appium@3.1.2) (2025-12-04)
**Note:** Version bump only for package appium
## [3.1.1](https://github.com/appium/appium/compare/appium@3.1.0...appium@3.1.1) (2025-11-12)
### Bug Fixes
* **appium:** Inject symlinks for all installed extensions ([#21664](https://github.com/appium/appium/issues/21664)) ([8f5aac3](https://github.com/appium/appium/commit/8f5aac3722c9572d61f7e6bef20fe43bb14e0674))
## [3.1.0](https://github.com/appium/appium/compare/appium@3.0.2...appium@3.1.0) (2025-10-08)
### Features
* add 21 WebDriver extension endpoints ([#21577](https://github.com/appium/appium/issues/21577)) ([7f906fc](https://github.com/appium/appium/commit/7f906fcf9a0dd84f348b0b3a79da818281f21835))
* add inspector to plugins installed via `appium setup` ([#21578](https://github.com/appium/appium/issues/21578)) ([1753dcd](https://github.com/appium/appium/commit/1753dcd5e9f4ee3a9bd869f2e846a8a1c68b6970))
* add W3C printPage endpoint ([#21576](https://github.com/appium/appium/issues/21576)) ([cbea4f2](https://github.com/appium/appium/commit/cbea4f2e97d2d291bd67fd98359b37caab1b21fa))
### Bug Fixes
* **appium:** fix base path handling in bidi ([#21611](https://github.com/appium/appium/issues/21611)) ([dad0757](https://github.com/appium/appium/commit/dad07575c9d754751160a53e0fb8053bbddac75b))
## [3.0.2](https://github.com/appium/appium/compare/appium@3.0.1...appium@3.0.2) (2025-09-09)
@@ -0,0 +1,36 @@
---
authors:
- sai
- srini
date: 2025-11-25
---
# Announcing LambdaTest as Appium's Newest Development Partner
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
<!-- more -->
<div style="text-align:center;width:100%">
<a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
</a>
</div>
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
About LambdaTest
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
@@ -55,3 +55,29 @@ Supported by: `@AppiumTestDistribution`
```sh title="Install This Tool"
npm install -g appium-installer
```
### [Jarvis Appium](https://github.com/AppiumTestDistribution/mcp-appium)
Jarvis Appium is a Model Context Protocol (MCP) server that provides mobile test development and
automation capabilities using Appium.
Supported by: `@AppiumTestDistribution`
```json title="Install This Tool"
// Add the following to your MCP client configuration
{
"mcpServers": {
"jarvis-appium": {
"disabled": false,
"timeout": 100,
"type": "stdio",
"command": "npx",
"args": ["jarvis-appium"],
"env": {
"ANDROID_HOME": "/path/to/android/sdk",
"CAPABILITIES_CONFIG": "/path/to/your/capabilities.json"
}
}
}
}
```
+20 -8
View File
@@ -22,9 +22,11 @@ server:
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8100
mjpegServerPort: 9100
mjpegScreenshotUrl: "http://localhost:9100"
appium:wdaLocalPort: 8100
appium:mjpegServerPort: 9100
appium:mjpegScreenshotUrl: "http://localhost:9100"
appium:platformVersion: "26.0"
appium:deviceName: "iPhone 17"
```
In the above YAML config file, we specify the Appium server port, the driver used, and parameters
@@ -39,9 +41,11 @@ server:
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8110
mjpegServerPort: 9110
mjpegScreenshotUrl: "http://localhost:9110"
appium:wdaLocalPort: 8110
appium:mjpegServerPort: 9110
appium:mjpegScreenshotUrl: "http://localhost:9110"
appium:platformVersion: "26.0"
appium:deviceName: "iPhone 16"
```
### Define the Grid node configs
@@ -60,11 +64,15 @@ port = 5555
[node]
detect-drivers = false
[events]
publish = "tcp://HUB_IP_ADDRESS:4442"
subscribe = "tcp://HUB_IP_ADDRESS:4443"
[relay]
url = "http://localhost:4723"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 13\", \"appium:automationName\": \"XCUITest\"}"
"1", "{\"platformName\": \"iOS\", \"appium:automationName\": \"XCUITest\"}"
]
```
@@ -76,11 +84,15 @@ port = 5565
[node]
detect-drivers = false
[events]
publish = "tcp://HUB_IP_ADDRESS:4442"
subscribe = "tcp://HUB_IP_ADDRESS:4443"
[relay]
url = "http://localhost:4733"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 12\", \"appium:automationName\": \"XCUITest\"}"
"1", "{\"platformName\": \"iOS\", \"appium:automationName\": \"XCUITest\"}"
]
```
+19 -13
View File
@@ -4,7 +4,7 @@ title: Appium Server Security
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
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
all the following are true:
- You're running your own Appium server locally or within a protected internal network
@@ -12,18 +12,18 @@ all the following are true:
- 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.
team puts many features behind a security protection mechanism, which forces system admins (the
people who 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.
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](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
Appium when starting it from the command line:
Appium, when starting it from the command line:
|<div style="width:10em">Parameter</div>|Description|
|---------------------------------------|-----------|
@@ -44,7 +44,7 @@ to the `bar` feature for all drivers.
## Insecure Features
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
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:
@@ -53,10 +53,10 @@ might use. Here is an incomplete list of examples from some of Appium's official
|`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|
|`execute_driver_script`| Allows sending a request that has multiple Appium commands.|Execute Driver Plugin|
Some insecure features operate on the server level, and do not require a driver session. Enabling
these features requires using the wildcard prefix:
Some insecure features operate on the server level and do not require a driver session. Enabling
these features require using the wildcard prefix:
|<div style="width:12em">Feature Name</div>|Description|
|------------|-----------|
@@ -73,17 +73,23 @@ appium --allow-insecure=first:foo
Turn on the `foo` feature for all drivers:
```bash
appium --allow-insecure=*:foo
appium --allow-insecure='*:foo'
```
Turn on the `foo` feature for all drivers _except_ `first`:
```bash
appium --allow-insecure=*:foo --deny-insecure=first:foo
appium --allow-insecure='*:foo' --deny-insecure=first:foo
```
Turn on all features _except_ `foo` for all drivers:
```bash
appium --relaxed-security --deny-insecure=*:foo
appium --relaxed-security --deny-insecure='*:foo'
```
Turn on multiple insecure features for specific drivers:
```bash
appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs
```
@@ -7,8 +7,8 @@ title: Appium Protocol
}
</style>
The following is a list of endpoints used in Appium that are defined in the Appium extension of the
W3C WebDriver protocol.
The following is a list of endpoints supported in Appium, that are defined in the Appium extension
of the W3C WebDriver protocol.
### getAppiumSessions
@@ -8,7 +8,7 @@ title: JSON Wire Protocol
</style>
The following is a list of legacy [JSON Wire Protocol (JSONWP)](https://www.selenium.dev/documentation/legacy/json_wire_protocol/)
endpoints used in Appium.
endpoints supported in Appium.
### getSession
@@ -8,7 +8,7 @@ title: Mobile JSON Wire Protocol
</style>
The following is a list of legacy [Mobile JSON Wire Protocol (MJSONWP)](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)
endpoints used in Appium.
endpoints supported in Appium.
### getRotation
+439 -2
View File
@@ -7,7 +7,7 @@ title: Other Protocols
}
</style>
The following is a list of endpoints used in Appium that are defined in other protocols.
The following is a list of endpoints supported in Appium that are defined in other protocols.
## Chromedriver Protocol
@@ -40,6 +40,441 @@ for a list of available methods and their parameters.
`any` - the result of executing the CDP method
## Compute Pressure Protocol
The [Compute Pressure protocol](https://www.w3.org/TR/compute-pressure/) is an extension of the W3C
WebDriver protocol.
### createVirtualPressureSource
```
POST /session/:sessionId/pressuresource
```
> Compute Pressure documentation: [Create Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#create-virtual-pressure-source)
Creates a new virtual pressure source.
#### Parameters
|<div style="width:6em">Name</div>|Description|Type|Default|
|--|--|--|--|
|`type`|Type of pressure source to create|string||
|`supported?`|Whether the pressure source should be configured as supported|boolean|`true`|
#### Response
`null`
### updateVirtualPressureSource
```
POST /session/:sessionId/pressuresource/:pressureSourceType
```
> Compute Pressure documentation: [Update Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#update-virtual-pressure-source)
Updates the state of a virtual pressure source with the type identified by `:pressureSourceType`.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`sample`|Pressure state. Supported values are `nominal`, `fair`, `serious`, or `critical`.|string|
#### Response
`null`
### deleteVirtualPressureSource
```
DELETE /session/:sessionId/pressuresource/:pressureSourceType
```
> Compute Pressure documentation: [Delete Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#delete-virtual-pressure-source)
Deletes the virtual pressure source with the type identified by `:pressureSourceType`.
#### Response
`null`
## Custom Handlers Protocol
The [Custom Handlers protocol](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)
is an extension of the W3C WebDriver protocol, defined by the HTML Standard specification.
### setRPHRegistrationMode
```
POST /session/:sessionId/custom-handlers/set-mode
```
> Custom Handlers documentation: [Set RPH Registration Mode](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)
Sets the protocol handler automation mode, for processing registrations of custom protocol handlers.
By default, this mode is set to `none`.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`mode`|Automation mode to set. Supported values are `autoAccept`, `autoReject`, or `none`.|string|
#### Response
`null`
## Device Posture Protocol
The [Device Posture protocol](https://www.w3.org/TR/device-posture/) is an extension of the W3C
WebDriver protocol.
### setDevicePosture
```
POST /session/:sessionId/deviceposture
```
> Device Posture documentation: [Set Device Posture](https://www.w3.org/TR/device-posture/#set-device-posture)
Sets the device posture, overriding the posture set by the device hardware.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`posture`|Posture to which the device should be set. Supported values are `continuous` or `folded`.|string|
#### Response
`null`
### clearDevicePosture
```
DELETE /session/:sessionId/deviceposture
```
> Device Posture documentation: [Clear Device Posture](https://www.w3.org/TR/device-posture/#clear-device-posture)
Clears the previously set device posture, returning posture control back to the device hardware.
#### Response
`null`
## Federated Credential Management Protocol
The [Federated Credential Management protocol](https://www.w3.org/TR/fedcm-1) (FedCM) is an
extension of the W3C WebDriver protocol. Clients can enable this protocol by using the
[`fedcm:accounts`](https://www.w3.org/TR/fedcm-1/#webdriver-capability) capability.
### fedCMCancelDialog
```
POST /session/:sessionId/fedcm/canceldialog
```
> FedCM documentation: [Cancel Dialog](https://www.w3.org/TR/fedcm-1/#webdriver-canceldialog)
Cancels the currently open FedCM dialog.
#### Response
`null`
### fedCMSelectAccount
```
POST /session/:sessionId/fedcm/selectaccount
```
> FedCM documentation: [Select Account](https://www.w3.org/TR/fedcm-1/#webdriver-selectaccount)
Selects an account to use for the currently open FedCM dialog.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`accountIndex`|Index of the account in the list of available accounts|number|
#### Response
`null`
### fedCMClickDialogButton
```
POST /session/:sessionId/fedcm/clickdialogbutton
```
> FedCM documentation: [Click Dialog Button](https://www.w3.org/TR/fedcm-1/#webdriver-clickdialogbutton)
Clicks a button in the currently open FedCM dialog.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`dialogButton`|Identifier of the button to click. Must be set to `ConfirmIdpLoginContinue`.|string|
#### Response
`null`
### fedCMGetAccounts
```
GET /session/:sessionId/fedcm/accountlist
```
> FedCM documentation: [Account List](https://www.w3.org/TR/fedcm-1/#webdriver-accountlist)
Retrieves all accounts that the user can select in the currently open FedCM dialog.
#### Response
`FedCMAccount[]` - an array of objects, where each object includes the following properties:
|<div style="width:10em">Name</div>|Description|Type|
|--|--|--|
|`accountId`|Account ID|string|
|`email`|Account email|string|
|`name`|Account name|string|
|`givenName?`|Account given name|string|
|`pictureUrl?`|Account picture URL|string|
|`idpConfigUrl`|URL of the identity provider configuration file|string|
|`loginState`|Login state. Set to `SignUp` if the account is not connected, otherwise `SignIn`.|string|
|`termsOfServiceUrl?`|Terms of Service URL of the website, if `loginState` is set to `SignUp`|string|
|`privacyPolicyUrl?`|Privacy Policy URL of the website, if `loginState` is set to `SignUp`|string|
### fedCMGetTitle
```
GET /session/:sessionId/fedcm/gettitle
```
> FedCM documentation: [Get Title](https://www.w3.org/TR/fedcm-1/#webdriver-gettitle)
Retrieves the title and subtitle (if one exists) of the currently open FedCM dialog.
#### Response
`FedCMDialogTitle` - an object with the following properties:
|Name|Description|Type|
|--|--|--|
|`title`|Dialog title|string|
|`subtitle?`|Dialog subtitle|string|
### fedCMGetDialogType
```
GET /session/:sessionId/fedcm/getdialogtype
```
> FedCM documentation: [Get Dialog Type](https://www.w3.org/TR/fedcm-1/#webdriver-getdialogtype)
Retrieves the type of the currently open FedCM dialog.
#### Response
`string` - can be set to `AutoReauthn`, `AccountChooser`, or `ConfirmIdpLogin`
### fedCMSetDelayEnabled
```
POST /session/:sessionId/fedcm/setdelayenabled
```
> FedCM documentation: [Set Delay Enabled](https://www.w3.org/TR/fedcm-1/#webdriver-setdelayenabled)
Sets the state of the promise rejection delay, which is used to prevent information leakage about
the logged in state of the user.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`enabled`|Whether to enable the promise rejection delay|boolean|
#### Response
`null`
### fedCMResetCooldown
```
POST /session/:sessionId/fedcm/resetcooldown
```
> FedCM documentation: [Reset Cooldown](https://www.w3.org/TR/fedcm-1/#webdriver-resetcooldown)
Resets the cooldown delay used after dismissing a FedCM dialog.
#### Response
`null`
## Generic Sensor Protocol
The [Generic Sensor protocol](https://www.w3.org/TR/generic-sensor/) is an extension of the W3C
WebDriver protocol.
### createVirtualSensor
```
POST /session/:sessionId/sensor
```
> Generic Sensor documentation: [Create Virtual Sensor](https://www.w3.org/TR/generic-sensor/#create-virtual-sensor-command)
Creates a new virtual sensor.
#### Parameters
|<div style="width:12em">Name</div>|Description|Type|Default|
|--|--|--|--|
|`type`|Type of sensor to create|string||
|`connected?`|Whether the sensor should be configured as connected|boolean|`true`|
|`maxSamplingFrequency?`|Maximum sensor sampling frequency|number||
|`minSamplingFrequency?`|Minimum sensor sampling frequency|number||
#### Response
`null`
### getVirtualSensorInfo
```
GET /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Get Virtual Sensor Information](https://www.w3.org/TR/generic-sensor/#get-virtual-sensor-information-command)
Retrieves information about the virtual sensor with the type identified by `:sensorType`.
#### Response
`GetVirtualSensorInfoResponse` - an object containing the `requestedSamplingFrequency` key, whose
value is the requested sampling frequency of the sensor type
### updateVirtualSensorReading
```
POST /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Update Virtual Sensor Reading](https://www.w3.org/TR/generic-sensor/#update-virtual-sensor-reading-command)
Updates the virtual sensor with the type identified by `:sensorType` with a new reading.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`reading`|Object containing reading properties specific to the sensor type|object|
#### Response
`null`
### deleteVirtualSensor
```
DELETE /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Delete Virtual Sensor](https://www.w3.org/TR/generic-sensor/#delete-virtual-sensor-command)
Deletes the virtual sensor with the type identified by `:sensorType`.
#### Response
`null`
## Permissions Protocol
The [Permissions protocol](https://www.w3.org/TR/permissions/) is an extension of the W3C WebDriver
protocol.
### setPermissions
```
POST /session/:sessionId/permissions
```
> Permissions documentation: [Set Permission](https://www.w3.org/TR/permissions/#webdriver-command-set-permission)
Simulates user modification of the permission state of a PermissionDescriptor (a permissible feature
with optional additional properties).
#### Parameters
|<div style="width:6em">Name</div>|Description|Type|
|--|--|--|
|`descriptor`|Object specifying the feature name in its `name` key, along with any other keys for additional properties|object|
|`state`|New permission state for this descriptor. Supported values are: `granted`, `denied`, or `prompt`.|string|
#### Response
`null`
## Reporting Protocol
The [Reporting protocol](https://www.w3.org/TR/reporting-1/) is an extension of the W3C WebDriver
protocol.
### generateTestReport
```
POST /session/:sessionId/reporting/generate_test_report
```
> Reporting documentation: [Generate Test Report](https://www.w3.org/TR/reporting-1/#generate-test-report-command)
Simulates the generation of a test report, which can be retrieved by registered reporting observers.
#### Parameters
|Name|Description|Type|Default|
|--|--|--|--|
|`message`|Message displayed in the report|string||
|`group?`|Destination group to deliver the report to|string|`default`|
#### Response
`null`
## Secure Payment Confirmation Protocol
The [Secure Payment Confirmation protocol](https://www.w3.org/TR/secure-payment-confirmation) (SPC)
is an extension of the W3C WebDriver protocol.
### setSPCTransactionMode
```
POST /session/:sessionId/secure-payment-confirmation/set-mode
```
> SPC documentation: [Set SPC Transaction Mode](https://www.w3.org/TR/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode)
Sets the transaction automation mode, for automated handling of transaction confirmation prompts.
By default, this mode is set to `none`.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`mode`|Automation mode to set. Supported values are `autoAccept`, `autoChooseToAuthAnotherWay`, `autoReject`, or `autoOptOut`.|string|
#### Response
`null`
## Selenium Protocol
The Selenium protocol is an extension of the W3C WebDriver protocol, supported in Appium clients
@@ -91,7 +526,9 @@ Retrieves the available log types that can be used to call the [`getLog`](#getlo
## Web Authentication Protocol
The [Web Authentication protocol](https://w3c.github.io/webauthn/) (WebAuthn) is an extension of
the W3C WebDriver protocol.
the W3C WebDriver protocol. Clients can enable this protocol by using the
[`webauthn:virtualAuthenticators`](https://w3c.github.io/webauthn/#sctn-automation-webdriver-capability)
capability.
### addVirtualAuthenticator
@@ -8,7 +8,7 @@ title: WebDriver Protocol
</style>
The following is a list of [W3C WebDriver protocol](https://w3c.github.io/webdriver/) endpoints
used in Appium.
supported in Appium.
!!! info
@@ -1070,3 +1070,45 @@ identified by `:elementId`.
#### Response
`string` - a base64-encoded PNG image
### printPage
```
POST /session/:sessionId/print
```
> WebDriver documentation: [Print Page](https://w3c.github.io/webdriver/#print-page)
Prints the page by rendering it as a paginated PDF document.
#### Parameters
|<div style="width:7em">Name</div>|Description|<div style="width:9em">Type</div>|Default|
|--|--|--|--|
|`orientation?`|Page orientation. Supported values are `portrait` or `landscape`.|string|`portrait`|
|`scale?`|Page scale. Supported values are in the range `[0.1, 2]`.|number|`1`|
|`background?`|Whether to include background images|boolean|`false`|
|`page?`|Object specifying the page width and height|[`PrintPageSize`](#printpagesize)|`{}`|
|`margin?`|Object specifying the page margins|[`PrintPageMargins`](#printpagemargins)|`{}`|
|`shrinkToFit?`|Whether to resize page contents to match `PrintPageSize.width`|boolean|`true`|
|`pageRanges?`|Array of pages to be printed, for example, `[1, 4, '8-9']`|array|`[]`|
##### `PrintPageSize`
|Name|Description|Type|Default|
|--|--|--|--|
|`width?`|Page width. Must be greater than or equal to `(2.54 / 72)`.|number|`21.59`|
|`height?`|Page height. Must be greater than or equal to `(2.54 / 72)`.|number|`27.94`|
##### `PrintPageMargins`
|Name|Description|Type|Default|
|--|--|--|--|
|`top?`|Page top margin. Must be greater than or equal to `0`.|number|`1`|
|`bottom?`|Page bottom margin. Must be greater than or equal to `0`.|number|`1`|
|`left?`|Page left margin. Must be greater than or equal to `0`.|number|`1`|
|`right?`|Page right margin. Must be greater than or equal to `0`.|number|`1`|
#### Response
`string` - a base64-encoded PDF document
@@ -20,7 +20,7 @@ mentioned below.
Installs the following extensions for browser webview testing:
* Drivers: `safari`[^1], `gecko`, `chromium`
* Plugins: `images`
* Plugins: `images`, `inspector`
#### Usage
@@ -33,7 +33,7 @@ appium setup browser
Installs the following extensions for desktop application testing:
* Drivers: `mac2`[^1], `windows`[^2]
* Plugins: `images`
* Plugins: `images`, `inspector`
#### Usage
@@ -46,7 +46,7 @@ appium setup desktop
Installs the following extensions for mobile testing:
* Drivers: `uiautomator2`, `xcuitest`[^1], `espresso`
* Plugins: `images`
* Plugins: `images`, `inspector`
#### Usage
@@ -0,0 +1,34 @@
---
authors:
- sai
- srini
date: 2025-11-25
---
# Announcing LambdaTest as Appium's Newest Development Partner
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
<!-- more -->
<div style="text-align:center;width:100%"><a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
</a>
</div>
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
About LambdaTest
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
@@ -59,3 +59,29 @@ Supported by: `@AppiumTestDistribution`
```sh title="Install This Tool"
npm install -g appium-installer
```
### [Jarvis Appium](https://github.com/AppiumTestDistribution/mcp-appium)
Jarvis Appium is a Model Context Protocol (MCP) server that provides mobile test development and
automation capabilities using Appium.
Supported by: `@AppiumTestDistribution`
```json title="Install This Tool"
// Add the following to your MCP client configuration
{
"mcpServers": {
"jarvis-appium": {
"disabled": false,
"timeout": 100,
"type": "stdio",
"command": "npx",
"args": ["jarvis-appium"],
"env": {
"ANDROID_HOME": "/path/to/android/sdk",
"CAPABILITIES_CONFIG": "/path/to/your/capabilities.json"
}
}
}
}
```
+20 -8
View File
@@ -22,9 +22,11 @@ server:
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8100
mjpegServerPort: 9100
mjpegScreenshotUrl: "http://localhost:9100"
appium:wdaLocalPort: 8100
appium:mjpegServerPort: 9100
appium:mjpegScreenshotUrl: "http://localhost:9100"
appium:platformVersion: "26.0"
appium:deviceName: "iPhone 17"
```
In the above YAML config file, we specify the Appium server port, the driver used, and parameters
@@ -39,9 +41,11 @@ server:
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8110
mjpegServerPort: 9110
mjpegScreenshotUrl: "http://localhost:9110"
appium:wdaLocalPort: 8110
appium:mjpegServerPort: 9110
appium:mjpegScreenshotUrl: "http://localhost:9110"
appium:platformVersion: "26.0"
appium:deviceName: "iPhone 16"
```
### Define the Grid node configs
@@ -60,11 +64,15 @@ port = 5555
[node]
detect-drivers = false
[events]
publish = "tcp://HUB_IP_ADDRESS:4442"
subscribe = "tcp://HUB_IP_ADDRESS:4443"
[relay]
url = "http://localhost:4723"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 13\", \"appium:automationName\": \"XCUITest\"}"
"1", "{\"platformName\": \"iOS\", \"appium:automationName\": \"XCUITest\"}"
]
```
@@ -76,11 +84,15 @@ port = 5565
[node]
detect-drivers = false
[events]
publish = "tcp://HUB_IP_ADDRESS:4442"
subscribe = "tcp://HUB_IP_ADDRESS:4443"
[relay]
url = "http://localhost:4733"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 12\", \"appium:automationName\": \"XCUITest\"}"
"1", "{\"platformName\": \"iOS\", \"appium:automationName\": \"XCUITest\"}"
]
```
+19 -13
View File
@@ -4,7 +4,7 @@ title: Appium Server Security
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
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
all the following are true:
- You're running your own Appium server locally or within a protected internal network
@@ -12,18 +12,18 @@ all the following are true:
- 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.
team puts many features behind a security protection mechanism, which forces system admins (the
people who 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.)
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.
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](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
Appium when starting it from the command line:
Appium, when starting it from the command line:
| <div style="width:10em">Parameter</div> | Description |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -44,7 +44,7 @@ to the `bar` feature for all drivers.
## Insecure Features
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
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:
@@ -53,10 +53,10 @@ might use. Here is an incomplete list of examples from some of Appium's official
| `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 |
| `execute_driver_script` | Allows sending a request that has multiple Appium commands. | Execute Driver Plugin |
Some insecure features operate on the server level, and do not require a driver session. Enabling
these features requires using the wildcard prefix:
Some insecure features operate on the server level and do not require a driver session. Enabling
these features require using the wildcard prefix:
| <div style="width:12em">Feature Name</div> | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------- |
@@ -73,17 +73,23 @@ appium --allow-insecure=first:foo
Turn on the `foo` feature for all drivers:
```bash
appium --allow-insecure=*:foo
appium --allow-insecure='*:foo'
```
Turn on the `foo` feature for all drivers _except_ `first`:
```bash
appium --allow-insecure=*:foo --deny-insecure=first:foo
appium --allow-insecure='*:foo' --deny-insecure=first:foo
```
Turn on all features _except_ `foo` for all drivers:
```bash
appium --relaxed-security --deny-insecure=*:foo
appium --relaxed-security --deny-insecure='*:foo'
```
Turn on multiple insecure features for specific drivers:
```bash
appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs
```
@@ -8,8 +8,8 @@ title: Appium Protocol
}
</style>
The following is a list of endpoints used in Appium that are defined in the Appium extension of the
W3C WebDriver protocol.
The following is a list of endpoints supported in Appium, that are defined in the Appium extension
of the W3C WebDriver protocol.
### getAppiumSessions
@@ -9,7 +9,7 @@ title: JSON Wire Protocol
</style>
The following is a list of legacy [JSON Wire Protocol (JSONWP)](https://www.selenium.dev/documentation/legacy/json_wire_protocol/)
endpoints used in Appium.
endpoints supported in Appium.
### getSession
@@ -9,7 +9,7 @@ title: Mobile JSON Wire Protocol
</style>
The following is a list of legacy [Mobile JSON Wire Protocol (MJSONWP)](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)
endpoints used in Appium.
endpoints supported in Appium.
### getRotation
+439 -2
View File
@@ -8,7 +8,7 @@ title: Other Protocols
}
</style>
The following is a list of endpoints used in Appium that are defined in other protocols.
The following is a list of endpoints supported in Appium that are defined in other protocols.
## Chromedriver Protocol
@@ -41,6 +41,441 @@ for a list of available methods and their parameters.
`any` - the result of executing the CDP method
## Compute Pressure Protocol
The [Compute Pressure protocol](https://www.w3.org/TR/compute-pressure/) is an extension of the W3C
WebDriver protocol.
### createVirtualPressureSource
```
POST /session/:sessionId/pressuresource
```
> Compute Pressure documentation: [Create Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#create-virtual-pressure-source)
Creates a new virtual pressure source.
#### Parameters
| <div style="width:6em">Name</div> | Description | Type | Default |
| --------------------------------- | ------------------------------------------------------------- | ------- | ------- |
| `type` | Type of pressure source to create | string | |
| `supported?` | Whether the pressure source should be configured as supported | boolean | `true` |
#### Response
`null`
### updateVirtualPressureSource
```
POST /session/:sessionId/pressuresource/:pressureSourceType
```
> Compute Pressure documentation: [Update Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#update-virtual-pressure-source)
Updates the state of a virtual pressure source with the type identified by `:pressureSourceType`.
#### Parameters
| Name | Description | Type |
| -------- | ----------------------------------------------------------------------------------------------------------------- | ------ |
| `sample` | Pressure state. Supported values are `nominal`, `fair`, `serious`, or `critical`. | string |
#### Response
`null`
### deleteVirtualPressureSource
```
DELETE /session/:sessionId/pressuresource/:pressureSourceType
```
> Compute Pressure documentation: [Delete Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#delete-virtual-pressure-source)
Deletes the virtual pressure source with the type identified by `:pressureSourceType`.
#### Response
`null`
## Custom Handlers Protocol
The [Custom Handlers protocol](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)
is an extension of the W3C WebDriver protocol, defined by the HTML Standard specification.
### setRPHRegistrationMode
```
POST /session/:sessionId/custom-handlers/set-mode
```
> Custom Handlers documentation: [Set RPH Registration Mode](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)
Sets the protocol handler automation mode, for processing registrations of custom protocol handlers.
By default, this mode is set to `none`.
#### Parameters
| Name | Description | Type |
| ------ | ------------------------------------------------------------------------------------------------------------------- | ------ |
| `mode` | Automation mode to set. Supported values are `autoAccept`, `autoReject`, or `none`. | string |
#### Response
`null`
## Device Posture Protocol
The [Device Posture protocol](https://www.w3.org/TR/device-posture/) is an extension of the W3C
WebDriver protocol.
### setDevicePosture
```
POST /session/:sessionId/deviceposture
```
> Device Posture documentation: [Set Device Posture](https://www.w3.org/TR/device-posture/#set-device-posture)
Sets the device posture, overriding the posture set by the device hardware.
#### Parameters
| Name | Description | Type |
| --------- | ------------------------------------------------------------------------------------------------------------------------- | ------ |
| `posture` | Posture to which the device should be set. Supported values are `continuous` or `folded`. | string |
#### Response
`null`
### clearDevicePosture
```
DELETE /session/:sessionId/deviceposture
```
> Device Posture documentation: [Clear Device Posture](https://www.w3.org/TR/device-posture/#clear-device-posture)
Clears the previously set device posture, returning posture control back to the device hardware.
#### Response
`null`
## Federated Credential Management Protocol
The [Federated Credential Management protocol](https://www.w3.org/TR/fedcm-1) (FedCM) is an
extension of the W3C WebDriver protocol. Clients can enable this protocol by using the
[`fedcm:accounts`](https://www.w3.org/TR/fedcm-1/#webdriver-capability) capability.
### fedCMCancelDialog
```
POST /session/:sessionId/fedcm/canceldialog
```
> FedCM documentation: [Cancel Dialog](https://www.w3.org/TR/fedcm-1/#webdriver-canceldialog)
Cancels the currently open FedCM dialog.
#### Response
`null`
### fedCMSelectAccount
```
POST /session/:sessionId/fedcm/selectaccount
```
> FedCM documentation: [Select Account](https://www.w3.org/TR/fedcm-1/#webdriver-selectaccount)
Selects an account to use for the currently open FedCM dialog.
#### Parameters
| Name | Description | Type |
| -------------- | ------------------------------------------------------ | ------ |
| `accountIndex` | Index of the account in the list of available accounts | number |
#### Response
`null`
### fedCMClickDialogButton
```
POST /session/:sessionId/fedcm/clickdialogbutton
```
> FedCM documentation: [Click Dialog Button](https://www.w3.org/TR/fedcm-1/#webdriver-clickdialogbutton)
Clicks a button in the currently open FedCM dialog.
#### Parameters
| Name | Description | Type |
| -------------- | ------------------------------------------------------------------------------------------------------------ | ------ |
| `dialogButton` | Identifier of the button to click. Must be set to `ConfirmIdpLoginContinue`. | string |
#### Response
`null`
### fedCMGetAccounts
```
GET /session/:sessionId/fedcm/accountlist
```
> FedCM documentation: [Account List](https://www.w3.org/TR/fedcm-1/#webdriver-accountlist)
Retrieves all accounts that the user can select in the currently open FedCM dialog.
#### Response
`FedCMAccount[]` - an array of objects, where each object includes the following properties:
| <div style="width:10em">Name</div> | Description | Type |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------ |
| `accountId` | Account ID | string |
| `email` | Account email | string |
| `name` | Account name | string |
| `givenName?` | Account given name | string |
| `pictureUrl?` | Account picture URL | string |
| `idpConfigUrl` | URL of the identity provider configuration file | string |
| `loginState` | Login state. Set to `SignUp` if the account is not connected, otherwise `SignIn`. | string |
| `termsOfServiceUrl?` | Terms of Service URL of the website, if `loginState` is set to `SignUp` | string |
| `privacyPolicyUrl?` | Privacy Policy URL of the website, if `loginState` is set to `SignUp` | string |
### fedCMGetTitle
```
GET /session/:sessionId/fedcm/gettitle
```
> FedCM documentation: [Get Title](https://www.w3.org/TR/fedcm-1/#webdriver-gettitle)
Retrieves the title and subtitle (if one exists) of the currently open FedCM dialog.
#### Response
`FedCMDialogTitle` - an object with the following properties:
| Name | Description | Type |
| ----------- | --------------- | ------ |
| `title` | Dialog title | string |
| `subtitle?` | Dialog subtitle | string |
### fedCMGetDialogType
```
GET /session/:sessionId/fedcm/getdialogtype
```
> FedCM documentation: [Get Dialog Type](https://www.w3.org/TR/fedcm-1/#webdriver-getdialogtype)
Retrieves the type of the currently open FedCM dialog.
#### Response
`string` - can be set to `AutoReauthn`, `AccountChooser`, or `ConfirmIdpLogin`
### fedCMSetDelayEnabled
```
POST /session/:sessionId/fedcm/setdelayenabled
```
> FedCM documentation: [Set Delay Enabled](https://www.w3.org/TR/fedcm-1/#webdriver-setdelayenabled)
Sets the state of the promise rejection delay, which is used to prevent information leakage about
the logged in state of the user.
#### Parameters
| Name | Description | Type |
| --------- | --------------------------------------------- | ------- |
| `enabled` | Whether to enable the promise rejection delay | boolean |
#### Response
`null`
### fedCMResetCooldown
```
POST /session/:sessionId/fedcm/resetcooldown
```
> FedCM documentation: [Reset Cooldown](https://www.w3.org/TR/fedcm-1/#webdriver-resetcooldown)
Resets the cooldown delay used after dismissing a FedCM dialog.
#### Response
`null`
## Generic Sensor Protocol
The [Generic Sensor protocol](https://www.w3.org/TR/generic-sensor/) is an extension of the W3C
WebDriver protocol.
### createVirtualSensor
```
POST /session/:sessionId/sensor
```
> Generic Sensor documentation: [Create Virtual Sensor](https://www.w3.org/TR/generic-sensor/#create-virtual-sensor-command)
Creates a new virtual sensor.
#### Parameters
| <div style="width:12em">Name</div> | Description | Type | Default |
| ---------------------------------- | ---------------------------------------------------- | ------- | ------- |
| `type` | Type of sensor to create | string | |
| `connected?` | Whether the sensor should be configured as connected | boolean | `true` |
| `maxSamplingFrequency?` | Maximum sensor sampling frequency | number | |
| `minSamplingFrequency?` | Minimum sensor sampling frequency | number | |
#### Response
`null`
### getVirtualSensorInfo
```
GET /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Get Virtual Sensor Information](https://www.w3.org/TR/generic-sensor/#get-virtual-sensor-information-command)
Retrieves information about the virtual sensor with the type identified by `:sensorType`.
#### Response
`GetVirtualSensorInfoResponse` - an object containing the `requestedSamplingFrequency` key, whose
value is the requested sampling frequency of the sensor type
### updateVirtualSensorReading
```
POST /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Update Virtual Sensor Reading](https://www.w3.org/TR/generic-sensor/#update-virtual-sensor-reading-command)
Updates the virtual sensor with the type identified by `:sensorType` with a new reading.
#### Parameters
| Name | Description | Type |
| --------- | ---------------------------------------------------------------- | ------ |
| `reading` | Object containing reading properties specific to the sensor type | object |
#### Response
`null`
### deleteVirtualSensor
```
DELETE /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Delete Virtual Sensor](https://www.w3.org/TR/generic-sensor/#delete-virtual-sensor-command)
Deletes the virtual sensor with the type identified by `:sensorType`.
#### Response
`null`
## Permissions Protocol
The [Permissions protocol](https://www.w3.org/TR/permissions/) is an extension of the W3C WebDriver
protocol.
### setPermissions
```
POST /session/:sessionId/permissions
```
> Permissions documentation: [Set Permission](https://www.w3.org/TR/permissions/#webdriver-command-set-permission)
Simulates user modification of the permission state of a PermissionDescriptor (a permissible feature
with optional additional properties).
#### Parameters
| <div style="width:6em">Name</div> | Description | Type |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| `descriptor` | Object specifying the feature name in its `name` key, along with any other keys for additional properties | object |
| `state` | New permission state for this descriptor. Supported values are: `granted`, `denied`, or `prompt`. | string |
#### Response
`null`
## Reporting Protocol
The [Reporting protocol](https://www.w3.org/TR/reporting-1/) is an extension of the W3C WebDriver
protocol.
### generateTestReport
```
POST /session/:sessionId/reporting/generate_test_report
```
> Reporting documentation: [Generate Test Report](https://www.w3.org/TR/reporting-1/#generate-test-report-command)
Simulates the generation of a test report, which can be retrieved by registered reporting observers.
#### Parameters
| Name | Description | Type | Default |
| --------- | ------------------------------------------ | ------ | --------- |
| `message` | Message displayed in the report | string | |
| `group?` | Destination group to deliver the report to | string | `default` |
#### Response
`null`
## Secure Payment Confirmation Protocol
The [Secure Payment Confirmation protocol](https://www.w3.org/TR/secure-payment-confirmation) (SPC)
is an extension of the W3C WebDriver protocol.
### setSPCTransactionMode
```
POST /session/:sessionId/secure-payment-confirmation/set-mode
```
> SPC documentation: [Set SPC Transaction Mode](https://www.w3.org/TR/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode)
Sets the transaction automation mode, for automated handling of transaction confirmation prompts.
By default, this mode is set to `none`.
#### Parameters
| Name | Description | Type |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| `mode` | Automation mode to set. Supported values are `autoAccept`, `autoChooseToAuthAnotherWay`, `autoReject`, or `autoOptOut`. | string |
#### Response
`null`
## Selenium Protocol
The Selenium protocol is an extension of the W3C WebDriver protocol, supported in Appium clients
@@ -92,7 +527,9 @@ Retrieves the available log types that can be used to call the [`getLog`](#getlo
## Web Authentication Protocol
The [Web Authentication protocol](https://w3c.github.io/webauthn/) (WebAuthn) is an extension of
the W3C WebDriver protocol.
the W3C WebDriver protocol. Clients can enable this protocol by using the
[`webauthn:virtualAuthenticators`](https://w3c.github.io/webauthn/#sctn-automation-webdriver-capability)
capability.
### addVirtualAuthenticator
@@ -9,7 +9,7 @@ title: WebDriver Protocol
</style>
The following is a list of [W3C WebDriver protocol](https://w3c.github.io/webdriver/) endpoints
used in Appium.
supported in Appium.
!!! info
@@ -1070,3 +1070,45 @@ identified by `:elementId`.
#### Response
`string` - a base64-encoded PNG image
### printPage
```
POST /session/:sessionId/print
```
> WebDriver documentation: [Print Page](https://w3c.github.io/webdriver/#print-page)
Prints the page by rendering it as a paginated PDF document.
#### Parameters
| <div style="width:7em">Name</div> | Description | <div style="width:9em">Type</div> | Default |
| --------------------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------- | ---------- |
| `orientation?` | Page orientation. Supported values are `portrait` or `landscape`. | string | `portrait` |
| `scale?` | Page scale. Supported values are in the range `[0.1, 2]`. | number | `1` |
| `background?` | Whether to include background images | boolean | `false` |
| `page?` | Object specifying the page width and height | [`PrintPageSize`](#printpagesize) | `{}` |
| `margin?` | Object specifying the page margins | [`PrintPageMargins`](#printpagemargins) | `{}` |
| `shrinkToFit?` | Whether to resize page contents to match `PrintPageSize.width` | boolean | `true` |
| `pageRanges?` | Array of pages to be printed, for example, `[1, 4, '8-9']` | array | `[]` |
##### `PrintPageSize`
| Name | Description | Type | Default |
| --------- | -------------------------------------------------------------------------------------------- | ------ | ------- |
| `width?` | Page width. Must be greater than or equal to `(2.54 / 72)`. | number | `21.59` |
| `height?` | Page height. Must be greater than or equal to `(2.54 / 72)`. | number | `27.94` |
##### `PrintPageMargins`
| Name | Description | Type | Default |
| --------- | ----------------------------------------------------------------------------------------- | ------ | ------- |
| `top?` | Page top margin. Must be greater than or equal to `0`. | number | `1` |
| `bottom?` | Page bottom margin. Must be greater than or equal to `0`. | number | `1` |
| `left?` | Page left margin. Must be greater than or equal to `0`. | number | `1` |
| `right?` | Page right margin. Must be greater than or equal to `0`. | number | `1` |
#### Response
`string` - a base64-encoded PDF document
@@ -21,7 +21,7 @@ mentioned below.
Installs the following extensions for browser webview testing:
- Drivers: `safari`[^1], `gecko`, `chromium`
- Plugins: `images`
- Plugins: `images`, `inspector`
#### Usage
@@ -34,7 +34,7 @@ appium setup browser
Installs the following extensions for desktop application testing:
- Drivers: `mac2`[^1], `windows`[^2]
- Plugins: `images`
- Plugins: `images`, `inspector`
#### Usage
@@ -47,7 +47,7 @@ appium setup desktop
Installs the following extensions for mobile testing:
- Drivers: `uiautomator2`, `xcuitest`[^1], `espresso`
- Plugins: `images`
- Plugins: `images`, `inspector`
#### Usage
+17 -17
View File
@@ -9,40 +9,40 @@ theme:
nav:
- 欢迎使用: index.md
- 博客: blog/index.md
- 简介:
- 简介:
- intro/index.md
- 背景:
- 背景:
- intro/appium.md
- intro/drivers.md
- intro/clients.md
- intro/history.md
- 快速开始:
- 快速开始:
- quickstart/index.md
- quickstart/requirements.md
- quickstart/install.md
- quickstart/uiauto2-driver.md
- 写一个测试:
- 写一个测试:
- 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
- ecosystem/drivers.md
- ecosystem/clients.md
- ecosystem/plugins.md
- ecosystem/tools.md
- Reference:
- 参考:
- reference/index.md
- Command Line Interface:
- 命令行界面:
- reference/cli/index.md
- reference/cli/server.md
- reference/cli/extensions.md
- reference/cli/setup.md
- reference/cli/env-vars.md
- API Endpoints:
- API 端点:
- reference/api/index.md
- reference/api/webdriver.md
- reference/api/bidi.md
@@ -51,11 +51,11 @@ nav:
- reference/api/appium.md
- reference/api/others.md
- reference/api/plugins.md
- 指南:
- 迁移:
- 指南:
- 迁移:
- guides/migrating-2-to-3.md
- guides/migrating-1-to-2.md
- 服务器/驱动程序配置:
- 服务器/驱动程序配置:
- guides/managing-exts.md
- guides/branch-testing.md
- guides/config.md
@@ -65,24 +65,24 @@ nav:
- guides/grid.md
- guides/caching.md
- guides/tls.md
- 会话配置:
- 会话配置:
- guides/caps.md
- guides/settings.md
- guides/execute-methods.md
- guides/context.md
- guides/event-timing.md
- More Resources:
- 更多资源:
- resources/index.md
- 开发:
- 开发:
- developing/index.md
- developing/build-drivers.md
- developing/build-plugins.md
- developing/build-docs.md
- developing/build-doctor-checks.md
- developing/sensitive.md
- 开发者参考:
- 开发者参考:
- developing/config-system.md
- Contributing:
- 贡献:
- contributing/index.md
- Sponsors:
- 赞助者:
- sponsors/index.md
@@ -36,7 +36,7 @@ Don't miss this chance to contribute to the Appium community and showcase your e
## How to Submit Your Proposal
Visit our website at [https://appiumconf.com/](https://appiumconf.com/) and Submit a Proposal. We're excited to see your innovative ideas and experiences with Appium!
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
@@ -0,0 +1,34 @@
---
authors:
- sai
- srini
date: 2025-11-25
---
# Announcing LambdaTest as Appium's Newest Development Partner
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
<!-- more -->
<div style="text-align:center;width:100%"><a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
</a>
</div>
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
About LambdaTest
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
+44 -70
View File
@@ -1,59 +1,45 @@
---
hide:
- navigation
- 导航栏
title: Contributing to Appium
title: 对Appium 的贡献
---
The Appium project would not exist without the many contributions of code, documentation,
maintenance, and support from companies and volunteers. As such, we welcome contributions!
Appium项目离不开来自公司和志愿者的代码、文档、维护和支持的众多贡献。 因此,我们欢迎贡献!
There are a lot of different ways to help the project - see below for everything you can do and the
processes to follow for each contribution method. Note that no matter how you contribute, your
participation is governed by our [Code of Conduct](https://github.com/appium/appium/blob/master/CONDUCT.md).
有许多不同的方式可以帮助项目——请参阅下方了解您可以做的一切以及每个贡献方法的流程。 请注意,无论您如何贡献,您的参与都受我们的[行为准则](https://github.com/appium/appium/blob/master/CONDUCT.md)管辖。
## Join the Discussion Forum
## 加入讨论论坛
You don't need to know the internals of Appium to be able to contribute! If you have experience with
using Appium and feel like sharing your knowledge with others, consider helping out users on the
Appium forums at [discuss.appium.io](https://discuss.appium.io/). Hop on over and see if there are
any questions that you can answer.
您不需要了解Appium的内部机制就能做出贡献! 如果您有使用Appium的经验,并愿意与他人分享您的知识,请考虑在Appium论坛[discuss.appium.io](https://discuss.appium.io/)上帮助用户。 快去看看是否有您能回答的问题。
## Report Bugs or Feature Requests
## 报告错误或功能请求
If you've encountered a bug, or have a cool feature in mind that you think Appium should support,
make sure to let us know at our [GitHub issue tracker](https://github.com/appium/appium/issues).
Please use the appropriate issue form template when creating your issue.
如果您遇到了一个bug,或者有一个很酷的功能想法,认为Appium应该支持,请务必在我们的[GitHub issue tracker](https://github.com/appium/appium/issues)上告诉我们。
请在创建issue时使用适当的issue表单模板。
## Triage Issues
## 对问题分类
In addition to creating issues, you can also help us investigate already reported issues. All you
need is enough familiarity with Appium to try and reproduce bugs.
除了创建issue,您还可以帮助我们调查已报告的问题。 您只需要对Appium有足够的熟悉程度来尝试重现bug。
You can get started by checking our [GitHub issue tracker](https://github.com/appium/appium/issues)
for issues with labels such as `Needs Triage` or `Needs Info`, and leaving relevant comments:
您可以通过检查我们的[GitHub issue tracker](https://github.com/appium/appium/issues)中带有标签如`Needs Triage`或`Needs Info`的问题开始,并留下相关评论:
- If the issue is a duplicate, drop a link to the original issue
- If the user has not provided enough information (such as Appium logs), ask them for more details
- If you can reproduce the problem on your own environment, provide all the information that you think
would help us track down the cause of the issue
- 如果问题是重复的,请提供指向原始issue的链接
- 如果用户没有提供足够的信息(如Appium日志),请向他们询问更多细节
- 如果您能在自己的环境中重现问题,请提供您认为有助于我们追踪问题原因的所有信息
For further information on triaging Appium issues (for any Appium project repository), please contact
any member of the [Technical Committee](https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee).
有关对Appium问题进行分类的更多信息(适用于任何Appium项目仓库),请联系[技术委员会](https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee)的任何成员。
## Contribute Code
## 贡献代码
We are always open to pull requests for improving the Appium code or documentation!
我们始终欢迎用于改进Appium代码或文档的拉取请求!
!!! info
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. Make sure to check the repo or discuss with maintainers. We would be glad to help
new contributors get started!
开发者信息可能不像面向用户的信息那样频繁更新,或者它在在线仓库中的当前形式可能最相关,而不是在这个发布的版本中。请务必检查仓库或与维护者讨论。我们很乐意帮助新贡献者入门!
Start by cloning the repository (we recommend [forking](https://github.com/appium/appium/fork)
it first):
首先克隆仓库(我们建议先[fork](https://github.com/appium/appium/fork)
它):
```sh
git clone https://github.com/appium/appium.git
@@ -62,35 +48,35 @@ cd appium
!!! 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).
如果您是 VS Code 用户,您可以使用 [Runme](https://runme.dev/api/runme?repository=https%3A%2F%2Fgithub.com%2Fappium%2Fappium.git&fileToOpen=packages%2Fappium%2Fdocs%2Fen%2Fcontributing%2Findex.md) 轻松地查看项目。
Install dependencies:
安装依赖:
```sh
npm install
```
From here on there are several things you can do.
接下来你可以做几件事情。
Build the project:
构建项目:
```sh
npm run build
```
Build the project and watch for changes:
构建项目并监视更改:
```sh
npm run dev
```
Start the locally built Appium server:
启动本地 Appium 服务器:
```sh
npm start
```
Run various tests:
运行测试:
```sh
npm run lint
@@ -102,57 +88,45 @@ npm run test:quick # unit and types
npm run test:slow # everything
```
You can also run tests for specific workspaces, e.g.:
您也可以运行特定工作区的测试,例如:
```sh
export APPIUM_WORKSPACE=@appium/base-driver
npm run test:unit -w $APPIUM_WORKSPACE
```
### Documentation
### 文档
The documentation for this project is [available in the project repository itself](https://github.com/appium/appium/tree/master/packages/appium/docs).
It is contained in Markdown files, which are built by our documentation system in the
`@appium/docutils` module. This module is based on [MkDocs](https://www.mkdocs.org/) and therefore
requires [Python](https://www.python.org/) to be installed on your system.
此项目的文档位于项目[仓库本身](https://github.com/appium/appium/tree/master/packages/appium/docs)中。
它包含在Markdown文件中,这些文件由`@appium/docutils`模块中的文档系统构建。 该模块基于[MkDocs](https://www.mkdocs.org/),因此需要在您的系统上安装[Python](https://www.python.org/)。
Install Python dependencies:
安装 Python 依赖:
```sh
npm run install-docs-deps
```
After making your changes, you can run the documentation server in dev mode:
安装 Python 依赖:
```sh
npm run dev:docs
```
You can then view the documentation at `http://127.0.0.1:8000/docs/en`.
然后你可以在 `http://127.0.1:8000/docs/en` 中查看文档。
## Translating Appium Documentation
## 翻译Appium 文档
The process of Appium documents localization into languages other than English is automated and is done via
the [Crowdin Translations Management System](https://crowdin.com). Do not edit any translated documents
directly in the GitHub Appium repository as they are going to be replaced with ones exported from Crowdin
during an upcoming sync.
Appium文档本地化为英语以外语言的过程是自动化的,通过[Crowdin翻译管理系统](https://crowdin.com)完成。 请勿直接在GitHub Appium仓库中编辑任何翻译文档,因为它们将在即将进行的同步中被从Crowdin导出的文档替换。
### Where To Start
### 从哪里开始
If you would like to contribute to the translation of Appium documents into your language then simply join
the translators group for the [Appium Documentation](https://crowdin.com/project/appium-documentation)
Crowdin project, and start translating documents there. If you see that your language is missing from
the list of available Crowdin languages then simply let us know by creating an
[issue](https://github.com/appium/appium/issues).
如果您想为Appium文档翻译成您的语言做出贡献,只需加入[Appium Documentation](https://crowdin.com/project/appium-documentation) Crowdin项目的翻译者组,然后在那里开始翻译文档。 如果您看到您的语言在Crowdin可用语言列表中缺失,请通过创建[issue](https://github.com/appium/appium/issues)告诉我们。
### Source Language Updates
### 源语言更新
Changes in documents are synchronized to Crowdin automatically via the `Update Crowdin English Docs` GitHub action.
This action is triggered automatically as soon as there are any changes under `packages/appium/docs/en/**.md`
or `packages/appium/docs/mkdocs-en.yml`.
文档中的更改通过 `Update Crowdin English Docs GitHub` action自动同步到Crowdin。
一旦 `packages/appium/docs/en/**.md` 或 `packages/appium/docs/mkdocs-en.yml` 下有任何更改,此action就会自动触发。
### Fetching Translated Documents
### 获取翻译文档
In order to fetch translated files from Crowdin to the GitHub repository it is necessary to trigger
the `Sync Crowdin Docs Translations` action. This action should also automatically create a PR with
corresponding translated resources included.
为了从Crowdin获取翻译文件到GitHub仓库,需要触发 `Sync Crowdin Docs Translations` action。 此action还会自动创建一个包含相应翻译资源的PR。
@@ -50,7 +50,7 @@ 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.
is not written in TypeScript.
2. Create a `mkdocs.yml` with the necessary configuration for MkDocs.
### Documenting Your Extension
@@ -21,13 +21,13 @@ 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.
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.
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:
@@ -579,7 +579,7 @@ three ways:
1. Extending the classic WebDriver protocol and creating client-side plugins to access the extensions via the classic HTTP interface
2. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface
3. Overloading the Execute Script command by defining Execute
Methods
Methods
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`
@@ -685,17 +685,17 @@ async execute(script, args) {
A couple notes about this system:
1. The arguments array sent via the call to Execute Script must contain only zero or one element(s). The
first item in the list is considered to be the parameters object for your method. These parameters
will be parsed, validated, and then applied to your overload method in the order specified in
`executeMethodMap` (the order specified in the `required` parameters list, followed by the
`optional` parameters list). I.e., this framework assumes only a single actual argument sent in via
Execute Script (and this argument should be an object with keys/values representing the
parameters your execute method expects).
first item in the list is considered to be the parameters object for your method. These parameters
will be parsed, validated, and then applied to your overload method in the order specified in
`executeMethodMap` (the order specified in the `required` parameters list, followed by the
`optional` parameters list). I.e., this framework assumes only a single actual argument sent in via
Execute Script (and this argument should be an object with keys/values representing the
parameters your execute method expects).
2. Appium does not automatically implement `execute` (the Execute Script handler) for you. You may
wish, for example, to only call the `executeMethod` helper function when you're not in proxy
mode!
wish, for example, to only call the `executeMethod` helper function when you're not in proxy
mode!
3. The `executeMethod` helper will reject with an error if a script name doesn't match one of the
script names defined as a command in `executeMethodMap`, or if there are missing parameters.
script names defined as a command in `executeMethodMap`, or if there are missing parameters.
One of the nice things about the Execute Method strategy is that methods implemented in this way
will be available via the classic or BiDi interfaces (since they will result in the same Appium
@@ -770,7 +770,7 @@ that multiple simultaneous sessions don't use the same resources:
1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc)
2. Just always use free resources (find a new random port for each session)
3. Have each driver express what resources it is using, then examine currently-used resources from
other drivers when a new session begins.
other drivers when a new session begins.
To support this third strategy, you can implement `get driverData` in your driver to return what
sorts of resources your driver is currently using, for example:
@@ -236,13 +236,13 @@ upstream server. In this case, we might run into a problem, because the plugin n
handle that command! The way Appium handles this is as follows:
1. When a command comes in, before deciding whether to proxy the command, the main protocol handler
checks to see whether a plugin would handle the command.
checks to see whether a plugin would handle the command.
2. If a plugin would _not_ handle the command--all proceeds as normal, and the request is either
proxied or not, based on the driver's proxy mode.
proxied or not, based on the driver's proxy mode.
3. If a plugin _would_ handle the command, then the proxy behavior is skipped for the time being,
and wrapped up as the `next` function sent to the plugin. So if you have a command handler in
your plugin, and you want to be sure that the default driver proxying _does_ take place, then
simply `await next()` instead of (or in addition to) whatever your plugin handler is doing.
and wrapped up as the `next` function sent to the plugin. So if you have a command handler in
your plugin, and you want to be sure that the default driver proxying _does_ take place, then
simply `await next()` instead of (or in addition to) whatever your plugin handler is doing.
### Throw WebDriver-specific errors
@@ -331,7 +331,7 @@ drivers, you can create new commands in one of two ways, just as is possible for
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
2. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface
3. Overloading the Execute Script command by defining Execute
Methods
Methods
#### Extending the HTTP Protocol
@@ -458,10 +458,10 @@ inside the plugin class:
1. The `executeMethodMap`, defined in just the same way as for drivers
2. The implementation of the command method as defined in `executeMethodMap` (in this case,
`plugMeIn`)
`plugMeIn`)
3. 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.
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
@@ -1,6 +1,7 @@
---
hide:
- toc
title: Masking Sensitive Log Data
---
@@ -59,3 +59,29 @@ Supported by: `@AppiumTestDistribution`
```sh title="Install This Tool"
npm install -g appium-installer
```
### [Jarvis Appium](https://github.com/AppiumTestDistribution/mcp-appium)
Jarvis Appium is a Model Context Protocol (MCP) server that provides mobile test development and
automation capabilities using Appium.
Supported by: `@AppiumTestDistribution`
```json title="Install This Tool"
// Add the following to your MCP client configuration
{
"mcpServers": {
"jarvis-appium": {
"disabled": false,
"timeout": 100,
"type": "stdio",
"command": "npx",
"args": ["jarvis-appium"],
"env": {
"ANDROID_HOME": "/path/to/android/sdk",
"CAPABILITIES_CONFIG": "/path/to/your/capabilities.json"
}
}
}
}
```
@@ -1,6 +1,7 @@
---
hide:
- toc
title: Managing Contexts
---
@@ -1,6 +1,7 @@
---
hide:
- toc
title: Execute Methods
---
@@ -9,10 +10,10 @@ defined by the W3C WebDriver spec, Appium needs a way for these "extended" comma
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.
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).
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.
@@ -133,9 +134,9 @@ Javascript execution:
1. The script string is just a command name; it will be provided by the driver documentation
2. 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_.
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.
+20 -8
View File
@@ -22,9 +22,11 @@ server:
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8100
mjpegServerPort: 9100
mjpegScreenshotUrl: "http://localhost:9100"
appium:wdaLocalPort: 8100
appium:mjpegServerPort: 9100
appium:mjpegScreenshotUrl: "http://localhost:9100"
appium:platformVersion: "26.0"
appium:deviceName: "iPhone 17"
```
In the above YAML config file, we specify the Appium server port, the driver used, and parameters
@@ -39,9 +41,11 @@ server:
use-drivers:
- xcuitest
default-capabilities:
wdaLocalPort: 8110
mjpegServerPort: 9110
mjpegScreenshotUrl: "http://localhost:9110"
appium:wdaLocalPort: 8110
appium:mjpegServerPort: 9110
appium:mjpegScreenshotUrl: "http://localhost:9110"
appium:platformVersion: "26.0"
appium:deviceName: "iPhone 16"
```
### Define the Grid node configs
@@ -60,11 +64,15 @@ port = 5555
[node]
detect-drivers = false
[events]
publish = "tcp://HUB_IP_ADDRESS:4442"
subscribe = "tcp://HUB_IP_ADDRESS:4443"
[relay]
url = "http://localhost:4723"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 13\", \"appium:automationName\": \"XCUITest\"}"
"1", "{\"platformName\": \"iOS\", \"appium:automationName\": \"XCUITest\"}"
]
```
@@ -76,11 +84,15 @@ port = 5565
[node]
detect-drivers = false
[events]
publish = "tcp://HUB_IP_ADDRESS:4442"
subscribe = "tcp://HUB_IP_ADDRESS:4443"
[relay]
url = "http://localhost:4733"
status-endpoint = "/status"
configs = [
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 12\", \"appium:automationName\": \"XCUITest\"}"
"1", "{\"platformName\": \"iOS\", \"appium:automationName\": \"XCUITest\"}"
]
```
+194 -194
View File
@@ -151,285 +151,285 @@ Icons are used to indicate endpoint support in either certain drivers, or in the
</div>
- `GET /sessions`
- :octicons-arrow-right-24: `GET /appium/sessions` :simple-appium:
- :octicons-arrow-right-24: `GET /appium/sessions` :simple-appium:
- `POST /session/:sessionId/accept_alert`
- :octicons-arrow-right-24: `POST /session/:sessionId/alert/accept` :simple-appium:
- :octicons-arrow-right-24: `mobile: alert` [execute method](./execute-methods.md) :material-apple:
- :octicons-arrow-right-24: `mobile: acceptAlert` execute method :material-android:
- :octicons-arrow-right-24: `POST /session/:sessionId/alert/accept` :simple-appium:
- :octicons-arrow-right-24: `mobile: alert` [execute method](./execute-methods.md) :material-apple:
- :octicons-arrow-right-24: `mobile: acceptAlert` execute method :material-android:
- `GET /session/:sessionId/alert_text`
- :octicons-arrow-right-24: `GET /session/:sessionId/alert/text` :simple-appium:
- :octicons-arrow-right-24: `GET /session/:sessionId/alert/text` :simple-appium:
- `POST /session/:sessionId/alert_text`
- :octicons-arrow-right-24: `POST /session/:sessionId/alert/text` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/alert/text` :simple-appium:
- `POST /session/:sessionId/appium/app/background`
- :octicons-arrow-right-24: `mobile: backgroundApp` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: backgroundApp` execute method :material-apple: :material-android: :material-coffee:
- `POST /session/:sessionId/appium/app/close`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: terminateApp` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: terminateApp` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: closeApp` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: terminateApp` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: terminateApp` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: closeApp` execute method :material-microsoft-windows:
- `POST /session/:sessionId/appium/app/end_test_coverage`
- :octicons-arrow-right-24: `mobile: shell` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: shell` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/app/launch`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: launchApp` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: activateApp` or `mobile: startActivity` execute methods :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: launchApp` or `macos: activateApp` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: launchApp` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: launchApp` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: activateApp` or `mobile: startActivity` execute methods :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: launchApp` or `macos: activateApp` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: launchApp` execute method :material-microsoft-windows:
- `POST /session/:sessionId/appium/app/reset`
- :octicons-arrow-right-24: `mobile: clearApp` execute method :material-apple: [^sim] :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: clearApp` execute method :material-apple: [^sim] :material-android: :material-coffee:
- `POST /session/:sessionId/appium/app/strings`
- :octicons-arrow-right-24: `mobile: getAppStrings` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getAppStrings` execute method :material-apple: :material-android: :material-coffee:
- `GET /session/:sessionId/appium/device/app_state`
- :octicons-arrow-right-24: `POST /session/:sessionId/appium/device/app_state` :simple-appium:
- :octicons-arrow-right-24: `mobile: queryAppState` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: queryAppState` execute method :material-apple-finder:
- :octicons-arrow-right-24: `POST /session/:sessionId/appium/device/app_state` :simple-appium:
- :octicons-arrow-right-24: `mobile: queryAppState` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: queryAppState` execute method :material-apple-finder:
- `GET /session/:sessionId/appium/device/current_activity`
- :octicons-arrow-right-24: `mobile: getCurrentActivity` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getCurrentActivity` execute method :material-android: :material-coffee:
- `GET /session/:sessionId/appium/device/current_package`
- :octicons-arrow-right-24: `mobile: getCurrentPackage` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getCurrentPackage` execute method :material-android: :material-coffee:
- `GET /session/:sessionId/appium/device/display_density`
- :octicons-arrow-right-24: `mobile: getDisplayDensity` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getDisplayDensity` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/finger_print`
- :octicons-arrow-right-24: `mobile: fingerPrint` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: fingerPrint` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/get_clipboard`
- :octicons-check-24: Moved to drivers: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getClipboard` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getPasteboard` execute method :material-apple: [^sim]
- :octicons-arrow-right-24: `windows: getClipboard` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getClipboard` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getPasteboard` execute method :material-apple: [^sim]
- :octicons-arrow-right-24: `windows: getClipboard` execute method :material-microsoft-windows:
- `POST /session/:sessionId/appium/device/gsm_call`
- :octicons-arrow-right-24: `mobile: gsmCall` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: gsmCall` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/gsm_signal`
- :octicons-arrow-right-24: `mobile: gsmSignal` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: gsmSignal` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/gsm_voice`
- :octicons-arrow-right-24: `mobile: gsmVoice` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: gsmVoice` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/is_locked`
- :octicons-arrow-right-24: `mobile: isLocked` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: isLocked` execute method :material-apple: :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/keyevent`
- :octicons-arrow-right-24: `mobile: keys` execute method :material-apple: (iPadOS only)
- :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: keys` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: keys` execute method :material-apple: (iPadOS only)
- :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: keys` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- `POST /session/:sessionId/appium/device/lock`
- :octicons-arrow-right-24: `mobile: lock` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: lock` execute method :material-apple: :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/long_press_keycode`
- :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/network_speed`
- :octicons-arrow-right-24: `mobile: networkSpeed` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: networkSpeed` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/open_notifications`
- :octicons-arrow-right-24: `mobile: statusBar` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: openNotifications` execute method :material-android:
- :octicons-arrow-right-24: `mobile: statusBar` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: openNotifications` execute method :material-android:
- `POST /session/:sessionId/appium/device/power_ac`
- :octicons-arrow-right-24: `mobile: powerAC` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: powerAC` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/power_capacity`
- :octicons-arrow-right-24: `mobile: powerCapacity` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: powerCapacity` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/press_keycode`
- :octicons-arrow-right-24: `mobile: keys` execute method :material-apple: (iPadOS only)
- :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: keys` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: keys` execute method :material-apple: (iPadOS only)
- :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: keys` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- `POST /session/:sessionId/appium/device/send_sms`
- :octicons-arrow-right-24: `mobile: sendSms` execute method :material-android: [^sim] :material-coffee: [^sim]
- :octicons-arrow-right-24: `mobile: sendSms` execute method :material-android: [^sim] :material-coffee: [^sim]
- `POST /session/:sessionId/appium/device/set_clipboard`
- :octicons-arrow-right-24: `mobile: setClipboard` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: setPasteboard` execute method :material-apple: [^sim]
- :octicons-arrow-right-24: `windows: setClipboard` execute method :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: setClipboard` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: setPasteboard` execute method :material-apple: [^sim]
- :octicons-arrow-right-24: `windows: setClipboard` execute method :material-microsoft-windows:
- `POST /session/:sessionId/appium/device/shake`
- :octicons-arrow-right-24: `mobile: shake` execute method :material-apple: [^sim]
- :octicons-arrow-right-24: `mobile: shake` execute method :material-apple: [^sim]
- `POST /session/:sessionId/appium/device/start_activity`
- :octicons-arrow-right-24: `mobile: startActivity` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: startActivity` execute method :material-android: :material-coffee:
- `GET /session/:sessionId/appium/device/system_bars`
- :octicons-arrow-right-24: `mobile: deviceScreenInfo` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: getSystemBars` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: deviceScreenInfo` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: getSystemBars` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/toggle_airplane_mode`
- :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/toggle_data`
- :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/toggle_location_services`
- :octicons-arrow-right-24: `mobile: toggleGps` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: toggleGps` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/toggle_wifi`
- :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/device/unlock`
- :octicons-arrow-right-24: `mobile: unlock` execute method :material-apple: :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: unlock` execute method :material-apple: :material-android: :material-coffee:
- `POST /session/:sessionId/appium/element/:elementId/value`
- :octicons-arrow-right-24: `POST /session/:sessionId/element/:elementId/value` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/element/:elementId/value` :simple-appium:
- `POST /session/:sessionId/appium/element/:elementId/replace_value`
- :octicons-arrow-right-24: `POST /session/:sessionId/element/:elementId/value` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/element/:elementId/value` :simple-appium:
- `POST /session/:sessionId/appium/getPerformanceData`
- :octicons-arrow-right-24: `mobile: getPerformanceData` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getPerformanceData` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/performanceData/types`
- :octicons-arrow-right-24: `mobile: getPerformanceDataTypes` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `mobile: getPerformanceDataTypes` execute method :material-android: :material-coffee:
- `POST /session/:sessionId/appium/receive_async_response`
- :octicons-arrow-right-24: `POST /session/:sessionId/execute/async` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/execute/async` :simple-appium:
- `POST /session/:sessionId/appium/simulator/toggle_touch_id_enrollment`
- :octicons-arrow-right-24: `mobile: enrollBiometric` execute method :material-apple: [^sim]
- :octicons-arrow-right-24: `mobile: enrollBiometric` execute method :material-apple: [^sim]
- `POST /session/:sessionId/appium/simulator/touch_id`
- :octicons-arrow-right-24: `mobile: sendBiometricMatch` execute method :material-apple: [^sim]
- :octicons-arrow-right-24: `mobile: sendBiometricMatch` execute method :material-apple: [^sim]
- `POST /session/:sessionId/appium/start_recording_screen`
- :octicons-check-24: Moved to drivers: :material-apple: :material-android: :material-coffee: :material-apple-finder: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: startXCTestScreenRecording` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: startMediaProjectionRecording` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: startRecordingScreen` or `macos: startNativeScreenRecording` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: startRecordingScreen` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-apple: :material-android: :material-coffee: :material-apple-finder: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: startXCTestScreenRecording` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: startMediaProjectionRecording` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: startRecordingScreen` or `macos: startNativeScreenRecording` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: startRecordingScreen` execute method :material-microsoft-windows:
- `POST /session/:sessionId/appium/stop_recording_screen`
- :octicons-check-24: Moved to drivers: :material-apple: :material-android: :material-coffee: :material-apple-finder: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: stopXCTestScreenRecording` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: stopMediaProjectionRecording` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: stopRecordingScreen` or `macos: stopNativeScreenRecording` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: stopRecordingScreen` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-apple: :material-android: :material-coffee: :material-apple-finder: :material-microsoft-windows:
- :octicons-arrow-right-24: `mobile: stopXCTestScreenRecording` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: stopMediaProjectionRecording` execute method :material-android: :material-coffee:
- :octicons-arrow-right-24: `macos: stopRecordingScreen` or `macos: stopNativeScreenRecording` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: stopRecordingScreen` execute method :material-microsoft-windows:
- `GET /session/:sessionId/application_cache/status`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `POST /session/:sessionId/buttondown`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: [W3C Actions API](https://www.selenium.dev/documentation/webdriver/actions_api/) (`pointerDown`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: [W3C Actions API](https://www.selenium.dev/documentation/webdriver/actions_api/) (`pointerDown`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- `POST /session/:sessionId/buttonup`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- `POST /session/:sessionId/click`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- `POST /session/:sessionId/dismiss_alert`
- :octicons-arrow-right-24: `POST /session/:sessionId/alert/dismiss` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/alert/dismiss` :simple-appium:
- `POST /session/:sessionId/doubleclick`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- `POST /session/:sessionId/element/active`
- :octicons-arrow-right-24: `GET /session/:sessionId/element/active` :simple-appium:
- :octicons-arrow-right-24: `GET /session/:sessionId/element/active` :simple-appium:
- `GET /session/:sessionId/element/:elementId/equals/:otherId`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- `GET /session/:sessionId/element/:elementId/location`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/rect` :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/rect` :simple-appium:
- `GET /session/:sessionId/element/:elementId/location_in_view`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- `GET /session/:sessionId/element/:elementId/pageIndex`
- :octicons-no-entry-24: MJSONWP protocol command with no direct replacement
- :octicons-no-entry-24: MJSONWP protocol command with no direct replacement
- `GET /session/:sessionId/element/:elementId/size`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/rect` :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/rect` :simple-appium:
- `POST /session/:sessionId/element/:elementId/submit`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `POST /session/:sessionId/execute`
- :octicons-arrow-right-24: `POST /session/:sessionId/execute/sync` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/execute/sync` :simple-appium:
- `POST /session/:sessionId/execute_async`
- :octicons-arrow-right-24: `POST /session/:sessionId/execute/async` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/execute/async` :simple-appium:
- `POST /session/:sessionId/keys`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`keyDown` & `keyUp`) :simple-appium:
- Selenium-based clients can also use [Send Keys](https://www.selenium.dev/documentation/webdriver/actions_api/keyboard/#send-keys)
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`keyDown` & `keyUp`) :simple-appium:
- Selenium-based clients can also use [Send Keys](https://www.selenium.dev/documentation/webdriver/actions_api/keyboard/#send-keys)
- `GET /session/:sessionId/local_storage`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `POST /session/:sessionId/local_storage`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `DELETE /session/:sessionId/local_storage`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `GET /session/:sessionId/local_storage/key/:key`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `DELETE /session/:sessionId/local_storage/key/:key`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `GET /session/:sessionId/local_storage/size`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `POST /session/:sessionId/log`
- :octicons-arrow-right-24: `POST /session/:sessionId/se/log` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/se/log` :simple-appium:
- `GET /session/:sessionId/log/types`
- :octicons-arrow-right-24: `GET /session/:sessionId/se/log/types` :simple-appium:
- :octicons-arrow-right-24: `GET /session/:sessionId/se/log/types` :simple-appium:
- `POST /session/:sessionId/moveto`
- :octicons-arrow-right-24: W3C Actions API (`pointerMove`) :simple-appium:
- Selenium-based clients can also use [Move by Offset](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#move-by-offset)
- :octicons-arrow-right-24: W3C Actions API (`pointerMove`) :simple-appium:
- Selenium-based clients can also use [Move by Offset](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#move-by-offset)
- `GET /session/:sessionId/screenshot/:elementId`
- :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/screenshot` :simple-appium:
- :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/screenshot` :simple-appium:
- `GET /session/:sessionId/session_storage`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `POST /session/:sessionId/session_storage`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `DELETE /session/:sessionId/session_storage`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `GET /session/:sessionId/session_storage/key/:key`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `DELETE /session/:sessionId/session_storage/key/:key`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `GET /session/:sessionId/session_storage/size`
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- :octicons-no-entry-24: JSONWP protocol command with no direct replacement
- `POST /session/:sessionId/timeouts/async_script`
- :octicons-arrow-right-24: `POST /session/:sessionId/timeouts` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/timeouts` :simple-appium:
- `POST /session/:sessionId/timeouts/implicit_wait`
- :octicons-arrow-right-24: `POST /session/:sessionId/timeouts` :simple-appium:
- :octicons-arrow-right-24: `POST /session/:sessionId/timeouts` :simple-appium:
- `POST /session/:sessionId/touch/click`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- Selenium-based clients can also use [Click and Release](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#click-and-release)
- :octicons-arrow-right-24: `mobile: tap` or `mobile: tapWithNumberOfTaps` execute methods :material-apple:
- :octicons-arrow-right-24: `mobile: clickGesture` execute method :material-android:
- :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: click`, `macos: rightClick`, `macos: press` or `macos: tap` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- Selenium-based clients can also use [Click and Release](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#click-and-release)
- :octicons-arrow-right-24: `mobile: tap` or `mobile: tapWithNumberOfTaps` execute methods :material-apple:
- :octicons-arrow-right-24: `mobile: clickGesture` execute method :material-android:
- :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: click`, `macos: rightClick`, `macos: press` or `macos: tap` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:
- `POST /session/:sessionId/touch/doubleclick`
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- Selenium-based clients can also use [Double Click](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#double-click)
- :octicons-arrow-right-24: `mobile: doubleTap` or `mobile: tapWithNumberOfTaps` execute methods :material-apple:
- :octicons-arrow-right-24: `mobile: doubleClickGesture` execute method :material-android:
- :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: doubleClick` or `macos: doubleTap` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:
- Selenium-based clients can also use [Double Click](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#double-click)
- :octicons-arrow-right-24: `mobile: doubleTap` or `mobile: tapWithNumberOfTaps` execute methods :material-apple:
- :octicons-arrow-right-24: `mobile: doubleClickGesture` execute method :material-android:
- :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: doubleClick` or `macos: doubleTap` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:
- `POST /session/:sessionId/touch/down`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- `POST /session/:sessionId/touch/flick`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pointerMove` & `pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `mobile: flingGesture` execute method :material-android:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pointerMove` & `pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `mobile: flingGesture` execute method :material-android:
- `POST /session/:sessionId/touch/longclick`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pause` & `pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `mobile: touchAndHold` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: longClickGesture` execute method :material-android:
- :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: press` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pause` & `pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `mobile: touchAndHold` execute method :material-apple:
- :octicons-arrow-right-24: `mobile: longClickGesture` execute method :material-android:
- :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: press` execute method :material-apple-finder:
- :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:
- `POST /session/:sessionId/touch/multi/perform`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `POST /session/:sessionId/actions` :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `POST /session/:sessionId/actions` :simple-appium:
- `POST /session/:sessionId/touch/move`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerMove`) :simple-appium:
- Selenium-based clients can also use [Move by Offset](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#move-by-offset)
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerMove`) :simple-appium:
- Selenium-based clients can also use [Move by Offset](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#move-by-offset)
- `POST /session/:sessionId/touch/perform`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `POST /session/:sessionId/actions` :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `POST /session/:sessionId/actions` :simple-appium:
- `POST /session/:sessionId/touch/scroll`
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pointerMove` & `pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `mobile: scroll` or `mobile: swipe` execute methods :material-apple:
- :octicons-arrow-right-24: `mobile: scrollGesture` or `mobile: swipeGesture` execute methods :material-android:
- :octicons-arrow-right-24: `mobile: swipe` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: scroll` or `macos: swipe` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: scroll` execute method :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pointerMove` & `pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `mobile: scroll` or `mobile: swipe` execute methods :material-apple:
- :octicons-arrow-right-24: `mobile: scrollGesture` or `mobile: swipeGesture` execute methods :material-android:
- :octicons-arrow-right-24: `mobile: swipe` execute method :material-coffee:
- :octicons-arrow-right-24: `macos: scroll` or `macos: swipe` execute methods :material-apple-finder:
- :octicons-arrow-right-24: `windows: scroll` execute method :material-microsoft-windows:
- `POST /session/:sessionId/touch/up`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: W3C Actions API (`pointerUp`) :simple-appium:
- :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:
- `GET /session/:sessionId/window_handle`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/window` :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/window` :simple-appium:
- `GET /session/:sessionId/window_handles`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/window/handles` :simple-appium:
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/window/handles` :simple-appium:
- `GET /session/:sessionId/window/handle`
- :octicons-arrow-right-24: `GET /session/:sessionId/window` :simple-appium:
- :octicons-arrow-right-24: `GET /session/:sessionId/window` :simple-appium:
- `POST /session/:sessionId/window/:windowhandle/maximize`
- :octicons-arrow-right-24: `POST /session/:sessionId/window/maximize` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
- :octicons-arrow-right-24: `POST /session/:sessionId/window/maximize` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
- `GET /session/:sessionId/window/:windowhandle/position`
- :octicons-arrow-right-24: `GET /session/:sessionId/window/rect` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
- :octicons-arrow-right-24: `GET /session/:sessionId/window/rect` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
- `POST /session/:sessionId/window/:windowhandle/position`
- :octicons-arrow-right-24: `POST /session/:sessionId/window/rect` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
- :octicons-arrow-right-24: `POST /session/:sessionId/window/rect` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
- `GET /session/:sessionId/window/:windowhandle/size`
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/window/rect` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
- :octicons-check-24: Moved to drivers: :material-microsoft-windows:
- :octicons-arrow-right-24: `GET /session/:sessionId/window/rect` :simple-appium:
- :fontawesome-solid-triangle-exclamation: Only supported for the current window
### Modified
@@ -438,22 +438,22 @@ parameters (note that no new parameters have been added). Each endpoint lists th
longer accepts, as well as the parameters it continues to accept in Appium 3.
- `POST /session`
- :octicons-x-24: `desiredCapabilities`, `requiredCapabilities`
- :octicons-check-24: `capabilities`
- :octicons-x-24: `desiredCapabilities`, `requiredCapabilities`
- :octicons-check-24: `capabilities`
- `POST /session/:sessionId/alert/text`
- :octicons-x-24: `value`
- :octicons-check-24: `text`
- :octicons-x-24: `value`
- :octicons-check-24: `text`
- `GET /session/:sessionId/appium/device/system_time`
- :octicons-x-24: `format`
- :octicons-check-24: None
- :octicons-x-24: `format`
- :octicons-check-24: None
- `POST /session/:sessionId/element/:elementId/value`
- :octicons-x-24: `value`
- :octicons-check-24: `text`
- :octicons-x-24: `value`
- :octicons-check-24: `text`
- `POST /session/:sessionId/timeouts`
- :octicons-x-24: `type`, `ms`
- :octicons-check-24: `script`, `pageLoad`, `implicit`
- :octicons-x-24: `type`, `ms`
- :octicons-check-24: `script`, `pageLoad`, `implicit`
- `POST /session/:sessionId/window`
- :octicons-x-24: `name`
- :octicons-check-24: `handle`
- :octicons-x-24: `name`
- :octicons-check-24: `handle`
[^sim]: Supported in emulators/simulators only
+19 -13
View File
@@ -4,7 +4,7 @@ title: Appium Server Security
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
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
all the following are true:
- You're running your own Appium server locally or within a protected internal network
@@ -12,18 +12,18 @@ all the following are true:
- 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.
team puts many features behind a security protection mechanism, which forces system admins (the
people who 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.)
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.
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](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
Appium when starting it from the command line:
Appium, when starting it from the command line:
| <div style="width:10em">Parameter</div> | Description |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -44,7 +44,7 @@ to the `bar` feature for all drivers.
## Insecure Features
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
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:
@@ -53,10 +53,10 @@ might use. Here is an incomplete list of examples from some of Appium's official
| `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 |
| `execute_driver_script` | Allows sending a request that has multiple Appium commands. | Execute Driver Plugin |
Some insecure features operate on the server level, and do not require a driver session. Enabling
these features requires using the wildcard prefix:
Some insecure features operate on the server level and do not require a driver session. Enabling
these features require using the wildcard prefix:
| <div style="width:12em">Feature Name</div> | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------- |
@@ -73,17 +73,23 @@ appium --allow-insecure=first:foo
Turn on the `foo` feature for all drivers:
```bash
appium --allow-insecure=*:foo
appium --allow-insecure='*:foo'
```
Turn on the `foo` feature for all drivers _except_ `first`:
```bash
appium --allow-insecure=*:foo --deny-insecure=first:foo
appium --allow-insecure='*:foo' --deny-insecure=first:foo
```
Turn on all features _except_ `foo` for all drivers:
```bash
appium --relaxed-security --deny-insecure=*:foo
appium --relaxed-security --deny-insecure='*:foo'
```
Turn on multiple insecure features for specific drivers:
```bash
appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs
```
@@ -1,6 +1,7 @@
---
hide:
- toc
title: Session Settings
---
+1
View File
@@ -1,6 +1,7 @@
---
hide:
- toc
title: SSL/TLS/SPDY Support
---
+6 -6
View File
@@ -1,6 +1,6 @@
---
hide:
- navigation
- 导航栏
- toc
title: 欢迎使用
@@ -44,11 +44,11 @@ title: 欢迎使用
- 查看 [**简介**](./intro/index.md) 以确保您理解关键概念
- 通过 [**快速开始**](./quickstart/index.md) 来设置并运行一个基本的 Android 测试
- 访问 [**生态系统**](./ecosystem/index.md) 页面,获取您可能想要使用的驱动程序、客户端和插件列表
- Consult the [**Reference**](./reference/index.md) page for information on the Appium CLI and supported endpoints
- Read the different [**Guides**](./guides/migrating-2-to-3.md) for a variety of instructions, tips and tricks
- Check out various third-party [**Resources**](./resources/index.md) to explore Appium around the web
- 访问 [**Reference**](./reference/index.md) 页面获取Appium CLI 和支持的端点信息
- 阅读不同版本的 [**指南**](./guides/migrating-2-to-3.md),了解各版本的说明、提示和技巧
- 查看各种第三方 [**资源**](./resources/index.md) 以探索网络上的 Appium
- 要创建自己的 Appium 扩展,请参阅 [**开发者**](./developing/index.md) 文档
- For contributions to Appium itself, refer to the [**Contributing**](./contributing/index.md) page
- Have a look at the [**Appium Blog**](./blog/index.md) to learn what's new in the project
- 有关对 Appium 的贡献,请查阅 [**贡献**](./contributing/index.md) 页面
- 查看 [**Appium博客**](./blog/index.md) ,了解项目中的新内容
</div>
+52 -161
View File
@@ -1,200 +1,91 @@
---
title: How Does Appium Work?
title: Appium 如何工作?
---
As mentioned on the main page, Appium is an open-source project and ecosystem of related software,
designed to facilitate UI automation of many app platforms. With the release of Appium 2, Appium
has the following primary goals:[^1]
正如主页所述,Appium 是一个开源项目和相关软件生态系统,旨在促进多种应用平台的 UI 自动化。 随着 Appium 2 的发布,Appium 具有以下主要目标:[^1]
- Make platform-specific automation capabilities available under a cross-platform, standard API
- Allow easy access to this API from any programming language
- Provide tools to enable convenient community development of Appium extensions
- 在跨平台标准 API 下提供特定于平台的自动化功能
- 允许从任何编程语言轻松访问此 API
- 提供工具以便社区方便地开发 Appium 扩展
[^1]: To meet these primary goals, we also work with a set of secondary goals or methodology
principles, which we also encourage for Appium extension developers:
[^1]: 为实现这些主要目标,我们还遵循一套次要目标或方法原则,我们也鼓励 Appium 扩展开发者遵循这些原则:
- As far as possible, rely on (and contribute to) open source technology
- As far as possible, rely on vendor-provided tools for a given platform
- As far as possible, rely on automation tools that allow automation of unmodified apps (prefer
not to require the user to build in additional SDKs or software that introduce discrepancies
between the test version of the app and the production version)
- As far as possible, rely on existing standards instead of creating new ones
- 尽可能依赖(并贡献于)开源技术
- 尽可能依赖给定平台的供应商提供的工具
- 尽可能依赖不修改应用就能实现自动化(最好不要要求用户构建额外的 SDK 或软件,从而在测试版本和生产版本之间引入差异)的自动化工具
- 尽可能依赖现有标准而不是创建新标准
So, take any app platform you know about, like iOS or Android. Appium wants for there to be a way
for developers and testers to write UI automation code for that platform, according to a single,
unified API. Based on Appium's goals, we have a lot of questions to answer to make it all work:
所以,以您了解的任何应用平台为例,如 iOS 或 Android。 Appium 希望开发者测试人员能够为该平台编写 UI 自动化代码,根据单一的统一 API。 根据 Appium 的目标,我们有很多问题需要回答以使其全部工作:
- Which API should that "single, unified" API be?
- How do we map that API to automation behaviour for a specific platform?
- How do we make that API accessible via multiple popular programming languages?
- “单一统一”的 API 应该是什么?
- 我们如何将此 API 映射到特定平台的自动化行为?
- 我们如何使此 API 通过多种流行编程语言访问?
There's another, larger, question lurking in the background here too, given that there are more app
platforms out there than just iOS and Android:
这里还有另一个更大的问题,鉴于除了 iOS 和 Android 之外还有更多应用平台:
- How do we enable automation for _all_ the platforms?
- 我们如何为_所有_平台启用自动化?
Exploring Appium's answers to these questions may not be the quickest way to learn what Appium is,
but it is certainly a good one! So let's dive in.
探索 Appium 对这些问题的答案可能不是学习 Appium 是什么的最快方式,但它肯定是一个好方法! 所以让我们深入了解。
## Appium's choice of API
## Appium 的 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://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.
Appium 非常幸运地继承了一个在 UI 自动化领域长期领先的技术,即 [Selenium](https://selenium.dev)。 Selenium 项目的目标是支持 Web 浏览器的 UI 自动化,因此我们可以将其视为占据 Appium 目标子集的一部分。 在此过程中,Selenium(以及后来合并的另一个名为 WebDriver 的项目)开发了一个相对稳定的浏览器自动化 API。
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. All the main browsers now
implement automation capabilities inline with the WebDriver spec, without the Selenium team having
to maintain any software that performs actual automation; standards for the win!
多年来,Selenium 与各种 Web 浏览器供应商和 [W3C](https://w3.org) 标准小组合作,将其 API 转变为官方 Web 浏览器标准,称为 [WebDriver 规范](https://w3c.github.io/webdriver/)。
所有主要浏览器现在都实现了符合 WebDriver 规范的自动化功能,而无需 Selenium 团队维护任何执行实际自动化的软件;标准获胜!
Appium's initial goals were to develop an automation standard for mobile apps (iOS and Android). We
could have made up something new, but in the spirit of joining forces and keeping standards, well,
standard, we decided to adopt the WebDriver spec as Appium's API.[^2] While user interaction on
websites and in mobile native apps are not entirely identical (with even greater differences once
we start to consider, for example, TV platforms controlled by simple remotes), the fact is that
most software UIs are pretty much the same. This means that the WebDriver spec provides automation
API primitives (finding elements, interacting with elements, loading pages or screens, etc...) that
more or less map to any platform.
Appium 的最初目标是为移动应用(iOS 和 Android)开发自动化标准。 我们本可以发明一些新的东西,但为了团结力量并保持标准的标准化,我们决定采用 WebDriver 规范作为 Appium 的 API。[^2] 虽然网站和移动原生应用的用户交互并不完全相同(一旦我们开始考虑例如由简单遥控器控制的电视平台,差异会更大),但事实是大多数软件 UI 都非常相似。 这意味着 WebDriver 规范提供了自动化 API 原语(查找元素、与元素交互、加载页面或屏幕等) 这些原语或多或少映射到任何平台。
[^2]: Technically, when Appium was first written, we were dealing with something older than the
WebDriver spec, called the JSON Wire Protocol. Since then, Appium continued to evolve along with
the W3C spec and is fully W3C-compliant.
[^2]: 从技术上讲,当 Appium 首次编写时,我们处理的是比 WebDriver 规范更古老的东西,称为 JSON Wire Protocol。 从那时起,Appium 继续与 W3C 规范一起演化,并完全符合 W3C 规范。
Of course, Appium wants to support the cases where user interaction _does_ differ from web to
mobile or web to TV, and so Appium also makes use of the built-in _extensibility_ of the WebDriver
spec. The result is that, no matter what platform you want to automate, when you use Appium, you
will do so using the standard WebDriver spec, with two caveats:
当然,Appium 希望支持用户交互从 Web 到移动或 Web 到电视确实不同的情况,因此 Appium 还利用 WebDriver 规范的内置_可扩展性_。 结果是,无论您想要自动化哪个平台,当您使用 Appium 时,您将使用标准 WebDriver 规范,但有两个注意事项:
- We might not have any way to support a particular WebDriver API command on a given platform, and
so some commands might be unsupported (for example, getting or setting cookies is not possible in
the world of native mobile app automation).
- We might support automation behaviours that go _beyond_ what's available in the WebDriver API
command list, though any such commands will be valid and spec-compliant extensions to the
WebDriver API.
- 我们可能无法在给定平台上支持特定的 WebDriver API 命令,因此某些命令可能不受支持(例如,在原生移动应用自动化世界中,获取或设置 cookie 是不可能的)。
- 我们可能支持超出 WebDriver API 命令列表的自动化行为,尽管任何此类命令将是有效的、符合规范的 WebDriver API 扩展。
How do you actually _use_ the WebDriver API, particularly in the context of Appium? We'll cover
that in the [section below](#universal-programming-language-access) on how Appium provides
universal programming language access. All you need to know for now is that the way Appium
introduces a universal UI automation interface is by implementing the WebDriver protocol.
您实际上如何_使用_ WebDriver API,特别是 Appium 的背景下? 我们将在下面的[部分](#universal-programming-language-access)中介绍 Appium 如何提供通用编程语言访问。 您现在只需要知道 Appium 通过实现 WebDriver 协议来引入通用 UI 自动化接口。
## Platform automation behaviour
## 平台自动化行为
The next question is, how does Appium map this protocol to automation behaviour on a wide range of
platforms? The trick is that, strictly speaking, Appium doesn't! It leaves this responsibility up
to a kind of software module called an Appium _driver_. There's a whole Driver
Introduction which you can read next, so we won't go into huge detail on how they
work for now.
下一个问题是,Appium 如何将此协议映射到广泛平台的自动化行为? 严格来说,Appium 没有! 它将此责任留给一种称为 Appium _驱动程序_ 的软件模块。 您可以阅读整个[驱动程序](./drivers.md)的介绍,所以我们现在不会深入细节。
What's important to understand at the moment is that a driver is kind of like a pluggable module
for Appium that gives Appium the power to automate a particular platform (or set of platforms,
depending on the goal of the driver). At the end of the day, a driver's responsibility is to simply
implement an Appium-internal interface representing the WebDriver protocol. How it implements this
interface is totally up to the driver, based on its strategy for making automation happen on
a specific platform. Typically, and with a lot more complexity and difficulty in the details,
a driver does this by relying on platform-specific automation technologies. For example, Apple
maintains an iOS automation technology called
[XCUITest](https://developer.apple.com/documentation/xctest/user_interface_tests). The Appium
driver that supports iOS app automation is called the XCUITest
Driver because ultimately what it does is
convert the WebDriver protocol to XCUITest library calls.
目前重要的是要理解驱动程序有点像 Appium 的可插拔模块,它赋予 Appium 自动化特定平台(或平台集,取决于驱动程序的目标)的能力。 最终,驱动程序的责任只是实现代表 WebDriver 协议的 Appium 内部接口。 它如何实现此接口完全取决于驱动程序,基于其在特定平台上实现自动化的策略。 通常,在细节上具有更多复杂性和难度,驱动程序通过依赖特定于平台的自动化技术来实现这一点。 例如,Apple 维护一种称为 [XCUITest](https://developer.apple.com/documentation/xctest/user_interface_tests) 的 iOS 自动化技术。 支持 iOS 应用自动化的 Appium 驱动程序称为 [XCUITest 驱动程序](https://github.com/appium/appium-xcuitest-driver),因为它最终所做的是将 WebDriver 协议转换为 XCUITest 库调用。
One of the reasons that drivers are independent, pluggable modules is that they work completely
differently from one another. The tools and requirements for building and using drivers for
different platforms are completely different. And so Appium lets you use just the drivers that you
need for your automation tasks. Choosing drivers and installing them so that you can use them with
your Appium instance is so important that Appium has its very own CLI for managing
drivers.
驱动程序是独立、可插拔模块的原因之一是它们彼此完全不同。 构建和使用不同平台的驱动程序的工具和要求完全不同。 因此,Appium 让您只使用您自动化任务所需的驱动程序。 选择驱动程序并安装它们以便与您的 Appium 实例一起使用非常重要,以至于 Appium 有自己的 [CLI 来管理驱动程序](../reference/cli/extensions.md)。
So, to answer our original question, the way that Appium provides access to automation capabilities
for a given platform is that the Appium team (or anyone else[^3]) writes a _driver_ for that
platform, implementing as much or little of the WebDriver protocol as desired. The driver can then
be installed by anyone using Appium.
因此,为了回答我们最初的问题,Appium 为给定平台提供自动化功能访问的方式是 Appium 团队(或任何人[^3])为该平台编写一个_驱动程序_,实现 WebDriver 协议的尽可能多或少的部分。 然后,任何使用 Appium 的人都可以安装驱动程序。
[^3]: You can build and share your own drivers! Check out Building
Drivers to learn more about how to develop drivers in Node.js
that can be used with Appium.
[^3]: 您可以构建和分享自己的驱动程序! 查看[构建驱动程序](../developing/build-drivers.md)以了解更多关于如何在 Node.js 中开发可与 Appium 一起使用的驱动程序的信息。
## Universal programming language access
## 通用编程语言访问
But what does it mean, or look like, to _use_ Appium, anyway? Since Appium is ultimately a Node.js
program, it _could_ have looked like importing Appium and its drivers as libraries into your own
Node.js programs. But that wouldn't meet Appium's goal of providing automation capabilities to
people using any popular programming language.
但使用 Appium 意味着什么,或者看起来像什么? 由于 Appium 最终是一个 Node.js 程序,它_可以_看起来像将 Appium 及其驱动程序作为库导入到您自己的 Node.js 程序中。 但这不会满足 Appium 的目标,即为使用任何流行编程语言的人提供自动化功能。
Luckily, the fact that Appium rode in on Selenium's coattails meant that we had a solution to this
problem from day one. You see, the WebDriver specification is actually an HTTP-based protocol,
meaning it is designed to be used over a network rather than within the memory of a single program.
幸运的是,Appium 继承 Selenium 的遗产意味着我们从一开始就有了这个问题的解决方案。 您看,WebDriver 规范实际上是一个基于 HTTP 的协议,这意味着它被设计为通过网络而不是单个程序的内存使用。
One of the main benefits of this "client-server" architecture is that it allows the automation
implementer (the thing doing the automation, in this case the 'server') to be completely distinct
from the automation runner (the thing defining what automation should be done, in what steps,
etc..., in this case the 'client'). Basically, all the "hard stuff" (actually figuring out how to
make automation happen on a given platform) can be handled in one place by the server, and "thin"
client libraries can be written in any programming language which simply encode HTTP requests to
the server in language-appropriate way. It's possible, in other words, to bring basic Appium
/ WebDriver capabilities to a new programming language relatively easily, assuming high-level HTTP
libraries exist, simply by coding up a basic HTTP client in that language.
这种“客户端-服务器”架构的主要好处之一是,它允许自动化实现者(执行自动化的事物,在这种情况下是“服务器”)与自动化运行者(定义应该做什么自动化、以什么步骤等的事物,在这种情况下是“客户端”)完全不同。 基本上,所有“困难的东西”(弄清楚如何在给定平台上实现自动化)可以在服务器的一个地方处理,“瘦”客户端库可以在任何编程语言中编写,这些库只需以适合语言的方式编码对服务器的 HTTP 请求。 换句话说,假设存在高级 HTTP 库,只需在该语言中编写基本的 HTTP 客户端,就可以相对容易地将基本的 Appium / WebDriver 功能引入新的编程语言。
There are a couple important takeaways here for you, the Appium user:
这里有几个重要的点供 Appium 用户了解:
- Appium is an _HTTP server_. It must run as a process on some computer for as long as you want to
be able to use it for automation. It must be accessible on the network to whichever computer you
want to use to run the automation from (whether that is the same machine or one across the
world).
- Unless you want to write raw HTTP calls or use cURL, using Appium for automation involves the use
of an [Appium Client](clients.md) in the language of your choice. The goal of each of these
clients is to encapsulate the WebDriver protocol so that rather than worrying about the protocol
itself, you can work with objects and methods that feel idiomatic for your language.
- The Appium server and the Appium client do _not_ need to be running on the same computer. You
simply need to be able to send HTTP requests from the client to the server over some network.
This greatly facilitates the use of cloud providers for Appium, since they can host the Appium
server and any related drivers and devices, and all you need to do is point your client script to
their secure endpoints.
- Appium 是一个_HTTP 服务器_。 只要您想使用它进行自动化,它必须在某台计算机上作为进程运行。 它必须在网络上可访问,以方便您想要运行自动化的任何计算机访问(无论是同一台机器还是世界另一端的机器)。
- 除非您想编写原始 HTTP 调用或使用 cURL,否则请使用您选择的语言的 [Appium 客户端](clients.md)进行自动化。 每个客户端的目标是将 WebDriver 协议封装,以便您不必担心协议本身,而是可以使用感觉适合您语言的对象和方法。
- Appium 服务器和 Appium 客户端_不需要_在同一台计算机上运行。 您只需能够通过某个网络从客户端向服务器发送 HTTP 请求。
这大大促进了云提供商对 Appium 的使用,因为他们可以托管 Appium 服务器以及任何相关驱动程序和设备,您只需将客户端脚本指向他们的安全端点。
And of course, none of this is about "testing" per se, purely about the use of Appium and its
client libraries for automation purposes. If you want to do automation for the purpose of
"testing", you'll likely want to enlist the help of test runners, test frameworks, and the like,
none of which need be related to Appium; one of the benefits of Appium's "universal accessibility"
is that it plays well with whatever set of tools you find most beneficial for your situation.
当然,这一切都不是关于“测试”本身,只是出于自动化目的使用 Appium 及其客户端库。 如果您想出于“测试”目的进行自动化,您可能希望利用测试运行器、测试框架等的帮助,这些都不需要与 Appium 相关;Appium“通用可访问性”的好处之一是它与您发现最适合您情况的任何工具集配合良好。
## Appium's huge scope
## Appium 的巨大范围
Appium's vision (automation of everything under a single API) is huge! Certainly, much bigger than
the team of core maintainers for the open source project. So how does Appium hope to achieve this
goal? Basically, by empowering the community to develop functionality on top of Appium as
a _platform_. This is what we call the Appium "ecosystem".
Appium 的愿景(在单一 API 下自动化一切)是巨大的! 当然,比开源项目的核心维护者团队大得多。 那么 Appium 如何希望实现这一目标? 基本上,通过授权社区在 Appium 之上作为_平台_开发功能。 这就是我们所谓的 Appium“生态系统”。
The Appium team does officially maintain a few drivers itself (for example, the XCUITest driver
that we spoke about earlier). But it cannot hope to have the platform-specific expertise or the
capacity to maintain drivers for many different platforms. But what we have done, particularly
beginning with Appium 2, is to provide tools to empower the community to join in our vision:
Appium 团队确实自己维护了一些驱动程序(例如,我们之前讨论的 XCUITest 驱动程序)。 但它无法拥有特定于平台的专业知识或维护许多不同平台的驱动程序的能力。 但我们所做的,特别是从 Appium 2 开始,是提供工具来授权社区加入我们的愿景:
- Anyone can create a driver simply by creating a Node.js module that conforms to the appropriate
conventions and implements any (sub|super)set of the WebDriver protocol. Creating a driver often
involves a minimal amount of code because the WebDriver protocol details are abstracted away, and
many helper libraries are available---the same libraries that power the Appium team's own
drivers.
- Sharing drivers with others is easy using the Appium driver CLI. There is no central authority.
Anyone can share drivers publicly or privately, for free or for sale. Drivers can be open or
closed source (though obviously we appreciate open source!).
- 任何人都可以通过创建一个符合适当约定并实现 WebDriver 协议的任何(子|超)集的 Node.js 模块来创建驱动程序。 创建驱动程序通常涉及最少的代码,因为 WebDriver 协议细节被抽象化,许多帮助库可用---这些库为 Appium 团队自己的驱动程序提供动力。
- 使用 Appium 驱动程序 CLI 与他人分享驱动程序很容易。 没有中央权威。
任何人都可以公开或私下分享驱动程序,免费或收费。 驱动程序可以是开源或闭源的(尽管我们欣赏开源!)。
Appium's vision of being a platform for development extends beyond the support of automation for
all app platforms. As a popular automation tool, there are many opportunities for integrating
Appium with all kinds of other tools and services. In addition, there are many feature ideas for
Appium, either as a core server or in its incarnation across various drivers, which the core team
will never have time to build. And so, with Appium 2, Appium has released a plugin system that
enables anyone to build and share modules that change how Appium works!
Appium 作为开发平台的愿景超越了对所有应用平台自动化支持。 作为一个流行的自动化工具,有许多机会将 Appium 与各种其他工具和服务集成。 此外,Appium 有许多功能想法,要么作为核心服务器,要么在其各种驱动程序中的化身,核心团队没有足够的时间构建。 因此,Appium 2 发布了一个插件系统,使任何人都可以构建和分享改变 Appium 工作方式的模块!
In the same way that drivers are easily shareable and consumable via the Appium driver CLI, plugins
can be published and consumed via a parallel [Plugin CLI](../reference/cli/extensions.md). Plugins
can do all sorts of things, for example adding the ability for Appium to find and interact with
screen regions based on a template image (as in the images). There are very few
limitations on what you can do with plugins, so you might also be interested in learning how to
[Build Plugins](../developing/build-plugins.md) in Node.js that can be used with Appium.
就像驱动程序可以通过 Appium 驱动程序 CLI 轻松分享和消费一样,插件可以通过[插件 CLI](../reference/cli/extensions.md)发布和消费。 插件可以做各种事情,例如添加 Appium 根据模板图像查找和与屏幕区域交互的能力(例如[图像插件](https://github.com/appium/appium/tree/master/packages/images-plugin))。 插件几乎没有限制,所以您可能也对学习如何在 Node.js 中[构建插件](../developing/build-plugins.md)以与 Appium 一起使用感兴趣。
So that's Appium: an extensible, universal interface for the UI automation of potentially
everything! Read on into some of the specific intro docs for more details, or check out the various
guides to dive into some more general concepts and features of Appium.
所以这就是 Appium:一个可扩展的、潜在一切的 UI 自动化通用接口! 继续阅读一些具体的介绍文档以获取更多细节,或查看各种指南以深入了解 Appium 的一些更一般概念和功能。
+23 -61
View File
@@ -1,57 +1,32 @@
---
hide:
- toc
title: Intro to Appium Clients
title: Appium 客户端简介
---
For all the reasons discussed in the [main Overview](./appium.md), Appium is based on the W3C
WebDriver specification. This means that
Appium implements a client-server architecture. The server (consisting of Appium itself along with
any drivers or plugins you are using for automation) is connected to the devices under test, and
is actually responsible for making automation happen on those devices. The client (driven by _you_,
the Appium test author) is responsible for sending commands to the server over the network, and
receiving responses from the server as a result. These responses can be used to tell whether
automation commands are successful, or might contain information that you queried about the state
of the application. This document is a conceptual introduction to the client side of this equation.
出于[概述](./appium.md)中讨论的所有原因,Appium 基于 [W3C WebDriver 规范](https://w3c.github.io/webdriver/)。 这意味着 Appium 实现了客户端-服务器架构。 服务器(由 Appium 本身以及您用于自动化的任何驱动程序或插件组成)连接到测试设备,并实际负责在这些设备上实现自动化。 客户端(由_您_驱动,Appium 测试作者)负责通过网络向服务器发送命令,并接收来自服务器的响应。 这些响应可用于判断自动化命令是否成功,或可能包含您查询的关于应用程序状态的信息。 本文档是对客户端方面的概念性介绍。
!!! info
```
For more about the server side of the equation (i.e., how does Appium actually control
devices?), check out our [Intro to Appium Drivers](./drivers.md). To skip to a list of links to
Appium client libraries, check out the [list of clients](../ecosystem/clients.md).
有关服务器端的信息(即 Appium 如何实际控制设备?),请查看我们的 [Appium 驱动程序简介](./drivers.md)。要跳转到 Appium 客户端库链接列表,请查看[客户端列表](../ecosystem/clients.md)。
```
What sorts of automation commands are available? That is up to the particular driver and plugins
that you are using in any given session. A standard set of commands would include, for example, the
following:
有哪些自动化命令可用? 那取决于您在任何给定会话中使用的特定驱动程序和插件。 一组标准命令可能包括以下内容:
- Find Element
- Click Element
- Get Page Source
- Take Screenshot
- 查找元素
- 点击元素
- 获取页面源代码
- 截取屏幕截图
If you look at these commands in the WebDriver specification, you'll notice that they are not
defined in terms of any particular programming language. They are not Java commands, or JavaScript
commands, or Python commands. Instead, they form part of an HTTP API which can be accessed from
within _any_ programming language (or none! you could just use cURL if you want).
如果您查看 WebDriver 规范中的这些命令,您会注意到它们不是以任何特定编程语言定义的。 它们不是 Java 命令、JavaScript 命令或 Python 命令。 相反,它们形成了可以通过_任何_编程语言访问的 HTTP API( 如果您愿意,您可以只使用 cURL)。
So, for example, the `Find Element` command corresponds to an HTTP `POST` request sent to the HTTP
endpoint `/session/:sessionid/element` (where in this case, `:sessionid` is a placeholder for the
unique session ID generated by the server in a previous call to `Create Session`).
例如,`查找元素`命令对应于发送到 HTTP 端点 `/session/:sessionid/element` 的 HTTP `POST` 请求(其中`:sessionid` 是服务器在之前 `创建会话` 调用中生成的唯一会话 ID 的占位符)。
This information is primarily useful for people developing technology that works with the WebDriver
spec. It's not particularly useful for people trying to write Appium or Selenium tests. When you
write an Appium test, you want to use a programming language you're familiar with. Luckily, there
exist a set of [Appium client libraries](../ecosystem/clients.md)[^1] that take care of the
responsibility of speaking HTTP to the Appium server. Instead, they expose a set of "native"
commands for a particular programming language, so that, to the test author, it just feels like
you're writing Python, or JavaScript, or Java.
此信息主要对开发与 WebDriver 规范一起工作的技术的人有用。 它对试图编写 Appium 或 Selenium 测试的人不是特别有用。 当您编写 Appium 测试时,您希望使用您熟悉的编程语言。 幸运的是,存在一组 [Appium 客户端库](../ecosystem/clients.md)[^1],它们负责向 Appium 服务器发起HTTP 的请求。 它们为特定编程语言公开了一组“原生”命令,以便对测试作者来说,它就像您在编写 Python、JavaScript 或 Java。
As an example, here's the same simple set of Appium commands in five different programming
languages, using the recommended Appium client binding for each language (note that this is not
working sample code including all appropriate imports; see each client library's instructions for
setup and command reference):
以下是使用 Appium 客户端在五种不同编程语言中实现相同的 Appium 命令集的示例(注意,这不是包含所有导入的工作示例代码;请参阅每个客户端库的设置和命令参考说明):
\=== "JavaScript (Webdriver.io)"
@@ -108,31 +83,18 @@ System.Console.WriteLine(driver.PageSource);
```
````
Each of these scripts, despite being in different languages, does the same thing under the hood:
尽管这些脚本使用不同的编程语言,但它们在底层做的事情是相同的:
1. Call `Find Element` with a `using` parameter of `xpath` and a `value` parameter expressing the
XPath query used to find an element. (If you're confused about these terms, you might find an
introduction to Appium or Selenium useful)
2. Call `Click Element` with the ID of the element found in the previous call.
3. Call `Get Element Text` with the ID of the same element, and print it to the console.
4. Call `Get Page Source` to retrieve the page/app source and print it to the console.
1. 调用 `Find Element`,使用 `using` 参数值为 `xpath`,以及 `value` 参数表达用于查找元素的 XPath 查询。 (如果你对这些术语感到困惑,可以参考 Appium 或 Selenium 的入门介绍)
2. 使用在上一次调用中找到的元素 ID 调用 `Click Element`。
3. 使用同一元素的 ID 调用 `Get Element Text`,并将其打印到控制台。
4. 调用 `Get Page Source` 来检索页面/应用程序源代码并将其打印到控制台。
The only other thing to keep in mind before choosing or using a client is that each client is
independently maintained. Just because a feature is available in one client, it doesn't mean it's
available in another client (though all clients support at least the standard W3C protocol plus any
common appium extensions). Just because one client has a nice set of helper functions, doesn't mean
another will. Some clients are kept very frequently up to date, and others are not! So when
thinking about choosing a library, the first consideration is the language you want to use, and the
second consideration is how full-featured and well-maintained the library is!
在选择或使用客户端之前,需要记住的另一件事是每个客户端都是独立维护的。 仅仅因为某个功能在一个客户端中可用,并不意味着它在另一个客户端中也可用(尽管所有客户端至少支持标准的 W3C 协议以及任何常见的 Appium 扩展)。 仅仅因为一个客户端有一套很好的辅助函数,并不意味着另一个客户端也会有。 有些客户端更新非常频繁,而其他客户端则不然! 因此,在考虑选择一个库时,首要考虑的是你想使用的语言,第二个考虑因素是该库的功能完善程度和维护情况!
To learn how to use an Appium client, visit that client's homepage to learn more. In many cases,
the Appium client for a given language is built _on top of_ the _Selenium_ client for that
language, and so certain Appium clients may only document the features which the Appium client
added on top of the Selenium client. All that to say, for a full reference, you may need to visit
both the Appium client documentation as well as the Selenium client documentation.
要学习如何使用 Appium 客户端,请访问该客户端的主页以了解更多信息。 在许多情况下,特定语言的 Appium 客户端是在该语言的 _Selenium_ 客户端之上构建的,因此某些 Appium 客户端可能只记录 Appium 客户端在 Selenium 客户端基础上添加的功能。 也就是说,要获得完整的参考,你可能需要访问 Appium 客户端文档以及 Selenium 客户端文档。
That's all you need to know about Appium clients! Head over to the
[Clients](../ecosystem/clients.md) page to check out the current list of clients.
这就是你需要了解的关于 Appium 客户端的全部内容! 前往 [客户端](../ecosystem/clients.md) 页面查看当前的客户端列表。
[^1]: These libraries are alternately called "clients", "client libraries", or "client bindings".
They all mean the same thing!
[^1]: 这些库也被称为"客户端"、"客户端库"或"客户端绑定"。
它们的意思都是一样的!
+1
View File
@@ -1,6 +1,7 @@
---
hide:
- toc
title: Appium in a Nutshell
---
+12 -18
View File
@@ -2,28 +2,22 @@
hide:
- toc
title: Getting Started
title: 入门指南
---
Let's get up and running with Appium! To successfully use this quickstart, it's recommended that
you first have read the [Introduction](../intro/index.md), so that you understand the concepts involved in
running Appium and writing Appium scripts.
让我们开始使用Appium! 为了成功使用此快速入门,建议您首先阅读[介绍](../intro/index.md),以便了解运行Appium和编写Appium脚本的概念。
The basic plan for this quickstart is as follows:
此快速入门的基本计划如下:
1. Install Appium
2. Install an Appium driver and its dependencies
- This guide provides instructions for the [UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver)
3. Install an Appium client library in your language of choice
- This guide contains options for JavaScript, Python, Java, Ruby, and .NET
4. Write and run a simple Appium automation script using a sample application
1. 安装Appium
2. 安装Appium驱动程序及其依赖项
- 本指南提供了[UiAutomator2 驱动程序](https://github.com/appium/appium-uiautomator2-driver) 的说明
3. 在您选择的语言中安装Appium客户端库
- 本指南包含JavaScript、Python、Java、Ruby和.NET的选项
4. 使用示例应用程序编写并运行简单的Appium自动化脚本
### Requirements
### 系统需求
Before getting started, make sure your system satisfies the
[requirements](../quickstart/requirements.md) for running the Appium server. Additional requirements
will be discussed in conjunction with installing the UiAutomator2 driver. The guide also assumes
you have basic command line proficiency on your platform, for example being able to run commands, set
and persist environment variables, etc...
在开始之前,请确保您的系统满足运行Appium服务器的[要求](../quickstart/requirements.md)。 其他要求将在安装UiAutomator2驱动程序时讨论。 本指南还假设您在平台上具有基本的命令行熟练度,例如能够运行命令、设置和持久化环境变量等...
Now you're ready to get started! So head on over to [Installing Appium](./install.md).
现在您准备开始了! 前往安装[Appium](./install.md)。
+13 -20
View File
@@ -2,42 +2,39 @@
hide:
- toc
title: Install Appium
title: 安装Appium
---
!!! info
!!! 信息
```
Before installing, make sure to check the [System Requirements](./requirements.md).
安装前,请确保检查 [系统要求] (./requirements.md)。
```
Appium can be installed globally using `npm`:
Appium 可以使用 "npm" 在全局安装:
```bash
npm install -g appium
```
!!! note
!!! 备注
```
Other package managers are not currently supported.
目前不支持其他软件包管理。
```
## Starting Appium
## 启动Appium
Appium can be started [using the command line](../reference/cli/index.md):
Appium 可以使用 [命令行](../reference/cli/index.md) 启动:
```
appium
```
This launches the Appium server process, which loads all the installed Appium drivers, and
begins waiting for new session requests from client connections (such as test automation scripts).
Since the server process is independent from its clients, it must be explicitly launched before
attempting to start a new session.
这会启动Appium服务器进程,该进程加载所有已安装的Appium驱动程序,并开始等待来自客户端连接(如测试自动化脚本)的新会话请求。
由于服务器进程独立于其客户端,因此必须在尝试启动新会话之前明确启动它。
When the server is launched, the console log will list all the valid URLs that clients can use to
connect to this server:
当服务器启动时,控制台日志将列出客户端可以用来连接到此服务器的所有有效URL:
```
[Appium] You can provide the following URLs in your client code to connect to this server:
@@ -45,10 +42,6 @@ connect to this server:
(... any other URLs ...)
```
Once a client requests a new session, the Appium server process will start logging all details about
this session until its termination. Keep this in mind - if you ever encounter issues with Appium
tests, you can always check the server log for more details.
一旦客户端请求新会话,Appium服务器进程将开始记录此会话的所有详细信息,直到其终止。 请记住这一点——如果您遇到Appium测试的问题,您可以随时检查服务器日志以获取更多详细信息。
So what's next? Even though Appium is installed and running, it does not come bundled with any
drivers, which means it cannot automate anything yet. We will therefore set up automation for
Android - continue to [Installing the UiAutomator2 Driver](./uiauto2-driver.md).
接下来是什么? 即使Appium已安装并运行,它也不捆绑任何驱动程序,这意味着它还不能自动化任何东西。 因此,我们将为Android设置自动化——继续[安装UiAutomator2驱动程序](./uiauto2-driver.md)。
@@ -1,22 +1,19 @@
---
hide:
- toc
title: Next Steps
title: 下一步
---
Now that you've successfully set up your system for Android automation and run a simple test,
you'll want to continue exploring this documentation. In particular, these are good guides and
reference materials especially for beginners:
现在您已成功为Android自动化设置了系统并运行了一个简单的测试,您将希望继续探索此文档。 特别是,这些是适合初学者的优秀指南和参考资料: 特别是,这些是适合初学者的优秀指南和参考资料:
- The [Ecosystem](../ecosystem/index.md) page: browse the available drivers, clients, plugins, and tools
- [Managing Appium Drivers and Plugins](../guides/managing-exts.md)
- [Capabilities](../guides/caps.md)
- [Settings](../guides/settings.md)
- [生态系统](../ecosystem/index.md) 页面:浏览可用的驱动程序、客户端、插件和工具
- [管理Appium驱动程序和插件](../guides/managing-exts.md)
- [功能](../guides/caps.md)
- [设置](../guides/settings.md)
You'll also find that the [Appium Inspector](https://github.com/appium/appium-inspector) is an
indispensable tool for writing Appium tests, as it enables visual inspection of apps and
helps you to discover element locators for use in your test scripts.
您还会发现[Appium Inspector](https://github.com/appium/appium-inspector)是编写Appium测试不可或缺的工具,因为它允许对应用进行视觉检查,并帮助您发现测试脚本中使用的元素定位器。
You might also take advantage of one of the many online Appium courses available to you.
您还可以利用众多可用的在线Appium课程之一。
Good luck and have fun!
祝您好运,玩得开心!
@@ -2,28 +2,20 @@
hide:
- toc
title: System Requirements
title: 系统要求
---
The basic requirements for the Appium server are:
Appium 服务器的基本要求如下:
- A macOS, Linux, or Windows operating system
- [Node.js](https://nodejs.org) version in the [SemVer](https://semver.org) range `^20.19.0 || ^22.12.0 || >=24.0.0`
- LTS is recommended
- [`npm`](https://npmjs.com) version `>=10` (`npm` is usually bundled with Node.js, but can be upgraded
independently)
- macOS、Linux 或 Windows 操作系统
- [Node.js](https://nodejs.org) 版本在 [SemVer](https://semver.org) 范围 `^20.19.0 || ^22.12.0 || >=24.0.0`
- 推荐使用 LTS 版本
- [`npm`](https://npmjs.com) 版本 `>=10`(`npm` 通常与 Node.js 捆绑,但可以独立升级)
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.
Appium 本身相对轻量,没有显著的磁盘空间或 RAM 要求。 即使在资源受限的环境如 Raspberry Pi 中,只要有 Node.js 就可以运行。
### 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.
用于自动化特定平台的驱动程序可能有其他要求。 请参考该平台的 [Appium 驱动程序](../ecosystem/drivers.md) 文档以获取其他依赖项。 普遍的情况是,给定平台的 Appium 驱动程序需要安装该平台的开发者工具链和 SDK。
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](../reference/cli/extensions.md#doctor).
为了帮助处理驱动程序要求,每个(官方)驱动程序都附带 Appium Doctor 工具,它允许验证是否已设置所有要求。 了解如何使用此工具的更多信息,请参阅 [命令行使用文档](../reference/cli/extensions.md#doctor)。
@@ -2,13 +2,13 @@
hide:
- toc
title: Write a Test (.NET)
title: 编写测试 (.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/).
[Appium .NET Client](https://github.com/appium/dotnet-client/) 是
官方的 Appium C# 客户端。 这个驱动程序是 Selenium C# 客户端的扩展。 它具有常规驱动程序的所有功能,但在之上添加了 Appium 特定的方法。 该驱动程序在公共 NuGet Gallery 上作为 [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.
现在,我们进入目录并创建一个新的 [NUnit](https://nunit.org/) 项目。 我们还将添加对 Appium.Net 驱动程序和其他依赖项的引用。
```bash
cd dotnet-client
@@ -16,12 +16,12 @@ dotnet new nunit --name appiumtest
cd appiumtest
# This will install the latest 5.x version
# 这将安装最新的 5.x 版本
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.
完成后,您的项目应该有一个占位符文件 `UnitTest1.cs`。 我们将替换代码以包含 OpenQA 命名空间、驱动程序的初始化以及实际测试。
```C# title="UnitTest1.cs"
using OpenQA.Selenium;
@@ -69,39 +69,31 @@ public class Tests
}
```
!!! 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.
这份指南的范围不包括对 dotnet 客户端库或此处发生的一切进行完整说明,因此我们暂时不对代码本身进行详细解释。您可能需要特别阅读 Appium [Capabilities](../guides/caps.md),以及熟悉 [dotnet 客户端驱动程序文档](https://github.com/appium/dotnet-client/) 以获得对您看到的各种 API 命令及其目的的更全面解释。
```
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 overridden using environment variables.
2. Starting an Appium session on the built-in Android settings app.
3. Finding the "Apps" list item and clicking it.
4. Ending the Appium session.
1. 定义一组"Capabilities"(参数)发送到 Appium 服务器,以便 Appium 知道您想要自动化什么。 有些参数可以使用环境变量覆盖。
2. 在内置的 Android 设置应用上启动 Appium 会话。
3. 查找"Apps"列表项并点击它。
4. 结束 Appium 会话。
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:
就是这样! 让我们试试。 在运行测试之前,请确保在另一个终端会话中运行 Appium 服务器,否则您会收到无法连接的错误。 然后,您可以执行脚本:
```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 "Apps" view in the emulator before the app closes again.
如果一切顺利,您将看到设置应用打开并在模拟器中导航到"Apps"视图,然后应用再次关闭。
Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.
恭喜,您已经开始了 Appium 之旅! 继续阅读一些 [后续步骤](./next-steps.md) 以进行探索。
+11 -13
View File
@@ -1,22 +1,20 @@
---
hide:
- toc
title: Write a Test (Java)
title: 编写测试 (Java)
---
The Appium team maintains an official [client](https://github.com/appium/java-client) for the Java programming language.
It is built on top of [Selenium](https://github.com/SeleniumHQ/selenium).
You can also use this client in your Kotlin projects.
Appium 团队维护了一个官方的 [客户端](https://github.com/appium/java-client) 用于 Java 编程语言。
它建立在 [Selenium](https://github.com/SeleniumHQ/selenium) 之上。
您也可以在 Kotlin 项目中使用此客户端。
Follow the [Add Appium java client to your test framework](https://github.com/appium/java-client#add-appium-java-client-to-your-test-framework)
tutorial in order to connect the library to your test framework sources.
按照 [将 Appium Java 客户端添加到您的测试框架](https://github.com/appium/java-client#add-appium-java-client-to-your-test-framework) 教程将库连接到您的测试框架源代码。
The Appium Java client has dedicated classes to support most of the official Appium drivers. For other drivers
you could simply use the [AppiumDriver](https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/AppiumDriver.java) class
or build your custom derivatives from it. Check the [Drivers Support](https://github.com/appium/java-client#drivers-support)
article to learn more about the current driver class implementations.
Appium Java 客户端具有专用类来支持大多数官方 Appium 驱动程序。 对于其他驱动程序,您可以简单地使用 [AppiumDriver](https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/AppiumDriver.java) 类
或从中构建自定义派生类。 查看 [驱动程序支持](https://github.com/appium/java-client#drivers-support) 文章以了解当前驱动程序类实现的更多信息。
Follow the [Usage Examples](https://github.com/appium/java-client#usage-examples) article in order understand
how to invoke Java client features from your test framework.
按照 [使用示例](https://github.com/appium/java-client#usage-examples) 文章以了解
如何从您的测试框架调用 Java 客户端功能。
Once you've managed to successfully run a test, you can read on for some [next steps](./next-steps.md) to explore.
一旦您成功运行了一个测试,您可以继续阅读一些 [后续步骤](./next-steps.md) 以进行探索。
+17 -32
View File
@@ -2,36 +2,30 @@
hide:
- toc
title: Write a Test (JS)
title: 编写测试 (JS)
---
To write an Appium test in JavaScript (Node.js), we need to choose an Appium-compatible client
library. The best-maintained library and the one the Appium team recommends using is
[WebdriverIO](https://webdriver.io), so let's use that. Since we already have Appium installed we
know our Node and NPM requirements are already satisfied. So just create a new project directory
somewhere on your computer and then initialize a new Node.js project in it:
要在 JavaScript (Node.js) 中编写 Appium 测试,我们需要选择一个与 Appium 兼容的客户端库。 维护最好的库,也是 Appium 团队推荐使用的,是 [WebdriverIO](https://webdriver.io),所以让我们使用它。 由于我们已经安装了 Appium,我们知道我们的 Node 和 NPM 已经满足要求。 所以在您的计算机上某个地方创建一个新的项目目录,然后在其中初始化一个新的 Node.js 项目:
```bash
npm init
```
It doesn't really matter what you put in the prompts, just so long as you end up with a valid
`package.json`.
提示中输入什么并不重要,只要最终得到一个有效的 `package.json`。
Now, install the `webdriverio` package via NPM:
现在,通过 NPM 安装 `webdriverio` 包:
```bash
npm i --save-dev webdriverio
```
Once this is done, your `package.json` file should include a section like the following:
完成后,您的 `package.json` 文件应该包含如下部分:
```json title="package.json"
--8<-- "./sample-code/quickstarts/js/package.json"
```
Now it's time to type up the test itself. Create a new file called `test.js` with the following
contents:
现在是编写测试本身的时候了。 创建一个名为 `test.js` 的新文件,内容如下:
```js title="test.js"
--8<-- "./sample-code/quickstarts/js/test.js"
@@ -40,38 +34,29 @@ contents:
!!! note
```
It's not within the scope of this guide to give a complete run-down on the WebdriverIO 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 excellent
[WebdriverIO documentation](https://webdriver.io/docs/gettingstarted) for a fuller explanation
of the various API commands you see and what their purpose is.
这份指南的范围不包括对 WebdriverIO 客户端库或此处发生的一切进行完整说明,因此我们暂时不对代码本身进行详细解释。您可能需要特别阅读 Appium [Capabilities](../guides/caps.md),以及熟悉优秀的 [WebdriverIO 文档](https://webdriver.io/docs/gettingstarted) 以获得对您看到的各种 API 命令及其目的的更全面解释。
```
!!! note
```
The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/js).
示例代码可从 [GitHub Appium 仓库](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/js) 获取。
```
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.
2. Starting an Appium session on the built-in Android settings app.
3. Finding the "Apps" list item and clicking it.
4. Pausing for a moment purely for visual effect.
5. Ending the Appium session.
1. 定义一组"Capabilities"(参数)发送到 Appium 服务器,以便 Appium 知道您想要自动化什么。
2. 在内置的 Android 设置应用上启动 Appium 会话。
3. 查找"Apps"列表项并点击它。
4. 暂停片刻纯粹为了视觉效果。
5. 结束 Appium 会话。
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:
就是这样! 让我们试试。 在运行测试之前,请确保在另一个终端会话中运行 Appium 服务器,否则您会收到无法连接的错误。 然后,您可以执行脚本:
```bash
node test.js
```
If all goes well, you'll see the Settings app open up and navigate to the "Apps" view before the
app closes again.
如果一切顺利,您将看到设置应用打开并导航到"Apps"视图,然后应用再次关闭。
Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.
恭喜,您已经开始了 Appium 之旅! 继续阅读一些 [后续步骤](./next-steps.md) 以进行探索。
+22 -28
View File
@@ -2,21 +2,21 @@
hide:
- toc
title: Write a Test (Python)
title: 编写测试 (Python)
---
The [Appium Python Client](https://github.com/appium/python-client) is
an official Appium client in Python, which is available via pypi under the [Appium-Python-Client](https://pypi.org/project/Appium-Python-Client/) package name.
It inherits from the [Selenium Python Binding](https://pypi.org/project/selenium/),
so installing the Appium Python Client includes the selenium binding.
[Appium Python Client](https://github.com/appium/python-client) 是
官方的 Python Appium 客户端,可通过 pypi 以 [Appium-Python-Client](https://pypi.org/project/Appium-Python-Client/) 包名获取。
它继承自 [Selenium Python Binding](https://pypi.org/project/selenium/),
因此安装 Appium Python Client 包括 selenium 绑定。
```bash
pip install Appium-Python-Client
```
This example uses Python's built-in `unittest` module, though you can use any Python test framework you want.
The Appium Python client adds the `appium:` vendor prefix automatically.
You usually do not need to worry about the prefix.
此示例使用 Python 的内置 `unittest` 模块,您也可以使用任何您想要的 Python 测试框架。
Appium Python 客户端自动添加 `appium:` 前缀。
您通常不需要担心前缀。
```python title="test.py"
--8<-- "./sample-code/quickstarts/py/test.py"
@@ -25,39 +25,33 @@ You usually do not need to worry about the prefix.
!!! note
```
It's not within the scope of this guide to give a complete run-down on the Python client
library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.
这份指南的范围不包括对 Python 客户端库或此处发生的一切进行完整说明,因此我们暂时不对代码本身进行详细解释。
- You may want to read up particularly on Appium [Capabilities](../guides/caps.md).
- [functional test code](https://github.com/appium/python-client/tree/master/test/functional) in Python Client GitHub repository should help to find more working example.
- [Documentation](https://appium.github.io/python-client-sphinx/) also helps to find methods
defined in the Appium Python Client.
- 您可能需要特别阅读 Appium [Capabilities](../guides/caps.md)。
- Python Client GitHub 仓库中的 [功能测试代码](https://github.com/appium/python-client/tree/master/test/functional) 应该有助于找到更多工作示例。
- [文档](https://appium.github.io/python-client-sphinx/) 也有助于找到 Appium Python Client 中定义的方法。
```
!!! note
```
The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/py).
示例代码可从 [GitHub Appium 仓库](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/py) 获取。
```
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.
2. Starting an Appium session on the built-in Android settings app.
3. Finding the "Apps" list item and clicking it.
4. Pausing for a moment purely for visual effect.
5. Ending the Appium session.
1. 定义一组"Capabilities"(参数)发送到 Appium 服务器,以便 Appium 知道您想要自动化什么。
2. 在内置的 Android 设置应用上启动 Appium 会话。
3. 查找"Apps"列表项并点击它。
4. 暂停片刻纯粹为了视觉效果。
5. 结束 Appium 会话。
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:
就是这样! 让我们试试。 在运行测试之前,请确保在另一个终端会话中运行 Appium 服务器,否则您会收到无法连接的错误。 然后,您可以执行脚本:
```bash
python test.py
```
If all goes well, you'll see the Settings app open up and navigate to the "Apps" view before the
app closes again.
如果一切顺利,您将看到设置应用打开并导航到"Apps"视图,然后应用再次关闭。
Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.
恭喜,您已经开始了 Appium 之旅! 继续阅读一些 [后续步骤](./next-steps.md) 以进行探索。
+26 -31
View File
@@ -2,18 +2,18 @@
hide:
- toc
title: Write a Test (Ruby)
title: 编写测试 (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.
[AppiumLib](https://github.com/appium/ruby_lib) 和 [AppiumLibCore](https://github.com/appium/ruby_lib_core)(**推荐**)是 Ruby 中的官方 Appium 客户端库,可通过 gem 以 [appium_lib](https://rubygems.org/gems/appium_lib) 和 [appium_lib_core](https://rubygems.org/gems/appium_lib_core) 包名获取。 appium_lib_core 继承自 Selenium Ruby Binding,而 appium_lib 继承自 appium_lib_core,因此安装这些库包括 selenium 绑定。 如果您需要一个不太复杂的客户端解决方案,我们推荐 `appium_lib_core`。 `appium_lib` 有一些核心没有的有用方法,但代价是更大的复杂性和可能在最新环境中不工作的历史方法。
As the first step, let's initialize a Gemfile to manage the dependency:
作为第一步,让我们初始化一个 Gemfile 来管理依赖项:
```bash
bundle init
```
Then, you could add Appium Ruby Client dependency as below:
然后,您可以如下添加 Appium Ruby Client 依赖项:
```bash
bundle add appium_lib_core
@@ -21,24 +21,24 @@ bundle add appium_lib_core
# bundle add appium_lib
```
Test code example below uses `test-unit` module, thus please run:
下面的测试代码示例使用 `test-unit` 模块,因此请运行:
```bash
bundle add test-unit
```
Once these steps has done, your `Gemfile` file should include:
一旦这些步骤完成,您的 `Gemfile` 文件应该包含:
```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.
`appium_lib_core` 是作为 Appium 客户端的主要部分。
`appium_lib` 有各种辅助方法,但驱动程序实例通常被设计为全局变量使用。 它可能导致处理实例的问题。
`appium_lib_core` 没有这样的全局变量。
This example is by the `appium_lib_core` with `test-unit` gem module.
Tes code in `appium_lib` should be similar.
此示例使用 `appium_lib_core` 和 `test-unit` gem 模块。
在 `appium_lib` 中的测试代码应该类似。
```ruby title="test.rb"
--8<-- "./sample-code/quickstarts/rb/test.rb"
@@ -47,39 +47,34 @@ Tes code in `appium_lib` should be similar.
!!! 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.
这份指南的范围不包括对 Ruby 客户端库或此处发生的一切进行完整说明,因此我们暂时不对代码本身进行详细解释。
- 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.
- 您可能需要特别阅读 Appium [Capabilities](../guides/caps.md)。
- appium_lib_core GitHub 仓库中的 [功能测试代码](https://github.com/appium/ruby_lib_core/tree/master/test/functional) 应该有助于找到更多工作示例。
- 文档 [appium_lib_core](https://www.rubydoc.info/github/appium/ruby_lib_core) 和 [appium_lib](https://www.rubydoc.info/github/appium/ruby_lib) 也有助于找到可用方法。
```
!!! note
```
The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/rb).
示例代码可从 [GitHub Appium 仓库](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.
2. Starting an Appium session on the built-in Android settings app.
3. Finding the "Apps" list item and clicking it.
4. Pausing for a moment purely for visual effect.
5. Ending the Appium session.
1. 定义一组"Capabilities"(参数)发送到 Appium 服务器,以便 Appium 知道您想要自动化什么。
2. 在内置的 Android 设置应用上启动 Appium 会话。
3. 查找"Apps"列表项并点击它。
4. 暂停片刻纯粹为了视觉效果。
5. 结束 Appium 会话。
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:
就是这样! 让我们试试。 在运行测试之前,请确保在另一个终端会话中运行 Appium 服务器,否则您会收到无法连接的错误。 然后,您可以执行脚本:
```bash
# Please run "bundle install" first if your environment has not run the installation command yet.
# 如果您的环境尚未运行安装命令,请先运行 "bundle install"。
bundle exec ruby test.rb
```
If all goes well, you'll see the Settings app open up and navigate to the "Apps" view before the
app closes again.
如果一切顺利,您将看到设置应用打开并导航到"Apps"视图,然后应用再次关闭。
Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.
恭喜,您已经开始了 Appium 之旅! 继续阅读一些 [后续步骤](./next-steps.md) 以进行探索。
@@ -1,81 +1,64 @@
---
title: Install the UiAutomator2 Driver
title: 安装 UiAutomator2 驱动程序
---
You can't do much with Appium unless you have a [driver](../intro/drivers.md), which is an
interface that allows Appium to automate a particular platform.
除非您有[驱动程序](../intro/drivers.md),否则您无法使用 Appium 做太多事情,驱动程序是一个允许 Appium 自动化特定平台的接口。
!!! info
```
For this quickstart guide, we're going to be automating an app on the Android platform, because
the system requirements for Android automation via Appium are the same as for Appium itself
(whereas the iOS driver, for example, requires you to be using macOS).
对于这个快速入门指南,我们将在 Android 平台上自动化一个应用,因为通过 Appium 进行 Android 自动化的系统要求与 Appium 本身相同(而 iOS 驱动程序,则要求您使用 macOS)。
```
The driver we're going to use is called the UiAutomator2
Driver. It's worth visiting that driver's
documentation and bookmarking it, because it will be an invaluable reference down the line.
我们要使用的驱动程序称为 [UiAutomator2 驱动程序](https://github.com/appium/appium-uiautomator2-driver)。 请访问该驱动程序的文档并将其加入书签,因为它将成为未来宝贵的参考。
## Set up Android automation requirements
## 设置 Android 自动化要求
According to the driver, in addition to a working Appium server, we also need to set up the following:
根据驱动程序,除了工作 Appium 服务器,我们还需要设置以下内容:
### Android SDK
- The easiest way to set up the Android SDK requirements is by downloading [Android Studio](https://developer.android.com/studio).
We need to use its SDK manager (_Settings -> Languages & Frameworks -> Android SDK_)
to download the following items:
- Android SDK Platform (select whichever Android platform we want to automate, for example, API level 30)
- Android SDK Platform-Tools
- If you wish, you can also download these items without Android Studio:
- Android SDK Platform can be downloaded using `sdkmanager` included in [Android command-line tools](https://developer.android.com/studio#command-line-tools-only)
- [Android SDK Platform-Tools](https://developer.android.com/tools/releases/platform-tools)
- Set up the `ANDROID_HOME` environment variable to point to the directory where the Android SDK is
installed. You can usually find the path to this directory in the Android Studio SDK manager. It
will contain the `platform-tools` and other directories.
- 设置 Android SDK 的最简单方法是下载 [Android Studio](https://developer.android.com/studio)。
我们需要使用其 SDK 管理器(_设置 -> 语言和框架 -> Android SDK_)下载以下项目:
- Android SDK 平台(选择我们想要自动化的任何 Android 平台,例如 API 级别 30)
- Android SDK 平台工具
- 如果您愿意,您也可以在没有 Android Studio 的情况下下载这些项目:
- Android SDK 平台可以使用包含在 [Android 命令行工具](https://developer.android.com/studio#command-line-tools-only) 中的 `sdkmanager` 下载
- [Android SDK 平台工具](https://developer.android.com/tools/releases/platform-tools)
- 设置 `ANDROID_HOME` 环境变量指向安装 Android SDK 的目录。 您通常可以在 Android Studio SDK 管理器中找到此目录的路径。 它将包含 `platform-tools` 和其他目录。
### Java JDK
- Install the Java JDK (for the most recent Android API levels, JDK 9 is required, otherwise JDK
8 is required). You can download this from [Oracle](https://jdk.java.net/) or [Adoptium](https://adoptium.net/en-GB/temurin/releases/).
Make sure you get the JDK and not the JRE.
- Set up the `JAVA_HOME` environment variable to point to the JDK home directory. It will contain
the `bin`, `include`, and other directories.
- 安装 Java JDK(对于最新的 Android API 级别,需要 JDK 9,否则请用 JDK 8)。 您可以从 [Oracle](https://jdk.java.net/) 或 [Adoptium](https://adoptium.net/en-GB/temurin/releases/) 下载此软件。
确保您获得 JDK 而不是 JRE。
- 设置 `JAVA_HOME` 环境变量指向 JDK 主目录。 它将包含 `bin`、`include` 和其他目录。
### Prepare the Device
### 准备设备
- If using an emulator, use Android Studio to create and launch an Android Virtual Device (AVD).
You may need to download the system images for the API level of the emulator you want to
create. Using the AVD creation wizard in Android Studio is generally the easiest way to do all of
this.
- If using a real device, you should [set it up for development and enable USB Debugging](https://developer.android.com/studio/debug/dev-options).
- With the emulator or device connected, you can run `adb devices` (via the binary located at
`$ANDROID_HOME/platform-tools/adb`) to verify that your device shows up as connected.
- 如果使用模拟器,使用 Android Studio 创建和启动 Android 虚拟设备 (AVD)。
您可能需要下载要创建的模拟器的 API 级别的系统映像。 使用 Android Studio 中的 AVD 创建向导通常是完成所有这些的最简单方法。
- 如果使用真实设备,您应该为其设置[开发者模式并启用 USB 调试](https://developer.android.com/studio/debug/dev-options)。
- 连接模拟器或设备后,您可以运行 `adb devices`(adb位于 `$ANDROID_HOME/platform-tools/adb`)来验证您的设备是否显示为已连接。
Once your device shows up as connected in `adb`, and you've verified that the environment variables
are set up correctly, you should be good to go! If you ran into problems with any of these steps,
refer to the driver documentation, or the various Android or Java documentation sites as necessary.
一旦您的设备在 `adb` 中显示为已连接,并且您验证了环境变量设置正确,您应该准备好了! 如果您在这些步骤中的任何一个遇到问题,请参考驱动程序文档,或根据需要参考各种 Android 或 Java 文档站点。
Also, congratulations: whether or not you intended to, you now have the Android developer toolchain
set up on your system, so you can get busy making Android apps if you want!
恭喜:无论您是否打算这样做,您现在已经在系统上设置了 Android 开发者工具链,所以如果您愿意,可以开始制作 Android 应用!
## Install the driver itself
## 安装驱动程序本身
### Standard Install
### 标准安装
Like all Appium drivers, the UiAutomator2 driver is installed via the [Appium Extension CLI](../reference/cli/extensions.md).
Since UiAutomator2 is maintained by the core Appium team, it has an 'official' driver name
(`uiautomator2`), which makes the installation simpler.
像所有 Appium 驱动程序一样,UiAutomator 2 驱动程序通过 [Appium 扩展 CLI](../reference/cli/extensions.md) 安装。
由于 UiAutomator 2 由核心 Appium 团队维护,它有一个“官方”驱动程序名称(`uiautomator2`),这使得安装更简单。
Before installing, make sure your Appium server is _not_ running (if it is, quit it with _Ctrl-C_).
Then run the following command:
在安装之前,确保您的 Appium 服务器_未_运行(如果正在运行,请用 _Ctrl-C_ 退出)。
然后运行以下命令:
```bash
appium driver install uiautomator2
```
It should produce output that looks something like:
它应该产生看起来像这样的输出:
```
Attempting to find and install driver 'uiautomator2'
@@ -85,57 +68,45 @@ Driver uiautomator2@2.0.5 successfully installed
- platformNames: ["Android"]
```
Note how the installation process specifies what platforms is the driver valid for (in this case,
`Android`), and what automation name (the `appium:automationName` [capability](../guides/caps.md))
must be used to select this driver for use during an Appium session (in this case, `UiAutomator2`).
注意安装过程如何指定驱动程序的适用平台(在这里选 `Android`),以及必须用于在 Appium 会话期间选择此驱动程序的自动化名称(`appium:automationName` [能力](../guides/caps.md))(在这里选 `UiAutomator2`)。
!!! note
```
In this quickstart we have used the [Extension CLI](../reference/cli/extensions.md) to install the
UiAutomator2 driver, but if you are incorporating Appium into a Node.js project, you might
prefer to use `npm` to manage Appium and its connected drivers. To learn more about this
technique, visit the guide on [managing Appium extensions](../guides/managing-exts.md).
在这个快速入门中,我们使用了 [CLI扩展](../reference/cli/extensions.md) 来安装 UiAutomator 2 驱动程序,但如果您将 Appium 纳入 Node.js 项目,您可能更喜欢使用 `npm` 来管理 Appium 及其连接的驱动程序。要了解更多关于此技术的信息,请访问关于[管理 Appium 扩展](../guides/managing-exts.md)的指南。
```
### Batch Install
### 批量安装
You may want to use Appium with more than one driver. One way to accomplish this is to run
`appium driver install <driver-name>` for each individual driver, but you can also install multiple
drivers in one go:
您可能希望将 Appium 与多个驱动程序一起使用。 一种方法是为每个单独的驱动程序运行 `appium driver install <driver-name>`,但您也可以一次性安装多个驱动程序:
```
appium setup
```
Running this will install Appium's mobile-specific drivers: UiAutomator2, [XCUITest](https://appium.github.io/appium-xcuitest-driver/)
(only if running macOS), and [Espresso](https://github.com/appium/appium-espresso-driver).
运行此命令将安装 Appium 的移动端特定驱动程序:UiAutomator2、[XCUITest](https://appium.github.io/appium-xcuitest-driver/)(仅在运行 macOS 时),以及 [Espresso](https://github.com/appium/appium-espresso-driver)。
You can also use this command to batch install drivers for desktop applications or desktop browsers.
For more details on this, refer to the [Setup command documentation](../reference/cli/setup.md).
您也可以使用此命令批量安装桌面应用程序或桌面浏览器的驱动程序。
有关更多详细信息,请参考[设置命令文档](../reference/cli/setup.md)。
### Validating the Install
### 验证安装
The UiAutomator2 driver, like all official Appium drivers, comes with the Appium Doctor tool, which
allows validating whether all prerequisites have been set up correctly:
UiAutomator2 驱动程序,像所有官方 Appium 驱动程序一样,带有 Appium Doctor 工具,它允许验证是否所有先决条件都已正确设置:
```
appium driver doctor uiautomator2
```
This guide has focused on essential requirements, so Appium Doctor may suggest one or more optional
fixes. But if you see `0 required fixes needed`, that means everything is set up!
本指南专注于基本要求,因此 Appium Doctor 可能建议一个或多个可选修复。 但如果您看到 `0 required fixes needed`,那意味着一切都设置好了!
Now, start the Appium server again (run `appium`), and you should see that the newly-installed
driver is listed as available:
现在,再次启动 Appium 服务器(运行 `appium`),您应该看到新安装的驱动程序列为可用:
```
[Appium] Available drivers:
[Appium] - uiautomator2@2.0.5 (automationName 'UiAutomator2')
```
With the Android setup complete and the UiAutomator2 driver installed, you're ready to write your
first test! Now select your preferred language and give it a shot:
Android 设置完成并安装了 UiAutomator2 驱动程序,准备编写第一个测试吧! 现在选择您喜欢的语言并试试:
<div class="grid cards" markdown>
@@ -8,8 +8,8 @@ title: Appium Protocol
}
</style>
The following is a list of endpoints used in Appium that are defined in the Appium extension of the
W3C WebDriver protocol.
The following is a list of endpoints supported in Appium, that are defined in the Appium extension
of the W3C WebDriver protocol.
### getAppiumSessions
@@ -9,7 +9,7 @@ title: JSON Wire Protocol
</style>
The following is a list of legacy [JSON Wire Protocol (JSONWP)](https://www.selenium.dev/documentation/legacy/json_wire_protocol/)
endpoints used in Appium.
endpoints supported in Appium.
### getSession
@@ -9,7 +9,7 @@ title: Mobile JSON Wire Protocol
</style>
The following is a list of legacy [Mobile JSON Wire Protocol (MJSONWP)](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)
endpoints used in Appium.
endpoints supported in Appium.
### getRotation
+439 -2
View File
@@ -8,7 +8,7 @@ title: Other Protocols
}
</style>
The following is a list of endpoints used in Appium that are defined in other protocols.
The following is a list of endpoints supported in Appium that are defined in other protocols.
## Chromedriver Protocol
@@ -41,6 +41,441 @@ for a list of available methods and their parameters.
`any` - the result of executing the CDP method
## Compute Pressure Protocol
The [Compute Pressure protocol](https://www.w3.org/TR/compute-pressure/) is an extension of the W3C
WebDriver protocol.
### createVirtualPressureSource
```
POST /session/:sessionId/pressuresource
```
> Compute Pressure documentation: [Create Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#create-virtual-pressure-source)
Creates a new virtual pressure source.
#### Parameters
| <div style="width:6em">Name</div> | Description | Type | Default |
| --------------------------------- | ------------------------------------------------------------- | ------- | ------- |
| `type` | Type of pressure source to create | string | |
| `supported?` | Whether the pressure source should be configured as supported | boolean | `true` |
#### Response
`null`
### updateVirtualPressureSource
```
POST /session/:sessionId/pressuresource/:pressureSourceType
```
> Compute Pressure documentation: [Update Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#update-virtual-pressure-source)
Updates the state of a virtual pressure source with the type identified by `:pressureSourceType`.
#### Parameters
| Name | Description | Type |
| -------- | ----------------------------------------------------------------------------------------------------------------- | ------ |
| `sample` | Pressure state. Supported values are `nominal`, `fair`, `serious`, or `critical`. | string |
#### Response
`null`
### deleteVirtualPressureSource
```
DELETE /session/:sessionId/pressuresource/:pressureSourceType
```
> Compute Pressure documentation: [Delete Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#delete-virtual-pressure-source)
Deletes the virtual pressure source with the type identified by `:pressureSourceType`.
#### Response
`null`
## Custom Handlers Protocol
The [Custom Handlers protocol](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)
is an extension of the W3C WebDriver protocol, defined by the HTML Standard specification.
### setRPHRegistrationMode
```
POST /session/:sessionId/custom-handlers/set-mode
```
> Custom Handlers documentation: [Set RPH Registration Mode](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)
Sets the protocol handler automation mode, for processing registrations of custom protocol handlers.
By default, this mode is set to `none`.
#### Parameters
| Name | Description | Type |
| ------ | ------------------------------------------------------------------------------------------------------------------- | ------ |
| `mode` | Automation mode to set. Supported values are `autoAccept`, `autoReject`, or `none`. | string |
#### Response
`null`
## Device Posture Protocol
The [Device Posture protocol](https://www.w3.org/TR/device-posture/) is an extension of the W3C
WebDriver protocol.
### setDevicePosture
```
POST /session/:sessionId/deviceposture
```
> Device Posture documentation: [Set Device Posture](https://www.w3.org/TR/device-posture/#set-device-posture)
Sets the device posture, overriding the posture set by the device hardware.
#### Parameters
| Name | Description | Type |
| --------- | ------------------------------------------------------------------------------------------------------------------------- | ------ |
| `posture` | Posture to which the device should be set. Supported values are `continuous` or `folded`. | string |
#### Response
`null`
### clearDevicePosture
```
DELETE /session/:sessionId/deviceposture
```
> Device Posture documentation: [Clear Device Posture](https://www.w3.org/TR/device-posture/#clear-device-posture)
Clears the previously set device posture, returning posture control back to the device hardware.
#### Response
`null`
## Federated Credential Management Protocol
The [Federated Credential Management protocol](https://www.w3.org/TR/fedcm-1) (FedCM) is an
extension of the W3C WebDriver protocol. Clients can enable this protocol by using the
[`fedcm:accounts`](https://www.w3.org/TR/fedcm-1/#webdriver-capability) capability.
### fedCMCancelDialog
```
POST /session/:sessionId/fedcm/canceldialog
```
> FedCM documentation: [Cancel Dialog](https://www.w3.org/TR/fedcm-1/#webdriver-canceldialog)
Cancels the currently open FedCM dialog.
#### Response
`null`
### fedCMSelectAccount
```
POST /session/:sessionId/fedcm/selectaccount
```
> FedCM documentation: [Select Account](https://www.w3.org/TR/fedcm-1/#webdriver-selectaccount)
Selects an account to use for the currently open FedCM dialog.
#### Parameters
| Name | Description | Type |
| -------------- | ------------------------------------------------------ | ------ |
| `accountIndex` | Index of the account in the list of available accounts | number |
#### Response
`null`
### fedCMClickDialogButton
```
POST /session/:sessionId/fedcm/clickdialogbutton
```
> FedCM documentation: [Click Dialog Button](https://www.w3.org/TR/fedcm-1/#webdriver-clickdialogbutton)
Clicks a button in the currently open FedCM dialog.
#### Parameters
| Name | Description | Type |
| -------------- | ------------------------------------------------------------------------------------------------------------ | ------ |
| `dialogButton` | Identifier of the button to click. Must be set to `ConfirmIdpLoginContinue`. | string |
#### Response
`null`
### fedCMGetAccounts
```
GET /session/:sessionId/fedcm/accountlist
```
> FedCM documentation: [Account List](https://www.w3.org/TR/fedcm-1/#webdriver-accountlist)
Retrieves all accounts that the user can select in the currently open FedCM dialog.
#### Response
`FedCMAccount[]` - an array of objects, where each object includes the following properties:
| <div style="width:10em">Name</div> | Description | Type |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------ |
| `accountId` | Account ID | string |
| `email` | Account email | string |
| `name` | Account name | string |
| `givenName?` | Account given name | string |
| `pictureUrl?` | Account picture URL | string |
| `idpConfigUrl` | URL of the identity provider configuration file | string |
| `loginState` | Login state. Set to `SignUp` if the account is not connected, otherwise `SignIn`. | string |
| `termsOfServiceUrl?` | Terms of Service URL of the website, if `loginState` is set to `SignUp` | string |
| `privacyPolicyUrl?` | Privacy Policy URL of the website, if `loginState` is set to `SignUp` | string |
### fedCMGetTitle
```
GET /session/:sessionId/fedcm/gettitle
```
> FedCM documentation: [Get Title](https://www.w3.org/TR/fedcm-1/#webdriver-gettitle)
Retrieves the title and subtitle (if one exists) of the currently open FedCM dialog.
#### Response
`FedCMDialogTitle` - an object with the following properties:
| Name | Description | Type |
| ----------- | --------------- | ------ |
| `title` | Dialog title | string |
| `subtitle?` | Dialog subtitle | string |
### fedCMGetDialogType
```
GET /session/:sessionId/fedcm/getdialogtype
```
> FedCM documentation: [Get Dialog Type](https://www.w3.org/TR/fedcm-1/#webdriver-getdialogtype)
Retrieves the type of the currently open FedCM dialog.
#### Response
`string` - can be set to `AutoReauthn`, `AccountChooser`, or `ConfirmIdpLogin`
### fedCMSetDelayEnabled
```
POST /session/:sessionId/fedcm/setdelayenabled
```
> FedCM documentation: [Set Delay Enabled](https://www.w3.org/TR/fedcm-1/#webdriver-setdelayenabled)
Sets the state of the promise rejection delay, which is used to prevent information leakage about
the logged in state of the user.
#### Parameters
| Name | Description | Type |
| --------- | --------------------------------------------- | ------- |
| `enabled` | Whether to enable the promise rejection delay | boolean |
#### Response
`null`
### fedCMResetCooldown
```
POST /session/:sessionId/fedcm/resetcooldown
```
> FedCM documentation: [Reset Cooldown](https://www.w3.org/TR/fedcm-1/#webdriver-resetcooldown)
Resets the cooldown delay used after dismissing a FedCM dialog.
#### Response
`null`
## Generic Sensor Protocol
The [Generic Sensor protocol](https://www.w3.org/TR/generic-sensor/) is an extension of the W3C
WebDriver protocol.
### createVirtualSensor
```
POST /session/:sessionId/sensor
```
> Generic Sensor documentation: [Create Virtual Sensor](https://www.w3.org/TR/generic-sensor/#create-virtual-sensor-command)
Creates a new virtual sensor.
#### Parameters
| <div style="width:12em">Name</div> | Description | Type | Default |
| ---------------------------------- | ---------------------------------------------------- | ------- | ------- |
| `type` | Type of sensor to create | string | |
| `connected?` | Whether the sensor should be configured as connected | boolean | `true` |
| `maxSamplingFrequency?` | Maximum sensor sampling frequency | number | |
| `minSamplingFrequency?` | Minimum sensor sampling frequency | number | |
#### Response
`null`
### getVirtualSensorInfo
```
GET /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Get Virtual Sensor Information](https://www.w3.org/TR/generic-sensor/#get-virtual-sensor-information-command)
Retrieves information about the virtual sensor with the type identified by `:sensorType`.
#### Response
`GetVirtualSensorInfoResponse` - an object containing the `requestedSamplingFrequency` key, whose
value is the requested sampling frequency of the sensor type
### updateVirtualSensorReading
```
POST /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Update Virtual Sensor Reading](https://www.w3.org/TR/generic-sensor/#update-virtual-sensor-reading-command)
Updates the virtual sensor with the type identified by `:sensorType` with a new reading.
#### Parameters
| Name | Description | Type |
| --------- | ---------------------------------------------------------------- | ------ |
| `reading` | Object containing reading properties specific to the sensor type | object |
#### Response
`null`
### deleteVirtualSensor
```
DELETE /session/:sessionId/sensor/:sensorType
```
> Generic Sensor documentation: [Delete Virtual Sensor](https://www.w3.org/TR/generic-sensor/#delete-virtual-sensor-command)
Deletes the virtual sensor with the type identified by `:sensorType`.
#### Response
`null`
## Permissions Protocol
The [Permissions protocol](https://www.w3.org/TR/permissions/) is an extension of the W3C WebDriver
protocol.
### setPermissions
```
POST /session/:sessionId/permissions
```
> Permissions documentation: [Set Permission](https://www.w3.org/TR/permissions/#webdriver-command-set-permission)
Simulates user modification of the permission state of a PermissionDescriptor (a permissible feature
with optional additional properties).
#### Parameters
| <div style="width:6em">Name</div> | Description | Type |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| `descriptor` | Object specifying the feature name in its `name` key, along with any other keys for additional properties | object |
| `state` | New permission state for this descriptor. Supported values are: `granted`, `denied`, or `prompt`. | string |
#### Response
`null`
## Reporting Protocol
The [Reporting protocol](https://www.w3.org/TR/reporting-1/) is an extension of the W3C WebDriver
protocol.
### generateTestReport
```
POST /session/:sessionId/reporting/generate_test_report
```
> Reporting documentation: [Generate Test Report](https://www.w3.org/TR/reporting-1/#generate-test-report-command)
Simulates the generation of a test report, which can be retrieved by registered reporting observers.
#### Parameters
| Name | Description | Type | Default |
| --------- | ------------------------------------------ | ------ | --------- |
| `message` | Message displayed in the report | string | |
| `group?` | Destination group to deliver the report to | string | `default` |
#### Response
`null`
## Secure Payment Confirmation Protocol
The [Secure Payment Confirmation protocol](https://www.w3.org/TR/secure-payment-confirmation) (SPC)
is an extension of the W3C WebDriver protocol.
### setSPCTransactionMode
```
POST /session/:sessionId/secure-payment-confirmation/set-mode
```
> SPC documentation: [Set SPC Transaction Mode](https://www.w3.org/TR/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode)
Sets the transaction automation mode, for automated handling of transaction confirmation prompts.
By default, this mode is set to `none`.
#### Parameters
| Name | Description | Type |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| `mode` | Automation mode to set. Supported values are `autoAccept`, `autoChooseToAuthAnotherWay`, `autoReject`, or `autoOptOut`. | string |
#### Response
`null`
## Selenium Protocol
The Selenium protocol is an extension of the W3C WebDriver protocol, supported in Appium clients
@@ -92,7 +527,9 @@ Retrieves the available log types that can be used to call the [`getLog`](#getlo
## Web Authentication Protocol
The [Web Authentication protocol](https://w3c.github.io/webauthn/) (WebAuthn) is an extension of
the W3C WebDriver protocol.
the W3C WebDriver protocol. Clients can enable this protocol by using the
[`webauthn:virtualAuthenticators`](https://w3c.github.io/webauthn/#sctn-automation-webdriver-capability)
capability.
### addVirtualAuthenticator
@@ -9,7 +9,7 @@ title: WebDriver Protocol
</style>
The following is a list of [W3C WebDriver protocol](https://w3c.github.io/webdriver/) endpoints
used in Appium.
supported in Appium.
!!! info
@@ -1070,3 +1070,45 @@ identified by `:elementId`.
#### Response
`string` - a base64-encoded PNG image
### printPage
```
POST /session/:sessionId/print
```
> WebDriver documentation: [Print Page](https://w3c.github.io/webdriver/#print-page)
Prints the page by rendering it as a paginated PDF document.
#### Parameters
| <div style="width:7em">Name</div> | Description | <div style="width:9em">Type</div> | Default |
| --------------------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------- | ---------- |
| `orientation?` | Page orientation. Supported values are `portrait` or `landscape`. | string | `portrait` |
| `scale?` | Page scale. Supported values are in the range `[0.1, 2]`. | number | `1` |
| `background?` | Whether to include background images | boolean | `false` |
| `page?` | Object specifying the page width and height | [`PrintPageSize`](#printpagesize) | `{}` |
| `margin?` | Object specifying the page margins | [`PrintPageMargins`](#printpagemargins) | `{}` |
| `shrinkToFit?` | Whether to resize page contents to match `PrintPageSize.width` | boolean | `true` |
| `pageRanges?` | Array of pages to be printed, for example, `[1, 4, '8-9']` | array | `[]` |
##### `PrintPageSize`
| Name | Description | Type | Default |
| --------- | -------------------------------------------------------------------------------------------- | ------ | ------- |
| `width?` | Page width. Must be greater than or equal to `(2.54 / 72)`. | number | `21.59` |
| `height?` | Page height. Must be greater than or equal to `(2.54 / 72)`. | number | `27.94` |
##### `PrintPageMargins`
| Name | Description | Type | Default |
| --------- | ----------------------------------------------------------------------------------------- | ------ | ------- |
| `top?` | Page top margin. Must be greater than or equal to `0`. | number | `1` |
| `bottom?` | Page bottom margin. Must be greater than or equal to `0`. | number | `1` |
| `left?` | Page left margin. Must be greater than or equal to `0`. | number | `1` |
| `right?` | Page right margin. Must be greater than or equal to `0`. | number | `1` |
#### Response
`string` - a base64-encoded PDF document
@@ -21,7 +21,7 @@ mentioned below.
Installs the following extensions for browser webview testing:
- Drivers: `safari`[^1], `gecko`, `chromium`
- Plugins: `images`
- Plugins: `images`, `inspector`
#### Usage
@@ -34,7 +34,7 @@ appium setup browser
Installs the following extensions for desktop application testing:
- Drivers: `mac2`[^1], `windows`[^2]
- Plugins: `images`
- Plugins: `images`, `inspector`
#### Usage
@@ -47,7 +47,7 @@ appium setup desktop
Installs the following extensions for mobile testing:
- Drivers: `uiautomator2`, `xcuitest`[^1], `espresso`
- Plugins: `images`
- Plugins: `images`, `inspector`
#### Usage
+10 -1
View File
@@ -454,9 +454,17 @@ class ExtensionCliCommand {
return {pkg, installPath};
});
/** @type {Promise<void>[]} */
const symlinkInjectionPromises = _.uniq([
...Object.values(this.config.installedExtensions).map((ext) => ext.installPath),
installPath,
]).map((instPath) => injectAppiumSymlink.bind(this)(path.join(instPath, 'node_modules')));
// After the extension is installed, we try to inject the appium module symlink
// into the extension's node_modules folder if it is not there yet.
await injectAppiumSymlink.bind(this)(path.join(installPath, 'node_modules'));
// We also inject the symlink into other installed extensions' node_modules folders
// as these might be cleaned up unexpectedly by npm
// (see https://github.com/appium/python-client/pull/1177#issuecomment-3419826643).
await Promise.all(symlinkInjectionPromises);
return this.getInstallationReceipt({
pkg,
@@ -736,6 +744,7 @@ class ExtensionCliCommand {
pkgName,
pkgVer: version,
});
delete extData[/** @type {string} */ (`${this.type}Name`)];
await this.config.updateExtension(installSpec, extData);
}
+1 -1
View File
@@ -34,7 +34,7 @@ const DRIVERS_ONLY_WINDOWS = ['windows'];
/**
* Plugin names listed in KNOWN_PLUGINS to install by default.
*/
export const DEFAULT_PLUGINS = ['images'];
export const DEFAULT_PLUGINS = ['images', 'inspector'];
/**
* Return a list of drivers available for current host platform.
+1 -1
View File
@@ -1,7 +1,7 @@
import betterAjvErrors from '@sidvind/better-ajv-errors';
import {lilconfig} from 'lilconfig';
import _ from 'lodash';
import yaml from 'yaml';
import * as yaml from 'yaml';
import {getSchema, validate} from './schema/schema';
/**
+1 -1
View File
@@ -6,7 +6,7 @@ import B from 'bluebird';
import {env, fs} from '@appium/support';
import _ from 'lodash';
import path from 'path';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {CURRENT_SCHEMA_REV, DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
import {INSTALL_TYPE_NPM, INSTALL_TYPE_DEV} from './extension-config';
import {packageDidChange} from './package-changed';
+1 -1
View File
@@ -118,7 +118,7 @@ function executeMethodMapToCommandsInfo(emm: ExecuteMethodMap<any>): RestMethods
const result: RestMethodsToCommandsMap = {};
for (const [name, info] of _.toPairs(emm)) {
result[name] = {
command: info.command,
command: info.command as string,
deprecated: info.deprecated,
info: info.info,
params: toRestCommandParams(info.params),
+7 -5
View File
@@ -27,7 +27,7 @@ import {
} from './config';
import {readConfigFile} from './config-file';
import {loadExtensions, getActivePlugins, getActiveDrivers} from './extension';
import {SERVER_SUBCOMMAND, LONG_STACKTRACE_LIMIT} from './constants';
import {SERVER_SUBCOMMAND, LONG_STACKTRACE_LIMIT, BIDI_BASE_PATH} from './constants';
import registerNode from './grid-register';
import {getDefaultsForSchema, validate as validateSchema} from './schema/schema';
import {
@@ -400,6 +400,7 @@ async function main(args) {
extraMethodMap,
cliArgs: parsedArgs,
};
const normalizedBasePath = normalizeBasePath(parsedArgs.basePath);
for (const timeoutArgName of ['keepAliveTimeout', 'requestTimeout']) {
if (_.isInteger(parsedArgs[timeoutArgName])) {
serverOpts[timeoutArgName] = parsedArgs[timeoutArgName] * 1000;
@@ -411,8 +412,9 @@ async function main(args) {
bidiServer.on('error', appiumDriver.onBidiServerError.bind(appiumDriver));
try {
server = await baseServer(serverOpts);
server.addWebSocketHandler('/bidi', bidiServer);
server.addWebSocketHandler('/bidi/:sessionId', bidiServer);
const bidiBasePath = `${normalizedBasePath}${BIDI_BASE_PATH}`;
server.addWebSocketHandler(bidiBasePath, bidiServer);
server.addWebSocketHandler(`${bidiBasePath}/:sessionId`, bidiServer);
} catch (err) {
logger.error(
`Could not configure Appium server. It's possible that a driver or plugin tried ` +
@@ -438,7 +440,7 @@ async function main(args) {
parsedArgs.nodeconfig,
parsedArgs.address,
parsedArgs.port,
parsedArgs.basePath,
normalizedBasePath,
);
}
} catch (err) {
@@ -464,7 +466,7 @@ async function main(args) {
const protocol = server.isSecure() ? 'https' : 'http';
const address = net.isIPv6(parsedArgs.address) ? `[${parsedArgs.address}]` : parsedArgs.address;
logServerAddress(
`${protocol}://${address}:${parsedArgs.port}${normalizeBasePath(parsedArgs.basePath)}`,
`${protocol}://${address}:${parsedArgs.port}${normalizedBasePath}`,
);
driverConfig.print();
-5
View File
@@ -484,11 +484,6 @@ export function isBroadcastIp(address) {
* @typedef {import('@appium/types').ConstraintsToCaps<C>} ConstraintsToCaps
*/
/**
* @template T
* @typedef {import('type-fest').StringKeyOf<T>} StringKeyOf
*/
/**
* @typedef {import('@appium/types').Constraints} Constraints
*/
+15 -15
View File
@@ -1,6 +1,6 @@
{
"name": "appium",
"version": "3.0.2",
"version": "3.1.2",
"description": "Automation for Apps.",
"keywords": [
"automation",
@@ -60,35 +60,35 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/base-driver": "^10.0.1",
"@appium/base-plugin": "^3.0.2",
"@appium/docutils": "^2.1.0",
"@appium/logger": "^2.0.1",
"@appium/base-driver": "^10.1.2",
"@appium/base-plugin": "^3.0.5",
"@appium/docutils": "^2.2.0",
"@appium/logger": "^2.0.3",
"@appium/schema": "^1.0.0",
"@appium/support": "^7.0.1",
"@appium/types": "^1.0.1",
"@sidvind/better-ajv-errors": "4.0.0",
"@appium/support": "^7.0.4",
"@appium/types": "^1.1.2",
"@sidvind/better-ajv-errors": "4.0.1",
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"argparse": "2.0.1",
"async-lock": "1.4.1",
"asyncbox": "3.0.0",
"axios": "1.11.0",
"axios": "1.13.2",
"bluebird": "3.7.2",
"lilconfig": "3.1.3",
"lodash": "4.17.21",
"lru-cache": "11.2.1",
"lru-cache": "11.2.4",
"ora": "5.4.1",
"package-changed": "3.0.0",
"resolve-from": "5.0.0",
"semver": "7.7.2",
"semver": "7.7.3",
"source-map-support": "0.5.21",
"teen_process": "3.0.1",
"type-fest": "4.41.0",
"winston": "3.17.0",
"teen_process": "3.0.4",
"type-fest": "5.3.0",
"winston": "3.18.3",
"wrap-ansi": "7.0.0",
"ws": "8.18.3",
"yaml": "2.8.1"
"yaml": "2.8.2"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
@@ -1,5 +1,5 @@
{
"devDependencies": {
"webdriverio": "9.19.2"
"webdriverio": "9.21.0"
}
}
@@ -111,14 +111,9 @@ describe('Driver CLI', function () {
});
it('should show updates for installed drivers with --updates', async function () {
if (process.env.CI) {
// FIXME XXX this test won't work until multiple versions of fake driver have been
// published which support appium 3
return this.skip();
}
if (system.isWindows()) {
// TODO figure out why this isn't working on windows
// TODO: Windows path handling may need fixes in npm exec or extension command parsing
return this.skip();
}
const versions = /** @type {string[]} */ (
@@ -143,7 +138,10 @@ describe('Driver CLI', function () {
/** @type {Record<string,import('appium/lib/cli/extension-command').InstalledExtensionListData>} */ (
await runList(['--updates'])
);
const updateVersion = String(fake.updateVersion || fake.unsafeUpdateVersion);
const updateVersion = fake.updateVersion || fake.unsafeUpdateVersion;
if (!updateVersion) {
throw new Error(`No update version found. Expected an update from ${penultimateFakeDriverVersionAsOfRightNow} to a newer version, but got null. This might indicate the update check is not working properly.`);
}
util.compareVersions(
String(updateVersion),
'>',
@@ -641,6 +641,39 @@ describe('FakeDriver via HTTP', function () {
result.should.eql('this is from bidi');
});
});
describe('Bidi protocol with base path', function () {
const basePath = '/wd/hub';
withServer({basePath});
const capabilities = {...caps, webSocketUrl: true, 'appium:runClock': true};
/** @type import('webdriverio').Browser **/
let driver;
beforeEach(async function () {
driver = await wdio({...wdOpts, path: basePath, capabilities});
});
afterEach(async function () {
if (driver) {
await driver.deleteSession();
}
});
it('should respond with bidi specific capability when a driver supports it', async function () {
should.exist(driver.capabilities.webSocketUrl);
});
it('should interpret the bidi protocol and let the driver handle it by command', async function () {
should.not.exist(await driver.getUrl());
await driver.browsingContextNavigate({
context: 'foo',
url: 'https://appium.io',
wait: 'complete',
});
await driver.getUrl().should.eventually.eql('https://appium.io');
});
});
});
describe('Bidi over SSL', function () {
@@ -687,6 +720,12 @@ describe('Bidi over SSL', function () {
chai.use(chaiAsPromised.default);
should = chai.should();
// Skip on Node.js 24+ due to spdy package incompatibility (http_parser removed)
const nodeMajorVersion = parseInt(process.version.slice(1).split('.')[0], 10);
if (nodeMajorVersion >= 24) {
return this.skip();
}
try {
await generateCertificate(certPath, keyPath);
} catch (e) {
+1 -1
View File
@@ -121,7 +121,7 @@ async function _runAppiumJson(appiumHome, args) {
/**
* Runs the `appium` executable with the given args in JSON mode.
* Will reject with the contents of `STDOUT` (which were to be pasred) if parsing into JSON fails.
* Will reject with the contents of `STDOUT` (which were to be parsed) if parsing into JSON fails.
*
* The caller must wrap the call (in parens) with a docstring containing a return type.
* i.e., add `@type {MyType}` tag.
+1 -1
View File
@@ -3,7 +3,7 @@
import {env, fs, npm, tempDir} from '@appium/support';
import path from 'node:path';
import resolveFrom from 'resolve-from';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {
DRIVER_TYPE,
EXT_SUBCOMMAND_INSTALL as INSTALL,
@@ -1,6 +1,6 @@
import {fs, tempDir} from '@appium/support';
import path from 'node:path';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {
CACHE_DIR_RELATIVE_PATH,
CURRENT_SCHEMA_REV,
+1 -1
View File
@@ -3,7 +3,7 @@ import _ from 'lodash';
import { AppiumConfigJsonSchema } from '@appium/schema';
// this must be a `require` because babel will not compile `node_modules`
// TOOD: consider just copying this into fixtures so we can make it ESM
// TODO: consider just copying this into fixtures so we can make it ESM
const {default: fakeDriverSchema} = require('@appium/fake-driver/build/lib/fake-driver-schema');
const schema = _.cloneDeep(AppiumConfigJsonSchema);
@@ -3,7 +3,7 @@
import fs from 'fs';
// eslint-disable-next-line import/named
import {createSandbox} from 'sinon';
import YAML from 'yaml';
import * as YAML from 'yaml';
import * as schema from '../../lib/schema/schema';
import {resolveFixture, rewiremock} from '../helpers';
@@ -549,7 +549,7 @@ describe('Manifest', function () {
expect(manifest.getExtensionData(DRIVER_TYPE)).to.have.property('myDriver');
});
describe('when the underyling implementation emits "error"', function () {
describe('when the underlying implementation emits "error"', function () {
beforeEach(function () {
// @ts-expect-error
MockGlob.callsFake(() => {
+32
View File
@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [10.1.2](https://github.com/appium/appium/compare/@appium/base-driver@10.1.1...@appium/base-driver@10.1.2) (2025-12-04)
**Note:** Version bump only for package @appium/base-driver
## [10.1.1](https://github.com/appium/appium/compare/@appium/base-driver@10.1.0...@appium/base-driver@10.1.1) (2025-11-12)
### Bug Fixes
* **base-driver:** Use shouldUpgradeCallback for proper upgrades processing ([#21706](https://github.com/appium/appium/issues/21706)) ([fc273da](https://github.com/appium/appium/commit/fc273da0ef04d3362f10c710f7c8692d7a03fd21))
## [10.1.0](https://github.com/appium/appium/compare/@appium/base-driver@10.0.1...@appium/base-driver@10.1.0) (2025-10-08)
### Features
* add 21 WebDriver extension endpoints ([#21577](https://github.com/appium/appium/issues/21577)) ([7f906fc](https://github.com/appium/appium/commit/7f906fcf9a0dd84f348b0b3a79da818281f21835))
* add W3C printPage endpoint ([#21576](https://github.com/appium/appium/issues/21576)) ([cbea4f2](https://github.com/appium/appium/commit/cbea4f2e97d2d291bd67fd98359b37caab1b21fa))
### Bug Fixes
* **base-driver,relaxed-caps-plugin,types:** add missing W3C caps ([#21642](https://github.com/appium/appium/issues/21642)) ([e6635b7](https://github.com/appium/appium/commit/e6635b737d0f42d8fd38c3d8bea70067d2e7c87a))
## [10.0.1](https://github.com/appium/appium/compare/@appium/base-driver@10.0.0...@appium/base-driver@10.0.1) (2025-09-09)
@@ -68,7 +68,7 @@ GET | `session/{sessionId}/alert_text` | G
POST | `session/{sessionId}/alert_text` | Sends keystrokes to the currently displayed dialog
POST | `session/{sessionId}/accept_alert` | Accepts the currently displayed alert dialog.
POST | `session/{sessionId}/dismiss_alert` | Dismisses the currently displayed alert dialog.
POST | `session/{sessionId}/moveto` | Move the pointer by an offset of the specificed element.
POST | `session/{sessionId}/moveto` | Move the pointer by an offset of the specified element.
POST | `session/{sessionId}/click` | Click on the current pointer position.
POST | `session/{sessionId}/touch/click` | Single tap on the touch enabled device.
POST | `session/{sessionId}/touch/down` | Finger down on the screen.
@@ -112,14 +112,14 @@ POST | `session/{sessionId}/appium/device/is_locked` | C
POST | `session/{sessionId}/appium/start_recording_screen` | start recording the screen.
POST | `session/{sessionId}/appium/stop_recording_screen` | stop recording the screen.
POST | `session/{sessionId}/appium/performanceData/types` | returns the information types of the system state which is supported to read as like cpu, memory, network traffic, and battery.
POST | `session/{sessionId}/appium/getPerformanceData` | returns the information of the system state which is supported to read as like cpu, memory, network traffic, and battery.
POST | `session/{sessionId}/appium/getPerformanceData` | returns the information of the system state which is supported to read as like cpu, memory, network traffic, and battery.
POST | `session/{sessionId}/appium/device/press_keycode` | Press a particular key code on the device.
POST | `session/{sessionId}/appium/device/long_press_keycode` | Press and hold a particular key code on the device.
POST | `session/{sessionId}/appium/device/keyevent` | Send a key code to the device.
GET | `session/{sessionId}/appium/device/current_activity` | Retrieve the current activity running on the device.
GET | `session/{sessionId}/appium/device/current_package` | Retrieve the current package running on the device.
POST | `session/{sessionId}/appium/device/install_app` | Install the given app onto the device.
POST | `session/{sessionId}/appium/device/remove_app` | Remote an app from the device.
POST | `session/{sessionId}/appium/device/remove_app` | Remove an app from the device.
POST | `session/{sessionId}/appium/device/app_installed` | Check whether the specified app is installed on the device.
POST | `session/{sessionId}/appium/device/hide_keyboard` | Hide the soft keyboard.
GET | `session/{sessionId}/appium/device/is_keyboard_shown` | Whether or not the soft keyboard is shown.
@@ -6,7 +6,7 @@ import type {
StandardCapabilities,
} from '@appium/types';
import type {
StringKeyOf,
KeyAsString,
MergeExclusive,
} from 'type-fest';
import _ from 'lodash';
@@ -112,7 +112,7 @@ export function validateCaps<C extends Constraints>(
/**
* Standard, non-prefixed capabilities
* @see https://www.w3.org/TR/webdriver/#dfn-table-of-standard-capabilities)
* @see https://www.w3.org/TR/webdriver2/#dfn-table-of-standard-capabilities)
*/
export const STANDARD_CAPS = Object.freeze(
new Set(
@@ -125,9 +125,11 @@ export const STANDARD_CAPS = Object.freeze(
'proxy',
'setWindowRect',
'timeouts',
'strictFileInteractability',
'unhandledPromptBehavior',
'userAgent',
'webSocketUrl',
]) as StringKeyOf<StandardCapabilities>[]
]) as KeyAsString<StandardCapabilities>[]
)
);
@@ -155,7 +157,7 @@ export function stripAppiumPrefixes<C extends Constraints>(caps: NSCapabilities<
// Strip out the 'appium:' prefix
for (const prefixedCap of prefixedCaps) {
const strippedCapName = prefixedCap.substring(APPIUM_VENDOR_PREFIX.length) as StringKeyOf<Capabilities<C>>;
const strippedCapName = prefixedCap.substring(APPIUM_VENDOR_PREFIX.length) as KeyAsString<Capabilities<C>>;
// If it's standard capability that was prefixed, add it to an array of incorrectly prefixed capabilities
if (isStandardCap(strippedCapName)) {
@@ -59,13 +59,13 @@ process.on('exit', () => {
});
/**
* Perform inital application package configuration
* Perform initial application package configuration
* to prepare it for the further consumption by a driver:
*
* - Manages caching logic
* - Downloads the app from a remote URL to the local filesystem
* - Determines package name
* - Checks basic requiremenets on the application package
* - Checks basic requirements on the application package
*
* @param {string} app
* @param {string|string[]|import('@appium/types').ConfigureAppOptions} options
+35 -16
View File
@@ -86,6 +86,39 @@ export function defaultToJSONContentType(req, res, next) {
next();
}
/**
* Core function to handle WebSocket upgrade requests by matching the request path
* against registered WebSocket handlers in the webSocketsMapping.
*
* @param {import('http').IncomingMessage} req - The HTTP request
* @param {import('stream').Duplex} socket - The network socket
* @param {Buffer} head - The first packet of the upgraded stream
* @param {import('@appium/types').StringRecord<import('@appium/types').WSServer>} webSocketsMapping - Mapping of paths to WebSocket servers
* @returns {boolean} - Returns true if the upgrade was handled, false otherwise
*/
export function tryHandleWebSocketUpgrade(req, socket, head, webSocketsMapping) {
if (_.toLower(req.headers?.upgrade) !== 'websocket') {
return false;
}
let currentPathname;
try {
currentPathname = new URL(req.url ?? '', 'http://localhost').pathname;
} catch {
currentPathname = req.url ?? '';
}
for (const [pathname, wsServer] of _.toPairs(webSocketsMapping)) {
if (match(pathname)(currentPathname)) {
wsServer.handleUpgrade(req, socket, head, (ws) => {
wsServer.emit('connection', ws, req);
});
return true;
}
}
log.info(`Did not match the websocket upgrade request at ${currentPathname} to any known route`);
return false;
}
/**
*
* @param {import('@appium/types').StringRecord<import('@appium/types').WSServer>} webSocketsMapping
@@ -93,23 +126,9 @@ export function defaultToJSONContentType(req, res, next) {
*/
export function handleUpgrade(webSocketsMapping) {
return (req, res, next) => {
if (!req.headers?.upgrade || _.toLower(req.headers.upgrade) !== 'websocket') {
return next();
if (tryHandleWebSocketUpgrade(req, req.socket, Buffer.from(''), webSocketsMapping)) {
return;
}
let currentPathname;
try {
currentPathname = new URL(req.url ?? '').pathname;
} catch {
currentPathname = req.url ?? '';
}
for (const [pathname, wsServer] of _.toPairs(webSocketsMapping)) {
if (match(pathname)(currentPathname)) {
return wsServer.handleUpgrade(req, req.socket, Buffer.from(''), (ws) => {
wsServer.emit('connection', ws, req);
});
}
}
log.info(`Did not match the websocket upgrade request at ${currentPathname} to any known route`);
next();
};
}
+182 -140
View File
@@ -14,6 +14,7 @@ import {
allowCrossDomainAsyncExecute,
handleIdempotency,
handleUpgrade,
tryHandleWebSocketUpgrade,
catch404Handler,
handleLogContext,
} from './middleware';
@@ -31,6 +32,158 @@ import {fs, timing} from '@appium/support';
const KEEP_ALIVE_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
/**
*
* @param {ServerOpts} opts
* @returns {Promise<AppiumServer>}
*/
export async function server(opts) {
const {
routeConfiguringFunction,
port,
hostname,
cliArgs = /** @type {import('@appium/types').ServerArgs} */ ({}),
allowCors = true,
basePath = DEFAULT_BASE_PATH,
extraMethodMap = {},
serverUpdaters = [],
keepAliveTimeout = KEEP_ALIVE_TIMEOUT_MS,
requestTimeout,
} = opts;
const app = express();
const httpServer = await createServer(app, cliArgs);
return await new B(async (resolve, reject) => {
// we put an async function as the promise constructor because we want some things to happen in
// serial (application of plugin updates, for example). But we still need to use a promise here
// because some elements of server start failure only happen in httpServer listeners. So the
// way we resolve it is to use an async function here but to wrap all the inner logic in
// try/catch so any errors can be passed to reject.
try {
const appiumServer = configureHttp({
httpServer,
reject,
keepAliveTimeout,
gracefulShutdownTimeout: cliArgs.shutdownTimeout,
});
const useLegacyUpgradeHandler = !hasShouldUpgradeCallback(httpServer);
configureServer({
app,
addRoutes: routeConfiguringFunction,
allowCors,
basePath,
extraMethodMap,
webSocketsMapping: appiumServer.webSocketsMapping,
useLegacyUpgradeHandler,
});
// allow extensions to update the app and http server objects
for (const updater of serverUpdaters) {
await updater(app, appiumServer, cliArgs);
}
// once all configurations and updaters have been applied, make sure to set up a catchall
// handler so that anything unknown 404s. But do this after everything else since we don't
// want to block extensions' ability to add routes if they want.
app.all('/*all', catch404Handler);
await startServer({
httpServer,
hostname,
port,
keepAliveTimeout,
requestTimeout,
});
resolve(appiumServer);
} catch (err) {
reject(err);
}
});
}
/**
* Sets up some Express middleware and stuff
* @param {ConfigureServerOpts} opts
*/
export function configureServer({
app,
addRoutes,
allowCors = true,
basePath = DEFAULT_BASE_PATH,
extraMethodMap = {},
webSocketsMapping = {},
useLegacyUpgradeHandler = true,
}) {
basePath = normalizeBasePath(basePath);
app.use(endLogFormatter);
app.use(handleLogContext);
// set up static assets
app.use(favicon(path.resolve(STATIC_DIR, 'favicon.ico')));
// eslint-disable-next-line import/no-named-as-default-member
app.use(express.static(STATIC_DIR));
// crash routes, for testing
app.use(`${basePath}/produce_error`, produceError);
app.use(`${basePath}/crash`, produceCrash);
// Only use legacy Express middleware for WebSocket upgrades if shouldUpgradeCallback is not available
// When shouldUpgradeCallback is available, upgrades are handled directly on the HTTP server
// to avoid Express middleware timeout issues with long-lived connections
if (useLegacyUpgradeHandler) {
app.use(handleUpgrade(webSocketsMapping));
}
if (allowCors) {
app.use(allowCrossDomain);
} else {
app.use(allowCrossDomainAsyncExecute(basePath));
}
app.use(handleIdempotency);
app.use(defaultToJSONContentType);
app.use(bodyParser.urlencoded({extended: true}));
app.use(methodOverride());
app.use(catchAllHandler);
// make sure appium never fails because of a file size upload limit
app.use(bodyParser.json({limit: '1gb'}));
// set up start logging (which depends on bodyParser doing its thing)
app.use(startLogFormatter);
addRoutes(app, {basePath, extraMethodMap});
// dynamic routes for testing, etc.
app.all('/welcome', welcome);
app.all('/test/guinea-pig', guineaPig);
app.all('/test/guinea-pig-scrollable', guineaPigScrollable);
app.all('/test/guinea-pig-app-banner', guineaPigAppBanner);
}
/**
* Normalize base path string
* @param {string} basePath
* @returns {string}
*/
export function normalizeBasePath(basePath) {
if (!_.isString(basePath)) {
throw new Error(`Invalid path prefix ${basePath}`);
}
// ensure the path prefix does not end in '/', since our method map
// starts all paths with '/'
basePath = basePath.replace(/\/$/, '');
// likewise, ensure the path prefix does always START with /, unless the path
// is empty meaning no base path at all
if (basePath !== '' && !basePath.startsWith('/')) {
basePath = `/${basePath}`;
}
return basePath;
}
/**
*
* @param {import('express').Express} app
@@ -70,127 +223,6 @@ async function createServer (app, cliArgs) {
}, app);
}
/**
*
* @param {ServerOpts} opts
* @returns {Promise<AppiumServer>}
*/
export async function server(opts) {
const {
routeConfiguringFunction,
port,
hostname,
cliArgs = /** @type {import('@appium/types').ServerArgs} */ ({}),
allowCors = true,
basePath = DEFAULT_BASE_PATH,
extraMethodMap = {},
serverUpdaters = [],
keepAliveTimeout = KEEP_ALIVE_TIMEOUT_MS,
requestTimeout,
} = opts;
const app = express();
const httpServer = await createServer(app, cliArgs);
return await new B(async (resolve, reject) => {
// we put an async function as the promise constructor because we want some things to happen in
// serial (application of plugin updates, for example). But we still need to use a promise here
// because some elements of server start failure only happen in httpServer listeners. So the
// way we resolve it is to use an async function here but to wrap all the inner logic in
// try/catch so any errors can be passed to reject.
try {
const appiumServer = configureHttp({
httpServer,
reject,
keepAliveTimeout,
gracefulShutdownTimeout: cliArgs.shutdownTimeout,
});
configureServer({
app,
addRoutes: routeConfiguringFunction,
allowCors,
basePath,
extraMethodMap,
webSocketsMapping: appiumServer.webSocketsMapping,
});
// allow extensions to update the app and http server objects
for (const updater of serverUpdaters) {
await updater(app, appiumServer, cliArgs);
}
// once all configurations and updaters have been applied, make sure to set up a catchall
// handler so that anything unknown 404s. But do this after everything else since we don't
// want to block extensions' ability to add routes if they want.
app.all('/*all', catch404Handler);
await startServer({
httpServer,
hostname,
port,
keepAliveTimeout,
requestTimeout,
});
resolve(appiumServer);
} catch (err) {
reject(err);
}
});
}
/**
* Sets up some Express middleware and stuff
* @param {ConfigureServerOpts} opts
*/
export function configureServer({
app,
addRoutes,
allowCors = true,
basePath = DEFAULT_BASE_PATH,
extraMethodMap = {},
webSocketsMapping = {},
}) {
basePath = normalizeBasePath(basePath);
app.use(endLogFormatter);
app.use(handleLogContext);
// set up static assets
app.use(favicon(path.resolve(STATIC_DIR, 'favicon.ico')));
// eslint-disable-next-line import/no-named-as-default-member
app.use(express.static(STATIC_DIR));
// crash routes, for testing
app.use(`${basePath}/produce_error`, produceError);
app.use(`${basePath}/crash`, produceCrash);
app.use(handleUpgrade(webSocketsMapping));
if (allowCors) {
app.use(allowCrossDomain);
} else {
app.use(allowCrossDomainAsyncExecute(basePath));
}
app.use(handleIdempotency);
app.use(defaultToJSONContentType);
app.use(bodyParser.urlencoded({extended: true}));
app.use(methodOverride());
app.use(catchAllHandler);
// make sure appium never fails because of a file size upload limit
app.use(bodyParser.json({limit: '1gb'}));
// set up start logging (which depends on bodyParser doing its thing)
app.use(startLogFormatter);
addRoutes(app, {basePath, extraMethodMap});
// dynamic routes for testing, etc.
app.all('/welcome', welcome);
app.all('/test/guinea-pig', guineaPig);
app.all('/test/guinea-pig-scrollable', guineaPigScrollable);
app.all('/test/guinea-pig-app-banner', guineaPigAppBanner);
}
/**
* Monkeypatches the `http.Server` instance and returns a {@linkcode AppiumServer}.
* This function _mutates_ the `httpServer` parameter.
@@ -212,6 +244,20 @@ function configureHttp({httpServer, reject, keepAliveTimeout, gracefulShutdownTi
return Boolean(this['_spdyState']?.secure);
};
// This avoids Express middleware timeout issues with long-lived WebSocket connections
// See: https://github.com/appium/appium/issues/20760
// See: https://github.com/nodejs/node/pull/59824
if (hasShouldUpgradeCallback(httpServer)) {
// shouldUpgradeCallback only returns a boolean to indicate if the upgrade should proceed
// eslint-disable-next-line dot-notation
appiumServer['shouldUpgradeCallback'] = (req) => _.toLower(req.headers?.upgrade) === 'websocket';
appiumServer.on('upgrade', (req, socket, head) => {
if (!tryHandleWebSocketUpgrade(req, socket, head, appiumServer.webSocketsMapping)) {
socket.destroy();
}
});
}
// http.Server.close() only stops new connections, but we need to wait until
// all connections are closed and the `close` event is emitted
const originalClose = appiumServer.close.bind(appiumServer);
@@ -294,29 +340,23 @@ async function startServer({
}
/**
* Normalize base path string
* @param {string} basePath
* @returns {string}
* Checks if the provided server instance supports `shouldUpgradeCallback`.
* This feature was added in Node.js v22.21.0 (LTS) and v24.9.0.
* @param {import('http').Server} server - The HTTP server instance to check
* @returns {boolean}
*/
export function normalizeBasePath(basePath) {
if (!_.isString(basePath)) {
throw new Error(`Invalid path prefix ${basePath}`);
function hasShouldUpgradeCallback(server) {
// Check if shouldUpgradeCallback is available on http.Server
// This is a runtime check that works regardless of TypeScript types
try {
// Use bracket notation to access property that may not exist in type definitions
// eslint-disable-next-line dot-notation
return typeof server['shouldUpgradeCallback'] !== 'undefined';
} catch {
return false;
}
// ensure the path prefix does not end in '/', since our method map
// starts all paths with '/'
basePath = basePath.replace(/\/$/, '');
// likewise, ensure the path prefix does always START with /, unless the path
// is empty meaning no base path at all
if (basePath !== '' && !basePath.startsWith('/')) {
basePath = `/${basePath}`;
}
return basePath;
}
/**
* Options for {@linkcode startServer}.
* @typedef StartServerOpts
@@ -386,4 +426,6 @@ export function normalizeBasePath(basePath) {
* @property {string} [basePath]
* @property {MethodMap} [extraMethodMap]
* @property {import('@appium/types').StringRecord} [webSocketsMapping={}]
* @property {boolean} [useLegacyUpgradeHandler=true] - Whether to use legacy Express middleware for WebSocket upgrades.
* Set to false when using shouldUpgradeCallback on the HTTP server (Node.js >= 22.21.0 or >= 24.9.0).
*/
@@ -3,7 +3,7 @@
import _ from 'lodash';
/**
* Determine whether the given agument is valid
* Determine whether the given argument is valid
* W3C capabilities instance.
*
* @param {any} caps
@@ -59,7 +59,7 @@ export function fixCaps(oldCaps, desiredCapConstraints, log) {
}
// int capabilities are often sent in as strings by frameworks
let intCaps = /** @type {import('type-fest').StringKeyOf<typeof caps>[]} */ (
let intCaps = /** @type {import('type-fest').KeyAsString<typeof caps>[]} */ (
_.keys(_.pickBy(desiredCapConstraints, (k) => k.isNumber === true))
);
for (let cap of intCaps) {
+267 -171
View File
@@ -16,14 +16,8 @@ const COMMAND_NAMES_CACHE = new LRUCache({
*/
export const METHOD_MAP = /** @type {const} */ ({
//
// W3C WebDriver
// https://www.w3.org/TR/webdriver1/
// #region W3C WebDriver
// https://www.w3.org/TR/webdriver2/
//
'/status': {
GET: {command: 'getStatus'},
},
'/session': {
POST: {
command: 'createSession',
@@ -33,10 +27,13 @@ export const METHOD_MAP = /** @type {const} */ ({
},
},
'/session/:sessionId': {
// TODO: Decide on the future of this route later
// TODO: JSONWP route, remove in the future
GET: {command: 'getSession', deprecated: true},
DELETE: {command: 'deleteSession'},
},
'/status': {
GET: {command: 'getStatus'},
},
'/session/:sessionId/timeouts': {
GET: {command: 'getTimeouts'},
POST: {
@@ -46,9 +43,6 @@ export const METHOD_MAP = /** @type {const} */ ({
},
},
},
'/session/:sessionId/window/handles': {
GET: {command: 'getWindowHandles'},
},
'/session/:sessionId/url': {
GET: {command: 'getUrl'},
POST: {command: 'setUrl', payloadParams: {required: ['url']}},
@@ -62,15 +56,8 @@ export const METHOD_MAP = /** @type {const} */ ({
'/session/:sessionId/refresh': {
POST: {command: 'refresh'},
},
'/session/:sessionId/screenshot': {
GET: {command: 'getScreenshot'},
},
'/session/:sessionId/frame': {
POST: {command: 'setFrame', payloadParams: {required: ['id']}},
},
'/session/:sessionId/frame/parent': {
POST: {command: 'switchToParentFrame'},
'/session/:sessionId/title': {
GET: {command: 'title'},
},
'/session/:sessionId/window': {
GET: {command: 'getWindowHandle'},
@@ -82,6 +69,25 @@ export const METHOD_MAP = /** @type {const} */ ({
},
DELETE: {command: 'closeWindow'},
},
'/session/:sessionId/window/handles': {
GET: {command: 'getWindowHandles'},
},
'/session/:sessionId/window/new': {
POST: {command: 'createNewWindow', payloadParams: {optional: ['type']}},
},
'/session/:sessionId/frame': {
POST: {command: 'setFrame', payloadParams: {required: ['id']}},
},
'/session/:sessionId/frame/parent': {
POST: {command: 'switchToParentFrame'},
},
'/session/:sessionId/window/rect': {
GET: {command: 'getWindowRect'},
POST: {
command: 'setWindowRect',
payloadParams: {optional: ['x', 'y', 'width', 'height']},
},
},
'/session/:sessionId/window/maximize': {
POST: {command: 'maximizeWindow'},
},
@@ -91,23 +97,11 @@ export const METHOD_MAP = /** @type {const} */ ({
'/session/:sessionId/window/fullscreen': {
POST: {command: 'fullScreenWindow'},
},
'/session/:sessionId/window/new': {
POST: {command: 'createNewWindow', payloadParams: {optional: ['type']}},
'/session/:sessionId/element/active': {
GET: {command: 'active'},
},
'/session/:sessionId/cookie': {
GET: {command: 'getCookies'},
POST: {command: 'setCookie', payloadParams: {required: ['cookie']}},
DELETE: {command: 'deleteCookies'},
},
'/session/:sessionId/cookie/:name': {
GET: {command: 'getCookie'},
DELETE: {command: 'deleteCookie'},
},
'/session/:sessionId/source': {
GET: {command: 'getPageSource'},
},
'/session/:sessionId/title': {
GET: {command: 'title'},
'/session/:sessionId/element/:elementId/shadow': {
GET: {command: 'elementShadowRoot'},
},
'/session/:sessionId/element': {
POST: {
@@ -121,12 +115,6 @@ export const METHOD_MAP = /** @type {const} */ ({
payloadParams: {required: ['using', 'value']},
},
},
'/session/:sessionId/element/active': {
GET: {command: 'active'},
},
'/session/:sessionId/element/:elementId': {
GET: {},
},
'/session/:sessionId/element/:elementId/element': {
POST: {
command: 'findElementFromElement',
@@ -139,41 +127,6 @@ export const METHOD_MAP = /** @type {const} */ ({
payloadParams: {required: ['using', 'value']},
},
},
'/session/:sessionId/element/:elementId/click': {
POST: {command: 'click'},
},
'/session/:sessionId/element/:elementId/text': {
GET: {command: 'getText'},
},
'/session/:sessionId/element/:elementId/value': {
POST: {
command: 'setValue',
payloadParams: {
required: ['text'],
},
},
},
'/session/:sessionId/element/:elementId/name': {
GET: {command: 'getName'},
},
'/session/:sessionId/element/:elementId/clear': {
POST: {command: 'clear'},
},
'/session/:sessionId/element/:elementId/selected': {
GET: {command: 'elementSelected'},
},
'/session/:sessionId/element/:elementId/enabled': {
GET: {command: 'elementEnabled'},
},
'/session/:sessionId/element/:elementId/attribute/:name': {
GET: {command: 'getAttribute'},
},
'/session/:sessionId/element/:elementId/displayed': {
GET: {command: 'elementDisplayed'},
},
'/session/:sessionId/element/:elementId/shadow': {
GET: {command: 'elementShadowRoot'},
},
'/session/:sessionId/shadow/:shadowId/element': {
POST: {
command: 'findElementFromShadowRoot',
@@ -186,39 +139,55 @@ export const METHOD_MAP = /** @type {const} */ ({
payloadParams: {required: ['using', 'value']},
},
},
'/session/:sessionId/element/:elementId/css/:propertyName': {
GET: {command: 'getCssProperty'},
'/session/:sessionId/element/:elementId/selected': {
GET: {command: 'elementSelected'},
},
'/session/:sessionId/element/:elementId/displayed': {
GET: {command: 'elementDisplayed'},
},
'/session/:sessionId/element/:elementId/attribute/:name': {
GET: {command: 'getAttribute'},
},
'/session/:sessionId/element/:elementId/property/:name': {
GET: {command: 'getProperty'},
},
'/session/:sessionId/element/:elementId/css/:propertyName': {
GET: {command: 'getCssProperty'},
},
'/session/:sessionId/element/:elementId/text': {
GET: {command: 'getText'},
},
'/session/:sessionId/element/:elementId/name': {
GET: {command: 'getName'},
},
'/session/:sessionId/element/:elementId/rect': {
GET: {command: 'getElementRect'},
},
'/session/:sessionId/element/:elementId/enabled': {
GET: {command: 'elementEnabled'},
},
'/session/:sessionId/element/:elementId/computedrole': {
GET: {command: 'getComputedRole'},
},
'/session/:sessionId/element/:elementId/computedlabel': {
GET: {command: 'getComputedLabel'},
},
'/session/:sessionId/actions': {
POST: {command: 'performActions', payloadParams: {required: ['actions']}},
DELETE: {command: 'releaseActions'},
'/session/:sessionId/element/:elementId/click': {
POST: {command: 'click'},
},
'/session/:sessionId/alert/text': {
GET: {command: 'getAlertText'},
'/session/:sessionId/element/:elementId/clear': {
POST: {command: 'clear'},
},
'/session/:sessionId/element/:elementId/value': {
POST: {
command: 'setAlertText',
command: 'setValue',
payloadParams: {
required: ['text'],
},
},
},
'/session/:sessionId/alert/accept': {
POST: {command: 'postAcceptAlert'},
},
'/session/:sessionId/alert/dismiss': {
POST: {command: 'postDismissAlert'},
},
'/session/:sessionId/element/:elementId/rect': {
GET: {command: 'getElementRect'},
'/session/:sessionId/source': {
GET: {command: 'getPageSource'},
},
'/session/:sessionId/execute/sync': {
POST: {command: 'execute', payloadParams: {required: ['script', 'args']}},
@@ -229,20 +198,60 @@ export const METHOD_MAP = /** @type {const} */ ({
payloadParams: {required: ['script', 'args']},
},
},
'/session/:sessionId/cookie': {
GET: {command: 'getCookies'},
POST: {command: 'setCookie', payloadParams: {required: ['cookie']}},
DELETE: {command: 'deleteCookies'},
},
'/session/:sessionId/cookie/:name': {
GET: {command: 'getCookie'},
DELETE: {command: 'deleteCookie'},
},
'/session/:sessionId/actions': {
POST: {command: 'performActions', payloadParams: {required: ['actions']}},
DELETE: {command: 'releaseActions'},
},
'/session/:sessionId/alert/dismiss': {
POST: {command: 'postDismissAlert'},
},
'/session/:sessionId/alert/accept': {
POST: {command: 'postAcceptAlert'},
},
'/session/:sessionId/alert/text': {
GET: {command: 'getAlertText'},
POST: {
command: 'setAlertText',
payloadParams: {
required: ['text'],
},
},
},
'/session/:sessionId/screenshot': {
GET: {command: 'getScreenshot'},
},
'/session/:sessionId/element/:elementId/screenshot': {
GET: {command: 'getElementScreenshot'},
},
'/session/:sessionId/window/rect': {
GET: {command: 'getWindowRect'},
'/session/:sessionId/print': {
POST: {
command: 'setWindowRect',
payloadParams: {optional: ['x', 'y', 'width', 'height']},
},
command: 'printPage',
payloadParams: {
optional: [
'orientation',
'scale',
'background',
'page',
'margin',
'shrinkToFit',
'pageRanges',
],
}
}
},
// #endregion
//
// Appium specific
//
// #region JSONWP
// https://www.selenium.dev/documentation/legacy/json_wire_protocol/
'/session/:sessionId/ime/available_engines': {
GET: {command: 'availableIMEEngines', deprecated: true},
},
@@ -262,9 +271,12 @@ export const METHOD_MAP = /** @type {const} */ ({
deprecated: true,
},
},
'/session/:sessionId/rotation': {
GET: {command: 'getRotation'},
POST: {command: 'setRotation', payloadParams: {required: ['x', 'y', 'z']}},
'/session/:sessionId/orientation': {
GET: {command: 'getOrientation'},
POST: {
command: 'setOrientation',
payloadParams: {required: ['orientation']}
},
},
'/session/:sessionId/location': {
GET: {
@@ -277,12 +289,13 @@ export const METHOD_MAP = /** @type {const} */ ({
deprecated: true,
},
},
'/session/:sessionId/orientation': {
GET: {command: 'getOrientation'},
POST: {
command: 'setOrientation',
payloadParams: {required: ['orientation']}
},
// #endregion
// #region MJSONWP
// https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md
'/session/:sessionId/rotation': {
GET: {command: 'getRotation'},
POST: {command: 'setRotation', payloadParams: {required: ['x', 'y', 'z']}},
},
'/session/:sessionId/context': {
GET: {command: 'getCurrentContext'},
@@ -299,33 +312,38 @@ export const METHOD_MAP = /** @type {const} */ ({
deprecated: true,
},
},
'/session/:sessionId/receive_async_response': {
POST: {
command: 'receiveAsyncResponse',
payloadParams: {required: ['status', 'value']},
deprecated: true,
},
},
// #endregion
// #region Appium
'/appium/sessions': {
GET: {command: 'getAppiumSessions'},
},
'/session/:sessionId/appium/capabilities': {
GET: {command: 'getAppiumSessionCapabilities'}
},
'/session/:sessionId/appium/settings': {
POST: {command: 'updateSettings', payloadParams: {required: ['settings']}},
GET: {command: 'getSettings'},
},
'/session/:sessionId/appium/commands': {
GET: {command: 'listCommands'},
},
'/session/:sessionId/appium/extensions': {
GET: {command: 'listExtensions'},
},
'/session/:sessionId/appium/events': {
POST: {command: 'getLogEvents', payloadParams: {optional: ['type']}},
},
'/session/:sessionId/appium/log_event': {
POST: {
command: 'logCustomEvent',
payloadParams: {required: ['vendor', 'event']},
},
},
'/session/:sessionId/appium/device/system_time': {
GET: {command: 'getDeviceTime'},
POST: {command: 'getDeviceTime', payloadParams: {optional: ['format']}},
},
// #region Applications Management
'/session/:sessionId/appium/device/install_app': {
POST: {
command: 'installApp',
payloadParams: {
required: ['appPath'],
optional: ['options'],
},
},
},
'/session/:sessionId/appium/device/activate_app': {
POST: {
command: 'activateApp',
@@ -335,15 +353,6 @@ export const METHOD_MAP = /** @type {const} */ ({
},
},
},
'/session/:sessionId/appium/device/remove_app': {
POST: {
command: 'removeApp',
payloadParams: {
required: [['appId'], ['bundleId']],
optional: ['options'],
},
},
},
'/session/:sessionId/appium/device/terminate_app': {
POST: {
command: 'terminateApp',
@@ -353,14 +362,6 @@ export const METHOD_MAP = /** @type {const} */ ({
},
},
},
'/session/:sessionId/appium/device/app_installed': {
POST: {
command: 'isAppInstalled',
payloadParams: {
required: [['appId'], ['bundleId']],
},
},
},
'/session/:sessionId/appium/device/app_state': {
POST: {
command: 'queryAppState',
@@ -369,7 +370,32 @@ export const METHOD_MAP = /** @type {const} */ ({
},
},
},
// #endregion
'/session/:sessionId/appium/device/install_app': {
POST: {
command: 'installApp',
payloadParams: {
required: ['appPath'],
optional: ['options'],
},
},
},
'/session/:sessionId/appium/device/remove_app': {
POST: {
command: 'removeApp',
payloadParams: {
required: [['appId'], ['bundleId']],
optional: ['options'],
},
},
},
'/session/:sessionId/appium/device/app_installed': {
POST: {
command: 'isAppInstalled',
payloadParams: {
required: [['appId'], ['bundleId']],
},
},
},
'/session/:sessionId/appium/device/hide_keyboard': {
POST: {
command: 'hideKeyboard',
@@ -388,48 +414,75 @@ export const METHOD_MAP = /** @type {const} */ ({
'/session/:sessionId/appium/device/pull_folder': {
POST: {command: 'pullFolder', payloadParams: {required: ['path']}},
},
'/session/:sessionId/appium/settings': {
POST: {command: 'updateSettings', payloadParams: {required: ['settings']}},
GET: {command: 'getSettings'},
},
'/session/:sessionId/appium/events': {
POST: {command: 'getLogEvents', payloadParams: {optional: ['type']}},
},
'/session/:sessionId/appium/log_event': {
// #endregion
// #region Unknown
'/session/:sessionId/receive_async_response': {
POST: {
command: 'logCustomEvent',
payloadParams: {required: ['vendor', 'event']},
command: 'receiveAsyncResponse',
payloadParams: {required: ['status', 'value']},
deprecated: true,
},
},
// #region Inspector
'/session/:sessionId/appium/commands': {
GET: {command: 'listCommands'},
},
'/session/:sessionId/appium/extensions': {
GET: {command: 'listExtensions'},
'/session/:sessionId/element/:elementId': {
GET: {},
},
// #endregion
//
// 3rd party vendor/protocol support
//
// #region Selenium/Chromium browsers
// #region Other Protocols
// Selenium/Chromium browsers
'/session/:sessionId/se/log': {
POST: {command: 'getLog', payloadParams: {required: ['type']}},
},
'/session/:sessionId/se/log/types': {
GET: {command: 'getLogTypes'},
},
// #endregion
// #region chromium devtools
// Chromium devtools
// https://chromium.googlesource.com/chromium/src/+/master/chrome/test/chromedriver/server/http_handler.cc
'/session/:sessionId/:vendor/cdp/execute': {
POST: {command: 'executeCdp', payloadParams: {required: ['cmd', 'params']}},
},
// #endregion
// #region Webauthn
// Reporting
// https://www.w3.org/TR/reporting-1/
'/session/:sessionId/reporting/generate_test_report': {
POST: {
command: 'generateTestReport',
payloadParams: {required: ['message'], optional: ['group']},
},
},
// Permissions
// https://www.w3.org/TR/permissions/
'/session/:sessionId/permissions': {
POST: {command: 'setPermissions', payloadParams: {required: ['descriptor', 'state']}},
},
// Device Posture
// https://www.w3.org/TR/device-posture/
'/session/:sessionId/deviceposture': {
POST: {command: 'setDevicePosture', payloadParams: {required: ['posture']}},
DELETE: {command: 'clearDevicePosture'},
},
// Generic Sensor
// https://www.w3.org/TR/generic-sensor/
'/session/:sessionId/sensor': {
POST: {
command: 'createVirtualSensor',
payloadParams: {
required: ['type'],
optional: ['connected', 'maxSamplingFrequency', 'minSamplingFrequency'],
},
},
},
'/session/:sessionId/sensors/:sensorType': {
GET: {command: 'getVirtualSensorInfo'},
POST: {command: 'updateVirtualSensorReading', payloadParams: {required: ['reading']}},
DELETE: {command: 'deleteVirtualSensor'},
},
// Custom Handlers
// https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation
'/session/:sessionId/custom-handlers/set-mode': {
POST: {command: 'setRPHRegistrationMode', payloadParams: {required: ['mode']}},
},
// Webauthn
// https://www.w3.org/TR/webauthn-2/#sctn-automation-add-virtual-authenticator
'/session/:sessionId/webauthn/authenticator': {
POST: {
@@ -469,6 +522,49 @@ export const METHOD_MAP = /** @type {const} */ ({
},
},
},
// Secure Payment Confirmation
// https://www.w3.org/TR/secure-payment-confirmation/
'/session/:sessionId/secure-payment-confirmation/set-mode': {
POST: {command: 'setSPCTransactionMode', payloadParams: {required: ['mode']}},
},
// Federated Credential Management
// https://www.w3.org/TR/fedcm-1/
'/session/:sessionId/fedcm/canceldialog': {
POST: {command: 'fedCMCancelDialog'},
},
'/session/:sessionId/fedcm/selectaccount': {
POST: {command: 'fedCMSelectAccount', payloadParams: {required: ['accountIndex']}},
},
'/session/:sessionId/fedcm/clickdialogbutton': {
POST: {command: 'fedCMClickDialogButton', payloadParams: {required: ['dialogButton']}},
},
'/session/:sessionId/fedcm/accountlist': {
GET: {command: 'fedCMGetAccounts'},
},
'/session/:sessionId/fedcm/gettitle': {
GET: {command: 'fedCMGetTitle'},
},
'/session/:sessionId/fedcm/getdialogtype': {
GET: {command: 'fedCMGetDialogType'},
},
'/session/:sessionId/fedcm/setdelayenabled': {
POST: {command: 'fedCMSetDelayEnabled', payloadParams: {required: ['enabled']}},
},
'/session/:sessionId/fedcm/resetcooldown': {
POST: {command: 'fedCMResetCooldown'},
},
// Compute Pressure
// https://www.w3.org/TR/compute-pressure/
'/session/:sessionId/pressuresource': {
POST: {
command: 'createVirtualPressureSource',
payloadParams: {required: ['type'], optional: ['supported']},
},
},
'/session/:sessionId/pressuresource/:pressureSourceType': {
POST: {command: 'updateVirtualPressureSource', payloadParams: {required: ['sample']}},
DELETE: {command: 'deleteVirtualPressureSource'},
},
// #endregion
});

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