Compare commits

..
Author SHA1 Message Date
github-actions 2c2820242f chore: publish
- appium@3.9.0
 - @appium/base-driver@10.8.2
 - @appium/base-plugin@3.3.6
 - @appium/docutils@3.0.2
 - @appium/driver-test-support@3.0.2
 - @appium/eslint-config-appium-ts@3.2.7
 - @appium/execute-driver-plugin@7.0.2
 - @appium/fake-driver@6.2.5
 - @appium/fake-plugin@4.4.2
 - @appium/images-plugin@5.0.2
 - @appium/opencv@5.0.2
 - @appium/oxc-config@1.1.3
 - @appium/plugin-test-support@3.0.2
 - @appium/relaxed-caps-plugin@3.0.2
 - @appium/storage-plugin@2.0.2
 - @appium/support@7.2.9
 - @appium/types@1.7.2
 - @appium/universal-xml-plugin@3.0.2
2026-10-27 06:50:21 +00:00
Mykola Mokhnach e967b607d7 fix(base-driver): reject browser-origin WebSocket upgrades unless CORS is enabled (#23102) 2026-10-27 07:48:16 +01:00
Mykola Mokhnach 60acd1d3d8 fix(support): keep _extractEntryTo from writing through symlinks (#23101) 2026-10-27 07:47:58 +01:00
Mykola Mokhnach dddd2c3051 fix(support): reject Windows drive-relative symlink targets in zip extraction (#23100) 2026-10-26 20:43:25 +01:00
Edgars Eglītis 66ee0e46fb chore: run audit fix (#23099) 2026-10-26 21:19:50 +02:00
Mikhail cc531cf436 docs: add XPath to UiSelector to Ecosystem tools document (#23098) 2026-10-26 15:05:16 +02:00
renovate[bot] 5f2e7685bb chore(oxc-config): update dependency oxlint-tsgolint to v7.0.2005 (#23097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-26 12:27:53 +00:00
github-actions[bot]andmykola-mokhnach b09e3c57cd docs(appium): Update documentation translations (#23093)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-26 08:01:41 +01:00
renovate[bot] 6a680adbf5 chore(docutils): update dependency mkdocs-git-revision-date-localized-plugin to v1.6.1 (#23096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-26 06:57:54 +00:00
Teodor Nikolov db41945811 docs(appium): add NovaWindows Hybrid mode (since v1.4.0) (#23089) 2026-10-25 12:51:12 +02:00
renovate[bot] 9ed545596d chore(deps): update dependency npm-run-all2 to v9.0.4 (#23088)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-25 08:27:37 +01:00
dependabot[bot] e0cf688b50 chore(deps): bump the npm_and_yarn group across 2 directories with 3 updates (#23080)
Bumps the npm_and_yarn group with 3 updates in the / directory: [body-parser](https://github.com/expressjs/body-parser), [undici](https://github.com/nodejs/undici) and [fast-uri](https://github.com/fastify/fast-uri).
Bumps the npm_and_yarn group with 1 update in the /packages/base-driver directory: [body-parser](https://github.com/expressjs/body-parser).


Updates `body-parser` from 2.3.0 to 2.4.0
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/v2.3.0...v2.4.0)

Updates `undici` from 7.30.0 to 7.30.1
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.30.0...v7.30.1)

Updates `undici` from 6.29.0 to 6.29.1
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.30.0...v7.30.1)

Updates `undici` from 8.11.2 to 8.12.3
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.30.0...v7.30.1)

Updates `fast-uri` from 3.1.8 to 3.1.9
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.8...v3.1.9)

Updates `body-parser` from 2.3.0 to 2.4.0
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-version: 2.4.0
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: undici
  dependency-version: 7.30.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: undici
  dependency-version: 6.29.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: undici
  dependency-version: 8.12.3
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: fast-uri
  dependency-version: 3.1.9
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: body-parser
  dependency-version: 2.4.0
  dependency-type: direct:production
  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>
2026-10-24 15:25:19 +03:00
renovate[bot] aea41abf53 chore(docutils): update dependency mkdocs-material to v9.8.0 (#23079)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-24 10:40:53 +00:00
renovate[bot] 43100de428 chore(oxc-config): update dependency oxfmt to v0.74.0 (#23071)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-24 09:46:50 +02:00
renovate[bot] 8b37725d8f chore(support): update dependency asyncbox to v6.5.0 (#23073)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-24 07:40:16 +00:00
renovate[bot] f915b6c320 chore(oxc-config): update dependency oxlint to v1.89.0 (#23072)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-24 06:15:55 +00:00
Kazuaki Matsuo 4c753a134d fix(support): prevent zip extraction through symlink chains (#23002) (#23069)
* fix(support): prevent zip extraction through symlink chains

* fix(support): address zip symlink review findings

* perf(support): revalidate only affected zip symlinks

* refactor(support): clarify zip symlink validation

* refactor(support): clarify symlink target traversal

* fix(appium): avoid npm audit during extension removal and e2e setup

* fix(support): normalize Unicode symlink dependency keys

* docs(support): shorten symlink validation comments

(cherry picked from commit 8e42cbc82d)
2026-10-24 14:50:15 +09:00
dependabot[bot] a6a69d36d3 chore(deps): bump ip-address (#23070)
Bumps the npm_and_yarn group with 1 update in the / directory: [ip-address](https://github.com/beaugunderson/ip-address).


Updates `ip-address` from 10.7.3 to 10.7.4
- [Release notes](https://github.com/beaugunderson/ip-address/releases)
- [Commits](https://github.com/beaugunderson/ip-address/compare/v10.7.3...v10.7.4)

---
updated-dependencies:
- dependency-name: ip-address
  dependency-version: 10.7.4
  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>
2026-10-23 20:40:02 +03:00
renovate[bot] fa75288c5e chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.72.0 (#23068)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-23 19:14:23 +02:00
renovate[bot] 76acef9339 chore(eslint-config-appium-ts): update dependency eslint-plugin-perfectionist to v5.13.0 (#23067)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-23 16:06:09 +00:00
github-actions[bot]andmykola-mokhnach 353e9b11e3 docs(appium): Update documentation translations (#23065)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-22 08:33:02 +02:00
renovate[bot] f0d549c46c chore(eslint-config-appium-ts): update dependency eslint-plugin-n to v18.5.0 (#23059)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-21 10:57:53 +00:00
Qingyuan Wang 8d85580b22 docs: remove incorrect claim that POST /timeouts no longer accepts type/ms (#23053) 2026-10-21 13:14:37 +03:00
github-actions[bot] 815fd3e3ca docs(appium): Update documentation translations (#23058) 2026-10-21 08:53:02 +02:00
dependabot[bot] 01de9bfb7d chore(deps): bump follow-redirects (#23056)
Bumps the npm_and_yarn group with 1 update in the / directory: [follow-redirects](https://github.com/follow-redirects/follow-redirects).


Updates `follow-redirects` from 1.16.0 to 1.16.1
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.16.0...v1.16.1)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-version: 1.16.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>
2026-10-20 21:06:40 +03:00
Edgars Eglītis 522f3975e1 docs: update driver repo links to docs sites (#23045) 2026-10-20 16:40:15 +03:00
renovate[bot] c7a88ebf37 chore(docutils): update dependency lilconfig to v3.1.4 (#23041)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-20 11:40:35 +00:00
Qingyuan Wang 88ea09a90f docs(contributing): fix dead Runme link (#23043)
The https://runme.dev/api/runme?... deep-link endpoint returns 404 (the service was removed). Link to the Runme homepage instead.
2026-10-20 12:47:39 +03:00
Qingyuan Wang fff33c6666 docs(readme): fix dead link to server CLI reference (#23037) 2026-10-20 12:31:58 +03:00
Qingyuan Wang f10fdf776b docs(guides): correct how event timings are returned by the events endpoint (#23036) 2026-10-20 12:28:58 +03:00
Qingyuan Wang 355d8630fb docs(guides): clarify whole-word matching for log-filters text rules (#23035) 2026-10-20 12:26:31 +03:00
Qingyuan Wang a9542ae474 docs(readme): fix dead links to renamed and relocated files (#23034) 2026-10-20 12:24:44 +03:00
Chinmay Jha 7ea5b75bfd docs: add Optics to Ecosystem tools document (#23033) 2026-10-20 12:21:58 +03:00
github-actions[bot]andmykola-mokhnach b995004d1a docs(appium): Update documentation translations (#23032)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-20 12:54:55 +09:00
Qingyuan Wang 99ace58ff8 docs(config): correct package.json property name for embedded config (#23027)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 21:20:25 +03:00
Qingyuan Wang 85371dd4e5 docs(cli): note hostname support in --address description (#23030)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 21:18:25 +03:00
Qingyuan Wang 23abcdef70 docs(cli): correct --callback-address default in server reference (#23029)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 21:03:13 +03:00
Qingyuan Wang 76481a7494 docs(managing-exts): fix garbled sentence about loading extensions from package.json (#23028)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 21:00:52 +03:00
Qingyuan Wang 17173e4dda docs(guides): fix three grammar typos in caps, caching and execute-methods (#23031)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 20:58:50 +03:00
renovate[bot] 6f74c79a4e chore(appium): update dependency argparse to v3.0.3 (#23019)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-19 13:27:02 +00:00
Qingyuan Wang c63c31155e docs(cli-reference): correct --source=github install spec format (#23020)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 15:05:16 +03:00
Qingyuan Wang d49b48984a docs(developing): fix dead links to renamed source files (#23016)
* docs(developing): fix dead links to renamed source files

Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>

* docs(developing): adjust sentence to reflect routes directory

Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>

---------

Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 14:01:49 +03:00
Qingyuan Wang 2bc0a2e15a docs(intro): fix a dead link to the routes directory (#23017)
* docs(intro): fix a dead link to the routes directory

Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>

* docs(intro): adjust sentence to reflect routes directory

Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>

---------

Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 13:59:04 +03:00
Qingyuan Wang 5d30656828 docs(guides): fix a dead link to the renamed helpers source file (#23018)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-19 12:32:21 +03:00
github-actions[bot]andmykola-mokhnach 034f50cdb7 docs(appium): Update documentation translations (#23015)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-19 12:30:06 +03:00
Mykola Mokhnach 3c20d79238 feat(appium): fallback to latest compatible extension version for CLI install (#23013) 2026-10-18 14:37:22 +02:00
Qingyuan Wang 011a1b7fd4 docs(branch-testing): fix wrong placeholder in the plugin uninstall command (#23012)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-18 14:24:36 +03:00
Qingyuan Wang d9b8e2d2b9 docs(quickstart): fix misspelled "Test" in the Ruby quickstart guide (#23011)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-18 14:22:37 +03:00
Qingyuan Wang f1e215880b docs(api): fix dead links to the type definition file in the API reference (#23010)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-18 13:36:47 +03:00
github-actions[bot]andmykola-mokhnach 11a484bed7 docs(appium): Update documentation translations (#23008)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-18 12:29:56 +03:00
Qingyuan Wang c65aaa9953 docs: fix spelling mistakes in comments and guides (#23009)
Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
2026-10-18 12:25:49 +03:00
Qingyuan Wang 241d2b29aa docs(readme): fix the broken license links in the appium package README (#23001)
* docs(readme): fix the broken license links in the appium package README

* docs(readme): also fix the broken Apache-2.0 license link
2026-10-17 14:02:28 +03:00
Qingyuan Wang 1a21c6f3e7 docs(plugins): remove the duplicated word in the official plugins intro (#23000)
* docs(plugins): remove the duplicated word in the official plugins intro

* docs(plugins): remove the duplicated word in the ja and zh guides

* docs(plugins): revert ja and zh copies; translations are synced with Crowdin
2026-10-17 13:59:24 +03:00
Qingyuan Wang f06e2f81cb docs(grid): fix misspelled grid-ip-address placeholder in the en guide (#22999)
* docs(grid): fix misspelled grid-ip-address placeholder in the en and ja guides

* docs(grid): fix the same placeholder misspelling in the zh guide

* docs(grid): revert ja and zh copies; translations are synced with Crowdin
2026-10-17 13:57:01 +03:00
Qingyuan Wang 94a89dafc5 docs(readme): fix dead link to the server CLI documentation (#22998) 2026-10-17 13:56:24 +03:00
renovate[bot] 615a2a40c5 chore(oxc-config): update dependency oxlint to v1.88.0 (#23005)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-17 10:54:09 +00:00
github-actions[bot]andmykola-mokhnach e8a09d2ad8 docs(appium): Update documentation translations (#23003)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-17 13:54:07 +03:00
renovate[bot] d88ec034cd chore(oxc-config): update dependency oxfmt to v0.73.0 (#23004)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-17 13:48:04 +03:00
renovate[bot] 8f57e0492c chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.71.2 (#22996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-16 16:52:51 +00:00
renovate[bot] 253180c168 chore(deps): update dependency lerna to v10.1.1 (#22995)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-16 12:24:06 +00:00
MikhailandClaude Opus 5.5 a7f59de487 docs: add XPath to Class Chain to Ecosystem tools document (#22997)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 12:54:12 +03:00
renovate[bot] d649360618 chore(deps): update dependency lerna to v10.1.0 (#22985)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-14 15:44:37 +00:00
renovate[bot] 42eaf8ecda chore(oxc-config): update dependency oxlint-tsgolint to v7.0.2004 (#22984)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-14 13:14:19 +00:00
renovate[bot] 613752a609 chore(support): update dependency uuid to v14.0.3 (#22980)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-13 18:54:47 +02:00
renovate[bot] 6db1e00041 chore(deps): update dependency @types/node to v24.19.2 (#22979)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-13 14:01:39 +00:00
Kazuaki Matsuo 14110e50b0 fix(appium): backport bidi close code validation (#22942) 2026-10-11 00:54:47 +09:00
renovate[bot] 08c86049c1 chore(oxc-config): update dependency oxfmt to v0.72.0 (#22931)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-10 18:34:31 +03:00
renovate[bot] 5f5f711184 chore(universal-xml-plugin): update dependency xpath to v0.0.35 (#22949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-10 12:27:14 +03:00
Mykola Mokhnach f2f0e2cc05 docs(governance): clarify that contributions are voluntary (#22938) 2026-10-10 08:48:10 +02:00
renovate[bot] 68d0fa4ab7 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.71.1 (#22930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-09 12:24:09 +00:00
dependabot[bot] 4a6c92680c chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates (#22937)
Bumps the npm_and_yarn group with 2 updates in the / directory: [brace-expansion](https://github.com/juliangruber/brace-expansion) and [smol-toml](https://github.com/squirrelchat/smol-toml).


Updates `brace-expansion` from 5.0.9 to 5.0.12
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v5.0.9...v5.0.12)

Updates `smol-toml` from 1.6.1 to 1.9.0
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.6.1...v1.9.0)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 5.0.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: smol-toml
  dependency-version: 1.9.0
  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>
2026-10-09 14:33:01 +03:00
renovate[bot] 61e18086dc chore(oxc-config): update dependency oxlint to v1.87.0 (#22936)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-09 10:07:39 +00:00
github-actions[bot]andmykola-mokhnach 6f68dc9093 docs(appium): Update documentation translations (#22927)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-09 13:01:09 +03:00
Edgars Eglītis 0dc96de9a9 chore: run audit fix (#22920) 2026-10-08 14:21:50 +03:00
renovate[bot] 868b7b67d4 chore(workflows): update actions/setup-node action to v7.1.0 (#22915)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-08 06:27:53 +00:00
renovate[bot] e560924400 chore(deps): update dependency http-cache-semantics to v4.3.0 (#22909)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-07 08:32:53 +00:00
renovate[bot] 5fbd98ec29 chore(support): update dependency shell-quote to v1.12.0 (#22904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-06 18:37:09 +02:00
dependabot[bot] 96d130ad93 chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates (#22905)
Bumps the npm_and_yarn group with 2 updates in the / directory: [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser) and [proxy-addr](https://github.com/jshttp/proxy-addr).


Updates `postcss-selector-parser` from 7.1.5 to 7.1.6
- [Release notes](https://github.com/postcss/postcss-selector-parser/releases)
- [Changelog](https://github.com/postcss/postcss-selector-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-selector-parser/compare/7.1.5...7.1.6)

Updates `proxy-addr` from 2.0.7 to 2.0.8
- [Release notes](https://github.com/jshttp/proxy-addr/releases)
- [Changelog](https://github.com/jshttp/proxy-addr/blob/master/HISTORY.md)
- [Commits](https://github.com/jshttp/proxy-addr/compare/v2.0.7...v2.0.8)

---
updated-dependencies:
- dependency-name: postcss-selector-parser
  dependency-version: 7.1.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: proxy-addr
  dependency-version: 2.0.8
  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>
2026-10-06 15:36:31 +03:00
renovate[bot] f986375024 chore(eslint-config-appium-ts): update dependency eslint-plugin-n to v18.4.1 (#22903)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-06 12:27:25 +00:00
github-actions[bot]andmykola-mokhnach e9dc5d6374 docs(appium): Update documentation translations (#22902)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-06 11:17:17 +03:00
Mykola Mokhnach 62413002a8 fix(base-driver): track and remove BiDi subscriptions by ID (#22895) 2026-10-05 16:10:19 +02:00
Mikhail Fleytman 77945ddaf1 fix(appium): prevent recursion when logging the first BiDi event of a method (#22891) 2026-10-05 15:05:37 +02:00
Kazuaki Matsuo 061d995735 docs: document contributor style conventions for agents (#22879)
* feat(oxc-config): restore class member ordering through JS plugins

* docs: document class method ordering for agents and contributors

* docs: keep ordering rules in the contributor style guide

* docs: simplify the agent style guide reference

* docs: add JSDoc and module ordering conventions
2026-10-05 15:10:06 +09:00
renovate[bot] 596ece7f11 chore(deps): update dependency @types/node to v24.19.1 (#22892)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-05 05:56:47 +00:00
github-actions[bot]andmykola-mokhnach 73e587fe3d docs(appium): Update documentation translations (#22856)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-03 12:47:03 +03:00
renovate[bot] 01d2b8f1e4 chore(support): update dependency shell-quote to v1.11.0 (#22858)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-03 09:46:49 +00:00
renovate[bot] 607a1ecf81 chore(oxc-config): update dependency oxlint to v1.86.0 (#22853)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-03 00:21:35 +00:00
renovate[bot] e621c6fe87 chore(universal-xml-plugin): update dependency fast-xml-parser to v5.11.2 (#22849)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-02 20:22:00 +00:00
renovate[bot] c27ced0d1d chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.71.0 (#22850)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-02 16:21:53 +00:00
renovate[bot] 7a3190e5e5 chore(deps): update definitelytyped (#22847)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-02 12:22:29 +00:00
renovate[bot] 1ca4bc311c chore(oxc-config): update dependency oxfmt to v0.71.0 (#22852)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-02 13:31:08 +03:00
David Burns a85a35e87d docs(appium): add llms.txt to the documentation site (#22839)
* docs(appium): add llms.txt to the documentation site

Adds an /llms.txt file (https://llmstxt.org/) so that LLMs can navigate the
Appium documentation without crawling it, following the same approach taken by
the Selenium project.

The file is hand-written rather than generated. Its value lies in the parts a
crawler could not work out on its own: a set of steering notes covering what
models reliably get wrong about Appium (Appium 1 era patterns, drivers needing
separate installation, the `appium:` capability prefix, `mobile:` execute
methods, the Appium 3 `--allow-insecure` scope prefix, and the move from
GET /sessions to GET /appium/sessions), followed by conceptually grouped links
with a description for each page.

MkDocs copies non-Markdown files in docs_dir to the site verbatim, so this
requires no plugin, no new dependency and no build configuration. It is served
at appium.io/docs/en/latest/llms.txt, and mike gives a per-version copy for
free.

Because the file is hand-written, nothing regenerates it when a page is renamed
or removed. check-llmstxt.js validates it against the documentation sources and
runs on every docs PR: broken links fail the build, while pages that exist but
are not listed produce a warning (or fail under --strict).

The root of appium.io is not produced by MkDocs, but crawlers look for
/llms.txt at the domain root. Since the links in the file are absolute, the
same file serves both locations, so the publish workflow copies it to the
gh-pages root on release. mike only writes under its docs/<lang> deploy prefix,
so this does not interfere with it.

English only, matching Selenium and WebdriverIO. The ja/zh docs are translated
via Crowdin, where hand-edited descriptions would drift out of sync.

* docs(appium): address llms.txt review feedback

- Describe the standard W3C capabilities as the specification's set rather than
  only browserName/browserVersion/platformName, so that generated code does not
  vendor-prefix acceptInsecureCerts, timeouts, pageLoadStrategy or webSocketUrl.
- Say that these pages describe Appium 3, and that Appium 2 is documented under
  its own version of the site, instead of claiming both are covered here.
- Note watchOS for the XCUITest driver, and the AI-related tools (Appium MCP,
  agent skills) alongside Appium Inspector.
- Correct the event timings entry: the endpoint works without the
  appium:eventTimings capability, which is being removed in Appium 4.
- check-llmstxt.js: a page that exists but is not listed is now an error rather
  than a warning, since a warning in CI logs is easy to miss. The --strict flag
  is gone, as that is now the only behaviour.
- check-llmstxt.js: validate relative and site-relative links too. A link such
  as /docs/en/3.7/guides/caps/ was previously treated as external and skipped,
  so a pinned version could have slipped past the check.
2026-10-02 13:18:58 +03:00
dependabot[bot] 43bb05cba0 chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates (#22851)
Bumps the npm_and_yarn group with 2 updates in the / directory: [undici](https://github.com/nodejs/undici) and [ip-address](https://github.com/beaugunderson/ip-address).


Updates `undici` from 7.29.0 to 7.30.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.29.0...v7.30.0)

Updates `undici` from 6.28.0 to 6.29.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.29.0...v7.30.0)

Updates `ip-address` from 10.7.0 to 10.7.3
- [Release notes](https://github.com/beaugunderson/ip-address/releases)
- [Commits](https://github.com/beaugunderson/ip-address/compare/v10.7.0...v10.7.3)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.30.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: undici
  dependency-version: 6.29.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: ip-address
  dependency-version: 10.7.3
  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>
2026-10-02 12:16:07 +03:00
github-actions[bot]andmykola-mokhnach 28e9501374 docs(appium): Update documentation translations (#22845)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-10-02 12:07:16 +03:00
renovate[bot] eed26a25fc chore(opencv): update dependency sharp to v0.35.5 (#22848)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-02 12:06:39 +03:00
Edgars Eglītis ecabd78fa1 docs: tune driver listing (#22844)
* docs: tune driver listing

* docs: update Espresso modes
2026-10-01 18:16:08 +03:00
dependabot[bot] e33b47f96b chore(deps): bump fast-uri in the npm_and_yarn group across 1 directory (#22831)
Bumps the npm_and_yarn group with 1 update in the / directory: [fast-uri](https://github.com/fastify/fast-uri).


Updates `fast-uri` from 3.1.6 to 3.1.8
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.6...v3.1.8)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.8
  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>
2026-09-30 13:01:00 +03:00
renovate[bot] bbf849380d chore(storage-plugin): update dependency ws to v8.22.0 (#22838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-30 08:16:03 +02:00
renovate[bot] ac93158af5 chore(eslint-config-appium-ts): update dependency eslint-plugin-n to v18.4.0 (#22837)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-30 06:14:45 +00:00
renovate[bot] 2bec48ebc0 chore(deps): update dependency @types/node to v24.19.0 (#22832)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-29 12:28:25 +00:00
renovate[bot] 9173346c3c chore(oxc-config): update dependency oxlint-tsgolint to v7.0.2003 (#22830)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 21:12:01 +00:00
renovate[bot] 9396d6d3b0 chore(eslint-config-appium-ts): update dependency eslint-plugin-perfectionist to v5.12.1 (#22824)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-27 12:24:25 +00:00
Kazuaki Matsuo 359ef4ba89 fix(support): preserve exclamation marks with apostrophes (#22816)
* fix(support): preserve exclamation marks with apostrophes

* test(support): use async shell execution and document workaround
2026-09-27 02:28:37 +09:00
renovate[bot] ac2c78c822 chore(oxc-config): update dependency oxlint to v1.85.0 (#22820)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-26 12:39:38 +00:00
renovate[bot] 59ab921d8e chore(execute-driver-plugin): update dependency webdriverio to v9.32.0 (#22818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-26 11:53:00 +00:00
renovate[bot] c051454e87 chore(oxc-config): update dependency oxfmt to v0.70.0 (#22819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-26 13:47:43 +02:00
renovate[bot] 3c48508904 chore(eslint-config-appium-ts): update dependency eslint-plugin-perfectionist to v5.12.0 (#22817)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-26 11:38:22 +00:00
renovate[bot] 9509d19e1b chore(docutils): update dependency yargs to v18.2.0 (#22814)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-25 12:06:11 +00:00
renovate[bot] 7723622d57 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.70.1 (#22813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-25 14:00:20 +02:00
github-actions eb5ce47b17 chore: publish
- appium@3.8.0
 - @appium/base-driver@10.8.1
 - @appium/base-plugin@3.3.5
 - @appium/docutils@3.0.1
 - @appium/driver-test-support@3.0.1
 - @appium/eslint-config-appium-ts@3.2.6
 - @appium/execute-driver-plugin@7.0.1
 - @appium/fake-driver@6.2.4
 - @appium/fake-plugin@4.4.1
 - @appium/images-plugin@5.0.1
 - @appium/logger@2.0.12
 - @appium/opencv@5.0.1
 - @appium/oxc-config@1.1.2
 - @appium/plugin-test-support@3.0.1
 - @appium/relaxed-caps-plugin@3.0.1
 - @appium/storage-plugin@2.0.1
 - @appium/strongbox@2.0.1
 - @appium/support@7.2.8
 - @appium/types@1.7.1
 - @appium/universal-xml-plugin@3.0.1
2026-09-24 18:25:54 +00:00
Mykola Mokhnach 7df378f401 fix(support): avoid TOCTOU race in getLockFileGuard() acquisition (#22807) 2026-09-23 08:42:29 +02:00
Mohamed Mostafa 4dd2e2d47d fix(support): do not delete a path when fs.mv destination is the source or inside it (#22806) 2026-09-23 08:35:12 +02:00
renovate[bot] dacc42ba0a chore(storage-plugin): update dependency lru-cache to v11.5.3 (#22802)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-22 19:36:17 +00:00
renovate[bot] 2502f538ff chore(deps): update dependency @types/node to v24.13.6 (#22801)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-22 16:29:05 +00:00
renovate[bot] 3f38f5cd74 chore(types): update dependency type-fest to v5.10.0 (#22798)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-21 23:31:41 +00:00
renovate[bot] 6891dd4eae chore(oxc-config): update dependency oxlint-tsgolint to v7.0.2002 (#22797)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-21 15:15:48 +00:00
Mykola Mokhnach 4e8e334cbc fix(appium): filter prerelease versions in driver update e2e test (#22794) 2026-09-20 15:15:22 +02:00
Mohamed Mostafa 3423e36689 fix(base-driver): keep existing contexts when session.subscribe is called again (#22780) 2026-09-20 14:19:29 +02:00
renovate[bot] 14a9d98641 chore(eslint-config-appium-ts): update dependency eslint-plugin-perfectionist to v5.11.1 (#22786)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-19 18:08:51 +02:00
renovate[bot] f79fafb816 chore(deps): update dependency @types/node to v24.13.5 (#22785)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-19 10:22:06 +00:00
Edgars Eglītis 443b0bdd03 chore(oxc-config): update oxc packages (#22787) 2026-09-19 12:38:39 +03:00
renovate[bot] 80fbf957c8 chore(docutils): update dependency mkdocs-git-revision-date-localized-plugin to v1.6.0 (#22782)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-18 23:43:43 +00:00
renovate[bot] 0443c84ec0 chore(execute-driver-plugin): update dependency webdriverio to v9.31.9 (#22781)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-18 08:43:04 +00:00
renovate[bot] a47fdb8e05 chore(execute-driver-plugin): update dependency webdriverio to v9.31.8 (#22779)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-16 17:52:21 +02:00
renovate[bot] e2c8f09bb9 chore(docutils): update dependency yaml to v2.9.1 (#22778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-16 17:52:08 +02:00
Mohamed Mostafa dc16d6970f fix(support): extract zip entries whose names start with dots (#22772) 2026-09-14 18:08:04 +02:00
renovate[bot] abfe1243a1 chore(base-driver): update dependency morgan to v1.12.1 (#22775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 13:44:06 +02:00
renovate[bot] 9bbf6b72bf chore(appium): update dependency argparse to v3.0.2 (#22773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 11:27:58 +00:00
renovate[bot] 0fa9c9bd80 chore(deps): update dependency @types/node to v24.13.4 (#22768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-13 13:46:08 +00:00
Mohamed Mostafa 9a70a44c83 fix(support): do not set file-sized Content-Length on default multipart uploads (#22766) 2026-09-12 19:02:21 +02:00
renovate[bot] 65e14685a8 chore(oxc-config): update dependency oxfmt to v0.67.0 (#22724)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-12 11:50:40 +03:00
renovate[bot] 29eeb28f86 chore(oxc-config): update dependency oxlint to v1.82.0 (#22726)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-12 06:39:44 +00:00
github-actions[bot]andmykola-mokhnach ac412b8723 docs(appium): Update documentation translations (#22759)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-09-11 19:36:59 +03:00
renovate[bot] 68740320d2 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.70.0 (#22761)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-11 12:14:22 +00:00
renovate[bot] 9dc6cd0019 chore(execute-driver-plugin): update dependency webdriverio to v9.31.7 (#22760)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-11 12:04:55 +00:00
Mohamed Mostafa 81c8b9da0a fix(base-driver): honor unquoted and RFC 5987 Content-Disposition filenames (#22755) 2026-09-11 08:19:50 +02:00
renovate[bot] 726348c2d5 chore(js): update dependency webdriverio to v9.31.6 (#22751)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-10 16:32:41 +00:00
Jack VanSickle 6c911debd7 feat(appium): accept package names for installed extension commands (#22747) 2026-09-10 07:25:36 +02:00
Edgars Eglītis 8ccb436701 chore(deps): bump ESLint and bplist-related dependencies (#22748) 2026-09-09 11:22:33 +03:00
Mohamed Mostafa f522b64456 fix(storage-plugin): map StorageArgumentError to InvalidArgumentError (#22734) 2026-09-08 06:50:51 +02:00
Mohamed Mostafa 3180558086 test(images-plugin): give the unit tests room to retry and finish on CI (#22743) 2026-09-08 06:44:12 +02:00
dependabot[bot] 9d07f6bc5e chore(deps): bump deepmerge-ts (#22739)
Bumps the npm_and_yarn group with 1 update in the / directory: [deepmerge-ts](https://github.com/RebeccaStevens/deepmerge-ts).


Updates `deepmerge-ts` from 7.1.6 to 8.0.2
- [Release notes](https://github.com/RebeccaStevens/deepmerge-ts/releases)
- [Changelog](https://github.com/RebeccaStevens/deepmerge-ts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RebeccaStevens/deepmerge-ts/compare/v7.1.6...v8.0.2)

---
updated-dependencies:
- dependency-name: deepmerge-ts
  dependency-version: 8.0.2
  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>
2026-09-07 12:42:56 +03:00
Edgars Eglītis b234e2b56b chore(oxc-config): bump oxc dependencies (#22737) 2026-09-07 12:11:56 +03:00
Edgars Eglītis b635641f24 chore: regenerate lockfile (#22728)
* chore: regenerate lockfile

* chore: regenerate again after a deeper cleanup
2026-09-05 14:10:02 +03:00
Edgars EglītisandMykola Mokhnach 6d720b1112 test(base-driver): fix invalid import (#22729)
* test: fix invalid import

* test: import BaseDriver from package entry in type test

tsd builds its type-check program from an explicit file list, which
trips TS6059 (composite project) when the raw lib source is imported
directly, pulling in the whole transitive dependency tree.

* fix: exclude test/types from base-driver's main tsc build

Importing @appium/base-driver by package name from within its own
test/types dir is a self-reference: the main composite build (tsc -b)
was including test/types too, so it tried to resolve the package's own
not-yet-emitted build/lib/index.d.ts while still generating it,
breaking the whole build. packages/strongbox already excludes
test/types from its main include for the same reason; tsd targets
test/types independently via its own "directory" config, unaffected
by this exclude.

* fix: use explicit tsconfig include instead of excluding test/types

Matches packages/strongbox's pattern of listing test subfolders
explicitly rather than excluding test/types from "test".

---------

Co-authored-by: Mykola Mokhnach <mokhnach@gmail.com>
2026-09-05 13:55:31 +03:00
Mohamed Mostafa 6ab17feb71 fix(appium): match insecure feature prefixes by automationName, case-insensitively (#22710) 2026-09-05 09:25:01 +02:00
Mohamed Mostafa afa4837530 fix(strongbox): reject item names that slugify to an empty path (#22717) 2026-09-04 18:37:47 +02:00
renovate[bot] 1ada93cf76 chore(types): update dependency type-fest to v5.9.0 (#22713)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-03 11:03:14 +00:00
dependabot[bot] b32e28d36d chore(deps): bump fast-uri in the npm_and_yarn group across 1 directory (#22711)
Bumps the npm_and_yarn group with 1 update in the / directory: [fast-uri](https://github.com/fastify/fast-uri).


Updates `fast-uri` from 3.1.5 to 3.1.7
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.5...v3.1.7)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.7
  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>
2026-09-03 10:50:55 +03:00
renovate[bot] 119e21f067 chore(opencv): update dependency sharp to v0.35.4 (#22712)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-03 07:40:13 +02:00
Mohamed Mostafa 6ba6faf6f5 fix(appium): do not treat a directory as a CLI argument file (#22709) 2026-09-02 20:40:47 +02:00
dependabot[bot] 422362a259 chore(deps): bump the npm_and_yarn group across 1 directory with 3 updates (#22707)
Bumps the npm_and_yarn group with 3 updates in the / directory: [@humanfs/node](https://github.com/humanwhocodes/humanfs/tree/HEAD/packages/node), [browserslist](https://github.com/browserslist/browserslist) and [qs](https://github.com/ljharb/qs).


Updates `@humanfs/node` from 0.16.6 to 0.16.8
- [Release notes](https://github.com/humanwhocodes/humanfs/releases)
- [Changelog](https://github.com/humanwhocodes/humanfs/blob/main/packages/node/CHANGELOG.md)
- [Commits](https://github.com/humanwhocodes/humanfs/commits/node-v0.16.8/packages/node)

Updates `browserslist` from 4.28.2 to 4.28.8
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.28.2...4.28.8)

Updates `qs` from 6.15.2 to 6.16.0
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.15.2...v6.16.0)

---
updated-dependencies:
- dependency-name: "@humanfs/node"
  dependency-version: 0.16.8
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: browserslist
  dependency-version: 4.28.8
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: qs
  dependency-version: 6.16.0
  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>
2026-09-02 19:30:56 +03:00
renovate[bot] 62bfe1566a chore(execute-driver-plugin): update dependency webdriverio to v9.31.5 (#22706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-02 15:28:34 +00:00
Kazuaki Matsuo 8a9350b8e9 docs: fix docs build (#22702) 2026-09-02 13:01:01 +09:00
github-actions[bot]andmykola-mokhnach bf51d27137 docs(appium): Update documentation translations (#22701)
Co-authored-by: mykola-mokhnach <7767781+mykola-mokhnach@users.noreply.github.com>
2026-09-02 12:21:52 +09:00
dependabot[bot] de00df0afa chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates (#22698)
Bumps the npm_and_yarn group with 2 updates in the / directory: [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser) and [tar](https://github.com/isaacs/node-tar).


Updates `postcss-selector-parser` from 7.1.1 to 7.1.4
- [Release notes](https://github.com/postcss/postcss-selector-parser/releases)
- [Changelog](https://github.com/postcss/postcss-selector-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-selector-parser/compare/v7.1.1...7.1.4)

Updates `tar` from 7.5.19 to 7.5.22
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.19...v7.5.22)

---
updated-dependencies:
- dependency-name: postcss-selector-parser
  dependency-version: 7.1.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: tar
  dependency-version: 7.5.22
  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>
2026-09-01 19:21:41 +03:00
renovate[bot] c3a48181c8 chore(oxc-config): update dependency oxlint to v1.80.0 (#22696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-01 16:05:19 +00:00
Edgars Eglītis 77dc09af36 docs: add watchOS blogpost (#22697) 2026-09-01 18:57:25 +03:00
renovate[bot] 59af10a17c chore(oxc-config): update dependency oxfmt to v0.65.0 (#22695)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-01 13:29:46 +03:00
renovate[bot] 6e989bd89a chore(support): update dependency axios to v1.20.0 (#22692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-01 10:09:07 +00:00
renovate[bot] 557e71f766 chore(deps): update dependency json-schema-to-typescript to v16 (#22694)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-01 13:03:25 +03:00
renovate[bot] 63d94d03c6 chore(eslint-config-appium-ts): update dependency typescript-eslint to v8.68.0 (#22693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-01 00:43:50 +00:00
renovate[bot] 8a0022c147 chore(base-driver): update dependency morgan to v1.12.0 (#22690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-31 21:10:49 +00:00
renovate[bot] 72ee77d139 chore(universal-xml-plugin): update dependency fast-xml-parser to v5.11.1 (#22691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-31 21:05:10 +00:00
renovate[bot] 70a01da4b2 chore(support): update dependency asyncbox to v6.4.3 (#22688)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-31 19:24:34 +00:00
renovate[bot] 1b705bcd24 chore(appium): update dependency argparse to v3.0.1 (#22689)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-31 19:11:44 +00:00
renovate[bot] 574bd6cbfb chore(execute-driver-plugin): update dependency webdriverio to v9.31.4 (#22687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-31 19:06:33 +00:00
Mohamed Mostafa 9c00b86ce7 fix(base-driver): reject invalid timeout with InvalidArgumentError (#22679) 2026-08-31 20:35:57 +02:00
Mohamed Mostafa 0c4da64aea fix(base-driver): skip unknown events in session.unsubscribe (#22671) 2026-08-29 17:26:32 +02:00
605 changed files with 22319 additions and 20992 deletions
+2
View File
@@ -23,6 +23,8 @@ targets:
path: ./packages/appium
- type: npm
path: ./packages/base-driver
- type: npm
path: ./packages/eslint-config-appium-ts
- type: npm
path: ./packages/fake-driver
- type: npm
+1 -1
View File
@@ -20,7 +20,7 @@ runs:
using: composite
steps:
- name: Use Node.js ${{ inputs.node-version }}
uses: actions/setup-node@v7.0.0
uses: actions/setup-node@v7.1.0
with:
node-version: ${{ inputs.node-version }}
cache: npm
+5
View File
@@ -68,6 +68,11 @@ labels:
matcher:
files: ['packages/driver-test-support/**']
- label: '@appium/eslint-config-appium-ts'
sync: true
matcher:
files: ['packages/eslint-config-appium-ts/**']
- label: '@appium/oxc-config'
sync: true
matcher:
-2
View File
@@ -3,7 +3,6 @@ on:
push:
branches:
- master
- appium4
# this list of paths could potentially impact the build
paths:
- '**/tsconfig*.json'
@@ -24,7 +23,6 @@ on:
pull_request:
branches:
- master
- appium4
paths:
- '**/tsconfig*.json'
- 'packages/base-driver/test-fixtures/**/*'
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
steps:
- uses: actions/checkout@v7.0.1
- name: Use Node.js LTS
uses: actions/setup-node@v7.0.0
uses: actions/setup-node@v7.1.0
with:
node-version: lts/*
cache: 'npm'
@@ -16,7 +16,7 @@ jobs:
with:
persist-credentials: false
- name: Use Node.js LTS
uses: actions/setup-node@v7.0.0
uses: actions/setup-node@v7.1.0
with:
node-version: lts/*
cache: 'npm'
@@ -17,7 +17,7 @@ jobs:
steps:
- uses: actions/checkout@v7.0.1
- name: Use Node.js LTS
uses: actions/setup-node@v7.0.0
uses: actions/setup-node@v7.1.0
with:
node-version: lts/*
cache: 'npm'
+8 -2
View File
@@ -10,7 +10,13 @@ permissions:
jobs:
prepare_matrix:
uses: appium/appium-workflows/.github/workflows/node-lts-matrix.yml@main
runs-on: ubuntu-latest
outputs:
versions: ${{ steps.generate-matrix.outputs.lts }}
steps:
- name: Select all current LTS versions of Node.js
id: generate-matrix
uses: msimerson/node-lts-versions@v2.0.2
check:
needs:
@@ -23,7 +29,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v7.0.0
uses: actions/setup-node@v7.1.0
with:
node-version: ${{ matrix.node-version }}
- name: Install Appium
+4
View File
@@ -49,5 +49,9 @@ jobs:
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
- name: Check llms.txt
run: npm run docs:check-llmstxt
- name: Build Docs
run: npm run docs:preview
- name: Verify llms.txt was published to the site
run: test -s packages/appium/docs/site/en/llms.txt
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v7.0.1
- name: Use Node.js LTS
uses: actions/setup-node@v7.0.0
uses: actions/setup-node@v7.1.0
with:
node-version: lts/*
cache: 'npm'
+30 -16
View File
@@ -13,11 +13,11 @@ on:
required: true
type: boolean
default: false
allow_legacy_peer_deps:
description: 'Beta branch only: pass --legacy-peer-deps to lerna''s internal npm calls, for when a dependent''s peerDependencies range still lags a just-bumped major (causes ERESOLVE otherwise). Leave off unless you hit that failure.'
required: true
type: boolean
default: false
bootstrap_packages:
description: 'One-time beta-branch bootstrap only: comma-separated package names (e.g. @appium/base-driver,@appium/support) to force-bump to their next-major beta (premajor --preid beta), bypassing conventional-commit detection. Leave empty for a normal release.'
required: false
type: string
default: ''
permissions:
contents: write
@@ -58,29 +58,43 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DRY_RUN: ${{ inputs.dry_run }}
RECOVER_MISSING_ONLY: ${{ inputs.recover_missing_only }}
ALLOW_LEGACY_PEER_DEPS: ${{ inputs.allow_legacy_peer_deps }}
BOOTSTRAP_PACKAGES: ${{ inputs.bootstrap_packages }}
run: |
set -euo pipefail
# On the beta branch ($BETA_BRANCH), every release is a beta prerelease anchored at its
# target major (see packages/semantic-release-config's "Next-major beta branches" docs
# for the equivalent semantic-release behavior this mirrors).
#
# allow_legacy_peer_deps: independent next-major beta.0 bumps can briefly outrun a
# dependent's committed peerDependencies range, aborting lerna's internal lockfile
# refresh with ERESOLVE. Opt-in only - it masks a real (if temporary) peer mismatch.
LEGACY_PEER_DEPS_FLAGS=""
if [ "$ALLOW_LEGACY_PEER_DEPS" = "true" ]; then
LEGACY_PEER_DEPS_FLAGS="--npm-client-args=--legacy-peer-deps"
fi
BETA_FLAGS=""
DIST_TAG_FLAGS=""
if [ "${{ github.ref_name }}" = "$BETA_BRANCH" ]; then
BETA_FLAGS="--conventional-prerelease --preid beta $LEGACY_PEER_DEPS_FLAGS"
BETA_FLAGS="--conventional-prerelease --preid beta"
DIST_TAG_FLAGS="--dist-tag beta"
fi
# One-time bootstrap for packages just starting their beta train: force them
# straight to <next-major>.0.0-beta.0 instead of waiting for/relying on a commit that
# happens to be marked as breaking. Not part of the normal release flow below - this
# exits early on its own.
if [ -n "$BOOTSTRAP_PACKAGES" ]; then
if [ "${{ github.ref_name }}" != "$BETA_BRANCH" ]; then
echo "bootstrap_packages is only meaningful on the $BETA_BRANCH branch" >&2
exit 1
fi
if [ "$RECOVER_MISSING_ONLY" = "true" ]; then
echo "bootstrap_packages cannot be combined with recover_missing_only" >&2
exit 1
fi
echo "Bootstrapping ${BOOTSTRAP_PACKAGES} to their next-major beta (premajor --preid beta), bypassing conventional-commit detection"
if [ "$DRY_RUN" = "true" ]; then
printf "n\n" | npx lerna version premajor --preid beta --exact --no-git-tag-version --no-push --force-publish="$BOOTSTRAP_PACKAGES"
else
npx lerna publish premajor --preid beta --exact --force-publish="$BOOTSTRAP_PACKAGES" --dist-tag beta --yes
fi
exit 0
fi
# Prints "<pkg_name>@<pkg_version>" to stdout for each non-private workspace package
# whose current package.json version is not yet on npm.
find_missing_packages() {
+15
View File
@@ -30,3 +30,18 @@ jobs:
run: npm run install-docs-deps
- name: Publish docs
run: npm run docs:publish
# The docs are deployed by mike into docs/<lang>/<version>, but crawlers look for
# /llms.txt at the domain root. The file's links are absolute, so the same file serves
# both locations.
- name: Publish llms.txt to the site root
run: |
cp packages/appium/docs/en/llms.txt "${RUNNER_TEMP}/llms.txt"
git checkout -f gh-pages
cp "${RUNNER_TEMP}/llms.txt" llms.txt
git add llms.txt
if git diff --cached --quiet -- llms.txt; then
echo "Root llms.txt is already up to date"
else
git commit -m "docs: update root llms.txt"
git push origin gh-pages
fi
+4
View File
@@ -0,0 +1,4 @@
# Repository guidance
Before changing code, read and follow the
[contributor style guide](packages/appium/docs/en/contributing/index.md#code-style).
+25
View File
@@ -149,6 +149,31 @@ a discretionary of special basis. Basically, this scheme is run at the project's
not a public service. Making contributions to the project under this scheme does not obligate the
project to pay you for such work, or otherwise compensate you in any way.
### Contributions Are Voluntary
Appium is a community-driven open source project, and all contributions to it are voluntary.
Opening a pull request, or responding to review feedback, does not create a contract, a
commission, a work-for-hire arrangement, or any other obligation on the part of the project, its
Committers, the TC, or the OpenJS Foundation. In particular:
- The project does not hire contractors, assign paid tasks, or quote per-PR, per-task, or hourly
rates. The "value tiers" above are an after-the-fact, discretionary gesture of appreciation, not
a price list.
- Compensation can't be requested, negotiated, or promised in advance, and it must not be made a
condition for starting, continuing, or revising a contribution. A value tier is only assigned by a
Committer after a change has been merged, and may be zero.
- Review feedback, including requests to extend, rework, or re-scope a change, is a normal part of
getting it merged and is never a reason to ask for additional payment.
- Contributors are free to stop working on a change at any time. Maintainers may pick it up, or
close it if it does not suit the project.
- Contributions that appear to be primarily motivated by obtaining payouts (for example, bulk or
low-effort changes, including AI-generated ones submitted without understanding or testing them)
may be closed, and repeated abuse of the scheme may result in the contributor being excluded from
it and from the project's spaces. Contributors are fully responsible for the content they submit,
regardless of the tools used to produce it.
If you are not comfortable contributing on these terms, please do not contribute.
### Raising Issues Related to Governance
This governance model necessarily leaves many situations unspecified. If
+2 -2
View File
@@ -133,7 +133,7 @@ appium plugin uninstall <plugin-name>
## Server Command Line Interface
In order to start sending commands to the Appium server, it must be running on the URL and port
where your client library expects it to listen. [Appium's command-line interface](http://appium.io/docs/en/latest/cli/server/)
where your client library expects it to listen. [Appium's command-line interface](https://appium.io/docs/en/latest/reference/cli/)
is used to launch and configure the server:
```bash
@@ -161,7 +161,7 @@ for the particular driver or whether it supports parallel sessions.
automation, all using the WebDriver model that's already the standard for web automation.
5. You can run your automated tests locally and in a cloud. There are multiple cloud providers that
support various Appium drivers (mostly targeting iOS and Android mobile automation).
6. [Appium Inspector](https://github.com/appium/appium-inspector) can be used to visually inspect
6. [Appium Inspector](https://appium.github.io/appium-inspector/) can be used to visually inspect
the page source of applications across different platforms, facilitating easier test development.
Investing in the [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means you
+38
View File
@@ -0,0 +1,38 @@
import appiumConfig from '@appium/eslint-config-appium-ts';
import {defineConfig, globalIgnores} from 'eslint/config';
// Create a modified config subset for test support files:
// Extract the test file related configs (Mocha plugin and custom rules),
// then override their 'files' property (match by name — resilient to new config entries).
const testFileConfigItems = appiumConfig.filter(
(item) => typeof item?.name === 'string' && item.name.startsWith('Test Files'),
);
const testSupportFiles = ['packages/driver-test-support/lib/**', 'packages/plugin-test-support/lib/**'];
const testSupportConfig = testFileConfigItems.map((item) => ({...item, files: testSupportFiles}));
export default defineConfig([
{
name: 'Base Config',
extends: [appiumConfig],
},
{
name: 'Test Support',
extends: [testSupportConfig],
},
{
name: 'Consistent type-only imports (all packages)',
files: ['**/*.{ts,tsx,mtsx}'],
rules: {
'@typescript-eslint/consistent-type-imports': [
'error',
{fixStyle: 'separate-type-imports', prefer: 'type-imports'},
],
},
},
globalIgnores([
'**/build-fixtures/**',
'packages/appium/docs/**/assets/**',
'packages/appium/docs/**/js/**',
'packages/appium/sample-code/**',
]),
]);
+8305 -6102
View File
File diff suppressed because it is too large Load Diff
+16 -14
View File
@@ -46,6 +46,7 @@
"dev": "run-s build:compile \"build:workspaces\" \"build:compile -- --watch\"",
"dev:docs": "npm run -w packages/appium dev:docs",
"docs": "npm run -w packages/appium build:docs",
"docs:check-llmstxt": "npm run -w packages/appium check:docs:llmstxt",
"docs:preview": "npm run -w packages/appium build:docs:preview",
"docs:publish": "npm run -w packages/appium publish:docs",
"doctor": "node ./scripts/doctor-stub.mjs",
@@ -81,46 +82,47 @@
},
"devDependencies": {
"@appium/oxc-config": "1.0.0",
"@tsconfig/node22": "22.0.0",
"@tsconfig/node20": "20.1.10",
"@types/async-lock": "1.4.2",
"@types/bluebird": "3.5.42",
"@types/content-disposition": "0.5.9",
"@types/express": "5.0.6",
"@types/finalhandler": "1.2.4",
"@types/jsftp": "2.1.5",
"@types/json-schema": "7.0.15",
"@types/klaw": "3.0.7",
"@types/klaw": "3.0.8",
"@types/lockfile": "1.0.4",
"@types/method-override": "3.0.0",
"@types/mime-types": "3.0.1",
"@types/morgan": "1.9.10",
"@types/node": "24.13.3",
"@types/picomatch": "4.0.3",
"@types/node": "24.19.2",
"@types/plist": "3.0.5",
"@types/pluralize": "0.0.33",
"@types/semver": "7.8.0",
"@types/serve-favicon": "2.5.7",
"@types/shell-quote": "1.7.5",
"@types/sinon": "22.0.0",
"@types/which": "3.0.4",
"@types/ws": "8.18.1",
"@types/ws": "8.18.2",
"@types/yargs": "17.0.35",
"asyncbox": "6.4.2",
"asyncbox": "6.5.0",
"conventional-changelog-conventionalcommits": "9.3.1",
"cpy-cli": "7.0.0",
"cross-env": "10.1.0",
"finalhandler": "2.1.1",
"json-schema-to-typescript": "15.0.4",
"lerna": "10.0.1",
"json-schema-to-typescript": "16.0.0",
"lerna": "10.1.1",
"mjpeg-consumer": "2.0.0",
"mjpeg-server": "0.3.1",
"npm-run-all2": "9.0.3",
"npm-run-all2": "9.0.4",
"rewiremock": "3.14.6",
"rimraf": "6.1.3",
"serve-static": "2.2.1",
"sinon": "22.1.0",
"teen_process": "4.2.1",
"tsd": "0.33.0",
"typescript": "6.0.3",
"webdriverio": "9.31.2",
"ws": "8.21.3"
"webdriverio": "9.32.0",
"ws": "8.22.0"
},
"overrides": {
"@sidvind/better-ajv-errors": {
@@ -129,10 +131,10 @@
"ajv-formats": {
"ajv": "8.20.0"
},
"http-cache-semantics": "4.2.0"
"http-cache-semantics": "4.3.0"
},
"engines": {
"node": "^22.22.2 || ^24.15.0 || >=26.0.0",
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
"npm": ">=10"
}
}
+11 -111
View File
@@ -3,131 +3,31 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.0.0-beta.2](https://github.com/appium/appium/compare/appium@4.0.0-beta.1...appium@4.0.0-beta.2) (2026-09-27)
### ⚠ BREAKING CHANGES
* **base-driver:** @appium/base-driver no longer exports server, normalizeBasePath, configureServer, ServerOpts, ConfigureServerOpts, ConfigureHttpOpts, or StartServerOpts, and no longer depends on express/morgan/body-parser/ method-override/path-to-regexp. Use the new @appium/http-server package instead.
* **base-driver:** appium/driver.js and driver.d.ts no longer re-export server/normalizeBasePath/configureServer/ServerOpts (or their types), and no longer use a blanket export *. Import from @appium/http-server directly if you were relying on this undocumented path.
## [3.9.0](https://github.com/appium/appium/compare/appium@3.8.0...appium@3.9.0) (2026-10-27)
### Features
* **appium:** accept package names for installed extension commands ([#22747](https://github.com/appium/appium/issues/22747)) ([#22812](https://github.com/appium/appium/issues/22812)) ([b7356ee](https://github.com/appium/appium/commit/b7356ee53eec3e322707eef0d2bd37976a47cfd2))
* **appium:** fallback to latest compatible extension version for CLI &#x60;install&#x60; ([#23013](https://github.com/appium/appium/issues/23013)) ([3c20d79](https://github.com/appium/appium/commit/3c20d7923806bcc2333670e6cef5c24c6da60d62))
### Bug Fixes
* **appium:** release the manifest lock before errAndQuit exits ([#22821](https://github.com/appium/appium/issues/22821)) ([dc0568b](https://github.com/appium/appium/commit/dc0568bc658961f5d6a28fb955d8092d51cf9523))
* **base-driver:** carry proxy req via AsyncLocalStorage instead of args ([#22799](https://github.com/appium/appium/issues/22799)) ([2596da0](https://github.com/appium/appium/commit/2596da02d201d7e5fbfd24cf9dd2801302f8abc7))
* **support:** narrow fs.glob overload for default withFileTypes/lazy ([#22795](https://github.com/appium/appium/issues/22795)) ([09a04f4](https://github.com/appium/appium/commit/09a04f48831e17b9b7f3b8dc0a72f0df5096ae51))
### Code Refactoring
* **base-driver:** extract the HTTP/Express server into @appium/http-server ([#22800](https://github.com/appium/appium/issues/22800)) ([225a1c6](https://github.com/appium/appium/commit/225a1c6d9d24fa2696699d4b61436a49b847d666))
* **appium:** backport bidi close code validation ([#22942](https://github.com/appium/appium/issues/22942)) ([14110e5](https://github.com/appium/appium/commit/14110e50b0bf3414c778e039acb7058a3c649e2e))
* **appium:** prevent recursion when logging the first BiDi event of a method ([#22891](https://github.com/appium/appium/issues/22891)) ([77945dd](https://github.com/appium/appium/commit/77945ddaf10665f9457f6bdc94f9103a631f5ca4))
* **base-driver:** track and remove BiDi subscriptions by ID ([#22895](https://github.com/appium/appium/issues/22895)) ([6241300](https://github.com/appium/appium/commit/62413002a83e70b14eb0a3979cd7a054757a0d80))
* **support:** prevent zip extraction through symlink chains ([#23002](https://github.com/appium/appium/issues/23002)) ([#23069](https://github.com/appium/appium/issues/23069)) ([4c753a1](https://github.com/appium/appium/commit/4c753a134d8e172cfec4caec9033fe2a3d884e27))
## [4.0.0-beta.1](https://github.com/appium/appium/compare/appium@4.0.0-beta.0...appium@4.0.0-beta.1) (2026-09-19)
### Bug Fixes
* **deps:** catch up peerDependencies to published beta.0; drop bootstrap_packages ([#22793](https://github.com/appium/appium/issues/22793)) ([b09efc3](https://github.com/appium/appium/commit/b09efc31c6967bbcf2c4314db9d2a0b6454fa8fb))
## [4.0.0-beta.0](https://github.com/appium/appium/compare/appium@3.7.0...appium@4.0.0-beta.0) (2026-09-19)
### ⚠ BREAKING CHANGES
* **base-driver:** align timeouts endpoints closer to W3C standard (#22776)
* users relying on the implicit debug default for console/file logs will now see info-level output unless they explicitly pass --log-level debug.
* **support:** Any script or tool that consumes Appium CLI output (driver/plugin list/install/update, doctor, etc.) and relies on the previous stream layout will need to be updated. Previously, non-JSON human-readable output (info/success/warning messages) was written to STDERR, with STDOUT reserved almost exclusively for --json output. Now that output goes to STDOUT, and only actual errors go to STDERR.
* **support:** Scripts that discarded STDOUT (1&gt;/dev/null) to suppress &quot;chatter&quot; while relying on STDERR for status text will now see that text on STDOUT instead.
* **support:** Scripts that captured STDERR to detect/log informational or success messages will no longer see them there — only genuine errors will appear on STDERR. --json output and error behavior are unaffected: --json continues to write clean JSON to STDOUT only, and errors continue to go to STDERR.
* **support:** @appium/logger&#x27;s Log class changes its default output stream from STDERR to STDOUT for all levels except error, and adds an errorStream/stderrLevel pair of properties. Any code that set .stream on a Log instance expecting it to capture all levels (including error) will now need to also set .errorStream to the same target.
* **base-driver:** @appium/base-driver&#x27;s default export (BaseDriver) and @appium/base-driver&#x27;s basedriver/helpers.js default export are removed; use the named exports instead. The appium/driver.js and driver.d.ts re-exports of the default are removed accordingly.
* **base-driver:** BaseDriver.reset() is removed; it was unused, not part of any protocol route or the Driver interface, and had no callers in this monorepo or any driver package that was checked.
* **base-driver:** BaseDriver&#x27;s constructor is removed in favor of inherited DriverCore construction; opts is no longer a required constructor argument (it now defaults to {}, matching DriverCore).
* **support:** @appium/support&#x27;s fs.glob option shape changed from the glob package&#x27;s GlobOptions to a smaller, @appium/support-owned GlobOptions interface. Supported fields: cwd, withFileTypes, absolute, lazy. Options like nodir/ignore/nocase are no longer supported directly — callers needing directory filtering can pass withFileTypes: true and filter on .isFile()/.isDirectory(); callers needing path exclusion can filter the returned array by pattern.
* **appium:** The --allow-cors CLI flag and allow-cors config file property have been removed. Use --allow-insecure&#x3D;*:cors (or --relaxed-security, optionally overridden with --deny-insecure&#x3D;*:cors) instead.
* **base-driver:** ISessionHandler.createSession (@appium/types) and LegacyCreateSessionArgs — overload and type deleted, single-argument signature only.
* **base-driver:** BaseDriver.createSession and AppiumDriver.createSession — collapsed to the single-argument mplementation; capability validation now checks the one argument directly instead of scanning three positions for the first W3C-shaped value.
* **base-driver:** FakeDriver.createSession (and the base-driver e2e test double) — overrides updated to match.
* **base-driver:** RelaxedCapsPlugin.createSession — this plugin existed specifically to normalize capabilities across the (now-gone) three positions; its hook is simplified to a single caps argument.
* **base-driver:** POST /session wire route (w3c.ts) — payloadParams.optional no longer sends capabilities three times into the command args.
* **base-driver:** BaseDriver.getSession, ISessionHandler.getSession, and the GET /session/:sessionId JSONWP route are gone. Use getAppiumSessionCapabilities to retrieve session capabilities and EventCommands.getLogEvents to retrieve event history instead.
* **base-driver:** The appium:eventTimings capability is removed; it only ever controlled whether getSession&#x27;s response was decorated with event history, which getLogEvents already exposes unconditionally.
* **support:** move npm-related helpers into appium package (#22721)
* **logger:** @appium/logger and @appium/support no longer export a default log — import the named log export instead.
* **logger:** AppiumLogger#errorAndThrow has been removed; use errorWithException instead.
* **logger:** Logger#enableProgress, disableProgress, progressEnabled, enableUnicode, disableUnicode have been removed; they were already permanently disabled no-ops.
* **base-plugin:** Plugin#logger has been removed; use Plugin#log instead.
* **base-plugin:** @appium/base-plugin no longer exports BasePlugin as the default export; use the named BasePlugin export.
* Core.driverData, DriverData, and the driverData parameter on ISessionHandler.createSession/deleteSession are gone. Any driver overriding get driverData() or relying on the umbrella driver passing sibling-session data into createSession/deleteSession needs to migrate off this mechanism.
* FakeDriver no longer supports the uniqueApp capability.
* **support:** npm.installPackage now takes a hasAppiumDependency boolean computed by the caller instead of importing the check itself, avoiding a support -&gt; appium dependency.
* **support:** The env export is removed from @appium/support.
* the minimum supported Node.js engine is set to ^22.22.2 || ^24.15.0 || &gt;&#x3D;26.0.0
* **base-driver:** @appium/base-driver no longer exports statusCodes or getSummaryByCode (the jsonwp-status module was removed).
* **base-driver:** errorFromMJSONWPStatusCode (aliased as errorFromCode) has been removed; use errorFromW3CJsonCode for W3C error-signature mapping.
* **base-driver:** ProtocolError instances no longer have a jsonwpCode property.
* **base-driver:** WebDriverProxy (formerly JWProxy) no longer proxies to or interprets responses from downstream servers speaking the legacy MJSONWP protocol; the ProtocolConverter class, COMMAND_URLS_CONFLICTS, and the downstreamProtocol getter/setter have been removed. Downstream automation servers must speak W3C WebDriver.
* **base-driver:** Responses no longer duplicate element references under the legacy ELEMENT key; only the W3C element-6066-11e4-a52e-4f735466cecf key is present. The MJSONWP_ELEMENT_KEY constant has been removed.
* **base-driver:** determineProtocol has been removed, and drivers can no longer produce the legacy {sessionId, status, value} response shape; all responses are now W3C-shaped regardless of how the client formatted its createSession capabilities.
* **base-driver:** DriverCore#setProtocolMJSONWP() has been removed.
* **base-driver:** The deprecated JWProxy export has been removed; use WebDriverProxy instead. Its source also moved from lib/jsonwp-proxy/proxy.js to lib/wd-proxy/proxy.js.
* **base-driver:** DriverCore#isMjsonwpProtocol() has been removed.
* **support:** The following @appium/support exports have been removed: process (getProcessIds, killProcess), mkdirp, imageUtil (requireSharp, cropBase64Image), mjpeg (MJpegStream), net&#x27;s FTP upload
support (FtpUploadOptions, NotHttpUploadOptions; uploadFile only supports http/https now), util&#x27;s uuidV1/uuidV3/uuidV5/localIp/cancellableDelay/multiResolve, and fs&#x27;s readPackageJsonFrom/findRoot/ F_OK/R_OK/W_OK/X_OK.
* **appium:** The --nodeconfig server argument and the server.nodeconfig config file property no longer exist. Users who need to register with a Selenium Grid should use the Grid 4 relay feature instead (see the Grid guide).
* **base-driver:** TLS-enabled Appium servers no longer negotiate SPDY/HTTP2 (spdy/2, spdy/3, spdy/3.1, h2) via ALPN; connections are now served as plain HTTPS (HTTP/1.1) using Node&#x27;s native https module. Clients relying on SPDY or HTTP/2 multiplexing against Appium&#x27;s TLS listener must switch to HTTP/1.1.
* **appium:** &#x60;npm install -g appium --drivers&#x3D;... --plugins&#x3D;...&#x60; no longer installs extensions automatically. Use &#x60;appium driver/plugin install&#x60; or add extensions to package.json instead.
* require(&#x27;@appium/support&#x27;) no longer works; consumers must import it instead.
* require(&#x27;@appium/base-driver&#x27;) no longer works; drivers extending BaseDriver via require must switch to import.
* require(&#x27;@appium/base-plugin&#x27;) no longer works; plugins extending BasePlugin via require must switch to import.
* require(&#x27;appium&#x27;) no longer works; plugins extending the package via require must switch to import.
* require(&#x27;@appium/fake-plugin&#x27;) no longer works; consumers must import it instead.
* require(&#x27;@appium/fake-driver&#x27;) no longer works; consumers must import it instead.
* require(&#x27;@appium/types&#x27;) no longer works; consumers must import it instead.
* require(&#x27;@appium/logger&#x27;) no longer works; consumers must import it instead.
* require(&#x27;@appium/schema&#x27;) no longer works; consumers must import it instead.
## [3.8.0](https://github.com/appium/appium/compare/appium@3.7.0...appium@3.8.0) (2026-09-24)
### Features
* **appium:** add --app-url-rules server arg to restrict remote app URLs ([#22753](https://github.com/appium/appium/issues/22753)) ([0b104f6](https://github.com/appium/appium/commit/0b104f6bf9b7180b111df40fd6a15b26d649eabd))
* **appium:** remove postinstall autoinstall-extensions script ([#22675](https://github.com/appium/appium/issues/22675)) ([cd0d8f1](https://github.com/appium/appium/commit/cd0d8f14e9d5906ecd1b438038a7f67f74f742fc))
* **appium:** remove Selenium Grid 3 support ([#22677](https://github.com/appium/appium/issues/22677)) ([8fcdcb3](https://github.com/appium/appium/commit/8fcdcb30b07c1ee582256fbef3538d6a3ceea5f2))
* **appium:** replace --allow-cors flag with --allow-insecure&#x3D;*:cors ([#22731](https://github.com/appium/appium/issues/22731)) ([926a0a5](https://github.com/appium/appium/commit/926a0a594935a6cf2e7375eb174eeb15af964f12))
* **appium:** validate extension manifests and extensions.yaml via ajv ([#22732](https://github.com/appium/appium/issues/22732)) ([8840f9f](https://github.com/appium/appium/commit/8840f9f9322b63bc8940c390b8230f1e5306fa62))
* backport diff from master ([#22749](https://github.com/appium/appium/issues/22749)) ([6323df1](https://github.com/appium/appium/commit/6323df1d7354f85cc631508f5cb6a3e35270d4bd))
* **base-driver:** add definitions for all WebDriver BiDi commands ([#22770](https://github.com/appium/appium/issues/22770)) ([ac01aa8](https://github.com/appium/appium/commit/ac01aa83ad73982eea48f856dfc0249b4a26e395))
* **base-driver:** align timeouts endpoints closer to W3C standard ([#22776](https://github.com/appium/appium/issues/22776)) ([93115d1](https://github.com/appium/appium/commit/93115d195773b011306ffb2e6d7d6cc935df0148))
* **base-driver:** remove legacy (M)JSONWP protocol support ([#22681](https://github.com/appium/appium/issues/22681)) ([0b83e77](https://github.com/appium/appium/commit/0b83e77e7a1c24a885d9895a99db30281cf4acea))
* **base-driver:** replace spdy with native https transport ([#22676](https://github.com/appium/appium/issues/22676)) ([ec7de47](https://github.com/appium/appium/commit/ec7de4768fdd8dde9d28db6fc2dfd63be45fd4c6))
* bump minimum supported Node.js engine to ^22.22.2 || ^24.15.0 || &gt;&#x3D;26.0.0 ([#22685](https://github.com/appium/appium/issues/22685)) ([9f4a11e](https://github.com/appium/appium/commit/9f4a11e7190290986d01743557e90e6e44f87638))
* Change the default log level to &#x60;info&#x60; ([#22756](https://github.com/appium/appium/issues/22756)) ([5e644a3](https://github.com/appium/appium/commit/5e644a392fbf11e2ca985408853d7f51aa85be17))
* convert remaining monorepo packages to ESM-only ([#22674](https://github.com/appium/appium/issues/22674)) ([3516e50](https://github.com/appium/appium/commit/3516e50ce6d022f4c0dc539071c593bf2983325f))
* **support:** move env/APPIUM_HOME resolution into appium package ([#22708](https://github.com/appium/appium/issues/22708)) ([8db8e57](https://github.com/appium/appium/commit/8db8e5748e26a7150cacbea09ba3ec52c5ce3fc0))
* **support:** remove deprecated APIs ([#22678](https://github.com/appium/appium/issues/22678)) ([e8ee716](https://github.com/appium/appium/commit/e8ee71685b4c21116e61c88fd8d2f0e39fac2edb))
* **types:** check execute method params against the command signature ([#22754](https://github.com/appium/appium/issues/22754)) ([b25fc20](https://github.com/appium/appium/commit/b25fc20c51a191c33695c1c71fbf129de834b52d))
* **appium:** accept package names for installed extension commands ([#22747](https://github.com/appium/appium/issues/22747)) ([6c911de](https://github.com/appium/appium/commit/6c911debd72cb7fe094d27671d1cf14098ff537a))
### Bug Fixes
* address code review cleanups (plist, env memoize, test reuse) ([#22740](https://github.com/appium/appium/issues/22740)) ([0df8834](https://github.com/appium/appium/commit/0df883463812d57d44a0d6d80e9b88f124361934))
* Address several TODOs ([#22762](https://github.com/appium/appium/issues/22762)) ([d6ef7e3](https://github.com/appium/appium/commit/d6ef7e3f1240f161df622c850aea06637f9d1078))
* adjust deprecated JSONWP/MJSONWP routes ([#22763](https://github.com/appium/appium/issues/22763)) ([b129cbb](https://github.com/appium/appium/commit/b129cbbcd55656ae7f33b80b4b52719eb5179509))
* **appium:** lock the extension manifest while driver/plugin commands run ([#22767](https://github.com/appium/appium/issues/22767)) ([a73644f](https://github.com/appium/appium/commit/a73644fb4f4e7b0363117ac1262d7018094b42ff))
* **base-driver:** clean up aborted session creation ([#22733](https://github.com/appium/appium/issues/22733)) ([33d866e](https://github.com/appium/appium/commit/33d866e57506e1546aa4870dde75f7209be107bc))
* declare dependencies that were only resolving via hoisting ([#22758](https://github.com/appium/appium/issues/22758)) ([bcf1c57](https://github.com/appium/appium/commit/bcf1c579997b8dbb8292b1a77583aeef40b11ba4))
* **support:** route non-error CLI console output to stdout ([#22742](https://github.com/appium/appium/issues/22742)) ([4eb4d7f](https://github.com/appium/appium/commit/4eb4d7f317a685d681b6cf4e25c15b617a8cc7df))
### Code Refactoring
* **base-driver:** remove deprecated getSession command ([#22725](https://github.com/appium/appium/issues/22725)) ([f71d980](https://github.com/appium/appium/commit/f71d980779d23e9a19d33285646fad128eae4917))
* **base-driver:** remove deprecated multi-argument createSession overload ([#22730](https://github.com/appium/appium/issues/22730)) ([db72249](https://github.com/appium/appium/commit/db722498739ae7fe1deef1b98e02d04b455a4f70))
* **base-driver:** replace command mixin with explicit named exports ([#22741](https://github.com/appium/appium/issues/22741)) ([506bfee](https://github.com/appium/appium/commit/506bfeeb9aa15c0dd1f481868d347cb9b0d37f86))
* **base-plugin:** remove deprecated legacy logger and default export ([#22718](https://github.com/appium/appium/issues/22718)) ([62db5f0](https://github.com/appium/appium/commit/62db5f0b20c496b495ce27d490453861ddefb259))
* **logger:** remove default exports and dead logging APIs ([#22719](https://github.com/appium/appium/issues/22719)) ([fe24f52](https://github.com/appium/appium/commit/fe24f527a4412ed86c7b5e5afe0c6e26dc569e6b))
* remove deprecated driverData mechanism ([#22716](https://github.com/appium/appium/issues/22716)) ([ef8a8e1](https://github.com/appium/appium/commit/ef8a8e1934bfdc9699c2b9a7eca3e2201b4b9f93))
* **support:** move npm-related helpers into appium package ([#22721](https://github.com/appium/appium/issues/22721)) ([d82d496](https://github.com/appium/appium/commit/d82d496f9e80d6628abface3b623601a6f9791f9))
* **support:** replace glob package with native node:fs glob ([#22735](https://github.com/appium/appium/issues/22735)) ([add1615](https://github.com/appium/appium/commit/add161560701ac7fb2bc372ddefd9317146fbae8))
* **appium:** do not treat a directory as a CLI argument file ([#22709](https://github.com/appium/appium/issues/22709)) ([6ba6faf](https://github.com/appium/appium/commit/6ba6faf6f533192afbdf9462dbbb3a5c1e5d85c5))
* **appium:** filter prerelease versions in driver update e2e test ([#22794](https://github.com/appium/appium/issues/22794)) ([4e8e334](https://github.com/appium/appium/commit/4e8e334cbc0ae910f521ae7ff7d3ed15f9be0a6a))
* **appium:** match insecure feature prefixes by automationName, case-insensitively ([#22710](https://github.com/appium/appium/issues/22710)) ([6ab17fe](https://github.com/appium/appium/commit/6ab17feb71d74c1f349616f22896faeb256a66ec))
## [3.7.0](https://github.com/appium/appium/compare/appium@3.6.0...appium@3.7.0) (2026-08-24)
+2 -2
View File
@@ -133,7 +133,7 @@ appium plugin uninstall <plugin-name>
## Server Command Line Interface
In order to start sending commands to the Appium server, it must be running on the URL and port
where your client library expects it to listen. [Appium's command-line interface](http://appium.io/docs/en/latest/cli/server/)
where your client library expects it to listen. [Appium's command-line interface](https://appium.io/docs/en/latest/reference/cli/)
is used to launch and configure the server:
```bash
@@ -161,7 +161,7 @@ for the particular driver or whether it supports parallel sessions.
automation, all using the WebDriver model that's already the standard for web automation.
5. You can run your automated tests locally and in a cloud. There are multiple cloud providers that
support various Appium drivers (mostly targeting iOS and Android mobile automation).
6. [Appium Inspector](https://github.com/appium/appium-inspector) can be used to visually inspect
6. [Appium Inspector](https://appium.github.io/appium-inspector/) can be used to visually inspect
the page source of applications across different platforms, facilitating easier test development.
Investing in the [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means you
+22 -1
View File
@@ -61,7 +61,7 @@ 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).
If you are VS Code user, you can easily check out the project using [Runme](https://runme.dev/).
Install dependencies:
```sh
@@ -103,6 +103,27 @@ export APPIUM_WORKSPACE=@appium/base-driver
npm run test:unit -w $APPIUM_WORKSPACE
```
### Code Style
#### JSDoc
Add concise JSDoc to all public class methods and exported functions.
#### Module Ordering
Place exported functions and classes before non-exported functions and classes in each module.
This rule does not apply to constants or variables.
#### Class Member Ordering
When adding or moving class methods, follow these conventions:
- Order methods by visibility: public → protected → private. Methods without an explicit visibility
modifier belong to the public group.
- Place private helper methods at the end of the class.
- Preserve existing order within each visibility group.
- Before finishing, check the ordering of methods you added or moved.
### Documentation
The documentation for this project is [available in the project repository itself](https://github.com/appium/appium/tree/master/packages/appium/docs).
@@ -62,6 +62,33 @@ them in `docs`, and add links to these files in `mkdocs.yml`.
Refer to the [MkDocs documentation](https://www.mkdocs.org/user-guide/writing-your-docs/) for
information on how to organize and structure your documentation.
### Helping LLMs Use Your Documentation
The [`/llms.txt` convention](https://llmstxt.org/) is a Markdown file at the root of a
documentation site, listing its most useful pages so that large language models can navigate the
site without crawling it. Appium's own documentation provides one at
[appium.io/docs/en/latest/llms.txt](https://appium.io/docs/en/latest/llms.txt), and you may want to
do the same for your extension.
MkDocs copies any non-Markdown file in your `docs` directory to the built site as-is, so all you
need to do is write an `llms.txt` and place it alongside your Markdown files. No plugin or build
configuration is required.
The value of this file lies in the parts a crawler could not have worked out on its own, so it is
worth writing by hand rather than generating it from your navigation:
- A short description of what your extension automates, and which platforms it targets
- The handful of things models reliably get wrong about your extension - removed capabilities,
renamed commands, patterns from an older major version that no longer apply
- Links to the pages that matter, with a description of each
Because links in `llms.txt` are read out of context, they must be absolute URLs. If you use Mike
for versioning, point them at your version alias (for example `latest`) rather than at a pinned
version, so that the file does not go stale. Note that a hand-written file can drift as pages are
renamed; Appium validates its own with a
[script](https://github.com/appium/appium/blob/master/packages/appium/docs/scripts/check-llmstxt.js)
that runs in CI, which you are welcome to adapt.
### Building the Docs
At this point, you can use the `appium-docs` CLI tool. Run this tool with no arguments to get the
@@ -80,8 +80,9 @@ The required subfields are:
capability to tell Appium to use *your* driver.
* `platformNames`: this is an array of one or more platform names considered valid for your driver.
When a user sends in the `platformName` capability to start a session, it must be included in
this list for your driver to handle the session. Known platform name strings include: `iOS`,
`tvOS`, `macOS`, `Windows`, `Android`.
this list for your driver to handle the session. These names should generally include the
operating systems your driver is targeting - for example, a driver targeting iOS would include
`iOS`, while a driver targeting the Chrome browser on Windows would include `Windows`.
* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
class which extends Appium's `BaseDriver` (see below).
@@ -229,6 +230,16 @@ async createSession(w3cCaps) {
}
```
!!! warning "Deprecated"
Older drivers may still define `createSession` with up to four parameters, e.g.
`createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData)`. This shape is a holdover from the
retired JSON Wire Protocol, which required desired and required caps as the first two
arguments; only the first W3C-shaped argument was ever used. The `otherDriverData` parameter is
likewise deprecated in favor of [IPC](#send-messages-to-plugins-running-on-the-same-session) for
coordinating with other concurrently-running sessions. New drivers should use the single-argument
form shown above.
You'll want to make sure to call `super.createSession` in order to get the session ID as well as
the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`
locally here would have no effect other than changing what the user sees in the create session
@@ -271,8 +282,8 @@ You handle WebDriver commands by implementing functions in your driver class. Ea
WebDriver Protocol, plus the various Appium extensions, has a corresponding function that you
implement if you want to support that command in your driver. The best way to see which commands
Appium supports and which method you need to implement for each command is to look at Appium's
[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js).
Each route object in this file tells you the command name as well as the parameters you'd expect to
[routes/](https://github.com/appium/appium/tree/master/packages/base-driver/lib/protocol/routes).
Each route object in this directory's files tells you the command name as well as the parameters you'd expect to
receive for that command.
Let's take this block for example:
@@ -313,7 +324,7 @@ Websockets. Implementing handlers for BiDi commands works just the same as imple
for WebDriver classic commands (described in the previous section). You simply define a method on
your driver of the appropriate name, and it will be called when the BiDi command is requested by
the client. To see which specific names you should use for BiDi commands, have a look at
[bidi-commands.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.js)
[bidi-commands.ts](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.ts)
You are not limited to BiDi commands that are defined in the official BiDi specification. If you
wish to define new commands, you may do so; you just need to tell Appium about them! See
@@ -534,7 +545,7 @@ this.proxyCommand = proxy.command.bind(proxy);
Here we are creating a proxy object and assigning some of its methods to `this` under the names
`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget
this step! The `WebDriverProxy` has a variety of other options [which you can check out in the
source code as well.](https://github.com/appium/appium/blob/master/packages/base-driver/lib/wd-proxy/proxy.ts)
source code as well.](https://github.com/appium/appium/blob/master/packages/base-driver/lib/jsonwp-proxy/proxy.ts)
Finally, we need a way to tell Appium when the proxy is active. For your driver it might always
be active, or it might only be active when in a certain context. You can define the logic as an
@@ -714,12 +725,6 @@ A couple notes about this system:
mode!
1. 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.
1. If your driver is written in TypeScript, declare the map `as const satisfies
ExecuteMethodMap<MyDriver>` (with `ExecuteMethodMap` imported from `@appium/types`). The
compiler then checks that each `command` names a method of your driver, and that the
`required`/`optional` params are consistent with that method's signature: the method must not
require a parameter which is listed as `optional` (or not listed at all), and must accept all
of the listed 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
@@ -794,32 +799,50 @@ that multiple simultaneous sessions don't use the same resources:
1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc)
1. Just always use free resources (find a new random port for each session)
1. Have each running instance of your driver publish and subscribe to messages on a shared IPC
channel, so sessions can coordinate directly with one another.
1. Have each driver express what resources it is using, then examine currently-used resources from
other drivers when a new session begins.
The per-session IPC channel described in [Send messages to plugins running on the same
session](#send-messages-to-plugins-running-on-the-same-session) is isolated per session, so it
can't be used for this: it doesn't let you talk to *other* sessions of your driver. Instead,
construct and hold on to your own `AppiumIpc` instance (exported from `appium/driver.js`) at
module scope in your driver's package, for example as a memoized singleton. Since Node.js caches
modules, every instance of your driver loaded within the same Appium server process will share
that one `AppiumIpc` object, and can use it to publish and subscribe to topics across sessions —
the same way the per-session channel works, just not scoped to a single session. See
[xcuitest-driver's `session-claim-handler.ts`](https://github.com/appium/appium-xcuitest-driver/blob/master/lib/session-claim-handler.ts)
for a real example, which uses this technique to detect and resolve conflicting sessions targeting
the same device UDID.
!!! warning "Deprecated"
The `driverData`-based mechanism described below is deprecated. Prefer
[IPC](#send-messages-to-plugins-running-on-the-same-session) for coordinating resources across
concurrently-running sessions instead.
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:
```js
get driverData() {
return {specialPort: 1234, specialFile: /path/to/file}
}
```
Now, when a new session is started on your driver, the `driverData` response from any other
simultaneously running drivers (of the same type) will also be included, as the last parameter of
the deprecated, multi-argument form of the `createSession` method:
```js
async createSession(jwpCaps, reqCaps, w3cCaps, driverData)
```
You can dig into this `driverData` array to see what resources other drivers are using to help
determine which ones you want to use for this particular session.
!!! warning
This only works for sessions running within the same Node.js process (i.e. the same Appium
server). It cannot coordinate sessions running on different Appium server processes; for that,
consider file-based locking or a similar out-of-process mechanism.
Be careful here, since `driverData` is only passed between sessions of a single running Appium
server. There's nothing to stop a user from running multiple Appium servers and requesting your
driver simultaneously on each of them. In this case, you won't be able to ensure independence
of resources via `driverData`, so you might consider using file-based locking mechanisms or
something similar.
!!! warning
Appium also doesn't provide any features for ensuring unrelated drivers don't interfere with
one another, so it's up to the drivers to allow users to specify resource locations or
addresses to avoid clashes.
It's also important to note you will only receive `driverData` for other instances of *your*
driver. So unrelated drivers also running may still be using some system resources. In general
Appium doesn't provide any features for ensuring unrelated drivers don't interfere with one
another, so it's up to the drivers to allow users to specify resource locations or addresses to
avoid clashes.
### Log events to the Appium event timeline
@@ -967,15 +990,10 @@ export type IpcMessage<T> = {
#### IPC Notes
There are some important things to keep in mind when using Appium's IPC feature:
- The `ipcSubscribe` method (and the IPC channel it subscribes to) is only available once
`onIpcInit` has been called, at the end of the `createSession` flow. It cannot be used statically
or in `createSession` hooks
- The channel that `ipcSubscribe` gives you access to is scoped to the current session, and is
shared only with the plugins active in that same session (this is also to prevent drivers/plugins
from accessing or reading data sent on IPC channels in other sessions.) To coordinate across
multiple concurrent sessions of your own driver instead, see [Make itself aware of resources
other concurrent drivers are
using](#make-itself-aware-of-resources-other-concurrent-drivers-are-using).
- IPC is only available once `onIpcInit` has been called, at the end of the `createSession` flow.
It cannot be used statically or in `createSession` hooks
- In sum, IPC is only for use during a session (this is also to prevent drivers/plugins from
accessing or reading data sent on IPC channels in other sessions.)
- The default max size of an IPC message is 1MB. This can be configured by the server-admin by
using the `--max-ipc-data-size` arg (value is a number in bytes).
- If a message exceeds the configured size, any call to `publish` methods will throw, so be
@@ -257,7 +257,7 @@ throw new errors.NoSuchElementError();
### Log messages to the Appium log
You can always use `console.log`, of course, but Appium provides a nice logger for you as
`this.log` (it has `.info`, `.debug`, `.warn`, `.error` methods on it for differing log
`this.logger` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log
levels). If you want to create an Appium logger outside of a plugin context (say in a script or
helper file), you can always construct your own too:
@@ -476,7 +476,7 @@ capability.
You probably don't normally need to update the Appium server object (which is an
[Express](https://expressjs.com/) server having already been
[configured](https://github.com/appium/appium/blob/master/packages/http-server/lib/server.ts)
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.ts)
in a variety of ways). But, for example, you could add new routes to the server to support your
plugin's requirements. To update the server you must implement the `static async updateServer`
method in your class. This method takes three parameters:
@@ -62,7 +62,7 @@ functionality (e.g., the `plugin` or `driver` subcommands).
Note that this file is the _base_ schema; this will become painfully relevant.
This file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
This file is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
especially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files.
It is more straightforward to explain how config files are validated, so we'll start there.
+13 -13
View File
@@ -15,34 +15,34 @@ To learn more about drivers, check out the [Driver Intro](../intro/drivers.md).
These drivers are currently maintained by the Appium team:
### [Chromium](https://github.com/appium/appium-chromium-driver)
### [Chromium](https://appium.github.io/appium-chromium-driver/)
* Target: Desktop and mobile Chromium browsers (Chrome, Microsoft Edge, etc.)
* Target: Desktop Chromium-based browsers (Chrome, Microsoft Edge, etc.)
* Mode: Web
```sh title="Install This Driver"
appium driver install chromium
```
### [Espresso](https://github.com/appium/appium-espresso-driver)
### [Espresso](https://appium.github.io/appium-espresso-driver/)
* Target: Android applications
* Mode: Native
* Target: Android applications (mobile, TV, Wear, XR, Automotive)
* Mode: Native, Hybrid, Web
```sh title="Install This Driver"
appium driver install espresso
```
### [Gecko](https://github.com/appium/appium-geckodriver)
### [Gecko](https://appium.github.io/appium-geckodriver/)
* Target: Desktop and mobile Gecko browsers (Firefox)
* Target: Desktop and mobile Gecko-based browsers (Firefox, etc.)
* Mode: Web
```sh title="Install This Driver"
appium driver install gecko
```
### [Mac2](https://github.com/appium/appium-mac2-driver)
### [Mac2](https://appium.github.io/appium-mac2-driver/)
* Target: macOS applications
* Mode: Native
@@ -51,7 +51,7 @@ appium driver install gecko
appium driver install mac2
```
### [Safari](https://github.com/appium/appium-safari-driver)
### [Safari](https://appium.github.io/appium-safari-driver/)
* Target: Desktop and mobile Safari browsers
* Mode: Web
@@ -60,9 +60,9 @@ appium driver install mac2
appium driver install safari
```
### [UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)
### [UiAutomator2](https://appium.github.io/appium-uiautomator2-driver/)
* Target: Android, Android TV, Android Wear applications
* Target: Android applications (mobile, TV, Wear, XR, Automotive)
* Modes: Native, Hybrid, Web
```sh title="Install This Driver"
@@ -85,7 +85,7 @@ appium driver install windows
### [XCUITest](https://appium.github.io/appium-xcuitest-driver/)
* Target: iOS, iPadOS, tvOS applications
* Target: iOS, iPadOS, tvOS, watchOS applications
* Modes: Native, Hybrid, Web
```sh title="Install This Driver"
@@ -161,7 +161,7 @@ appium driver install --source=npm @itsmeaj/appium-linux-driver
[Windows driver](#windows)
* Target: Windows applications
* Mode: Native
* Mode: Native, Hybrid
* Supported by: Community / Automate The Planet
```sh title="Install This Driver"
+1 -1
View File
@@ -12,7 +12,7 @@ for more specialised automation workflows.
## Official Plugins
These plugins are are currently maintained by the Appium team:
These plugins are currently maintained by the Appium team:
### [Execute Driver](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin)
@@ -104,3 +104,44 @@ Supported by: `@AppiumTestDistribution`
```sh title="Install This Tool"
npm install -g appium-installer
```
### [Optics](https://github.com/mozarkai/optics-framework)
Optics is an open-source test automation framework that uses Appium to drive Android, iOS,
Android TV, Samsung Tizen and LG webOS apps (and Selenium or Playwright for web). Tests are written
as CSV or YAML keyword steps, and the same keywords are available as a Python library, a Robot
Framework library, an HTTP API and an MCP server. Element lookup falls back from XPath to visible
text, OCR and image matching.
Supported by: `@chinmayajha`
```sh title="Install This Tool"
pip install "optics-framework[mobile]"
```
### [XPath to Class Chain](https://github.com/domovou69/xpath-to-class-chain)
XPath to Class Chain is a command-line tool for migrating iOS XPath locators in test code to
`-ios class chain` selectors. It converts the XPaths that have an exact class chain equivalent,
converts with a warning those that only have a close one (such as grouped positions `(//X)[n]`),
and skips the rest with a reason (for example, sibling or parent axes).
Supported by: `@domovou69`
```sh title="Install This Tool"
npm install -g xpath-to-class-chain
```
### [XPath to UiSelector](https://github.com/domovou69/xpath-to-uiselector)
XPath to UiSelector is a command-line tool for migrating Android XPath locators in test code to
`-android uiautomator` selectors. It converts the XPaths that have an exact `UiSelector`
equivalent, converts with a warning those that only have a close one (such as `//A//B`), and skips
the rest with a reason. The strategy call is rewritten together with the string, for example
`AppiumBy.xpath` becomes `AppiumBy.androidUIAutomator`.
Supported by: `@domovou69`
```sh title="Install This Tool"
npm install -g xpath-to-uiselector
```
@@ -52,6 +52,6 @@ After the PR is merged there is no need to use the local plugin/driver deploymen
to switch back to the package managed by NPM. Follow the next steps for that:
- Unlink the installed driver/plugin from the server by running `appium driver uninstall <driver_name>` or
`appium plugin uninstall <driver_name>`.
`appium plugin uninstall <plugin_name>`.
- Delete the local source folder (`rm -rf <full_path_to_plugin_or_driver_folder_with_fetched_sources>`).
- Install the driver or the plugin from NPM. Check the component README in order to find a proper command for that.
+2 -2
View File
@@ -8,14 +8,14 @@ principles, so you could create more performant and efficient test suite executi
## Why Caching Is Necessary
Mobile application bundles could reach hundreds of megabytes is size. This could become a serious
Mobile application bundles could reach hundreds of megabytes in size. This could become a serious
performance issue if a test suite is executed, and it is necessary to fetch/extract the same application
bundle for each test.
## What Is Cached
Caching could be applied to application bundles generated by
[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.js#L107) helper call.
[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.ts#L99) helper call.
Inherited drivers can customize their caching logic by providing own `onPostProcess`
(or both `inDownload` and `onPostProcess`) property definition, but the general
rule of thumb is that we need to cache locally all application bundles need to be downloaded and/or extracted
+1 -1
View File
@@ -24,7 +24,7 @@ to launch. In order to achieve this, Appium defines its own [extension capabilit
## Common Appium Capabilities
According to the WebDriver spec, extension capabilities must include a namespace prefix (signifying
the vendor introducing the capability), and the namespace must end a colon (`:`). Appium's vendor
the vendor introducing the capability), and the namespace must end in a colon (`:`). Appium's vendor
prefix is `appium:`, and so any Appium-specific capabilities must include this prefix. Depending on
your Appium client, the prefix may be added automatically or in conjunction with certain interfaces,
but it is always a good practice to explicitly include it for clarity.
+1 -1
View File
@@ -34,7 +34,7 @@ discovered and loaded by Appium:
- `appium.config.cjs`
- `.appiumrc` (which is considered to be JSON)
Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium`
Further, _if your project uses Node.js,_ you can store the configuration inside an `appiumConfig`
property in your `package.json` and it will be automatically discovered.
### Config File Search
+11 -8
View File
@@ -6,16 +6,17 @@ title: Retrieving Event Timings
---
Appium comes with the ability to retrieve timing information about startup
information and command length. This is an advanced feature; event and
command timings are collected automatically for the duration of a session.
information and command length. This is an advanced feature; the server records
event timings for every session.
The `POST /session/:id/appium/events` response (i.e., the response to
`driver.logs.events` or similar, depending on client) has the following
structure:
The timings can be retrieved at any point during a session via the
`POST /session/:id/appium/events` endpoint (i.e., the response to
`driver.logs.events` or similar, depending on client). The response body is the
event history object itself. This is its structure:
```
{
"<event_type>": [<occurence_timestamp_1>, ...],
"<event_type>": [<occurrence_timestamp_1>, ...],
"commands": [
{
"cmd": "<command_name>",
@@ -27,7 +28,7 @@ structure:
}
```
In other words, the `events` property has 2 kinds of properties of its own:
In other words, the event history object has 2 kinds of properties of its own:
* Properties which are the names of event types
* The `commands` property
@@ -61,7 +62,9 @@ generate various kinds of reports from event timings output:
!!! note
In the past, events were available as a part of `GET /session/:id` response
In the past, when the `appium:eventTimings` capability was set to `true`, the event history
was also returned as an `events` property of the (now deprecated) `GET /session/:id`
response
## Add a custom event
@@ -16,7 +16,7 @@ by client libraries. There are two main strategies for this:
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.
decide how they wish to implement new commands.
This guide is designed to specifically help you understand the "Execute Method" strategy. This
pattern is commonly used in official Appium drivers and other third-party extensions.
@@ -67,7 +67,7 @@ function, but the function itself—the snippet—is always a string and is the
In the world of Appium, we are usually not automating a web browser, which means this command is
not particularly useful. But it *is* useful as a way to encode the name of an arbitrary command and
to provide parameters. For example, the [XCUITest
Driver](https://github.com/appium/appium-xcuitest-driver) has implemented a command that lets a client
Driver](https://appium.github.io/appium-xcuitest-driver/) has implemented a command that lets a client
terminate a running application if you know the ID (the `bundleId`) of the app. The way that the
driver makes this command available is via the Execute Method `mobile: terminateApp`. Instead of
providing a JavaScript function to the "Execute Script" command, the user provides a _known string_
+59
View File
@@ -117,3 +117,62 @@ hub, you'll be able to send all your Appium traffic via the single hub endpoint
And of course, you're able to link up Appium servers and nodes running on different machines in
your network to form a larger grid.
## Using Selenium Grid 3
It is possible to register your Appium server with a local [Selenium Grid 3](https://www.selenium.dev/documentation/legacy/selenium_3/grid_3/)
([setup docs](https://www.selenium.dev/documentation/legacy/grid_3/setting_up_your_own_grid/)) instance by using the
`--nodeconfig` server argument.
```bash
appium server --nodeconfig /path/to/nodeconfig.json --base-path=/wd/hub
```
In the referenced config file you have to define the `browserName`, `version` and `platform`
capabilities and based on these parameters the grid will re-direct your test to the right device.
You will also need to configure your host details and the Selenium Grid details. For a full list of
all parameters and descriptions see
[here](https://www.selenium.dev/documentation/legacy/selenium_3/grid_setup/).
Once you start the Appium server it will register with the grid, and you will see your device on
the grid console page:
`http://**\<grid-ip-address\>**:**\<grid-port\>**/grid/console`
### Example Grid Node Configuration JSON
```json
{
"capabilities":
[
{
"browserName": "<e.g._iPhone5_or_iPad4>",
"version":"<version_of_iOS_e.g._7.1>",
"maxInstances": 1,
"platform":"<platform_e.g._MAC_or_ANDROID>"
}
],
"configuration":
{
"cleanUpCycle":2000,
"timeout":30000,
"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
"url":"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub",
"host": "<host_name_appium_server_or_ip-address_appium_server>",
"port": <appium_port>,
"maxSession": 1,
"register": true,
"registerCycle": 5000,
"hubPort": <grid_port>,
"hubHost": "<Grid_host_name_or_grid_ip-address>",
"hubProtocol": "<Protocol_of_Grid_defaults_to_http>"
}
}
```
If `url`, `host`, and `port` are not given, the config will be auto updated to point to
`localhost:<appium-port>`.
If your Appium server is running on a different machine to your Selenium Grid server, make sure you
use an external name/IP address in your `host` and `url` configuration; `localhost` and `127.0.0.1`
will prevent Selenium Grid from connecting correctly.
@@ -18,8 +18,11 @@ Each rule is an object with a set of predefined properties. The following rule p
supported:
- `pattern`: A valid Javascript RegExp pattern to replace. Must be a valid non-empty pattern.
- `text`: A simple non-empty exact text match to replace. Either this property or the above one must
be provided. `pattern` has priority over `text` if both are provided.
- `text`: A simple non-empty exact text to replace. Either this property or the above one must
be provided. `pattern` has priority over `text` if both are provided. Note that the text is
matched as a whole word: special characters are escaped and word boundaries (`\b`) are added on
the sides where the value begins or ends with a word character. For example, a rule with text
`pass` replaces `pass` in `my pass here`, but does not match inside `password`.
- `flags`: Regular expression flags for the given pattern. Supported flags are the same as for the
standard JavaScript [RegExp constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2).
Note that the `g` (global matching) flag is always enabled.
@@ -25,7 +25,7 @@ appium driver install xcuitest
```
This command will install the latest version of the
[XCUITest Driver](https://github.com/appium/appium-xcuitest-driver). The Extension CLI comes with a variety
[XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/). The Extension CLI comes with a variety
of commands and parameters; see the documentation for that command for all the specifics.
The all-important question when Appium is managing your extensions for you is: where are they installed?
@@ -63,7 +63,7 @@ like any other dependency. Basically, whenever you run Appium, if you have not e
1. Try to determine whether the _current directory_ is inside an `npm` package.
1. If so, it will check whether `appium` is a dependency (dev, prod, or peer) in the project's
`package.json`
1. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will ignore load
1. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will load
drivers and plugins defined in that `package.json` file instead.
This means you are freely able to add Appium drivers and plugins as regular package dependencies or
@@ -31,6 +31,10 @@ installing it only installs the core Appium server, without any drivers.
When it comes to installing Appium 2 drivers, there are several approaches you can take:
* Add the `--drivers` flag when installing Appium, for example:
```bash
npm i -g appium --drivers=xcuitest,uiautomator2
```
* Use the [Appium Extension CLI](../reference/cli/extensions.md), for example:
```bash
appium driver install uiautomator2
@@ -102,10 +106,10 @@ and it is recommended to migrate to the following replacements:
|Appium 1 Package|Replacement in Appium 2|
|--|--|
|iOS Driver|[XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/latest/)|
|UiAutomator Driver|[UiAutomator2](https://github.com/appium/appium-uiautomator2-driver/)|
|iOS Driver|[XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/)|
|UiAutomator Driver|[UiAutomator2](https://appium.github.io/appium-uiautomator2-driver/)|
|`wd` Client|[WebdriverIO Client](https://webdriver.io/)|
|Appium Desktop|[Appium Inspector](https://github.com/appium/appium-inspector)|
|Appium Desktop|[Appium Inspector](https://appium.github.io/appium-inspector/)|
!!! info "Actions Needed"
@@ -148,9 +148,9 @@ Icons are used to indicate endpoint support in either certain drivers, or in the
- :simple-appium:{ .lg } - Appium server
- :material-apple:{ .lg } - [XCUITest driver](https://appium.github.io/appium-xcuitest-driver/latest/)
- :material-android:{ .lg } - [UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver/)
- :material-coffee:{ .lg } - [Espresso driver](https://github.com/appium/appium-espresso-driver)
- :material-apple-finder:{ .lg } - [Mac2 driver](https://github.com/appium/appium-mac2-driver)
- :material-android:{ .lg } - [UiAutomator2 driver](https://appium.github.io/appium-uiautomator2-driver/)
- :material-coffee:{ .lg } - [Espresso driver](https://appium.github.io/appium-espresso-driver/)
- :material-apple-finder:{ .lg } - [Mac2 driver](https://appium.github.io/appium-mac2-driver/)
- :material-microsoft-windows:{ .lg } - [Windows driver](https://github.com/appium/appium-windows-driver)
</div>
@@ -454,9 +454,6 @@ longer accepts, as well as the parameters it continues to accept in Appium 3.
* `POST /session/:sessionId/element/:elementId/value`
* :octicons-x-24: `value`
* :octicons-check-24: `text`
* `POST /session/:sessionId/timeouts`
* :octicons-x-24: `type`, `ms`
* :octicons-check-24: `script`, `pageLoad`, `implicit`
* `POST /session/:sessionId/window`
* :octicons-x-24: `name`
* :octicons-check-24: `handle`
@@ -1,294 +0,0 @@
---
title: Migrating to Appium 4
---
<style>
.md-typeset .grid {
grid-template-columns: repeat(auto-fit,minmax(min(100%,11rem),1fr));
}
</style>
This document is a guide for those who are using Appium 3 and would like to upgrade to Appium 4.
It contains a list of breaking changes, as well as suggestions for handling them.
Appium 4 focuses on modernizing the codebase (Node.js requirements, ESM-only packages, dropping
long-deprecated protocol support and APIs) rather than introducing a large number of new
user-facing features. Most Appium users only need to check the [Node.js version](#node-2222-required)
section below; the remaining breaking changes mostly affect driver and plugin developers, or users
of specific removed flags/endpoints.
## Installation
Appium 4 is currently only available as a beta release, published under the `beta` npm dist-tag.
The installation method otherwise remains the same as for Appium 3. If you want to upgrade, you
can simply install Appium 4 on top of your existing installation:
```bash
# optional: `appium setup reset`
npm install -g appium@beta
```
## Breaking Changes
### Node 22.22+ Required
Appium 3 required Node `^20.19.0 || ^22.12.0 || >=24.0.0`. Appium 4 drops Node 20 support and
bumps the minimum required version to `^22.22.2 || ^24.15.0 || >=26.0.0`.
!!! info "Actions Needed"
Upgrade Node.js to `v22.22.2`/`v24.15.0` or newer
### All Packages Are Now ESM-Only
Every `@appium/*` package (and `appium` itself) is now published as `"type": "module"` with no
CommonJS build. `require()` no longer works for these packages. This affects anyone importing
Appium or a driver/plugin package directly from Node.js code, not just driver/plugin developers.
!!! info "Actions Needed"
Import Appium packages with ESM `import` syntax, or use dynamic `import()` from CommonJS code
### `--nodeconfig` Flag Removed
Support for registering with a legacy Selenium Grid 3 hub has been removed, along with the
`--nodeconfig` server argument and the `server.nodeconfig` config file property.
!!! info "Actions Needed"
If you relied on Grid 3 registration, use the [Selenium Grid 4 relay feature](./grid.md) instead
### `--allow-cors` Flag Removed
CORS is now gated behind the same [insecure feature](./security.md) mechanism used for other
server-level features (e.g. `session_discovery`), instead of its own dedicated flag.
!!! info "Actions Needed"
Replace `--allow-cors` with `--allow-insecure=*:cors` (or enable it via `--relaxed-security`)
### Extension Auto-Install on `npm install` Removed
The `npm install -g appium --drivers=... --plugins=...` postinstall hook that automatically
installed extensions has been removed, since npm postinstall hooks are a supply-chain security
risk and newer npm versions no longer support passing custom arguments to them.
!!! info "Actions Needed"
Use `appium driver install`/`appium plugin install`, or declare extensions in your project's
`package.json`, instead of `--drivers`/`--plugins` install-time arguments
### Default Log Level Changed to `info`
The default `--log-level` changed from `debug` to `info`. Debug-level logging is very verbose and
mostly only useful for troubleshooting.
!!! info "Actions Needed"
Pass `--log-level debug` explicitly if you rely on the previous verbosity
### CLI Output Streams Split
Appium's CLI commands (`driver`/`plugin install|list|update`, `doctor`, etc.) used to write all
non-JSON output to `STDERR`. Human-readable output (`log`/`ok`/`info`/`warn`) now goes to
`STDOUT`; only `error` output still goes to `STDERR`. The main server's log output (Winston-based)
is unaffected, since it already split streams this way.
!!! info "Actions Needed"
If you have scripts that capture Appium CLI output, make sure they read from the correct stream
### TLS Server No Longer Negotiates SPDY/HTTP2
Appium's TLS-enabled server used the unmaintained `spdy` package, which allowed negotiating
SPDY/HTTP2 over ALPN. It has been replaced with Node's native `https` module, which only serves
plain HTTPS (HTTP/1.1).
!!! info "Actions Needed"
Clients relying on SPDY or HTTP/2 multiplexing against Appium's TLS listener must switch to
plain HTTPS (HTTP/1.1)
### Timeout Errors Now Return HTTP 500
Per the W3C WebDriver standard, `TimeoutError` and `ScriptTimeoutError` now map to HTTP `500`
instead of `408`. The stale `408` mapping could cause keep-alive clients/proxies to auto-retry an
already-executed timed-out command.
!!! info "Actions Needed"
None, unless your code inspects the raw HTTP status code of a timeout response
### Timeouts Endpoint Aligned With W3C Standard
`GET/SET /timeouts` is now closer to [the W3C standard](https://w3c.github.io/webdriver/#timeouts):
* `POST /session/:sessionId/timeouts` now also accepts the standard `command` parameter; the
legacy `type`/`ms` parameters are deprecated
* `POST /session/:sessionId/timeouts` no longer errors out when none of `script`/`pageLoad`/`implicit`
are provided
* `GET /session/:sessionId/timeouts` now also returns `script` and `pageLoad`, in addition to the
existing `implicit` and Appium-specific `command` values
* Driver-level `timeouts()`/`ISessionHandler` type declarations narrow `implicit` to a `number`,
matching `script`/`pageLoad` (the wire endpoint still coerces numeric strings at runtime)
!!! info "Actions Needed"
Update any code that sends the `type`/`ms` timeout parameters or a `string` value for `implicit`
### BiDi Commands No Longer Accept Stray `sessionId`/`id` Params
Unlike HTTP endpoints, WebDriver BiDi commands have no URL-derived session/element id, so a stray
`sessionId` or `id` key inside BiDi command params is no longer silently accepted; it is now
validated like any other unknown parameter.
!!! info "Actions Needed"
Remove `sessionId`/`id` from the parameters of any custom BiDi command invocation
## Endpoint Changes
The following endpoints have been removed:
* `GET/POST /session/:sessionId/ime/*` (all IME endpoints, legacy JSONWP)
* `GET /session/:sessionId/location`, `POST /session/:sessionId/location` (legacy geolocation, legacy JSONWP)
* `GET /session/:sessionId/network_connection`, `POST /session/:sessionId/network_connection` (legacy MJSONWP)
* `POST /session/:sessionId/receive_async_response` (legacy JSONWP)
* `GET /session/:sessionId/element/:elementId` (undocumented legacy JSONWP stub)
* `GET /session/:sessionId` (deprecated `getSession`; see [below](#getsession-command-removed) for
its replacement)
The `orientation`, `context`/`contexts`, and `rotation` deprecated endpoints are unaffected and
remain available.
## Changes for Driver and Plugin Developers
The following changes primarily affect authors of Appium drivers, plugins, or tools that import
Appium's internal packages directly (`@appium/base-driver`, `@appium/base-plugin`,
`@appium/support`, `@appium/logger`). They do not affect most Appium end users.
### Remaining Legacy (M)JSONWP Support Removed From `@appium/base-driver`
Beyond the removed endpoints above, the internal machinery that translated between the legacy
(M)JSONWP protocol and W3C WebDriver has been removed:
* `ProtocolError` instances no longer carry a `jsonwpCode` property, and error responses no longer
include a legacy numeric `status` code (`errorFromMJSONWPStatusCode`, aliased as `errorFromCode`,
has been removed; use `errorFromW3CJsonCode`)
* Responses no longer duplicate element references under the legacy `ELEMENT` key; only the W3C
`element-6066-11e4-a52e-4f735466cecf` key is present
* `WebDriverProxy` (formerly `JWProxy`, now removed as a name) no longer converts responses from a
downstream automation server speaking legacy MJSONWP; downstream servers must speak W3C WebDriver
* `determineProtocol`, `DriverCore#setProtocolMJSONWP()`, and `DriverCore#isMjsonwpProtocol()` have
been removed; drivers can no longer produce the legacy `{sessionId, status, value}` response shape
* `@appium/base-driver` no longer exports `statusCodes`/`getSummaryByCode` (the `jsonwp-status`
module was removed)
!!! info "Actions Needed"
Ensure any downstream automation server a driver proxies to (via `WebDriverProxy`) speaks pure
W3C WebDriver; update code referencing the removed exports to their W3C equivalents
### `@appium/base-driver` Default Export Removed
`BaseDriver` is no longer exported as `@appium/base-driver`'s default export, and
`basedriver/helpers.js`'s default export has been removed as well. `BaseDriver`'s constructor no
longer takes command-mixin machinery into account, and the unused `BaseDriver.reset()` method has
been removed.
!!! info "Actions Needed"
Replace `import BaseDriver from '@appium/base-driver'` with `import {BaseDriver} from '@appium/base-driver'`
### `@appium/base-plugin` Default Export and Legacy Logger Removed
`BasePlugin` is no longer the default export of `@appium/base-plugin`. `Plugin#logger` has been
removed in favor of `Plugin#log`, and `Plugin#name`/`Plugin#cliArgs` are now read-only.
!!! info "Actions Needed"
* Replace `import BasePlugin from '@appium/base-plugin'` with `import {BasePlugin} from '@appium/base-plugin'`
* Replace `this.logger` with `this.log` in plugin code
### `@appium/logger` Default Export and Dead APIs Removed
`@appium/logger` and `@appium/support` no longer export a default `log`. `AppiumLogger#errorAndThrow`
has been removed in favor of `errorWithException`. The long-disabled, no-op progress/unicode
methods (`enableProgress`, `disableProgress`, `progressEnabled`, `enableUnicode`, `disableUnicode`)
have also been removed.
!!! info "Actions Needed"
* Import the named `log` export instead of the default export
* Replace `errorAndThrow` calls with `errorWithException`
### `driverData` Mechanism Removed
The deprecated `driverData` mechanism (`Core.driverData`, the `driverData` parameter on
`createSession`/`deleteSession`, and the `DriverData` type) has been removed, superseded by
`IAppiumIpc`.
!!! info "Actions Needed"
Drivers overriding `get driverData()` or relying on it for cross-session coordination need to
migrate to `IAppiumIpc`
### `createSession` Multi-Argument Overload Removed
`createSession` no longer accepts the legacy multi-argument form
(`createSession(jwpCaps, reqCaps, w3cCaps)`), a holdover from JSONWP. Only the single
`w3cCapabilities` argument is supported now.
!!! info "Actions Needed"
Update any driver or plugin overriding `createSession` to use the single-argument signature
### `getSession` Command Removed
`BaseDriver.getSession` and `ISessionHandler.getSession` have been removed (see [Endpoint
Changes](#endpoint-changes) for the removed route), along with the `appium:eventTimings`
capability that controlled whether its response included event history.
!!! info "Actions Needed"
Use `GET /session/:sessionId/appium/capabilities` to retrieve session capabilities, and
`POST /session/:sessionId/appium/events` to retrieve event history (now returned unconditionally)
### `@appium/support` Deprecated APIs Removed
The following `@appium/support` exports have been removed: `process` (`getProcessIds`,
`killProcess`), `mkdirp`, `imageUtil` (`requireSharp`, `cropBase64Image`), `mjpeg` (`MJpegStream`),
`net`'s FTP upload support, `util`'s `uuidV1`/`uuidV3`/`uuidV5`/`localIp`/`cancellableDelay`/`multiResolve`,
`fs`'s `readPackageJsonFrom`/`findRoot`/`F_OK`/`R_OK`/`W_OK`/`X_OK`, `npm`/`NPM` (moved into the
`appium` package), and `env` (moved into the `appium` package). `node.requirePackage()` and
`system.macOsxVersion()` have also been removed. `fs.glob()` is now backed by Node's native
`fs.promises.glob` instead of the `glob` package, with a narrower `GlobOptions` shape.
!!! info "Actions Needed"
None for typical drivers/plugins, which don't use these low-level helpers directly. If you do,
switch to the suggested replacement or a native Node.js API
### Legacy Test Pages Removed From `@appium/base-driver`
The built-in test fixture routes (`/welcome`, `/test/guinea-pig*`, `/produce_error`, `/crash`),
the `STATIC_DIR` export, and the `APPIUM_ENABLE_LEGACY_TEST_PAGES` environment variable have been
removed.
!!! info "Actions Needed"
Driver test suites that relied on these fixtures should host their own local test server
## New Features
* [`--app-url-rules`](./security.md#restricting-remote-app-urls) lets server operators restrict
which hosts/IPs an `appium:app` URL is allowed to be downloaded from (allow/deny lists, HTTPS-only,
credentials, redirect limits)
* Definitions for all current [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) commands are
now included for introspection/validation purposes
* `ExecuteMethodMap` type declarations now check `params` against the target method's signature at
compile time, catching mismatched required/optional execute method parameters in driver code
* Extension manifests and `extensions.yaml` are now validated with `ajv`/JSON Schema; a corrupted
`extensions.yaml` now resets to an empty manifest with a warning instead of crashing later with a
confusing error
* `appium driver`/`appium plugin` CLI commands now lock the extension manifest while running,
preventing concurrent processes from silently clobbering each other's changes
-115
View File
@@ -85,118 +85,3 @@ Turn on multiple insecure features for specific drivers:
```bash
appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs
```
## Restricting Remote App URLs
Several drivers accept a URL instead of a local path in capabilities such as `appium:app`, in which
case the Appium server downloads the application package from that URL before starting the session.
By default, any `http:` or `https:` URL is accepted. Server hosts who want to control which URLs
their server is allowed to download from can do so with the `--app-url-rules` argument (or the
`server.app-url-rules` property in a [configuration file](./config.md)). Its value is a JSON object
(or a path to a JSON file) with any of the following properties:
|<div style="width:10em">Rule</div>|Description|Default|
|----------------------------------|-----------|-------|
|`allow`|List of hostname patterns, IP addresses, or CIDR subnets. If non-empty, a hostname or its resolved address must match _at least one_|`[]`|
|`deny`|List of hostname patterns, IP addresses, or CIDR subnets. A matching hostname or resolved address is rejected, even if an `allow` rule also matches|`[]`|
|`httpsOnly`|Only accept `https:` URLs|`false`|
|`allowCredentials`|Accept URLs containing a username and/or password (e.g. `https://user:pass@host/app.apk`)|`true`|
|`maxRedirects`|Maximum number of HTTP redirects to follow while downloading. Set to `0` to reject any redirect|`21`|
Hostnames are normalized (lowercased, converted to Punycode, trailing dot removed) before matching
and resolved on every download. Address rules apply to literal addresses and all dynamically
resolved IPv4/IPv6 addresses. The rules are also applied to every redirect, so redirects cannot be
used to escape them. If a URL violates any rule, the session is not created and a generic error
is returned. The violated rule is deliberately neither reported to the client nor written to the
server log, since server logs are often handed over to clients as well. URL schemes, ports, paths,
queries, and fragments are not matched.
Hostname patterns use the [picomatch](https://github.com/micromatch/picomatch#globbing-features)
glob syntax and are matched against the whole hostname:
|Pattern|Matches|
|-------|-------|
|`artifacts.example.com`|Exactly this hostname|
|`*.example.com`|Any subdomain of `example.com` (including nested ones, like `a.b.example.com`), but not `example.com` itself|
|`*example.com`|Any hostname ending with `example.com`, including `example.com` itself|
|`apps.{staging,prod}.example.com`|`apps.staging.example.com` and `apps.prod.example.com`|
|`build-?.example.com`|`build-1.example.com`, `build-a.example.com`, etc.|
|`node[0-9].example.com`|`node0.example.com` to `node9.example.com`|
IP address rules match a single address (`192.0.2.10`, `2001:db8::1`) or a whole subnet in CIDR
notation (`10.0.0.0/8`, `2001:db8::/32`). IPv4 rules also match IPv4-mapped IPv6 addresses
(e.g. `::ffff:10.1.2.3`).
!!! note
These rules only apply to URLs the server downloads via the standard app configuration helper,
which is used for `appium:app` and similar capabilities by all official drivers. Drivers may
define custom capabilities with URLs that are processed differently and thus are not covered.
!!! note
If the server downloads applications through an HTTP proxy (configured via the `HTTP_PROXY`,
`HTTPS_PROXY` and `NO_PROXY` environment variables), the proxy resolves the destination host
itself, so rules containing IP addresses or subnets cannot be enforced for proxied downloads.
Such downloads are rejected; either exclude the download hosts from proxying via `NO_PROXY`
or only use hostname-based rules.
### Examples
Only allow HTTPS downloads from an internal artifact server, without credentials in the URL and
without following redirects:
```bash
appium --app-url-rules='{"allow": ["artifacts.example.com", "10.0.0.0/8"], "httpsOnly": true, "allowCredentials": false, "maxRedirects": 0}'
```
The same configuration as part of a config file:
```yaml
server:
app-url-rules:
allow:
- 'artifacts.example.com'
- '10.0.0.0/8'
httpsOnly: true
allowCredentials: false
maxRedirects: 0
```
Allow downloads from any subdomain of `example.com` and from two IPv6 subnets, except from the
staging environment:
```yaml
server:
app-url-rules:
allow:
- '*.example.com'
- '2001:db8:1::/48'
- '2001:db8:2::/48'
deny:
- '*.staging.example.com'
```
Allow downloads from anywhere, except from the server itself, private networks, link-local
addresses (such as cloud metadata services), and any `.internal` hostname:
```yaml
server:
app-url-rules:
deny:
- 'localhost'
- '*.internal'
- '127.0.0.0/8'
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '169.254.0.0/16'
- '::1/128'
- 'fc00::/7'
- 'fe80::/10'
```
The rules in the last example are applied to the addresses each hostname resolves to, so they
cannot be bypassed via DNS. Note that the `deny` list also blocks any download from the server's
own private network, so a private artifact server must be excluded from the `deny` rules in order
to work.
+7 -6
View File
@@ -2,7 +2,7 @@
hide:
- toc
title: SSL/TLS Support
title: SSL/TLS/SPDY Support
---
Appium 2.2 introduces the option to start the Appium server with SSL/TLS support.
@@ -19,14 +19,15 @@ Both arguments must be provided and should contain paths to a valid
[X509 PEM](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/)
certificate and its corresponding private key.
After the server is started use the `https` protocol and a client supporting SSL/TLS to
communicate to it.
After the server is started use the `https` protocol and a client supporting SSL/TLS or
[SPDY](https://en.wikipedia.org/wiki/SPDY) to communicate to it.
### Supported Features
Once a secure server socket is established it uses Node.js' native
[`https`](https://nodejs.org/api/https.html) module to serve connections. All insecure client
connections will be rejected by the server.
Once a secure server socket is established it supports the following protocols:
`['h2', 'spdy/3.1', 'spdy/3', 'spdy/2', 'http/1.1', 'http/1.0']`. See
[the SPDY node module documentation](https://www.npmjs.com/package/spdy) to get more details about
its features. All insecure client connections will be rejected by the server.
### Self-Signed Certificates
+1 -1
View File
@@ -99,7 +99,7 @@ a driver does this by relying on platform-specific automation technologies. For
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](https://github.com/appium/appium-xcuitest-driver) because ultimately what it does is
Driver](https://appium.github.io/appium-xcuitest-driver/) because ultimately what it does is
convert the WebDriver protocol to XCUITest library calls.
One of the reasons that drivers are independent, pluggable modules is that they work completely
-10
View File
@@ -39,16 +39,6 @@ So, for example, the `Find Element` command corresponds to an HTTP `POST` reques
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`).
If the client disconnects before Appium finishes sending a `Create Session` response and the
request has no `X-Idempotency-Key`, Appium deletes the new session once driver setup completes.
Setup is not interrupted. With an accepted idempotency key, a retry that arrives before setup
finishes waits for the same session ID, or the same error if setup failed. If the original client
and all waiting retries disconnect before setup finishes, Appium deletes the new session and
discards its cached result; a later retry starts a new session. Otherwise, Appium keeps the session
and caches its response for replay while it remains in the bounded, in-memory idempotency cache.
Disconnecting after a response was sent, or during a command in an existing session, does not
automatically end that session. Use `Delete Session` when you are done.
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
+5 -5
View File
@@ -19,7 +19,7 @@ Appium, called `BaseDriver`. You could have something very close to a "working"
very simple lines of code:
```js
import {BaseDriver} from '@appium/base-driver'
import BaseDriver from '@appium/base-driver'
class MyNewDriver extends BaseDriver {
}
@@ -49,8 +49,8 @@ async setUrl(url) {
[^1]: You might notice that `setUrl` doesn't look anything like `Navigate To`, so how did we know
to use it rather than some other random string? Well, Appium's WebDriver-protocol-to-method-name
mapping is defined in a special file within the `@appium/base-driver` package called
[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js).
mappings are defined in special files within the `@appium/base-driver` package's
[routes/](https://github.com/appium/appium/tree/master/packages/base-driver/lib/protocol/routes) directory.
So if you're writing a driver, this is where you would go to figure out what method names to use
and what parameters to expect. Or you could look at the source for any of the main Appium
drivers!
@@ -81,7 +81,7 @@ from there is up to you, the driver author!
## Automation mapping
But *typically* what driver authors want to do is to provide automation behaviours for a given
platform(s) that are semantically very similar to the the WebDriver spec implementations for
platform(s) that are semantically very similar to the WebDriver spec implementations for
browsers. When you want to find an element, you should get a reference to a UI element. When you
want to click or tap that element, the resulting behaviour should be the same as if a person were
to click or tap on the element. And so on.
@@ -175,7 +175,7 @@ be passed back directly to the client, without any XCUITest driver code seeing i
This architectural pattern provides a nice bonus for driver authors who choose to deal with the
WebDriver protocol everywhere, rather than constructing bespoke protocols. It also means that
Appium can create wrapper drivers for any other existing WebDriver implementation very easily. If
you look at the [Appium Safari driver](https://github.com/appium/appium-safari-driver) code, for
you look at the [Appium Safari driver](https://appium.github.io/appium-safari-driver/) code, for
example, you'll see that it implements basically no standard commands, because all of these are
proxied directly to an underlying SafariDriver process.
+142
View File
@@ -0,0 +1,142 @@
# Appium
> Appium is an open-source framework for UI automation of many app platforms - mobile (iOS, Android, Tizen), browser (Chrome, Firefox, Safari), desktop (macOS, Windows), TV (Roku, tvOS, Android TV, Samsung) and more - driven over the W3C WebDriver protocol.
Appium is split into four parts: the Appium server, which defines the core APIs; drivers, which
implement connectivity to a specific platform; clients, which implement Appium's API in a specific
programming language; and plugins, which change or extend the server's behaviour. To automate
anything you need the server, at least one driver, and a client.
Notes for tools generating Appium code from this documentation:
- Appium 3 is the current major version, and these pages describe Appium 3. Appium 2 is still
supported but is documented separately, under its own version of this site, reachable from the
version selector. Appium 1 is no longer supported: `DesiredCapabilities`, `MobileBy`, the
`findElementByAccessibilityId` family of methods, and the `/wd/hub` server base path are all
Appium 1 era patterns - the default base path has been `/` since Appium 2.
- Drivers are not bundled with the server. Install them explicitly, for example
`appium driver install uiautomator2` or `appium driver install xcuitest`.
- Appium 3 requires Node.js in the range `^20.19.0 || ^22.12.0 || >=24.0.0`, and npm 10 or newer.
- Standard W3C capabilities are written without a prefix. `platformName`, `browserName` and
`browserVersion` are the ones used most often with Appium, and the rest of the specification's
set - `acceptInsecureCerts`, `pageLoadStrategy`, `timeouts`, `webSocketUrl` and so on - is also
accepted, mostly by the browser drivers. Every Appium-specific capability needs the `appium:`
vendor prefix - `appium:automationName`, `appium:app`, `appium:udid` - or must be nested,
unprefixed, inside an `appium:options` object.
- Capabilities cannot be changed once a session has started. Parameters that are adjustable during
a session are exposed through the Settings API instead.
- Driver-specific commands are usually Execute Methods rather than new client methods: call the
standard `Execute Script` command with a known command name such as `mobile: terminateApp`, and
pass a *single* object whose keys are the parameter names. Do not invent client-side method names
for these.
- Beyond the small common set documented here, capabilities, execute methods, settings and locator
strategies are defined by each driver and documented on that driver's own site. Refer users to
the driver's documentation rather than guessing names.
- Appium 3 removed many endpoints that were deprecated in Appium 2. Check the Appium 3 migration
guide before using an endpoint carried over from older code.
- `GET /sessions` was removed. Session discovery is now `GET /appium/sessions`, and requires
starting the server with `--allow-insecure=*:session_discovery`.
- In Appium 3, every `--allow-insecure` feature name must carry a scope prefix: either a driver
name (`uiautomator2:adb_shell`) or the wildcard (`*:adb_shell`).
- WebDriver BiDi support is opt-in per session, via the standard `webSocketUrl` capability.
- Contexts model the difference between native and webview modes. `Get Contexts` always returns at
least one context, conventionally named `NATIVE_APP`.
## Getting started
- [Appium Documentation](https://appium.io/docs/en/latest/): documentation home for the Appium server and its ecosystem.
- [Appium in a Nutshell](https://appium.io/docs/en/latest/intro/): how the server, drivers, clients and plugins fit together, and what you need to install.
- [How Does Appium Work?](https://appium.io/docs/en/latest/intro/appium/): the goals and architecture of the Appium project.
- [Intro to Appium Drivers](https://appium.io/docs/en/latest/intro/drivers/): what a driver is, and how Appium supports unrelated platforms through them.
- [Intro to Appium Clients](https://appium.io/docs/en/latest/intro/clients/): Appium's client-server architecture and its relationship to the W3C WebDriver specification.
- [Getting Started](https://appium.io/docs/en/latest/quickstart/): the quickstart path - install Appium, install a driver, install a client, run a first script.
- [System Requirements](https://appium.io/docs/en/latest/quickstart/requirements/): supported operating systems and the required Node.js and npm versions.
- [Install Appium](https://appium.io/docs/en/latest/quickstart/install/): installing the Appium server with npm.
- [Install the UiAutomator2 Driver](https://appium.io/docs/en/latest/quickstart/uiauto2-driver/): installing an Android driver and its Android SDK prerequisites.
- [Write a Test (JS)](https://appium.io/docs/en/latest/quickstart/test-js/): a first Appium script in JavaScript with WebdriverIO.
- [Write a Test (Python)](https://appium.io/docs/en/latest/quickstart/test-py/): a first Appium script in Python.
- [Write a Test (Java)](https://appium.io/docs/en/latest/quickstart/test-java/): a first Appium script in Java.
- [Write a Test (Ruby)](https://appium.io/docs/en/latest/quickstart/test-rb/): a first Appium script in Ruby.
- [Write a Test (.NET)](https://appium.io/docs/en/latest/quickstart/test-dotnet/): a first Appium script in C#.
- [Next Steps](https://appium.io/docs/en/latest/quickstart/next-steps/): where to go after the quickstart.
## Drivers, clients and plugins
Which driver you install determines which platform you can automate, and the driver's own
documentation is the authoritative source for its capabilities and commands.
- [The Appium Ecosystem](https://appium.io/docs/en/latest/ecosystem/): index of officially-supported and community-supported Appium projects.
- [Appium Drivers](https://appium.io/docs/en/latest/ecosystem/drivers/): every known driver with its install command and documentation link. Official drivers include UiAutomator2 and Espresso (Android), XCUITest (iOS, iPadOS, tvOS, watchOS), Mac2 (macOS), Windows, Chromium, Gecko and Safari.
- [Appium Clients](https://appium.io/docs/en/latest/ecosystem/clients/): official clients for Java, Python, Ruby and .NET, plus community clients including WebdriverIO, Nightwatch.js, Robot Framework, Rust and Swift.
- [Appium Plugins](https://appium.io/docs/en/latest/ecosystem/plugins/): optional extensions that modify or extend server behaviour. Not required for standard automation.
- [Appium-Related Tools](https://appium.io/docs/en/latest/ecosystem/tools/): tools for installation, test development and inspection, such as Appium Inspector, and tools for driving Appium from an AI agent, such as the Appium MCP server and the Appium agent skills.
- [Managing Drivers and Plugins](https://appium.io/docs/en/latest/guides/managing-exts/): installing, listing, updating and removing extensions, and installing from sources other than the official index.
## Sessions and capabilities
- [Session Capabilities](https://appium.io/docs/en/latest/guides/caps/): how capabilities work, the `appium:` vendor prefix, `appium:options` grouping, BiDi opt-in via `webSocketUrl`, and always-match versus first-match.
- [Session Properties](https://appium.io/docs/en/latest/reference/session/): the key properties of a session - capabilities, execute methods, settings and locator strategies - and which are defined by the server versus the driver.
- [Capabilities](https://appium.io/docs/en/latest/reference/session/caps/): the full list of capabilities recognized by the Appium server and base driver, and therefore supported by every driver.
- [Session Settings](https://appium.io/docs/en/latest/guides/settings/): parameters that, unlike capabilities, can be adjusted while a session is running.
- [Execute Methods](https://appium.io/docs/en/latest/guides/execute-methods/): the `mobile:` command convention that drivers use to expose commands beyond the WebDriver spec, with examples in every official client language.
- [Managing Contexts](https://appium.io/docs/en/latest/guides/context/): switching between native and webview modes with the Get Contexts, Get Current Context and Set Context commands.
- [Caching of Application Bundles](https://appium.io/docs/en/latest/guides/caching/): how the base driver caches application builds, and how to use it for faster suite execution.
- [Retrieving Event Timings](https://appium.io/docs/en/latest/guides/event-timing/): startup and command timing information, retrieved from the `POST /session/:sessionId/appium/events` endpoint. The `appium:eventTimings` capability described on that page is not required for the endpoint to work, and is being removed in Appium 4.
## Server configuration and the command line
- [Command Line Interface](https://appium.io/docs/en/latest/reference/cli/): the `appium` executable and its `server`, `driver`, `plugin` and `setup` subcommands.
- [appium server](https://appium.io/docs/en/latest/reference/cli/server/): the complete set of server command-line arguments.
- [appium driver/plugin](https://appium.io/docs/en/latest/reference/cli/extensions/): the extension management subcommands - `install`, `list`, `update`, `uninstall`, `run` and `doctor`.
- [appium setup](https://appium.io/docs/en/latest/reference/cli/setup/): installing a preset bundle of extensions for mobile, browser or desktop automation.
- [Environment Variables](https://appium.io/docs/en/latest/reference/cli/env-vars/): advanced behaviour toggled through the environment rather than CLI arguments.
- [The Appium Config File](https://appium.io/docs/en/latest/guides/config/): supplying server arguments through a config file instead of the command line. CLI arguments take precedence.
- [Filtering the Appium Log](https://appium.io/docs/en/latest/guides/log-filters/): redacting passwords, device identifiers and other sensitive values from server logs with `--log-filters`.
- [Header Handling](https://appium.io/docs/en/latest/guides/headers/): request ID tracking through the `x-request-id` header.
- [SSL/TLS/SPDY Support](https://appium.io/docs/en/latest/guides/tls/): starting the server with secure connections enabled.
- [Appium and Selenium Grid](https://appium.io/docs/en/latest/guides/grid/): relaying commands from a Selenium Grid to an Appium server.
## Security
- [Appium Server Security](https://appium.io/docs/en/latest/guides/security/): the insecure-feature mechanism, and the `--allow-insecure`, `--deny-insecure` and `--relaxed-security` flags. In Appium 3 every feature name requires a scope prefix.
- [Insecure Features](https://appium.io/docs/en/latest/reference/cli/insecure-features/): the features defined at the server and official-plugin level, including `session_discovery` and `execute_driver_script`. Drivers define their own in their own documentation.
## API endpoints
- [Reference](https://appium.io/docs/en/latest/reference/): index of the core interfaces supported by the Appium server.
- [API Endpoints](https://appium.io/docs/en/latest/reference/api/): endpoints exposed by the base driver, and therefore inherited by every driver.
- [WebDriver Protocol](https://appium.io/docs/en/latest/reference/api/webdriver/): the W3C WebDriver endpoints Appium supports.
- [WebDriver BiDi Protocol](https://appium.io/docs/en/latest/reference/api/bidi/): the W3C WebDriver BiDi commands Appium supports. These are commands over a WebSocket, not URL endpoints, and require the `webSocketUrl` capability.
- [Appium Protocol](https://appium.io/docs/en/latest/reference/api/appium/): endpoints defined by Appium's own extension of the WebDriver protocol.
- [Plugin Endpoints](https://appium.io/docs/en/latest/reference/api/plugins/): endpoints added or modified by the official plugins.
- [Other Protocols](https://appium.io/docs/en/latest/reference/api/others/): additional supported endpoints, including the Chromedriver protocol extension.
## Migrating between major versions
- [Migrating to Appium 3](https://appium.io/docs/en/latest/guides/migrating-2-to-3/): every breaking change from Appium 2 to 3 - the Node 20 minimum, removed and modified endpoints, the mandatory `--allow-insecure` scope prefix, and the move from `GET /sessions` to `GET /appium/sessions`.
- [Migrating to Appium 2](https://appium.io/docs/en/latest/guides/migrating-1-to-2/): the Appium 1 to 2 changes, including drivers becoming separately installed extensions and the default base path changing from `/wd/hub` to `/`.
## Building drivers and plugins
- [Developing Appium Extensions](https://appium.io/docs/en/latest/developing/): overview of building your own driver or plugin against Appium's modular structure.
- [Building Drivers](https://appium.io/docs/en/latest/developing/build-drivers/): writing a driver, including command definitions, capability constraints and execute methods.
- [Building Plugins](https://appium.io/docs/en/latest/developing/build-plugins/): writing a plugin that modifies or extends server behaviour.
- [Building Doctor Checks](https://appium.io/docs/en/latest/developing/build-doctor-checks/): shipping preconditions checks that `appium driver doctor` can run for your extension.
- [Building Documentation](https://appium.io/docs/en/latest/developing/build-docs/): using `@appium/docutils` to build an MkDocs site for your extension.
- [Masking Sensitive Log Data](https://appium.io/docs/en/latest/developing/sensitive/): marking values as sensitive so they are redacted from extension logs.
- [Appium's Config System](https://appium.io/docs/en/latest/developing/config-system/): how the schema-driven config file and CLI argument system works internally.
- [Local Validation Of Extension PRs](https://appium.io/docs/en/latest/guides/branch-testing/): installing a driver or plugin from an unmerged branch to test it locally.
## Contributing
- [Contributing to Appium](https://appium.io/docs/en/latest/contributing/): how to contribute code, documentation, maintenance and support to the project.
## Optional
- [Appium Blog](https://appium.io/docs/en/latest/blog/): release announcements and project news.
- [Additional Resources](https://appium.io/docs/en/latest/resources/): third-party courses, books, talks and tutorials.
- [Appium Project History](https://appium.io/docs/en/latest/intro/history/): how the project evolved since 2012, of interest mostly for background.
- [Sponsors & Backers](https://appium.io/docs/en/latest/sponsors/): the project's sponsorship program.
- [Source repository](https://github.com/appium/appium): the Appium server implementation.
- [JSON Wire Protocol](https://appium.io/docs/en/latest/reference/api/jsonwp/): legacy pre-W3C protocol, listed for historical reference. Do not base new code on it.
- [Mobile JSON Wire Protocol](https://appium.io/docs/en/latest/reference/api/mjsonwp/): legacy pre-W3C mobile protocol extension, listed for historical reference. Do not base new code on it.
+1 -1
View File
@@ -13,7 +13,7 @@ The basic plan for this quickstart is as follows:
1. Install Appium
1. Install an Appium driver and its dependencies
- This guide provides instructions for the [UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver)
- This guide provides instructions for the [UiAutomator2 driver](https://appium.github.io/appium-uiautomator2-driver/)
1. Install an Appium client library in your language of choice
- This guide contains options for JavaScript, Python, Java, Ruby, and .NET
1. Write and run a simple Appium automation script using a sample application
@@ -14,7 +14,7 @@ reference materials especially for beginners:
- [Capabilities](../guides/caps.md)
- [Settings](../guides/settings.md)
You'll also find that the [Appium Inspector](https://github.com/appium/appium-inspector) is an
You'll also find that the [Appium Inspector](https://appium.github.io/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.
@@ -39,7 +39,7 @@ The `appium_lib_core` is the main part as an Appium client.
`appium_lib_core` does not have such a global variable.
This example is by the `appium_lib_core` with `test-unit` gem module.
Tes code in `appium_lib` should be similar.
Test code in `appium_lib` should be similar.
```ruby title="test.rb"
--8<-- "./sample-code/quickstarts/rb/test.rb"
@@ -12,7 +12,7 @@ interface that allows Appium to automate a particular platform.
(whereas the iOS driver, for example, requires you to be using macOS).
The driver we're going to use is called the [UiAutomator2
Driver](https://github.com/appium/appium-uiautomator2-driver). It's worth visiting that driver's
Driver](https://appium.github.io/appium-uiautomator2-driver/). It's worth visiting that driver's
documentation and bookmarking it, because it will be an invaluable reference down the line.
## Set up Android automation requirements
@@ -105,7 +105,7 @@ 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).
(only if running macOS), and [Espresso](https://appium.github.io/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).
@@ -89,7 +89,7 @@ Retrieves the URL endpoints and WebDriver BiDi commands supported in the current
#### Response
`ListCommandsResponse` - an object containing all supported endpoints and BiDi commands, grouped by
their origin (base Appium, driver-specific, or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)
their origin (base Appium, driver-specific, or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command-maps.ts)
for a detailed structure of this object.
### listExtensions
@@ -103,7 +103,7 @@ Retrieves the [execute methods](../../guides/execute-methods.md) supported in th
#### Response
`ListExtensionsResponse` - an object containing all supported execute methods, grouped by their
origin (driver-specific or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)
origin (driver-specific or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command-maps.ts)
for a detailed structure of this object.
### getCurrentAppiumContext
+10 -5
View File
@@ -46,7 +46,7 @@ Subscribes to one or more BiDi events.
#### Response
`null`
`{subscription: string}` — a unique subscription ID that can be passed to `session.unsubscribe`.
### bidiUnsubscribe
@@ -56,15 +56,20 @@ session.unsubscribe
> WebDriver BiDi documentation: [session.unsubscribe](https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe)
Unsubscribes from one or more BiDi events.
Unsubscribes using either previously returned subscription IDs or event names.
Removing a subscription ID preserves any overlapping subscriptions.
#### Parameters
|Name|Description|Type|Default|
|--|--|--|--|
|`contexts?`|Contexts in which to unsubscribe from the specified events. By default, the global scope is applied.|string[]|`['']`|
|`events`|Names of events to unsubscribe from|string[]||
|`subscriptions?`|Non-empty list of subscription IDs returned by `session.subscribe`. Cannot be combined with `events` or `contexts`.|string[]||
|`contexts?`|Non-standard, only together with `events`: contexts in which to unsubscribe from the specified events. By default, the global scope is applied.|string[]|`['']`|
|`events?`|Non-empty list of event names to unsubscribe from. Required when `subscriptions` is omitted.|string[]||
All subscription IDs must be known to the current session. An unknown ID causes an `invalid argument`
error without removing any subscriptions. Subscription IDs are cleared when the session is deleted.
#### Response
`null`
`{}`
@@ -10,6 +10,125 @@ title: JSON Wire Protocol
The following is a list of legacy [JSON Wire Protocol (JSONWP)](https://www.selenium.dev/documentation/legacy/json_wire_protocol/)
endpoints supported in Appium.
### getSession
```
GET /session/:sessionId
```
> JSONWP documentation: [/session/:sessionId](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionid)
Retrieves the capabilities of the current session.
Appium implements a modified version of this endpoint. If the `appium:eventTimings` capability is
set to `true`, the returned result will additionally include the `events` key, whose value contains
the event history and timings.
!!! warning "Deprecated"
For retrieving capabilities, please use [`getAppiumSessionCapabilities`](./appium.md#getappiumsessioncapabilities).<br />
For retrieving event history, please use [`getLogEvents`](./appium.md#getlogevents).
#### Response
`Capabilities` - an object containing the session capabilities, and the event history (if applicable)
### availableIMEEngines
```
GET /session/:sessionId/ime/available_engines
```
> JSONWP documentation: [/session/:sessionId/ime/available_engines](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeavailable_engines)
Retrieves all IME (input method editor) engines available on the device under test.
!!! warning "Deprecated"
In the future, this endpoint will be moved to the [UiAutomator2 and Espresso drivers](../../ecosystem/drivers.md)
#### Response
`string[]` - a list of available IME engines
### getActiveIMEEngine
```
GET /session/:sessionId/ime/active_engine
```
> JSONWP documentation: [/session/:sessionId/ime/active_engine](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeactive_engine)
Retrieves the name of the active IME engine.
!!! warning "Deprecated"
In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers
#### Response
`string` - the name of the active IME engine
### isIMEActivated
```
GET /session/:sessionId/ime/activated
```
> JSONWP documentation: [/session/:sessionId/ime/activated](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeactivated)
Determines if IME input is available and active.
!!! warning "Deprecated"
In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers
#### Response
`boolean` - `true` if IME is active, otherwise `false`
### deactivateIMEEngine
```
POST /session/:sessionId/ime/deactivate
```
> JSONWP documentation: [/session/:sessionId/ime/deactivate](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimedeactivate)
Deactivates the currently active IME engine.
!!! warning "Deprecated"
In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers
#### Response
`null`
### activateIMEEngine
```
POST /session/:sessionId/ime/activate
```
> JSONWP documentation: [/session/:sessionId/ime/activate](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeactivate)
Activates an IME engine.
!!! warning "Deprecated"
In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers
#### Parameters
|Name|Description|Type|
|--|--|--|
|`engine`|Name of the IME engine to activate|string|
#### Response
`null`
### getOrientation
```
@@ -51,3 +170,53 @@ Sets the orientation of the device under test.
#### Response
`null`
### getGeoLocation
```
GET /session/:sessionId/location
```
> JSONWP documentation: [/session/:sessionId/location](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidlocation)
Retrieves the current location of the device under test.
!!! warning "Deprecated"
Please use driver-specific extension methods such as `mobile: getGeoLocation` or
`mobile: getSimulatedLocation`
#### Response
`Location` - an object with the following properties:
|Name|Description|Type|
|--|--|--|
|`altitude`|Altitude of the device location|number|
|`latitude`|Latitude of the device location|number|
|`longitude`|Longitude of the device location|number|
### setGeoLocation
```
POST /session/:sessionId/location
```
> JSONWP documentation: [/session/:sessionId/location](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidlocation)
Sets the current location of the device under test.
!!! warning "Deprecated"
Please use driver-specific extension methods such as `mobile: setGeoLocation` or
`mobile: setSimulatedLocation`
#### Parameters
|Name|Description|Type|
|--|--|--|
|`location`|New device latitude, longitude and altitude|[`Location`](#response_6)|
#### Response
`null`
@@ -119,3 +119,53 @@ Retrieves all available application contexts.
#### Response
`string[]` - the names of available contexts
### getNetworkConnection
```
GET /session/:sessionId/network_connection
```
> MJSONWP documentation: [Device Modes](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#device-modes)
Retrieves the current state of network types (data, Wi-Fi, airplane mode).
!!! warning "Deprecated"
Please use driver-specific extension methods such as `mobile: getConnectivity`
#### Response
`NetworkConnectionState` - a number indicating the current network state:
|Value|Data|Wi-Fi|Airplane Mode|
|--|--|--|--|
|`0`|OFF|OFF|OFF|
|`1`|OFF|OFF|ON|
|`2`|OFF|ON|OFF|
|`4`|ON|OFF|OFF|
|`6`|ON|ON|OFF|
### setNetworkConnection
```
POST /session/:sessionId/network_connection
```
> MJSONWP documentation: [Device Modes](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#device-modes)
Sets the state of network types (data, Wi-Fi, airplane mode).
!!! warning "Deprecated"
Please use driver-specific extension methods such as `mobile: setConnectivity`
#### Parameters
|<div style="width:6em">Name</div>|Description|<div style="width:18em">Type</div>|
|--|--|--|
|`parameters`|Object containing the `type` key, whose value is the desired network state|`{"type": `[`NetworkConnectionState`](#response_5)`}`|
#### Response
[`NetworkConnectionState`](#response_5) - the new network state
@@ -25,11 +25,18 @@ POST /session
Creates a new WebDriver session.
Appium implements a modified version of this endpoint for historical reasons. While the W3C
endpoint only accepts 1 parameter, Appium's implementation allows up to 3 parameters, as this was
required by the legacy JSON Wire Protocol (JSONWP). Since Appium 2, the JSONWP format is no longer
supported, and any of the 3 parameters can be used to specify the W3C capabilities.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`capabilities?`|Capabilities of the new session|`W3CDriverCaps`|
|`w3cCapabilities1?`|Capabilities of the new session|`W3CDriverCaps`|
|`w3cCapabilities2?`|Another location for the new session capabilities (legacy)|`W3CDriverCaps`|
|`w3cCapabilities?`|Another location for the new session capabilities (legacy)|`W3CDriverCaps`|
#### Response
@@ -84,19 +91,14 @@ GET /session/:sessionId/timeouts
Retrieves the timeout values of the current session.
Appium implements a modified version of this endpoint, by also returning the value of the `command`
timeout for supported drivers and contexts.
#### Response
`GetTimeoutsResult` - an object with the following properties:
|Name|Description|Type|
|--|--|--|
|`script`|Script timeout|number|
|`pageLoad`|Page load timeout|number|
|`command`|Command timeout|number|
|`implicit`|Implicit wait timeout|number|
|`command`|Appium command timeout|number|
### timeouts
@@ -108,17 +110,13 @@ POST /session/:sessionId/timeouts
Sets the timeout values of the current session.
Appium implements a modified version of this endpoint by adding the optional `command` parameter
for supported drivers and contexts.
#### Parameters
|Name|Description|Type|
|--|--|--|
|`script?`|Script timeout (in milliseconds)|number|
|`implicit?`|Implicit wait timeout (in milliseconds)|number|
|`pageLoad?`|Page load timeout (in milliseconds)|number|
|`command?`|Appium command timeout (in milliseconds)|number|
|`script?`|Script timeout (in milliseconds)|number|
#### Response
@@ -81,7 +81,7 @@ appium {driver|plugin} install <install-spec>
|--|--|
|None|The short name of an official extension, with optional modifiers as supported by `npm install` (e.g. version or tag)|
|`git`|The Git URL of the extension|
|`github`|The GitHub repository URL of the extension|
|`github`|The GitHub repository slug of the extension, in the form `<org>/<repo>`|
|`local`|The local path to the extension containing its `package.json` file|
|`npm`|The name of the `npm` package, with optional modifiers as supported by `npm install` (e.g. version or tag)|
@@ -114,7 +114,7 @@ appium {driver|plugin} install <install-spec>
- Install the XCUITest driver from GitHub:
```
appium driver install https://github.com/appium/appium-xcuitest-driver --source=github --package=appium-xcuitest-driver
appium driver install appium/appium-xcuitest-driver --source=github --package=appium-xcuitest-driver
```
- Install the XCUITest driver using a Git URL:
@@ -14,7 +14,6 @@ they can only be enabled using the wildcard (`*`) prefix:
| Feature Name | Description |
|-------------------|-------------------------------------------------------------------------------|
|`session_discovery`|Allows retrieving the list of active server sessions via `GET /appium/sessions`|
|`cors` |Allows web browser connections to the server from any host |
Of course, Appium drivers and plugins are free to define additional insecure features of their own.
@@ -26,12 +26,12 @@ appium
|<div style="width:15em">Argument</div>|Description|Type|<div style="width:7em">Default</div>|
|--|--|--|--|
|`--address`, `-a`|IPv4/IPv6 address to listen on|string|`0.0.0.0`|
|`--address`, `-a`|IPv4/IPv6 address or a hostname to listen on|string|`0.0.0.0`|
|`--allow-cors`|Allow web browser connections from any host|boolean|`false`|
|`--allow-insecure`|List of [insecure features](../../guides/security.md) that should be allowed in this server's sessions. Individual features can be overridden by `--deny-insecure`. Has no effect in combination with `--relaxed-security`.|array<string>|`[]`|
|`--allow-unknown-args`|Do not exit if unrecognized command-line arguments are passed to the server; ignore them instead. Useful when the Appium CLI is wrapped by external tooling that appends extra flags.|boolean|`false`|
|`--app-url-rules`|Rules that remote application URLs (e.g. in the `appium:app` capability) must satisfy before the server downloads them. See the [Restricting Remote App URLs](../../guides/security.md#restricting-remote-app-urls) guide for details. Can be a path to a JSON file or raw JSON.|object||
|`--base-path`, `-pa`|Base path to use as the prefix for all webdriver routes running on the server|string|`""`|
|`--callback-address`, `-ca`|Callback IP address|string|`0.0.0.0`|
|`--callback-address`, `-ca`|Callback IP address|string|same as `--address`|
|`--callback-port`, `-cp`|Callback port|integer|`4723`|
|`--config`|Path to an [Appium configuration JSON file](../../guides/config.md)|string||
|`--debug-log-spacing`|Add exaggerated spacing in logs to help with visual inspection|boolean|`false`|
@@ -44,7 +44,7 @@ appium
|`--local-timezone`|Use local timezone for log timestamps|boolean|`false`|
|`--log`, `-g`|Path to a file where the server logs should be output. This does not affect output on the console.|string||
|`--log-filters`|List of log filtering rules. See the [log filtering guide](../../guides/log-filters.md) for details.|array||
|`--log-level`|The log level for the server logs. Supported values are `debug`, `info`, `warn`, or `error`. Combining two supported values using a colon (e.g. `warn:debug`) allows to set separate log levels for the console and file outputs, respectively.|string|`info`|
|`--log-level`|The log level for the server logs. Supported values are `debug`, `info`, `warn`, or `error`. Combining two supported values using a colon (e.g. `warn:debug`) allows to set separate log levels for the console and file outputs, respectively.|string|`debug`|
|`--log-format`|The log format of the server logs. Supported values are `text`, `json`, or `pretty_json`. Setting the value to `json` disables colors.|string|`text`|
|`--log-no-colors`|Disable colors in the server log|boolean|`false`|
|`--log-timestamp`|Show timestamps in the server log|boolean|`false`|
@@ -52,6 +52,7 @@ appium
|`--max-ipc-data-size`|Maximum byte size of IPC message objects.|integer|`1048576` (1MB)|
|`--max-ipc-topics`|Maximum number of IPC topics per session.|integer|`1000`|
|`--no-perms-check`|Skip various permission checks on the server startup|boolean|`false`|
|`--nodeconfig`|JSON configuration for registering Appium as a node with Selenium Grid 3|object||
|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object||
|`--plugins-import-chunk-size`|Maximum number of plugins that can be imported in parallel on server startup|number|`7`|
|`--port`, `-p`|Port to listen on|integer|`4723`|
@@ -32,8 +32,9 @@ default value.
| <div style="width:19em">Capability</div> | Description | Type | Default |
|--|--|--|--|
| `webSocketUrl` | Toggle support of the WebDriver BiDi protocol | `boolean` ||
| `appium:eventTimings` (deprecated) | Toggle collection of [Event Timings](../../guides/event-timing.md). This capability is deprecated - please use the [`getLogEvents`](../api/appium.md#getlogevents) endpoint instead. | `boolean` ||
| `appium:newCommandTimeout` | Number of seconds the Appium server should wait for clients to send commands before stopping the session. A value of `0` disables the timeout. | `number` | `60` |
| `appium:printPageSourceOnFindFailure` | Toggle retrieval of the the page source and its printing to the Appium log, whenever a request to find an element fails | `boolean` ||
| `appium:printPageSourceOnFindFailure` | Toggle retrieval of the page source and its printing to the Appium log, whenever a request to find an element fails | `boolean` ||
### Validated Capabilities
+22 -1
View File
@@ -62,7 +62,7 @@ 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).
If you are VS Code user, you can easily check out the project using [Runme](https://runme.dev/).
Install dependencies:
@@ -109,6 +109,27 @@ export APPIUM_WORKSPACE=@appium/base-driver
npm run test:unit -w $APPIUM_WORKSPACE
```
### Code Style
#### JSDoc
Add concise JSDoc to all public class methods and exported functions.
#### Module Ordering
Place exported functions and classes before non-exported functions and classes in each module.
This rule does not apply to constants or variables.
#### Class Member Ordering
When adding or moving class methods, follow these conventions:
- Order methods by visibility: public → protected → private. Methods without an explicit visibility
modifier belong to the public group.
- Place private helper methods at the end of the class.
- Preserve existing order within each visibility group.
- Before finishing, check the ordering of methods you added or moved.
### Documentation
The documentation for this project is [available in the project repository itself](https://github.com/appium/appium/tree/master/packages/appium/docs).
@@ -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
@@ -62,6 +62,33 @@ them in `docs`, and add links to these files in `mkdocs.yml`.
Refer to the [MkDocs documentation](https://www.mkdocs.org/user-guide/writing-your-docs/) for
information on how to organize and structure your documentation.
### Helping LLMs Use Your Documentation
The [`/llms.txt` convention](https://llmstxt.org/) is a Markdown file at the root of a
documentation site, listing its most useful pages so that large language models can navigate the
site without crawling it. Appium's own documentation provides one at
[appium.io/docs/en/latest/llms.txt](https://appium.io/docs/en/latest/llms.txt), and you may want to
do the same for your extension.
MkDocs copies any non-Markdown file in your `docs` directory to the built site as-is, so all you
need to do is write an `llms.txt` and place it alongside your Markdown files. No plugin or build
configuration is required.
The value of this file lies in the parts a crawler could not have worked out on its own, so it is
worth writing by hand rather than generating it from your navigation:
- A short description of what your extension automates, and which platforms it targets
- The handful of things models reliably get wrong about your extension - removed capabilities,
renamed commands, patterns from an older major version that no longer apply
- Links to the pages that matter, with a description of each
Because links in `llms.txt` are read out of context, they must be absolute URLs. If you use Mike
for versioning, point them at your version alias (for example `latest`) rather than at a pinned
version, so that the file does not go stale. Note that a hand-written file can drift as pages are
renamed; Appium validates its own with a
[script](https://github.com/appium/appium/blob/master/packages/appium/docs/scripts/check-llmstxt.js)
that runs in CI, which you are welcome to adapt.
### Building the Docs
At this point, you can use the `appium-docs` CLI tool. Run this tool with no arguments to get the
@@ -80,8 +80,9 @@ The required subfields are:
capability to tell Appium to use _your_ driver.
- `platformNames`: this is an array of one or more platform names considered valid for your driver.
When a user sends in the `platformName` capability to start a session, it must be included in
this list for your driver to handle the session. Known platform name strings include: `iOS`,
`tvOS`, `macOS`, `Windows`, `Android`.
this list for your driver to handle the session. These names should generally include the
operating systems your driver is targeting - for example, a driver targeting iOS would include
`iOS`, while a driver targeting the Chrome browser on Windows would include `Windows`.
- `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
class which extends Appium's `BaseDriver` (see below).
@@ -283,8 +284,8 @@ You handle WebDriver commands by implementing functions in your driver class. Ea
WebDriver Protocol, plus the various Appium extensions, has a corresponding function that you
implement if you want to support that command in your driver. The best way to see which commands
Appium supports and which method you need to implement for each command is to look at Appium's
[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js).
Each route object in this file tells you the command name as well as the parameters you'd expect to
[routes/](https://github.com/appium/appium/tree/master/packages/base-driver/lib/protocol/routes).
Each route object in this directory's files tells you the command name as well as the parameters you'd expect to
receive for that command.
Let's take this block for example:
@@ -327,7 +328,7 @@ Websockets. Implementing handlers for BiDi commands works just the same as imple
for WebDriver classic commands (described in the previous section). You simply define a method on
your driver of the appropriate name, and it will be called when the BiDi command is requested by
the client. To see which specific names you should use for BiDi commands, have a look at
[bidi-commands.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.js)
[bidi-commands.ts](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.ts)
You are not limited to BiDi commands that are defined in the official BiDi specification. If you
wish to define new commands, you may do so; you just need to tell Appium about them! See
@@ -482,7 +482,7 @@ capability.
You probably don't normally need to update the Appium server object (which is an
[Express](https://expressjs.com/) server having already been
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.ts)
in a variety of ways). But, for example, you could add new routes to the server to support your
plugin's requirements. To update the server you must implement the `static async updateServer`
method in your class. This method takes three parameters:
@@ -65,7 +65,7 @@ functionality (e.g., the `plugin` or `driver` subcommands).
Note that this file is the _base_ schema; this will become painfully relevant.
```
This file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
This file is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
especially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files.
It is more straightforward to explain how config files are validated, so we'll start there.
+13 -13
View File
@@ -17,34 +17,34 @@ If you maintain an Appium driver that you would like to be listed here, feel fre
These drivers are currently maintained by the Appium team:
### [Chromium](https://github.com/appium/appium-chromium-driver)
### [Chromium](https://appium.github.io/appium-chromium-driver/)
- Target: Desktop and mobile Chromium browsers (Chrome, Microsoft Edge, etc.)
- Target: Desktop Chromium-based browsers (Chrome, Microsoft Edge, etc.)
- Mode: Web
```sh title="Install This Driver"
appium driver install chromium
```
### [Espresso](https://github.com/appium/appium-espresso-driver)
### [Espresso](https://appium.github.io/appium-espresso-driver/)
- Target: Android applications
- Mode: Native
- Target: Android applications (mobile, TV, Wear, XR, Automotive)
- Mode: Native, Hybrid, Web
```sh title="Install This Driver"
appium driver install espresso
```
### [Gecko](https://github.com/appium/appium-geckodriver)
### [Gecko](https://appium.github.io/appium-geckodriver/)
- Target: Desktop and mobile Gecko browsers (Firefox)
- Target: Desktop and mobile Gecko-based browsers (Firefox, etc.)
- Mode: Web
```sh title="Install This Driver"
appium driver install gecko
```
### [Mac2](https://github.com/appium/appium-mac2-driver)
### [Mac2](https://appium.github.io/appium-mac2-driver/)
- Target: macOS applications
- Mode: Native
@@ -53,7 +53,7 @@ appium driver install gecko
appium driver install mac2
```
### [Safari](https://github.com/appium/appium-safari-driver)
### [Safari](https://appium.github.io/appium-safari-driver/)
- Target: Desktop and mobile Safari browsers
- Mode: Web
@@ -62,9 +62,9 @@ appium driver install mac2
appium driver install safari
```
### [UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)
### [UiAutomator2](https://appium.github.io/appium-uiautomator2-driver/)
- Target: Android, Android TV, Android Wear applications
- Target: Android applications (mobile, TV, Wear, XR, Automotive)
- Modes: Native, Hybrid, Web
```sh title="Install This Driver"
@@ -89,7 +89,7 @@ appium driver install windows
### [XCUITest](https://appium.github.io/appium-xcuitest-driver/)
- Target: iOS, iPadOS, tvOS applications
- Target: iOS, iPadOS, tvOS, watchOS applications
- Modes: Native, Hybrid, Web
```sh title="Install This Driver"
@@ -169,7 +169,7 @@ This driver is recommended as a drop-in replacement for the partially unmaintain
```
- Target: Windows applications
- Mode: Native
- Mode: Native, Hybrid
- Supported by: Community / Automate The Planet
```sh title="Install This Driver"
+1 -1
View File
@@ -14,7 +14,7 @@ If you maintain an Appium plugin that you would like to be listed here, feel fre
## Official Plugins
These plugins are are currently maintained by the Appium team:
These plugins are currently maintained by the Appium team:
### [Execute Driver](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin)
@@ -113,3 +113,30 @@ Supported by: `@AppiumTestDistribution`
```sh title="Install This Tool"
npm install -g appium-installer
```
### [Optics](https://github.com/mozarkai/optics-framework)
Optics is an open-source test automation framework that uses Appium to drive Android, iOS,
Android TV, Samsung Tizen and LG webOS apps (and Selenium or Playwright for web). Tests are written
as CSV or YAML keyword steps, and the same keywords are available as a Python library, a Robot
Framework library, an HTTP API and an MCP server. Element lookup falls back from XPath to visible
text, OCR and image matching.
Supported by: `@chinmayajha`
```sh title="Install This Tool"
pip install "optics-framework[mobile]"
```
### [XPath to Class Chain](https://github.com/domovou69/xpath-to-class-chain)
XPath to Class Chain is a command-line tool for migrating iOS XPath locators in test code to
`-ios class chain` selectors. It converts the XPaths that have an exact class chain equivalent,
converts with a warning those that only have a close one (such as grouped positions `(//X)[n]`),
and skips the rest with a reason (for example, sibling or parent axes).
Supported by: `@domovou69`
```sh title="Install This Tool"
npm install -g xpath-to-class-chain
```
@@ -52,6 +52,6 @@ After the PR is merged there is no need to use the local plugin/driver deploymen
to switch back to the package managed by NPM. Follow the next steps for that:
- Unlink the installed driver/plugin from the server by running `appium driver uninstall <driver_name>` or
`appium plugin uninstall <driver_name>`.
`appium plugin uninstall <plugin_name>`.
- Delete the local source folder (`rm -rf <full_path_to_plugin_or_driver_folder_with_fetched_sources>`).
- Install the driver or the plugin from NPM. Check the component README in order to find a proper command for that.
+2 -2
View File
@@ -8,14 +8,14 @@ principles, so you could create more performant and efficient test suite executi
## Why Caching Is Necessary
Mobile application bundles could reach hundreds of megabytes is size. This could become a serious
Mobile application bundles could reach hundreds of megabytes in size. This could become a serious
performance issue if a test suite is executed, and it is necessary to fetch/extract the same application
bundle for each test.
## What Is Cached
Caching could be applied to application bundles generated by
[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.js#L107) helper call.
[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.ts#L99) helper call.
Inherited drivers can customize their caching logic by providing own `onPostProcess`
(or both `inDownload` and `onPostProcess`) property definition, but the general
rule of thumb is that we need to cache locally all application bundles need to be downloaded and/or extracted
+2 -2
View File
@@ -24,7 +24,7 @@ to launch. In order to achieve this, Appium defines its own [extension capabilit
## 一般的なAppiumのCapabilities
According to the WebDriver spec, extension capabilities must include a namespace prefix (signifying
the vendor introducing the capability), and the namespace must end a colon (`:`). Appium's vendor
the vendor introducing the capability), and the namespace must end in a colon (`:`). Appium's vendor
prefix is `appium:`, and so any Appium-specific capabilities must include this prefix. Depending on
your Appium client, the prefix may be added automatically or in conjunction with certain interfaces,
but it is always a good practice to explicitly include it for clarity.
@@ -78,7 +78,7 @@ BiDi commands, so make sure to reference their documentation.
## `appium:options` を使用して機能をグループ化する
テストで `appium:` 機能を多用すると、繰り返しが多くなる可能性があります。 代わりに、すべての機能を単一の `appium:options` 機能のオブジェクト値として組み合わせることもできます。その場合、オブジェクト内の機能にプレフィックスを使用する必要はありません。 例:
テストで `appium:` 機能を多用すると、繰り返しが多くなる可能性があります。代わりに、すべての機能を単一の `appium:options` 機能のオブジェクト値として組み合わせることもできます。その場合、オブジェクト内の機能にプレフィックスを使用する必要はありません。例:
```json
{
+2 -2
View File
@@ -36,7 +36,7 @@ discovered and loaded by Appium:
- `appium.config.cjs`
- `.appiumrc` (which is considered to be JSON)
Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium`
Further, _if your project uses Node.js,_ you can store the configuration inside an `appiumConfig`
property in your `package.json` and it will be automatically discovered.
### Config File Search
@@ -98,5 +98,5 @@ The above configuration corresponds to the `--driver-xcuitest-webkit-debug-proxy
```
All properties are case-sensitive and will be in
[kebab-case](https://en.wikipedia.org/wiki/Naming_convention_\(programming\)#Delimiter-separated_words).
[kebab-case](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Delimiter-separated_words).
For example, `callback-port` is allowed, but `callbackPort` is not.
+11 -10
View File
@@ -6,18 +6,17 @@ title: Retrieving Event Timings
---
Appium comes with the ability to retrieve timing information about startup
information and command length. This is an advanced feature that is controlled
by the use of the `appium:eventTimings` capability (set it to `true` to log event
timings).
information and command length. This is an advanced feature; the server records
event timings for every session.
With this capability turned on, the `POST /session/:id/appium/events` response (i.e.,
the response to `driver.logs.events` or similar, depending on client) will be
decorated with an `events` property. This is the structure of that `events`
property:
The timings can be retrieved at any point during a session via the
`POST /session/:id/appium/events` endpoint (i.e., the response to
`driver.logs.events` or similar, depending on client). The response body is the
event history object itself. This is its structure:
```
{
"<event_type>": [<occurence_timestamp_1>, ...],
"<event_type>": [<occurrence_timestamp_1>, ...],
"commands": [
{
"cmd": "<command_name>",
@@ -29,7 +28,7 @@ property:
}
```
In other words, the `events` property has 2 kinds of properties of its own:
In other words, the event history object has 2 kinds of properties of its own:
- Properties which are the names of event types
- The `commands` property
@@ -64,7 +63,9 @@ generate various kinds of reports from event timings output:
!!! note
```
In the past, events were available as a part of `GET /session/:id` response
In the past, when the `appium:eventTimings` capability was set to `true`, the event history
was also returned as an `events` property of the (now deprecated) `GET /session/:id`
response
```
## Add a custom event
@@ -10,13 +10,13 @@ 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.
decide how they wish to implement new commands.
This guide is designed to specifically help you understand the "Execute Method" strategy. This
pattern is commonly used in official Appium drivers and other third-party extensions.
@@ -134,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.
+1 -1
View File
@@ -137,7 +137,7 @@ all parameters and descriptions see
Once you start the Appium server it will register with the grid, and you will see your device on
the grid console page:
`http://**\<grid-ip-adress\>**:**\<grid-port\>**/grid/console`
`http://**\<grid-ip-address\>**:**\<grid-port\>**/grid/console`
### Example Grid Node Configuration JSON
@@ -18,8 +18,11 @@ Each rule is an object with a set of predefined properties. The following rule p
supported:
- `pattern`: A valid Javascript RegExp pattern to replace. Must be a valid non-empty pattern.
- `text`: A simple non-empty exact text match to replace. Either this property or the above one must
be provided. `pattern` has priority over `text` if both are provided.
- `text`: A simple non-empty exact text to replace. Either this property or the above one must
be provided. `pattern` has priority over `text` if both are provided. Note that the text is
matched as a whole word: special characters are escaped and word boundaries (`\b`) are added on
the sides where the value begins or ends with a word character. For example, a rule with text
`pass` replaces `pass` in `my pass here`, but does not match inside `password`.
- `flags`: Regular expression flags for the given pattern. Supported flags are the same as for the
standard JavaScript [RegExp constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2).
Note that the `g` (global matching) flag is always enabled.
@@ -27,7 +27,7 @@ appium driver install xcuitest
```
This command will install the latest version of the
[XCUITest Driver](https://github.com/appium/appium-xcuitest-driver). The Extension CLI comes with a variety
[XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/). The Extension CLI comes with a variety
of commands and parameters; see the documentation for that command for all the specifics.
The all-important question when Appium is managing your extensions for you is: where are they installed?
@@ -65,7 +65,7 @@ like any other dependency. Basically, whenever you run Appium, if you have not e
1. Try to determine whether the _current directory_ is inside an `npm` package.
2. If so, it will check whether `appium` is a dependency (dev, prod, or peer) in the project's
`package.json`
3. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will ignore load
3. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will load
drivers and plugins defined in that `package.json` file instead.
This means you are freely able to add Appium drivers and plugins as regular package dependencies or
@@ -2,7 +2,7 @@
title: Appium 2 へ移行する
---
このドキュメントは既にAppium 1 を利用している人がAppium 2 に移行するための手引きです。 破壊的変更の一覧や、実行環境・テストコードをAppium 2 互換にするための方法が含まれます。
このドキュメントは既にAppium 1 を利用している人がAppium 2 に移行するための手引きです。破壊的変更の一覧や、実行環境・テストコードをAppium 2 互換にするための方法が含まれます。
Appium 2 is the biggest Appium release in over 5 years. It is _not_ focused on changing the
automation behavior for any particular platform, but instead re-envisions Appium into an
@@ -111,12 +111,12 @@ The Appium 1 ecosystem included several drivers, clients and other packages that
deprecated and replaced with newer packages. Appium 2 no longer includes support for these packages,
and it is recommended to migrate to the following replacements:
| Appium 1 Package | Replacement in Appium 2 |
| ------------------ | -------------------------------------------------------------------------- |
| iOS Driver | [XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/latest/) |
| UiAutomator Driver | [UiAutomator2](https://github.com/appium/appium-uiautomator2-driver/) |
| `wd` Client | [WebdriverIO Client](https://webdriver.io/) |
| Appium Desktop | [Appium Inspector](https://github.com/appium/appium-inspector) |
| Appium 1 Package | Replacement in Appium 2 |
| ------------------ | -------------------------------------------------------------------- |
| iOS Driver | [XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/) |
| UiAutomator Driver | [UiAutomator2](https://appium.github.io/appium-uiautomator2-driver/) |
| `wd` Client | [WebdriverIO Client](https://webdriver.io/) |
| Appium Desktop | [Appium Inspector](https://appium.github.io/appium-inspector/) |
!!! info "Actions Needed"
+196 -200
View File
@@ -8,8 +8,7 @@ title: Appium 3 へ移行する
}
</style>
このドキュメントは既にAppium 2 を利用している人がAppium 3 に移行するための手引きです。
破壊的変更と、それらを処理するためのヒントが含まれています。
このドキュメントは既にAppium 2 を利用している人がAppium 3 に移行するための手引きです。破壊的変更と、それらを処理するためのヒントが含まれています。
Appium 2 はAppiumアーキテクチャ全体の大きな見直しをしました。 Appium 3 は限られた破壊的変更のみの比較的小さな更新であり、移行プロセスがはるかに簡易になります。
@@ -142,293 +141,293 @@ Icons are used to indicate endpoint support in either certain drivers, or in the
- :simple-appium:{ .lg } - Appium server
- :material-apple:{ .lg } - [XCUITest driver](https://appium.github.io/appium-xcuitest-driver/latest/)
- :material-android:{ .lg } - [UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver/)
- :material-coffee:{ .lg } - [Espresso driver](https://github.com/appium/appium-espresso-driver)
- :material-apple-finder:{ .lg } - [Mac2 driver](https://github.com/appium/appium-mac2-driver)
- :material-android:{ .lg } - [UiAutomator2 driver](https://appium.github.io/appium-uiautomator2-driver/)
- :material-coffee:{ .lg } - [Espresso driver](https://appium.github.io/appium-espresso-driver/)
- :material-apple-finder:{ .lg } - [Mac2 driver](https://appium.github.io/appium-mac2-driver/)
- :material-microsoft-windows:{ .lg } - [Windows driver](https://github.com/appium/appium-windows-driver)
</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
@@ -437,22 +436,19 @@ 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`
- `POST /session/:sessionId/timeouts`
- :octicons-x-24: `type`, `ms`
- :octicons-check-24: `script`, `pageLoad`, `implicit`
- :octicons-x-24: `value`
- :octicons-check-24: `text`
- `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
+2 -2
View File
@@ -23,9 +23,9 @@ title: How Does Appium Work?
iOSとAndroidだけでなくより多くのアプリプラットフォームが存在していることを考えると、その背景には別の、より大きな疑問が潜んでいます。
- どのようにして_全ての_プラットフォームに対して自動化を実現するか?
- どのようにし&#x3066;_&#x5168;て&#x306E;_&#x30D7;ラットフォームに対して自動化を実現するか?
これらの疑問へのAppiumの答えを知ることは、Appiumが何かを学ぶ最短の方法ではないかもしれませんが、確かな道になります。 では、見ていきましょう。
これらの疑問へのAppiumの答えを知ることは、Appiumが何かを学ぶ最短の方法ではないかもしれませんが、確かな道になります。では、見ていきましょう。
## Appium's choice of API
+4 -4
View File
@@ -49,8 +49,8 @@ async setUrl(url) {
[^1]: You might notice that `setUrl` doesn't look anything like `Navigate To`, so how did we know
to use it rather than some other random string? Well, Appium's WebDriver-protocol-to-method-name
mapping is defined in a special file within the `@appium/base-driver` package called
[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js).
mappings are defined in special files within the `@appium/base-driver` package's
[routes/](https://github.com/appium/appium/tree/master/packages/base-driver/lib/protocol/routes) directory.
So if you're writing a driver, this is where you would go to figure out what method names to use
and what parameters to expect. Or you could look at the source for any of the main Appium
drivers!
@@ -81,7 +81,7 @@ from there is up to you, the driver author!
## Automation mapping
But _typically_ what driver authors want to do is to provide automation behaviours for a given
platform(s) that are semantically very similar to the the WebDriver spec implementations for
platform(s) that are semantically very similar to the WebDriver spec implementations for
browsers. When you want to find an element, you should get a reference to a UI element. When you
want to click or tap that element, the resulting behaviour should be the same as if a person were
to click or tap on the element. And so on.
@@ -175,7 +175,7 @@ be passed back directly to the client, without any XCUITest driver code seeing i
This architectural pattern provides a nice bonus for driver authors who choose to deal with the
WebDriver protocol everywhere, rather than constructing bespoke protocols. It also means that
Appium can create wrapper drivers for any other existing WebDriver implementation very easily. If
you look at the [Appium Safari driver](https://github.com/appium/appium-safari-driver) code, for
you look at the [Appium Safari driver](https://appium.github.io/appium-safari-driver/) code, for
example, you'll see that it implements basically no standard commands, because all of these are
proxied directly to an underlying SafariDriver process.
+3 -3
View File
@@ -5,19 +5,19 @@ hide:
title: Getting Started
---
さっそくAppiumを使ってみましょう! このクイックスタートをうまく使うために、[はじめに](../intro/index.md)を読み、Appiumの実行やスクリプトの記述に関わる概念を理解することをお勧めします。
さっそくAppiumを使ってみましょう!このクイックスタートをうまく使うために、[はじめに](../intro/index.md)を読み、Appiumの実行やスクリプトの記述に関わる概念を理解することをお勧めします。
このクイックスタートは以下の通り進めます:
1. Appiumをインストールする
2. Appiumドライバーとその依存関係をインストールする
- このガイドでは、[UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver) について説明します
- This guide provides instructions for the [UiAutomator2 driver](https://appium.github.io/appium-uiautomator2-driver/)
3. お好みの言語でAppiumクライアント・ライブラリをインストールする
- このガイドでは、JavaScript、Python、Java、Ruby、.NETの例で説明します
4. サンプルアプリケーションを使用した簡単なAppiumでの自動化スクリプトの作成と実行
### 必要条件
始める前に、お使いのシステムが[要件](../quickstart/requirements.md) を満たしていることを確認してください。 追加要件については、UiAutomator2 ドライバーのインストールと合わせて説明します。 また、このガイドでは基本的なコマンド実行や環境変数の設定と保持などができることを前提としています。
始める前に、お使いのシステムが[要件](../quickstart/requirements.md) を満たしていることを確認してください。追加要件については、UiAutomator2 ドライバーのインストールと合わせて説明します。また、このガイドでは基本的なコマンド実行や環境変数の設定と保持などができることを前提としています。
さあ、これで準備は整いました! [Appiumのインストール](./install.md)に進んでください。
@@ -5,14 +5,16 @@ hide:
title: 次のステップ
---
Android自動化用のシステムの設定と簡単なテストの実行が完了したら、このドキュメントを引き続き参照してください。 特に初心者にとって、これらは優れたガイドと参考資料です:
Android自動化用のシステムの設定と簡単なテストの実行が完了したら、このドキュメントを引き続き参照してください。特に初心者にとって、これらは優れたガイドと参考資料です:
- [エコシステム](../ecosystem/index.md) ページ: 利用可能なドライバー、クライアント、プラグイン、ツールを見る
- [Appium ドライバーとプラグインの管理](../guides/managing-exts.md)
- [Capabilities](../guides/caps.md)
- [Settings](../guides/settings.md)
また、[Appium Inspector](https://github.com/appium/appium-inspector) は、アプリの視覚的な検査を可能にし、テストスクリプトで使用する要素ロケーターを見つけるのに役立つ、Appium テストの作成に不可欠なツールです。
You'll also find that the [Appium Inspector](https://appium.github.io/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 コースもご活用いただけます。
@@ -38,7 +38,7 @@ The `appium_lib_core` is the main part as an Appium client.
`appium_lib_core` does not have such a global variable.
This example is by the `appium_lib_core` with `test-unit` gem module.
Tes code in `appium_lib` should be similar.
Test code in `appium_lib` should be similar.
```ruby title="test.rb"
--8<-- "./sample-code/quickstarts/rb/test.rb"
@@ -109,7 +109,7 @@ 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).
(only if running macOS), and [Espresso](https://appium.github.io/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).
@@ -90,7 +90,7 @@ Retrieves the URL endpoints and WebDriver BiDi commands supported in the current
#### Response
`ListCommandsResponse` - an object containing all supported endpoints and BiDi commands, grouped by
their origin (base Appium, driver-specific, or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)
their origin (base Appium, driver-specific, or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command-maps.ts)
for a detailed structure of this object.
### listExtensions
@@ -104,7 +104,7 @@ Retrieves the [execute methods](../../guides/execute-methods.md) supported in th
#### Response
`ListExtensionsResponse` - an object containing all supported execute methods, grouped by their
origin (driver-specific or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)
origin (driver-specific or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command-maps.ts)
for a detailed structure of this object.
### getCurrentAppiumContext
+12 -7
View File
@@ -47,7 +47,7 @@ Subscribes to one or more BiDi events.
#### Response
`null`
`{subscription: string}` — a unique subscription ID that can be passed to `session.unsubscribe`.
### bidiUnsubscribe
@@ -57,15 +57,20 @@ session.unsubscribe
> WebDriver BiDi documentation: [session.unsubscribe](https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe)
Unsubscribes from one or more BiDi events.
Unsubscribes using either previously returned subscription IDs or event names.
Removing a subscription ID preserves any overlapping subscriptions.
#### Parameters
| Name | Description | Type | Default |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | ------- |
| `contexts?` | Contexts in which to unsubscribe from the specified events. By default, the global scope is applied. | string[] | `['']` |
| `events` | Names of events to unsubscribe from | string[] | |
| Name | Description | Type | Default |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------- |
| `subscriptions?` | Non-empty list of subscription IDs returned by `session.subscribe`. Cannot be combined with `events` or `contexts`. | string[] | |
| `contexts?` | Non-standard, only together with `events`: contexts in which to unsubscribe from the specified events. By default, the global scope is applied. | string[] | `['']` |
| `events?` | Non-empty list of event names to unsubscribe from. Required when `subscriptions` is omitted. | string[] | |
All subscription IDs must be known to the current session. An unknown ID causes an `invalid argument`
error without removing any subscriptions. Subscription IDs are cleared when the session is deleted.
#### Response
`null`
`{}`
@@ -82,7 +82,7 @@ appium {driver|plugin} install <install-spec>
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| None | The short name of an official extension, with optional modifiers as supported by `npm install` (e.g. version or tag) |
| `git` | The Git URL of the extension |
| `github` | The GitHub repository URL of the extension |
| `github` | The GitHub repository slug of the extension, in the form `<org>/<repo>` |
| `local` | The local path to the extension containing its `package.json` file |
| `npm` | The name of the `npm` package, with optional modifiers as supported by `npm install` (e.g. version or tag) |
@@ -115,7 +115,7 @@ appium {driver|plugin} install <install-spec>
- Install the XCUITest driver from GitHub:
```
appium driver install https://github.com/appium/appium-xcuitest-driver --source=github --package=appium-xcuitest-driver
appium driver install appium/appium-xcuitest-driver --source=github --package=appium-xcuitest-driver
```
- Install the XCUITest driver using a Git URL:
@@ -26,12 +26,12 @@ appium
| <div style="width:15em">Argument</div> | Description | Type | <div style="width:7em">Default</div> |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -------------------------------------------------------- |
| `--address`, `-a` | IPv4/IPv6 address to listen on | string | `0.0.0.0` |
| `--address`, `-a` | IPv4/IPv6 address or a hostname to listen on | string | `0.0.0.0` |
| `--allow-cors` | Allow web browser connections from any host | boolean | `false` |
| `--allow-insecure` | List of [insecure features](../../guides/security.md) that should be allowed in this server's sessions. Individual features can be overridden by `--deny-insecure`. Has no effect in combination with `--relaxed-security`. | array<string> | `[]` |
| `--allow-unknown-args` | Do not exit if unrecognized command-line arguments are passed to the server; ignore them instead. Useful when the Appium CLI is wrapped by external tooling that appends extra flags. | boolean | `false` |
| `--base-path`, `-pa` | Base path to use as the prefix for all webdriver routes running on the server | string | `""` |
| `--callback-address`, `-ca` | Callback IP address | string | `0.0.0.0` |
| `--callback-address`, `-ca` | Callback IP address | string | same as `--address` |
| `--callback-port`, `-cp` | Callback port | integer | `4723` |
| `--config` | Path to an [Appium configuration JSON file](../../guides/config.md) | string | |
| `--debug-log-spacing` | Add exaggerated spacing in logs to help with visual inspection | boolean | `false` |
@@ -34,7 +34,7 @@ default value.
| `webSocketUrl` | Toggle support of the WebDriver BiDi protocol | `boolean` | |
| `appium:eventTimings` (deprecated) | Toggle collection of [Event Timings](../../guides/event-timing.md). This capability is deprecated - please use the [`getLogEvents`](../api/appium.md#getlogevents) endpoint instead. | `boolean` | |
| `appium:newCommandTimeout` | Number of seconds the Appium server should wait for clients to send commands before stopping the session. A value of `0` disables the timeout. | `number` | `60` |
| `appium:printPageSourceOnFindFailure` | Toggle retrieval of the the page source and its printing to the Appium log, whenever a request to find an element fails | `boolean` | |
| `appium:printPageSourceOnFindFailure` | Toggle retrieval of the page source and its printing to the Appium log, whenever a request to find an element fails | `boolean` | |
### Validated Capabilities
-1
View File
@@ -57,7 +57,6 @@ nav:
- reference/api/plugins.md
- Guides:
- Migration:
- guides/migrating-3-to-4.md
- guides/migrating-2-to-3.md
- guides/migrating-1-to-2.md
- Server/Driver Configuration:
+17 -12
View File
@@ -10,16 +10,18 @@
/* eslint-disable promise/prefer-await-to-callbacks */
/* eslint-disable promise/prefer-await-to-then */
import {readFileSync} from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import {deploy, buildSite} from '@appium/docutils';
import semver from 'semver';
import {log, LANGS, DOCS_DIR, DOCS_BRANCH, DOCS_PREFIX, DOCS_REMOTE, LATEST_ALIAS} from './utils.js';
const {version} = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
const {
log,
LANGS,
DOCS_DIR,
DOCS_BRANCH,
DOCS_PREFIX,
DOCS_REMOTE,
LATEST_ALIAS,
} = require('./utils');
const path = require('node:path');
const semver = require('semver');
const {version} = require('../../package.json');
const branch = process.env.APPIUM_DOCS_BRANCH ?? DOCS_BRANCH;
const basePrefix = process.env.APPIUM_DOCS_PREFIX ?? DOCS_PREFIX;
@@ -32,6 +34,9 @@ const push = Boolean(process.env.APPIUM_DOCS_PUBLISH);
* Builds and optionally deploys docs for each supported language.
*/
async function main() {
// @appium/docutils is ESM-only; this file is CommonJS, so it must be loaded dynamically
const {deploy, buildSite} = await import('@appium/docutils');
log.info(`Building Appium docs and committing to ${DOCS_BRANCH}`);
const semVersion = semver.parse(version);
@@ -64,10 +69,10 @@ async function main() {
}
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
if (require.main === module) {
main().catch((err) => {
throw err;
});
}
export default main;
module.exports = main;
@@ -0,0 +1,176 @@
/**
* Validates `docs/en/llms.txt` against the documentation sources.
*
* `llms.txt` is hand-written, so nothing regenerates it when a page is added, renamed or removed.
* This check fails the build when it points at a page that no longer exists, and when a page has
* been added without being listed.
*
* For simplicity this file is not transpiled and is run directly via an npm script.
* @module
*/
// @ts-check
/* eslint-disable no-console */
const fs = require('node:fs/promises');
const path = require('node:path');
const DOCS_EN_DIR = path.resolve(__dirname, '..', 'en');
const LLMS_TXT_PATH = path.join(DOCS_EN_DIR, 'llms.txt');
/**
* Base URL that every link to our own documentation must use. `llms.txt` is served from a versioned
* directory but is consumed out of context, so the links inside it have to be absolute, and they
* have to point at the `latest` alias rather than at a pinned version.
*/
const SITE_BASE_URL = 'https://appium.io/docs/en/latest';
/**
* Pages that are deliberately absent from `llms.txt`, and should not be warned about.
*/
const UNLISTED_PAGES = [
// individual blog posts; the blog index is listed instead
/^blog\/posts\//,
];
/**
* Extracts the target of every Markdown link in `contents`.
* @param {string} contents
* @returns {string[]}
*/
function extractLinks(contents) {
return [...contents.matchAll(/\[[^\]]+\]\(([^)\s]+)\)/g)].map(([, url]) => url);
}
/**
* Maps a documentation URL back to the source files that could have produced it.
*
* MkDocs builds directory URLs by default, so `guides/caps.md` is served at `guides/caps/`, and
* `intro/index.md` is served at `intro/`. Both spellings are accepted here.
*
* @param {string} url an URL underneath {@linkcode SITE_BASE_URL}
* @returns {string[]} candidate paths, relative to the `en` docs dir
*/
function candidateSourcePaths(url) {
const withoutBase = url.slice(SITE_BASE_URL.length);
const pagePath = withoutBase.replace(/#.*$/, '').replace(/^\//, '').replace(/\/$/, '');
if (!pagePath) {
return ['index.md'];
}
return [`${pagePath}.md`, path.posix.join(pagePath, 'index.md')];
}
/**
* Finds every Markdown page in the English docs, as paths relative to the `en` docs dir.
* @returns {Promise<string[]>}
*/
async function findAllPages() {
const entries = await fs.readdir(DOCS_EN_DIR, {recursive: true});
return entries
.map((entry) => entry.split(path.sep).join(path.posix.sep))
.filter((entry) => entry.endsWith('.md'))
.sort();
}
/**
* Checks that every documentation link in `llms.txt` resolves to a source file.
* @param {string[]} links
* @returns {Promise<string[]>} error messages
*/
async function findBrokenLinks(links) {
const errors = [];
for (const link of links) {
const isOurDocs = link.includes('appium.io/docs/') || link.startsWith('/docs/');
// relative and site-relative links do not survive being read out of context, and a link to our
// docs that is not under the `latest` alias goes stale as soon as a new version is released
const isAbsolute = /^[a-z][a-z\d+.-]*:/i.test(link);
if ((!isAbsolute || isOurDocs) && !link.startsWith(SITE_BASE_URL)) {
errors.push(`${link}\n must be an absolute link under ${SITE_BASE_URL}`);
continue;
}
if (!link.startsWith(SITE_BASE_URL)) {
// external link; not ours to validate
continue;
}
const candidates = candidateSourcePaths(link);
const found = await Promise.all(
candidates.map(async (candidate) => {
try {
await fs.access(path.join(DOCS_EN_DIR, candidate));
return true;
} catch {
return false;
}
})
);
if (!found.includes(true)) {
errors.push(`${link}\n no such page (looked for ${candidates.join(' and ')})`);
}
}
return errors;
}
/**
* Finds pages that exist but are not linked from `llms.txt`.
* @param {string[]} links
* @param {string[]} pages
* @returns {string[]}
*/
function findUnlistedPages(links, pages) {
const linked = new Set(
links
.filter((link) => link.startsWith(SITE_BASE_URL))
.flatMap((link) => candidateSourcePaths(link))
);
return pages.filter(
(page) => !linked.has(page) && !UNLISTED_PAGES.some((pattern) => pattern.test(page))
);
}
/**
* Validates `llms.txt`. Both broken links and unlisted pages fail the build.
*/
async function main() {
const contents = await fs.readFile(LLMS_TXT_PATH, 'utf-8');
const links = extractLinks(contents);
const pages = await findAllPages();
const brokenLinks = await findBrokenLinks(links);
const unlistedPages = findUnlistedPages(links, pages);
if (unlistedPages.length) {
console.error(
`\nERROR: ${unlistedPages.length} page(s) are not listed in llms.txt. Add them, or add ` +
`them to UNLISTED_PAGES in this script if they are intentionally omitted:`
);
for (const page of unlistedPages) {
console.error(` - ${page}`);
}
}
if (brokenLinks.length) {
console.error(`\nERROR: ${brokenLinks.length} link(s) in llms.txt do not resolve:`);
for (const error of brokenLinks) {
console.error(` - ${error}`);
}
}
if (brokenLinks.length || unlistedPages.length) {
throw new Error(
`llms.txt has ${brokenLinks.length} broken link(s) and is missing ` +
`${unlistedPages.length} page(s)`
);
}
console.log(`\nllms.txt is valid: ${links.length} link(s) checked, ${pages.length} page(s) found`);
}
if (require.main === module) {
main().catch((err) => {
console.error(err.message);
process.exitCode = 1;
});
}
module.exports = main;
@@ -3,14 +3,11 @@
/* eslint-disable promise/prefer-await-to-callbacks */
/* eslint-disable promise/prefer-await-to-then */
import {realpathSync} from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
const path = require('node:path');
const {fs} = require('@appium/support');
const {AppiumConfigJsonSchema} = require('@appium/schema');
import {AppiumConfigJsonSchema} from '@appium/schema';
import {fs} from '@appium/support';
const DOC_PATH = path.resolve(import.meta.dirname, '..', 'en', 'cli', 'args.md');
const DOC_PATH = path.resolve(__dirname, '..', 'en', 'cli', 'args.md');
const START_TAG = `<!-- AUTOGEN-START -->`;
const STOP_TAG = `<!-- AUTOGEN-STOP -->`;
@@ -92,10 +89,10 @@ async function writeNewDoc(preStart, argTable, postEnd) {
await fs.writeFile(DOC_PATH, newContents);
}
if (process.argv[1] && fileURLToPath(import.meta.url) === realpathSync(process.argv[1])) {
if (require.main === module) {
main().catch((err) => {
throw err;
});
}
export default main;
module.exports = main;
+14 -5
View File
@@ -2,19 +2,28 @@
// for simplicity this file is not transpiled and is run directly via an npm script
//
import path from 'node:path';
import {logger} from '@appium/support';
const {logger} = require('@appium/support');
const path = require('node:path');
const log = logger.getLogger('Docs');
const DOCS_REMOTE = 'origin';
const DOCS_BRANCH = 'gh-pages';
const DOCS_PREFIX = 'docs';
const DOCS_DIR = path.resolve(import.meta.dirname, '..');
const DOCS_DIR = path.resolve(__dirname, '..');
const LATEST_ALIAS = 'latest';
const ASSETS_DIR = path.join(DOCS_DIR, 'assets');
const LANGS = ['en', 'ja', 'zh'];
const DEFAULT_LANG = 'en';
export {log, DOCS_DIR, ASSETS_DIR, LANGS, DEFAULT_LANG, DOCS_BRANCH, DOCS_PREFIX, DOCS_REMOTE, LATEST_ALIAS};
module.exports = {
log,
DOCS_DIR,
ASSETS_DIR,
LANGS,
DEFAULT_LANG,
DOCS_BRANCH,
DOCS_PREFIX,
DOCS_REMOTE,
LATEST_ALIAS,
};
@@ -7,7 +7,7 @@ date: 2024-07-13
# Appium Conf 2024: 现在开始征集提案
我们很兴奋地宣布,Appium Conf 已回归并在2024年上线! 这是官方的Appium会议,您可以在会上了解Appium 2中的所有新内容。 并探索设备自动化测试、移动应用程序和桌面应用程序的最新版本。
我们很兴奋地宣布,Appium Conf 已回归并在2024年上线!这是官方的Appium会议,您可以在会上了解Appium 2中的所有新内容。 并探索设备自动化测试、移动应用程序和桌面应用程序的最新版本。
<!-- more -->
@@ -19,7 +19,7 @@ date: 2024-07-13
## 标记您的日历:2024年9月13日
2024年9月13日,请加入我们,参加Appium团队和世界顶级移动测试和自动化专家为期一天的鼓舞人心且实用的演讲。 随着Appium 2.0的成熟,这是您深入了解并学习如何最大限度地发挥其潜力的机会。
2024年9月13日,请加入我们,参加Appium团队和世界顶级移动测试和自动化专家为期一天的鼓舞人心且实用的演讲。随着Appium 2.0的成熟,这是您深入了解并学习如何最大限度地发挥其潜力的机会。
## 为什么参加了2024年的Appium Conf ?
@@ -30,16 +30,16 @@ date: 2024-07-13
## 征集提案:分享您的知识!
我们正在寻找来自全球各地的各种演讲者,他们渴望分享移动测试自动化的创新想法和用例。 如果您有使用Appium的经验和见解,可以使测试从业者社区受益,我们想听听您的意见!
我们正在寻找来自全球各地的各种演讲者,他们渴望分享移动测试自动化的创新想法和用例。如果您有使用Appium的经验和见解,可以使测试从业者社区受益,我们想听听您的意见!
不要错过这个机会,为Appium社区做出贡献,并在全球舞台上展示你的专业知识。
## 如何提交您的提案
访问我们的网站 [https://appiumconf.com/](https://appiumconf.com/) 并[提交提案](https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch)。 我们很高兴看到您在 Appium 中的创新想法和经验!
访问我们的网站 [https://appiumconf.com/](https://appiumconf.com/) 并[提交提案](https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch)。我们很高兴看到您在 Appium 中的创新想法和经验!
## 敬请期待
关注我们的网站和社交媒体频道以了解会议日程安排的更新, 主旨演讲人和2024年Appium Conf 的更令人兴奋的细节。
加入我们来塑造移动设备测试自动化的未来。 立即提交您的提案,成为这一激动人心的活动的一部分!
加入我们来塑造移动设备测试自动化的未来。立即提交您的提案,成为这一激动人心的活动的一部分!
+32 -14
View File
@@ -5,22 +5,21 @@ hide:
title: 对Appium 的贡献
---
Appium项目离不开来自公司和志愿者的代码、文档、维护和支持的众多贡献。 因此,我们欢迎贡献!
Appium项目离不开来自公司和志愿者的代码、文档、维护和支持的众多贡献。因此,我们欢迎贡献!
有许多不同的方式可以帮助项目——请参阅下方了解您可以做的一切以及每个贡献方法的流程。 请注意,无论您如何贡献,您的参与都受我们的[行为准则](https://github.com/appium/.github/blob/master/CODE_OF_CONDUCT.md)管辖。
有许多不同的方式可以帮助项目——请参阅下方了解您可以做的一切以及每个贡献方法的流程。请注意,无论您如何贡献,您的参与都受我们的[行为准则](https://github.com/appium/.github/blob/master/CODE_OF_CONDUCT.md)管辖。
## 加入讨论论坛
您不需要了解Appium的内部机制就能做出贡献! 如果您有使用Appium的经验,并愿意与他人分享您的知识,请考虑在Appium论坛[discuss.appium.io](https://discuss.appium.io/)上帮助用户。 快去看看是否有您能回答的问题。
您不需要了解Appium的内部机制就能做出贡献!如果您有使用Appium的经验,并愿意与他人分享您的知识,请考虑在Appium论坛[discuss.appium.io](https://discuss.appium.io/)上帮助用户。快去看看是否有您能回答的问题。
## 报告错误或功能请求
如果您遇到了一个bug,或者有一个很酷的功能想法,认为Appium应该支持,请务必在我们的[GitHub issue tracker](https://github.com/appium/appium/issues)上告诉我们。
请在创建issue时使用适当的issue表单模板。
如果您遇到了一个bug,或者有一个很酷的功能想法,认为Appium应该支持,请务必在我们的[GitHub issue tracker](https://github.com/appium/appium/issues)上告诉我们。请在创建issue时使用适当的issue表单模板。
## 对问题分类
除了创建issue,您还可以帮助我们调查已报告的问题。 您只需要对Appium有足够的熟悉程度来尝试重现bug。
除了创建issue,您还可以帮助我们调查已报告的问题。您只需要对Appium有足够的熟悉程度来尝试重现bug。
您可以通过检查我们的[GitHub issue tracker](https://github.com/appium/appium/issues)中带有标签如`Needs Triage`或`Needs Info`的问题开始,并留下相关评论:
@@ -48,7 +47,7 @@ cd appium
!!! info
如果您是 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) 轻松地查看项目。
If you are VS Code user, you can easily check out the project using [Runme](https://runme.dev/).
安装依赖:
@@ -95,10 +94,30 @@ export APPIUM_WORKSPACE=@appium/base-driver
npm run test:unit -w $APPIUM_WORKSPACE
```
### Code Style
#### JSDoc
Add concise JSDoc to all public class methods and exported functions.
#### Module Ordering
Place exported functions and classes before non-exported functions and classes in each module.
This rule does not apply to constants or variables.
#### Class Member Ordering
When adding or moving class methods, follow these conventions:
- Order methods by visibility: public → protected → private. Methods without an explicit visibility
modifier belong to the public group.
- Place private helper methods at the end of the class.
- Preserve existing order within each visibility group.
- Before finishing, check the ordering of methods you added or moved.
### 文档
此项目的文档位于项目[仓库本身](https://github.com/appium/appium/tree/master/packages/appium/docs)中。
它包含在Markdown文件中,这些文件由`@appium/docutils`模块中的文档系统构建。 该模块基于[MkDocs](https://www.mkdocs.org/),因此需要在您的系统上安装[Python](https://www.python.org/)。
此项目的文档位于项目[仓库本身](https://github.com/appium/appium/tree/master/packages/appium/docs)中。它包含在Markdown文件中,这些文件由`@appium/docutils`模块中的文档系统构建。该模块基于[MkDocs](https://www.mkdocs.org/),因此需要在您的系统上安装[Python](https://www.python.org/)。
安装 Python 依赖:
@@ -116,17 +135,16 @@ npm run dev:docs
## 翻译Appium 文档
Appium文档本地化为英语以外语言的过程是自动化的,通过[Crowdin翻译管理系统](https://crowdin.com)完成。 请勿直接在GitHub Appium仓库中编辑任何翻译文档,因为它们将在即将进行的同步中被从Crowdin导出的文档替换。
Appium文档本地化为英语以外语言的过程是自动化的,通过[Crowdin翻译管理系统](https://crowdin.com)完成。请勿直接在GitHub Appium仓库中编辑任何翻译文档,因为它们将在即将进行的同步中被从Crowdin导出的文档替换。
### 从哪里开始
如果您想为Appium文档翻译成您的语言做出贡献,只需加入[Appium Documentation](https://crowdin.com/project/appium-documentation) Crowdin项目的翻译者组,然后在那里开始翻译文档。 如果您看到您的语言在Crowdin可用语言列表中缺失,请通过创建[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)告诉我们。
### 源语言更新
文档中的更改通过 `Update Crowdin English Docs GitHub` action自动同步到Crowdin。
一旦 `packages/appium/docs/en/**.md` 或 `packages/appium/docs/mkdocs-en.yml` 下有任何更改,此action就会自动触发。
文档中的更改通过 `Update Crowdin English Docs GitHub` action自动同步到Crowdin。一旦 `packages/appium/docs/en/**.md` 或 `packages/appium/docs/mkdocs-en.yml` 下有任何更改,此action就会自动触发。
### 获取翻译文档
为了从Crowdin获取翻译文件到GitHub仓库,需要触发 `Sync Crowdin Docs Translations` action。 此action还会自动创建一个包含相应翻译资源的PR。
为了从Crowdin获取翻译文件到GitHub仓库,需要触发 `Sync Crowdin Docs Translations` action。此action还会自动创建一个包含相应翻译资源的PR。
@@ -2,14 +2,13 @@
title: 构建文档
---
一旦你为 Appium 构建了 [驱动](./build-drivers.md) 或 [插件](./build-plugins.md),通常也会希望为用户说明这个扩展是如何工作的。 最基础的方式就是编写一个简短的 `README.md`,并将它放在项目仓库的根目录中。
不过,这样做可能会耗费不少精力。
一旦你为 Appium 构建了 [驱动](./build-drivers.md) 或 [插件](./build-plugins.md),通常也会希望为用户说明这个扩展是如何工作的。最基础的方式就是编写一个简短的 `README.md`,并将它放在项目仓库的根目录中。不过,这样做可能会耗费不少精力。
Appium 项目已经提供了辅助工具,并且我们把这些工具打包好了,以便生态系统中的驱动和插件开发者也能使用。 这些工具最好的入门方式是查看一个现有的 Appium 驱动仓库,看看它是如何组织文档的,例如 [XCUITest 驱动仓库](https://github.com/appium/appium-xcuitest-driver)。 不过,本指南会先介绍基本的实现思路。
Appium 项目已经提供了辅助工具,并且我们把这些工具打包好了,以便生态系统中的驱动和插件开发者也能使用。这些工具最好的入门方式是查看一个现有的 Appium 驱动仓库,看看它是如何组织文档的,例如 [XCUITest 驱动仓库](https://github.com/appium/appium-xcuitest-driver)。不过,本指南会先介绍基本的实现思路。
### 概念架构
Appium 采用 [MkDocs](https://www.mkdocs.org/) 作为基于 Markdown 的文档站点的生成工具。 它使用 Python 工具链(而不是 Node.js),但这恰好是我们当前需求下最合适的选择。 你可以自行调整,不过默认情况下,Appium 的工具链也会假设你使用 [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) 主题与扩展来搭建 MkDocs。
Appium 采用 [MkDocs](https://www.mkdocs.org/) 作为基于 Markdown 的文档站点的生成工具。它使用 Python 工具链(而不是 Node.js),但这恰好是我们当前需求下最合适的选择。你可以自行调整,不过默认情况下,Appium 的工具链也会假设你使用 [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) 主题与扩展来搭建 MkDocs。
为了让你的文档能够支持不同版本(通常是每个小版本一个),我们还会捆绑 [Mike](https://github.com/jimporter/mike)。
@@ -37,18 +36,45 @@ npx appium-docs init
这一步会:
1. 创建一个 `tsconfig.json`(如果当前还没有的话)。 即使你的扩展并不是 TypeScript 编写的,这也是必需的。
1. 创建一个 `tsconfig.json`(如果当前还没有的话)。即使你的扩展并不是 TypeScript 编写的,这也是必需的。
2. 创建一个 `mkdocs.yml`,其中包含 MkDocs 所需的配置。
### 为你的扩展编写文档
此时你就可以开始为扩展编写文档了。 默认情况下,MkDocs 会在 `docs` 目录中查找 Markdown 文件。 因此,你可以创建文档文件并放入 `docs`,然后在 `mkdocs.yml` 里添加相应链接。
此时你就可以开始为扩展编写文档了。默认情况下,MkDocs 会在 `docs` 目录中查找 Markdown 文件。因此,你可以创建文档文件并放入 `docs`,然后在 `mkdocs.yml` 里添加相应链接。
请参考 [MkDocs 文档](https://www.mkdocs.org/user-guide/writing-your-docs/) 来了解如何组织与构建你的文档结构。
### 帮助LLMs 使用您的文档
The [`/llms.txt` convention](https://llmstxt.org/) is a Markdown file at the root of a
documentation site, listing its most useful pages so that large language models can navigate the
site without crawling it. Appium's own documentation provides one at
[appium.io/docs/en/latest/llms.txt](https://appium.io/docs/en/latest/llms.txt), and you may want to
do the same for your extension.
MkDocs copies any non-Markdown file in your `docs` directory to the built site as-is, so all you
need to do is write an `llms.txt` and place it alongside your Markdown files. No plugin or build
configuration is required.
The value of this file lies in the parts a crawler could not have worked out on its own, so it is
worth writing by hand rather than generating it from your navigation:
- A short description of what your extension automates, and which platforms it targets
- The handful of things models reliably get wrong about your extension - removed capabilities,
renamed commands, patterns from an older major version that no longer apply
- Links to the pages that matter, with a description of each
Because links in `llms.txt` are read out of context, they must be absolute URLs. If you use Mike
for versioning, point them at your version alias (for example `latest`) rather than at a pinned
version, so that the file does not go stale. Note that a hand-written file can drift as pages are
renamed; Appium validates its own with a
[script](https://github.com/appium/appium/blob/master/packages/appium/docs/scripts/check-llmstxt.js)
that runs in CI, which you are welcome to adapt.
### 构建文档
在这个阶段,你可以使用 `appium-docs` CLI 工具。 运行这个工具时不传任何参数,可以看到完整的帮助信息,以及所有可用的子命令与参数。 下面是几个常见用法示例:
在这个阶段,你可以使用 `appium-docs` CLI 工具。运行这个工具时不传任何参数,可以看到完整的帮助信息,以及所有可用的子命令与参数。下面是几个常见用法示例:
```bash
# 生成参考文档并将 mkdocs 站点构建到 site 目录
@@ -2,7 +2,7 @@
title: 构建 Doctor Checks
---
Appium Doctor 的目标,是帮助用户完成驱动或插件的前置条件配置。 有时这些前置条件可能相当复杂,需要一定的技术知识。 Doctor checks是由扩展作者编写的普通 Node.js 类实例,它可以自动完成诊断并尝试修复发现的问题。 为了提供更好的使用体验,这些检查项有时也会是交互式的。
Appium Doctor 的目标,是帮助用户完成驱动或插件的前置条件配置。有时这些前置条件可能相当复杂,需要一定的技术知识。 Doctor checks是由扩展作者编写的普通 Node.js 类实例,它可以自动完成诊断并尝试修复发现的问题。为了提供更好的使用体验,这些检查项有时也会是交互式的。
本教程适用于希望帮助用户处理复杂配置或设置步骤的插件或驱动作者。
@@ -10,14 +10,13 @@ Appium Doctor 的目标,是帮助用户完成驱动或插件的前置条件配
### 类型要求
术语 `Doctor Check` 的字面含义,是指一个实现了 [IDoctorCheck 接口](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts) 的 JavaScript 类实例。
这个接口定义了以下方法和属性:
术语 `Doctor Check` 的字面含义,是指一个实现了 [IDoctorCheck 接口](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts) 的 JavaScript 类实例。这个接口定义了以下方法和属性:
- `diagnose(): Promise<DoctorCheckResult>`:包含诊断某个问题的代码
- `fix(): Promise<string|null>`:如果 `hasAutofix()` 返回 true,则修复实际问题;否则返回一段手动修复的说明。 如果此方法抛出名为 `FixSkippedError` 的异常,并且 `hasAutofix()` 返回 true,那么该调用结果将被忽略。
- `fix(): Promise<string|null>`:如果 `hasAutofix()` 返回 true,则修复实际问题;否则返回一段手动修复的说明。如果此方法抛出名为 `FixSkippedError` 的异常,并且 `hasAutofix()` 返回 true,那么该调用结果将被忽略。
- `hasAutofix(): boolean`:表示调用 `fix()` 是否能解决发现的问题
- `isOptional(): boolean`:表示发现的问题是否可以被忽略且不是阻塞性问题
- `log: AppiumLogger`:可用于日志输出。 这个属性可以由实例自行赋值,也可以由 Appium 服务在未赋值时自动提供。
- `log: AppiumLogger`:可用于日志输出。这个属性可以由实例自行赋值,也可以由 Appium 服务在未赋值时自动提供。
`diagnose()` 方法返回的 `DoctorCheckResult` 对象必须包含以下属性:
@@ -27,7 +26,7 @@ Appium Doctor 的目标,是帮助用户完成驱动或插件的前置条件配
### 清单要求
一个扩展可以向 Appium 导出多个 Doctor checks。 为了让这些检查项在对应扩展安装后能够被服务端 CLI 正确识别,它们需要在package .json 清单文件中列在 `appium.doctor.checks` 部分,格式类似下面这样:
一个扩展可以向 Appium 导出多个 Doctor checks。为了让这些检查项在对应扩展安装后能够被服务端 CLI 正确识别,它们需要在package .json 清单文件中列在 `appium.doctor.checks` 部分,格式类似下面这样:
```json
// ...
@@ -80,8 +80,9 @@ The required subfields are:
capability to tell Appium to use _your_ driver.
- `platformNames`: this is an array of one or more platform names considered valid for your driver.
When a user sends in the `platformName` capability to start a session, it must be included in
this list for your driver to handle the session. Known platform name strings include: `iOS`,
`tvOS`, `macOS`, `Windows`, `Android`.
this list for your driver to handle the session. These names should generally include the
operating systems your driver is targeting - for example, a driver targeting iOS would include
`iOS`, while a driver targeting the Chrome browser on Windows would include `Windows`.
- `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
class which extends Appium's `BaseDriver` (see below).
@@ -283,8 +284,8 @@ You handle WebDriver commands by implementing functions in your driver class. Ea
WebDriver Protocol, plus the various Appium extensions, has a corresponding function that you
implement if you want to support that command in your driver. The best way to see which commands
Appium supports and which method you need to implement for each command is to look at Appium's
[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js).
Each route object in this file tells you the command name as well as the parameters you'd expect to
[routes/](https://github.com/appium/appium/tree/master/packages/base-driver/lib/protocol/routes).
Each route object in this directory's files tells you the command name as well as the parameters you'd expect to
receive for that command.
Let's take this block for example:
@@ -327,7 +328,7 @@ Websockets. Implementing handlers for BiDi commands works just the same as imple
for WebDriver classic commands (described in the previous section). You simply define a method on
your driver of the appropriate name, and it will be called when the BiDi command is requested by
the client. To see which specific names you should use for BiDi commands, have a look at
[bidi-commands.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.js)
[bidi-commands.ts](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.ts)
You are not limited to BiDi commands that are defined in the official BiDi specification. If you
wish to define new commands, you may do so; you just need to tell Appium about them! See
@@ -1,51 +1,29 @@
---
title: Building Plugins
title: 开发插件
---
This is a high-level guide for developing Appium plugins, which is not something most Appium users
need to know or care about. If you are not familiar with Appium plugins yet from a user
perspective, check out the [list of plugins](../ecosystem/plugins.md) to play around with some and get
an idea of the sorts of things that plugins can do. Plugins are a powerful system for augmenting
Appium's functionality or changing the way Appium works. They can be distributed to other Appium
users and can extend Appium's ecosystem in all kinds of interesting ways! (There is also
a significant amount of overlap here with developing Appium drivers, so you may also want to check
out the [building drivers](./build-drivers.md) guide for further inspiration.)
这是一份开发 Appium 插件的高层指南——大多数 Appium 用户并不需要知道或关心这些内容。如果你还不太熟悉面向用户视角的 Appium 插件,可以先看看[插件列表](../ecosystem/plugins.md),动手试用几个,
了解插件大致能做哪些事情。插件是一套强大的机制,用来增强 Appium 的功能或改变 Appium 的运行方式。它们可以分发给其他 Appium 用户,并以各种有趣的方式扩展 Appium 的生态!(此外,开发插件与开发Appium 驱动有很大重叠,所以你也不妨看看[开发驱动](./build-drivers.md)指南获取更多灵感。)
## Before you create your plugin
## 创建插件之前
Before creating your plugin, it's good to have a general idea of what you want your plugin to
accomplish and whether it will be possible to implement it given the restrictions of the Appium
platform. Reading through this guide will help you understand what's possible. In general, Appium's
plugin system is extremely powerful and no attempts have been made to artificially limit what's
possible with them (which is a main reason that all plugins are opt-in by the system administrator
responsible for starting the Appium server---plugins are powerful and should only be used when
explicitly trusted!).
在创建插件之前,最好对你希望插件完成什么、以及在 Appium 平台的限制下是否可能实现有一个大致的判断。通读本指南能帮你理解哪些事情是可行的。总体而言,Appium 的插件系统非常强大,我们并没有人为地去限制插件能做什么(这也是所有插件都必须由负责启动 Appium 服务器的系统管理员显式启用的主要原因——插件很强大,只应在你明确信任它时才使用!)
## Other plugins to reference
## 可供参考的其他插件
There are a wide variety of open source Appium plugins available for perusal. It's definitely
recommended to explore the code for some other plugins before embarking on writing your own. The
Appium team maintains a set of official plugins in the Appium GitHub
repo. Links to other open source plugins can be found in the
[Plugin list](../ecosystem/plugins.md)
有大量开源的 Appium 插件可供查阅。我们强烈建议在动手写自己的插件之前,先看看其他插件的代码。 Appium 团队在 [Appium 的 GitHub 仓库](https://github.com/appium/appium)中维护了一套官方插件。其他开源插件的链接可以在[插件列表](../ecosystem/plugins.md)中找到。
## Basic requirements for plugins
## 插件的基本要求
These are the things your plugin _must_ do (or be), if you want it to be a valid Appium plugin.
如果你想让某个东西成为一个合法的 Appium 插件,以下是&#x5B83;_&#x5FC5;&#x987B;_&#x505A;到(或满足)的事情。
### Node.js package with Appium extension metadata
### 带 Appium 扩展元数据的 Node.js 包
All Appium plugins are fundamentally Node.js packages, and therefore must have a valid
`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in
Node.js so it can be loaded by Appium.
所有 Appium 插件本质上都是 Node.js 包,因此必须有一个合法的 `package.json`。你的插件并&#x4E0D;_&#x5C40;&#x9650;_&#x4E8E;用 Node.js 编写,但它必须提供一个用 Node.js 编写的适配器,以便 Appium 能够加载它。
Your `package.json` must include `appium` as a `peerDependency`. The requirements for the
dependency versions should be as loose as possible (unless you happen to know your plugin will only
work with certain versions of Appium). For Appium 2, for example, this would look something like
`^2.0.0`, declaring that your plugin works with any version of Appium that starts with 2.x.
你的 `package.json` 必须将 `appium` 声明为 `peerDependency`。对依赖版本的要求应尽量宽松(除非你明确知道你的插件只能与某些特定版本的 Appium 配合工作)。以 Appium 2 为例,写成 `^2.0.0` 即可,表示你的插件兼容所有 2.x 版本的 Appium。
Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension
metadata'):
你的 `package.json` 必须包含一个 `appium` 字段,如下所示(我们称之为"Appium 扩展元数据"):
````
```json
@@ -60,19 +38,14 @@ metadata'):
```
````
The required subfields are:
必需的子字段如下:
- `pluginName`: this should be a short name for your plugin.
- `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
class which extends Appium's `BasePlugin` (see below).
- `pluginName`:你的插件的简短名称。
- `mainClass`:从 `main` 字段具名导出(CommonJS 风格)的类。它必须是继承自 Appium 的 `BasePlugin` 的类(见下文)。
### Extend Appium's `BasePlugin` class
### 继承 Appium 的 `BasePlugin` 类
Ultimately, your plugin is much easier to write because most of the hard work of defining patterns
for overriding commands is done for you. This is
all encoded up as a class which Appium exports for you to use, called `BasePlugin`. It is exported
from `appium/plugin`, so you can use one of these styles to import it and create your _own_ class
that extends it:
归根结底,你的插件之所以好写,是因为定义"重写命令"的各种模式所需的繁重工作已经替你完成了。这一切都封装在一个 Appium 导出的类中,名为 `BasePlugin`。它从 `appium/plugin` 导出,你可以用下面任一方式导入它,并创建继承它&#x7684;_&#x4F60;自己&#x7684;_&#x7C7B;:
```js
import {BasePlugin} from 'appium/plugin';
@@ -83,48 +56,38 @@ export class MyPlugin extends BasePlugin {
}
```
!!! note
!!! 注意
```
In all the code samples below, whenever we reference an example method, it is assumed
that it is defined _within_ the class, though this is not explicitly written, for the sake of
clarity and space.
在下面所有代码示例中,凡是给出示例方法的地方,都默认它是定义在类_内部_的;为了简洁和省篇幅,文中没有显式写出这一点。
```
### Make your plugin available
### 让你的插件可用
That's basically it! With a Node.js package exporting a plugin class and with correct Appium
extension metadata, you've got yourself an Appium plugin! Now it doesn't _do_ anything, but you can
load it up in Appium, activate it, etc...
基本就是这样!一个导出插件类的 Node.js 包,再加上正确的 Appium 扩展元数据,你就拥有了一个 Appium 插件!虽然它还什么都&#x4E0D;_&#x505A;_,但你已经可以在 Appium 中加载它、启用它了……
To make it available to users, you could publish it via NPM. When you do so, your plugin will be
installable via the Appium CLI:
要让其他用户能用你的插件,你可以通过 NPM 发布它。发布之后,用户就可以通过 Appium CLI 安装它:
```
appium plugin install --source=npm <plugin-package-on-npm>
```
It's a good idea to test your plugin first, of course. One way to see how it works within Appium is
to install it locally first:
当然,最好先测试你的插件。观察它在 Appium 中如何工作的一个方式,是先以本地方式安装它:
```
appium plugin install --source=local /path/to/your/plugin
```
And of course, plugins must be "activated" during Appium server start, so make sure you direct your
users to do so:
另外别忘了,启动 Appium 服务器之前,要先启用插件,所以请务必告知用户这一点:
```
appium --use-plugins=plugin-name
```
### Developing your plugin
### 插件的开发流程
How you develop your plugin is up to you. It is convenient, however, to run it from within Appium
without having to do lots of publishing and installing. The most straightforward way to do this is
to include the most recent version of Appium as a `devDependency` (although its being already
included as a `peerDependency` is sufficient in newer versions of NPM), and then also your own plugin,
like this:
如何开发你的插件完全由你决定。不过,直接在 Appium 内部运行会很方便,无需进行繁琐的发布与安装操作。最直接的做法是把最新版本的 Appium 作为 `devDependency`(在较新版本的 NPM 中,它已经作为
`peerDependency` 被引入,也足够了),同时把你的插件也作为依赖引入,例如:
```json
{
@@ -137,26 +100,19 @@ like this:
}
```
Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your plugin is
listed as a dependency alongside it, it will be automatically "installed" and available. You can
design your e2e tests this way, or if you're writing them in Node.js, you can simply import
Appium's start server methods to handle starting and stopping the Appium server in Node.
这样,你就可以在本地运行 Appium(`npm exec appium` 或 `npx appium`),并且由于你的插件与它并列列为依赖,它会被自动"安装"并可用。你可以按这种方式设计你的 e2e 测试;如果用 Node.js 编写测试,你还可以直接导入 Appium 的启动服务方法,在 Node 中启停 Appium 服务器。
Of course, you can always install it locally as described above as well.
当然,你也随时可以按上文所说的方式以本地源安装。
Anytime you make changes to your plugin code, you'll need to restart the Appium server to make sure
it picks up the latest code. As with drivers, you can set the `APPIUM_RELOAD_EXTENSIONS`
environment variable if you wish Appium to try to re-require your plugin module when a new session
starts.
每次修改插件代码后,你都需要重启 Appium 服务器,才能确保它加载最新的代码。与驱动一样,如果你希望Appium 在新会话启动时尝试重新 require 你的插件模块,可以设置`APPIUM_RELOAD_EXTENSIONS`环境变量。
## Standard plugin implementation ideas
## 插件实现的标准思路
These are things you will probably find yourself wanting to do when creating a plugin.
以下是创建插件时你多半会想做的事情。
### Set up state in a constructor
### 在构造函数中初始化状态
If you define your own constructor, you'll need to call `super` to make sure all the standard state
is set up correctly:
如果你定义了自己的构造函数,需要调用 `super`,确保所有标准状态被正确初始化:
```js
constructor(...args) {
@@ -165,28 +121,20 @@ constructor(...args) {
}
```
The `args` parameter here is the object containing all the CLI args used to start the Appium
server.
这里的 `args` 参数是包含启动 Appium 服务器所用全部 CLI 参数的对象。
### Intercept and handle specific Appium commands
### 拦截并处理特定的 Appium 命令
This is the most normal behavior for Appium plugins -- to modify or replace the execution of one or
more commands that would normally be handled by the active driver. To override the default command
handling, you need to implement `async` methods in your class with the same name as the Appium
commands to be handled (just exactly how drivers themselves are
implemented). Curious what command names there
are? They are defined in the Appium base driver's
[routes.js](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js) file,
and of course you can add more as defined in the next section.
这是 Appium 插件最常见的用法——修改或替换本应由当前驱动处理的一个或多个命令的执行。要覆盖默认的命令处理逻辑,你需要在类中实现与所要处理的 Appium 命令同名的 `async` 方法(和[驱动本身的实现方式](./build-drivers.md#implement-webdriver-classic-commands)完全一致)。想知道都有哪些命令名?它们定义在 Appium base driver 的
[routes.js](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js) 文件中,当然你还可以按下一节介绍的方式添加更多命令。
Each command method is sent the following arguments:
每个命令方法都会收到以下参数:
1. `next`: This is a reference to an `async` function which encapsulates the chain of behaviors which would take place if this plugin were not handling the command. You can choose to call the next behavior in the chain at any point in your logic (by making sure to include `await next()` somewhere), or not. If you don't, it means the default behavior (or any plugins registered after this one) won't be run.
2. `driver`: This is the object representing the driver handling the current session. You have access to it for any work you need to do, for example calling other driver methods, checking capabilities or settings, etc...
3. `...args`: A spread array with any arguments that have been applied to the command by the user.
1. `next`:指向一个 `async` 函数的引用,该函数封装了一系列行为链——如果当前插件未处理该命令,这些行为便会随之发生。你可以在逻辑中的任意位置选择调用链中的下一个行为(只需确保在某处包含 `await next()` 即可),也可以选择不调用。如果不调用,就意味着默认行为(或注册在该插件之后的其他插件)不会被执行。
2. `driver`:该对象代表负责处理当前会话的驱动程序。您可以根据需要使用它来执行各项操作,例如调用驱动程序的其他方法、检查功能配置或设置等。
3. `...args`:一个包含用户在调用命令时所传入的所有参数的数组(通过展开语法获取)。
For example, if we wanted to override the `setUrl` command to simply add some extra logging on top,
we would implement as follows:
例如,如果我们想覆盖 `setUrl` 命令,只在原有行为上追加一些日志,可以这样实现:
```js
async setUrl(next, driver, url) {
@@ -198,20 +146,16 @@ async setUrl(next, driver, url) {
}
```
### Intercept and handle _all_ Appium commands
### 拦截并处&#x7406;_&#x6240;有_ Appium 命令
You might find yourself in a position where you want to handle _all_ commands, in order to inspect
payloads to determine whether or not to act in some way. If so, you can implement `async handle`,
and any command that is not handled by one of your named methods will be handled by this method
instead. It takes the following parameters (with all the same semantics as above):
你可能会遇到这样一种情况:需要处&#x7406;_&#x6240;&#x6709;_&#x547D;令,以便检查其中的有效载荷,从而决定是否要采取某种行动。这种情况下,你可以实现 `async handle`,任何没有被你具名方法处理的命令都会交给这个方法处理。它接收以下参数(语义与上文完全一致):
1. `next`
2. `driver`
3. `cmdName` - string representing the command being run
3. `cmdName` —— 表示正在运行的命令的字符串
4. `...args`
For example, let's say we want to log timing for all Appium commands as part of a plugin. We could
do this by implementing `handle` in our plugin class as follows:
例如我们想在一个插件中记录所有 Appium 命令的耗时。我们可以这样在插件类中实现 `handle`:
```js
async handle(next, driver, cmdName, ...args) {
@@ -226,31 +170,17 @@ async handle(next, driver, cmdName, ...args) {
}
```
### Working with driver proxies
### 与驱动代理打交道
There is a bit of a gotcha with handling Appium commands. Appium drivers have the ability to turn
on a special 'proxy' mode, wherein the Appium server process takes a look at incoming URLs, and
decides whether to forward them on to some upstream WebDriver server. It could happen that
a command which a plugin wants to handle is designated as a command which is being proxied to an
upstream server. In this case, we might run into a problem, because the plugin never gets a chance to
handle that command! The way Appium handles this is as follows:
在处理 Appium 命令时有一个坑。 Appium 驱动可以开启一种特殊的"代理"模式:在该模式下,Appium 服务器进程会查看进来的 URL,并决定是否把它们转发给某个上游 WebDriver 服务器。可能出现这样的情况:插件想要处理的某个命令,恰好属于被代理到上游服务器的命令。这时就会有问题——插件根本得不到处理该命令的机会! Appium 对这种情况的处理方式如下:
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.
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.
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.
1. 当一个命令进来时,主协议处理器在决定是否代理该命令之前,会先检查是否有插件要处理它。
2. 如&#x679C;_&#x6CA1;&#x6709;_&#x63D2;件要处理该命令——一切照旧,请求是否被代理取决于驱动的代理模式。
3. 如&#x679C;_&#x6709;_&#x63D2;件要处理该命令,那么代理行为此时会被跳过,并被包装成传给插件的 `next` 函数。所以,如果你的插件里有该命令的处理器,又希望确保驱动的默认代理行&#x4E3A;_&#x786E;&#x5B9E;_&#x53D1;生,只需在你插件处理器所做的事情之外(或之中)`await next()` 即可。
### Throw WebDriver-specific errors
### 抛出 WebDriver 专用错误
The WebDriver spec defines a set of error
codes to accompany command responses if an
error occurred. Appium has created error classes for each of these codes, so you can throw the
appropriate error from inside a command, and it will do the right thing in terms of the protocol
response to the user. To get access to these error classes, import them from `appium/driver`:
WebDriver 规范定义了一组错误代码,以便在发生错误时随命令响应一并返回。 Appium 为每个错误码都创建了对应的错误类,因此你可以在命令内部抛出相应的错误,Appium 会按照协议规范把它正确地响应给用户。要获得这些错误类,从 `appium/driver` 导入即可:
```js
import {errors} from 'appium/driver';
@@ -258,39 +188,30 @@ import {errors} from 'appium/driver';
throw new errors.NoSuchElementError();
```
### Log messages to the Appium log
### 向 Appium 日志写消息
You can always use `console.log`, of course, but Appium provides a nice logger for you as
`this.logger` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log
levels). If you want to create an Appium logger outside of a plugin context (say in a script or
helper file), you can always construct your own too:
你当然可以随时用 `console.log`,但 Appium 为你提供了一个更贴心的日志器 `this.logger`(它有 `.info`、`.debug`、`.log`、`.warn`、`.error` 等不同日志级别的方法)。如果你想在插件上下文之外(比如脚本或辅助文件中)创建 Appium 日志器,也可以自行构造:
```js
import {logging} from 'appium/support';
const log = logging.getLogger('MyPlugin');
```
## Further possibilities for Appium plugins
## Appium 插件的进阶能力
These are things your plugin _can_ do to take advantage of extra plugin features or do its job more
conveniently.
这些是你的插&#x4EF6;_&#x53EF;&#x4EE5;_&#x5B9E;现的功能,旨在利用插件的额外特性,或让插件能更便捷地完成其任务。
### Add a schema for custom command line arguments
### 为自定义命令行参数添加 schema
You can add custom CLI args if you want your plugin to receive data from the command line when the
Appium server is started (for example, ports that a server administrator should set that should not
be passed in as capabilities).
如果你希望插件在 Appium 服务器启动时从命令行接收数据,就可以添加自定义 CLI 参数(例如由服务器
管理员设定的端口,这类参数不适合通过能力传入)。
This works largely the same for plugins as it does for drivers, so for more details have a look at
the equivalent section in the building drivers
doc.
插件的这部分机制与驱动基本一致,更多细节请参见[开发驱动文档](./build-drivers.md#add-a-schema-for-custom-command-line-arguments)中的对应章节。
The only difference is that to construct the CLI argument name, you prefix it with
`--plugin-<name>`. So for example, if you have a plugin named `pluggo` and a CLI arg defined with
the name `electro-port`, you can set it when starting Appium via `--plugin-pluggo-electro-port`.
唯一的区别是:构造 CLI 参数名时,前缀要用 `--plugin-<name>`。例如,你的插件名为 `pluggo`,其中定义了一个名为 `electro-port` 的 CLI 参数,那么在启动 Appium 时可以通过
`--plugin-pluggo-electro-port` 来设置它。
Setting args via a configuration file is also supported, as it is for drivers, but under the
`plugin` field instead. For example:
通过配置文件设置参数同样是支持的,与驱动一样,只是要写在 `plugin` 字段下。例如
```json
{
@@ -304,13 +225,9 @@ Setting args via a configuration file is also supported, as it is for drivers, b
}
```
### Add plugin scripts
### 添加插件脚本
Sometimes you might want users of your plugin to be able to run scripts outside the context of
a session (for example, to run a script that pre-builds aspects of your plugin). To support this,
you can add a map of script names and JS files to the `scripts` field within your Appium extension
metadata. So let's say you've created a script in your project that lives in a `scripts` directory
in your project, named `plugin-prebuild.js`. Then you could add a `scripts` field like this:
有时你可能希望插件用户能够在会话上下文之外运行脚本(例如运行一个预先构建插件某些部分的脚本)。为支持这一点,你可以在 Appium 扩展元数据的 `scripts` 字段中添加一个"脚本名 → JS 文件"的映射。假设你在项目的 `scripts` 目录下创建了一个名为 `plugin-prebuild.js` 的脚本,那么可以像这样添加 `scripts` 字段:
```json
{
@@ -320,25 +237,19 @@ in your project, named `plugin-prebuild.js`. Then you could add a `scripts` fiel
}
```
Now, assuming your plugin is named `myplugin`, users of your plugin can run `appium plugin run
myplugin prebuild`, and your script will execute.
假设你的插件名为 `myplugin`,现在,插件用户就可以运行 `appium plugin run myplugin prebuild`,你的脚本便会执行。
### Add new Appium commands
### 添加新的 Appium 命令
If you want to offer functionality that doesn't map to any of the existing commands supported by
drivers, you can create new commands in one of two ways, just as is possible for drivers:
如果您希望提供某种功能,而该功能无法对应到驱动程序所支持的现有命令中,那么您可以采用以下两种方式之一来创建新命令——这与驱动程序中的做法相同:
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
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
1. 扩展 WebDriver 协议,并编写客户端插件来访问这些扩展
2. 用新的模块和方法扩展 WebDriver BiDi 协议,客户端通过 BiDi 接口访问
3. 通过定义 [Execute Method](../guides/execute-methods.md) 来重载 Execute Script 命令
#### Extending the HTTP Protocol
#### 扩展 HTTP 协议
If you want to follow the first path, you can direct Appium to recognize new methods and add them
to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`
static variable in your driver class to an object of the same form as Appium's `routes.js` object.
For example, here is part of the `newMethodMap` for the `FakePlugin` example driver:
如果你想采用第一种方式,可以引导 Appium 识别新方法,并将它们添加到其允许的 HTTP 路由和命令名称集合中。具体做法是:在你的驱动类中,将静态变量 `newMethodMap` 赋值为一个对象,该对象的结构应与 Appium 中 `routes.js` 所定义的对象一致。例如,以下是 `FakePlugin` 示例驱动程序中 `newMethodMap` 的部分内容:
```js
static newMethodMap = {
@@ -356,38 +267,23 @@ static newMethodMap = {
};
```
!!! note
!!! 注意
```
If you're using TypeScript, static member objects like these should be defined `as const`.
如果你使用 TypeScript,像这样的静态成员对象应当用 `as const` 来定义。
```
In this example we're adding a few new routes and a total of 3 new commands. For more examples of
how to define commands in this way, it's best to have a look through `routes.js`. Now all you need
to do is implement the command handlers in the same way you'd implement any other Appium command.
示例中,我们添加了几个新路由,总共新增了 3 条命令。若想查看更多以这种方式定义命令的示例,建议查阅 `routes.js` 文件。接下来,你只需按照实现其他任何 Appium 命令的方式,去实现这些命令的处理程序即可。
Note also the special `neverProxy` key for commands; this is generally a good idea to set to `true`
for plugins, since your plugin might be active for a driver that is put into proxy mode but hasn't
bothered to decline proxying for these (new and therefore unknown) commands. Setting `neverProxy`
to `true` here will cause Appium to never proxy these routes and therefore ensure your plugin
handles them, even if a driver is in proxy mode.
此外,请注意针对命令的特殊 `neverProxy` 键;对于插件而言,通常建议将其设置为 `true`。这是因为,当驱动程序处于“代理模式”时,它可能并未明确拒绝代理某些命令(由于是新增的,因而未知的)。将 `neverProxy` 设置为 `true`,可确保 Appium 绝不会代理这些请求路径,从而保证它们始终由您的插件来处理——即便驱动程序正处于代理模式下,也不例外。
The downside of adding new commands via `newMethodMap` is that people using the standard Appium
clients won't have nice client-side functions designed to target these endpoints. So you would need
to create and release client-side plugins for each language you want to support (directions or
examples can be found at the relevant client docs).
通过 `newMethodMap` 添加新命令的不足之处在于,使用标准 Appium 客户端的用户将无法直接调用专为这些端点设计的、便捷的客户端函数。因此,针对你想要支持的每种编程语言,你都需要创建并发布相应的客户端插件(相关说明或示例可在各客户端的文档中找到)。
#### Extending the BiDi Protocol
#### 扩展 BiDi 协议
You can also make new commands accessible via the WebDriver BiDi (WebSocket-based) protocol. BiDi
commands come in two parts: a "module", which is basically a container or namespace, and
a "command", which is the name of your new command.
您还可以通过 WebDriver BiDi(基于 WebSocket 的协议)来提供新的命令。 BiDi 命令由两部分组成:“模块”(本质上是一个容器或命名空间)以及“命令”(即您所定义的新命令的名称)。
As with the first method, you teach Appium to recognize your new BiDi commands by adding a static
field to your driver class, called `newBidiCommands`. It has a format similar to `newMethodMap`.
Basically it encapsulates information about the BiDi module, BiDi command name, reference to your
driver instance method that will handle the command, and required and optional parameters. Here's
an example of a `newBidiCommands` as implemented on an imaginary driver:
与第一种方法类似,你可以通过在驱动类中添加一个名为 `newBidiCommands` 的静态字段,来让 Appium 识别你新增的 BiDi 命令。该字段的格式与 `newMethodMap` 类似。它主要封装了以下信息:BiDi 模块、BiDi 命令名称、指向驱动实例中负责处理该命令的方法的引用,以及该命令所需的必选参数和可选参数。以下是在一个虚构驱动程序中实现 `newBidiCommands` 的示例:
```js
static newBidiCommands = {
@@ -406,35 +302,20 @@ static newBidiCommands = {
};
```
In this imaginary example, we have defined two new BiDi commands: `appium:video.startFramerateCapture` and
`appium:video.stopFramerateCapture`. The first command takes a required and an optional parameter, and the
second does not. When you have implemented the `startFrameCap` and `stopFrameCap` methods on your
plugin class, they will be called whenever the BiDi commands are triggered by a client. The
signatures for these methods would look as follows:
在这个虚构的示例中,我们定义了两个新的 BiDi 命令:`appium:video.startFramerateCapture` 和 `appium:video.stopFramerateCapture`。第一个命令包含一个必选参数和一个可选参数,而第二个命令则不需要任何参数。当你在插件类中实现了 `startFrameCap` 和 `stopFrameCap` 方法后,每当客户端触发这些 BiDi 命令时,相应的方法就会被调用。这些方法的签名如下所示:
```js
async startFrameCap(next: () => Promise<any>, driver: DriverClass, videoSource: string, showOnScreen: boolean): Promise<any>;
async stopFrameCap(next: () => Promise<any>, driver: DriverClass): Promise<any>;
```
As with adding or overriding existing HTTP protocol commands, these methods are injected with
a `next` parameter and a `driver` parameter. The `driver` object represents the driver currently
owning the session, and calling `await next()` will execute/return the behavior that would execute
were the plugin not active (i.e., the driver's own handling of that method, or the chain of
commands executed with the same name by other active plugins).
与添加或重写现有的 HTTP 协议命令类似,这些方法在注入时会包含 `next` 和 `driver` 两个参数。 `driver` 对象代表当前拥有该会话的驱动程序;调用 `await next()` 则会执行(或返回)在插件未激活时本应执行的行为——即驱动程序自身对该方法的处理逻辑,或者是其他已激活插件中同名命令的执行链。
Note that, currently, if a driver has BiDi proxying turned on, plugins will not be able to override
BiDi methods handled by the proxy. Also note that since these are custom BiDi commands, our module
name should include a vendor prefix (we chose `appium:`, but you can/should choose something that
makes sense for your extension).
请注意,目前如果启用了 BiDi 代理,插件将无法覆盖由该代理处理的 BiDi 方法。此外,由于这些属于自定义 BiDi 命令,我们的模块名称中应包含厂商前缀(我们选择了 `appium:`,您可以而且应该,根据您的扩​​展功能,选择一个合适的名称)。
#### Overloading Execute Script
#### 重载 Execute Script
An alternative to these ways of doing things is to overload a command which all WebDriver clients
have access to already: Execute Script. Make sure to read the section on adding new
commands in
the Building Drivers guide to understand the way this works in general. The way it works with
plugins is only slightly different. Let's look at an example taken from Appium's `fake-plugin`:
除了上述做法外,还有另一种选择:重载一个所有 WebDriver 客户端均可调用的命令——“执行脚本”(Execute Script)。请务必阅读“构建驱动程序”指南中关于[添加新命令](./build-drivers.md#extend-the-existing-protocol-with-new-commands)的章节,以了解其基本运作机制。在插件场景下,其运作方式仅有细微差别。让我们来看一个取自 Appium “模拟插件”(fake-plugin)的示例:
```js
static executeMethodMap = {
@@ -453,60 +334,36 @@ async execute(next, driver, script, args) {
}
```
We have three important components shown here which make this system work, all of which are defined
inside the plugin class:
这里有三个让这套机制运转起来的关键组件,它们都定义在插件类内部:
1. The `executeMethodMap`, defined in just the same way as for drivers
2. The implementation of the command method as defined in `executeMethodMap` (in this case,
`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.
1. `executeMethodMap`,定义方式与驱动完全相同
2. `executeMethodMap` 中所声明命令方法的实现(本例中为 `plugMeIn`)
3. 覆盖/处理 `execute` 命令。与其他插件命令处理器一样,前两个参数是 `next` 和 `driver`,随后是脚本名和参数。 `BasePlugin` 提供了一个辅助方法,我们可以把这些参数原样传给它调用。
Overriding Execute Methods from drivers works as you'd expect: if your plugin defines an Execute
Method with the same name as that of a driver, your command (in this case `plugMeIn`) will be
called first. You can choose to run the driver's original behaviour via `next` if you want.
覆盖驱动定义的 Execute Method 的效果符合直觉:如果你的插件定义了与驱动同名的 Execute Method,会先调用你的命令(本例中为 `plugMeIn`)。如果需要,你可以通过 `next` 执行驱动的原有行为。
### Emit BiDi Events
### 触发 BiDi 事件
Your plugin can emit custom BiDi events in exactly the same way as Appium
drivers.
你的插件触发自定义 BiDi 事件的方式,与 Appium 驱动完全一致。
### Build Appium Doctor checks
### 构建 Appium Doctor 检查
Your users can run `appium plugin doctor <pluginName>` to run installation and health checks. Visit
the [Building Doctor Checks](./build-doctor-checks.md) guide for more information on this
capability.
你的用户可以运行 `appium plugin doctor <pluginName>` 来执行安装与健康检查。关于这一能力的更多信息,请访问[构建 Doctor 检查](./build-doctor-checks.md)指南。
### Update the Appium server object
### 更新 Appium 服务器对象
You probably don't normally need to update the Appium server object (which is an
[Express](https://expressjs.com/) server having already been
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)
in a variety of ways). But, for example, you could add new routes to the server to support your
plugin's requirements. To update the server you must implement the `static async updateServer`
method in your class. This method takes three parameters:
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.ts)
in a variety of ways). 但你可以为服务器添加新的路由来支撑你的插件的需求。要更新服务器,你必须在类中实现 `static async updateServer` 方法。该方法接收三个参数:
- `expressApp`: the Express app object
- `httpServer`: the Node HTTP server object
- `cliArgs`: a map of the CLI args used to start the Appium server
- `expressApp`:Express app 对象
- `httpServer`:Node HTTP 服务器对象
- `cliArgs`:启动 Appium 服务器所用 CLI 参数的映射
You can do whatever you want with them inside the `updateServer` method. You might want to
reference how these objects are created and worked with in the BaseDriver code, so that you know
you're not undoing or overriding anything standard and important. But if you insist, you can, with
results you'll need to test! Warning: this should be considered an advanced feature and requires
knowledge of Express, as well as the care not to do anything that could affect the operation of
other parts of the Appium server!
在 `updateServer` 方法中,你可以随心所欲地处理这些对象。建议参考 `BaseDriver` 代码中创建及使用这些对象的方式,以确保不会破坏或覆盖任何标准且关键的功能。当然,如果你执意要这样做也是可以的,但务必进行充分测试以验证结果!警告:这属于高级功能,需要你具备 Express 相关知识;同时请务必小心,确保所做的修改不会影响 Appium 服务器其他部分的正常运行!
`updateServer` runs _after_ Appium's own routes are registered, so `expressApp.use(...)` here
won't see requests to paths Appium already owns — Express matches middleware and routes in
registration order. For middleware that must see requests to those routes too (e.g. logging or
auth), use `httpServer.frontRouter` instead: Appium mounts this
[Router](https://expressjs.com/en/5x/api/router/) before any route is registered, so anything
attached to it — even from inside `updateServer` — still runs ahead of route matching. Note this
is still _after_ Appium's own baseline middleware (CORS, WebSocket upgrade handling, body
parsing, etc.), so it won't see requests Appium itself has already rejected, e.g. a CORS
preflight failure or a body that failed to parse:
`updateServer` 在 Appium 自身的路由注册完成后执行,因此此处通过 `expressApp.use(...)` 添加的中间件无法捕获那些已被 Appium 占用的路径请求——Express 是按照注册顺序来匹配中间件和路由的。如果某些中间件必须能够处理这些路径的请求(例如日志记录或身份验证),请改用 `httpServer.frontRouter`:Appium 会在所有路由注册之前挂载该[路由](https://expressjs.com/en/5x/api/router/),因此挂载到它上面的任何内容(即使是在 `updateServer` 内部添加的)也都会在路由匹配之前执行。需要注意的是,这仍然发生在 Appium 基础中间件(如 CORS 处理、WebSocket 升级处理、请求体解析等)之后;因此,如果请求已被 Appium 本身拒绝(例如 CORS 预检失败或请求体解析失败),这些中间件将无法捕获到此类请求。
```js
static async updateServer(expressApp, httpServer, cliArgs) {
@@ -517,16 +374,9 @@ static async updateServer(expressApp, httpServer, cliArgs) {
}
```
### Handle unexpected session shutdown
### 处理会话意外关闭
When developing a plugin you may want to add some cleanup logic for when a session ends. You would
naturally do this by adding a handler for `deleteSession`. This works in most cases, except when
the session does not finish cleanly. Appium sometimes determines that a session has finished
unexpectedly, and in these situations, Appium will look for a method called `onUnexpectedShutdown`
in your plugin class, which will be called (passing the current session driver as the first
parameter, and the error object representing the cause of the shutdown as the second), giving you
an opportunity to take any steps that might be necessary to clean up from the session. For example,
keeping in mind that the function is not `await`ed you could implement something like this:
在开发插件时,你可能需要在会话结束时执行一些清理逻辑。通常,你可以通过为 `deleteSession` 添加处理程序来实现这一点。这种方法在大多数情况下都有效,但如果会话未能正常结束,则不适用。 Appium 有时会判定会话已异常终止;在这种情况下,Appium 会在你的插件类中查找名为 `onUnexpectedShutdown` 的方法并将其调用(该方法接收两个参数:第一个是当前的会话驱动程序,第二个是导致终止的错误对象)。这让你有机会执行必要的清理操作。考虑到该函数不会被 `await`(即不会等待其执行完成),你可以按如下方式进行实现:
```js
async onUnexpectedShutdown(driver, cause) {
@@ -538,11 +388,6 @@ async onUnexpectedShutdown(driver, cause) {
}
```
### Send messages to the driver or other plugins running on the same session
### 向同一会话中运行的驱动程序或其他插件发送消息
Even though drivers and plugins don't know anything about each other, it's possible for them to
send messages that other drivers or plugins can listen for, within the context of the same session,
using an IPC channel. Given that the developer instructions for this feature are the same for
drivers and plugins, please head over to the IPC development docs for
drivers at the driver
development guide.
尽管驱动程序和插件彼此并不了解,但它们仍可在同一会话的上下文中,通过 IPC(进程间通信)通道发送消息,供其他驱动程序或插件接收。针对此功能的开发说明对于驱动程序和插件而言是相同的,请参阅“驱动程序开发指南”中有关[驱动程序](./build-drivers.md#send-messages-to-plugins-running-on-the-same-session) IPC 开发的文档。

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