Compare commits

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

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

* Fix typos in security documentation

* Update security.md for multiple insecure features

Clarified section on enabling multiple insecure features for drivers.

* Update security.md to remove insecure feature examples

Removed examples of insecure feature commands.

* Remove section on multiple insecure features

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

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

* Update lockfile

---------

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

* update lock

---------

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

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

* fix: linter errors

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Mykola Mokhnach <mokhnach@gmail.com>
2025-11-15 13:36:18 +01:00
renovate[bot] a09c85e59e chore(support): update dependency which to v6 (#21720)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 12:49:37 +02:00
renovate[bot] 050bad8f12 chore(deps): update dependency @types/yargs to v17.0.35 (#21717)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 08:37:55 +00:00
renovate[bot] 38c918711a chore(universal-xml-plugin): update dependency fast-xml-parser to v5.3.2 (#21716)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 00:44:07 +00:00
renovate[bot] 982d33e318 chore(deps): update dependency lerna to v9.0.1 (#21715)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 18:30:00 +00:00
renovate[bot] 46bd0512d7 chore(deps): update dependency @types/sinon to v20 (#21714)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 08:42:26 +02:00
renovate[bot] 4d8189d68a chore(driver-test-support): update dependency chai to v6.2.1 (#21712)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-13 00:43:36 +00:00
renovate[bot] e357a55ebc chore(deps): update dependency @types/node to v24.10.1 (#21711)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 18:07:03 +00:00
renovate[bot] 1dff1300e6 chore(docutils): update dependency mkdocs-material to v9.7.0 (#21710)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 04:33:06 +00:00
74 changed files with 3404 additions and 3658 deletions
+10 -19
View File
@@ -15,10 +15,6 @@ inputs:
description: Whether to run npm run build
required: false
default: 'true'
clear-v8-cache:
description: Whether to clear V8 code cache (for Node.js 24+ compatibility)
required: false
default: 'true'
runs:
using: composite
@@ -28,23 +24,18 @@ runs:
with:
node-version: ${{ inputs.node-version }}
cache: npm
- name: Install dependencies
uses: bahmutov/npm-install@v1
- name: SocketDev Security Check
uses: SocketDev/action@v1
with:
useRollingCache: true
install-command: ${{ inputs.install-command }}
mode: firewall-free
- name: Install dependencies
shell: bash
run: |
# Replace npm with sfw npm in the install command
install_cmd="${{ inputs.install-command }}"
install_cmd="${install_cmd//npm /sfw npm }"
$install_cmd
- name: Build packages
if: ${{ inputs.run-build == 'true' }}
shell: bash
run: npm run build
- name: Clear V8 code cache
if: ${{ inputs.clear-v8-cache == 'true' }}
shell: bash
run: |
# Clear V8 code cache to avoid bytecode deserialization errors
if [[ -d "$HOME/.node" ]]; then
rm -rf "$HOME/.node"/* 2>/dev/null || true
fi
if [[ -d "$HOME/.cache/node" ]]; then
rm -rf "$HOME/.cache/node"/* 2>/dev/null || true
fi
+7 -18
View File
@@ -54,20 +54,14 @@ concurrency:
jobs:
prepare_matrix:
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@v1
uses: appium/appium-workflows/.github/workflows/node-lts-matrix.yml@main
prepare_e2e_packages:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.discover-packages.outputs.packages }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Discover packages with e2e tests
id: discover-packages
run: |
@@ -116,14 +110,13 @@ jobs:
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
install-command: npm ci --foreground-scripts
run-build: 'true'
clear-v8-cache: 'true'
- name: Run smoke tests
run: npm run test:smoke
@@ -136,14 +129,13 @@ jobs:
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
install-command: npm ci --foreground-scripts
run-build: 'true'
clear-v8-cache: 'true'
- name: Run unit tests
run: npm run test:unit
@@ -156,14 +148,13 @@ jobs:
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
install-command: npm ci --foreground-scripts
run-build: 'true'
clear-v8-cache: 'true'
- name: Run type tests
run: npm run test:types
@@ -180,14 +171,13 @@ jobs:
package_dir: ${{ fromJSON(needs.prepare_e2e_packages.outputs.packages) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup, install and build
uses: ./.github/actions/setup-build
with:
node-version: ${{ matrix.node-version }}
install-command: npm ci --foreground-scripts
run-build: 'true'
clear-v8-cache: 'true'
- name: Run E2E tests for ${{ matrix.package_dir }}
run: |
set -o pipefail
@@ -198,13 +188,12 @@ jobs:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup and install (no build)
uses: ./.github/actions/setup-build
with:
node-version: lts/*
install-command: npm ci
run-build: 'false'
clear-v8-cache: 'false'
- name: ESLint
run: npm run lint:ci
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Cleanup
run: |
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
project_name: appium-inspector
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Use Node.js LTS
uses: actions/setup-node@v6
with:
@@ -12,7 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Use Node.js LTS
uses: actions/setup-node@v6
with:
@@ -27,7 +29,7 @@ jobs:
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_DOCS_PROJECT_ID }}
CROWDIN_TOKEN: ${{ secrets.CROWDIN_DOCS_TOKEN }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7.0.8
uses: peter-evans/create-pull-request@v7.0.9
with:
token: ${{ github.token }}
commit-message: 'docs(appium): Update documentation translations'
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Use Node.js LTS
uses: actions/setup-node@v6
with:
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
name: Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install dependencies (Node.js)
uses: bahmutov/npm-install@v1
with:
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
env:
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
ref: master
- name: Install dependencies
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Use Node.js LTS
uses: actions/setup-node@v6
with:
+4 -9
View File
@@ -4,12 +4,7 @@ on:
types: [opened, edited, synchronize, reopened]
jobs:
conventional:
name: PR Title
runs-on: ubuntu-latest
steps:
- uses: beemojs/conventional-pr-action@v3
with:
config-preset: angular
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
lint:
uses: appium/appium-workflows/.github/workflows/pr-title.yml@main
with:
config-preset: angular
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: |
git config user.name github-actions
git config user.email github-actions@github.com
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
name: Check Renovate Configs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Validate Renovate Config
uses: rinchsan/renovate-config-validator@v0.2.0
with:
+2519 -3156
View File
File diff suppressed because it is too large Load Diff
+15 -15
View File
@@ -86,7 +86,7 @@
"devDependencies": {
"@colors/colors": "1.6.0",
"@eslint/js": "9.39.1",
"@tsconfig/node20": "20.1.6",
"@tsconfig/node20": "20.1.8",
"@types/argparse": "2.0.17",
"@types/archiver": "7.0.0",
"@types/async-lock": "1.4.2",
@@ -94,22 +94,22 @@
"@types/bluebird": "3.5.42",
"@types/chai": "5.2.3",
"@types/chai-as-promised": "8.0.2",
"@types/express": "5.0.5",
"@types/express": "5.0.6",
"@types/jsftp": "2.1.5",
"@types/json-schema": "7.0.15",
"@types/klaw": "3.0.7",
"@types/lockfile": "1.0.4",
"@types/lodash": "4.17.20",
"@types/lodash": "4.17.21",
"@types/method-override": "3.0.0",
"@types/mocha": "10.0.10",
"@types/mv": "2.1.4",
"@types/ncp": "2.0.8",
"@types/node": "24.10.0",
"@types/node": "24.10.1",
"@types/pluralize": "0.0.33",
"@types/semver": "7.7.1",
"@types/serve-favicon": "2.5.7",
"@types/shell-quote": "1.7.5",
"@types/sinon": "17.0.4",
"@types/sinon": "21.0.0",
"@types/sinon-chai": "4.0.0",
"@types/source-map-support": "0.5.10",
"@types/supports-color": "8.1.3",
@@ -118,9 +118,9 @@
"@types/wrap-ansi": "3.0.0",
"@types/ws": "8.18.1",
"@types/xmldom": "0.1.34",
"@types/yargs": "17.0.34",
"@types/yargs": "17.0.35",
"asyncbox": "3.0.0",
"chai": "6.2.0",
"chai": "6.2.1",
"chai-as-promised": "8.0.2",
"conventional-changelog-conventionalcommits": "7.0.2",
"cpy-cli": "6.0.0",
@@ -129,30 +129,30 @@
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-typescript": "4.4.4",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-mocha": "10.5.0",
"eslint-plugin-mocha": "11.2.0",
"eslint-plugin-promise": "7.2.1",
"finalhandler": "2.1.0",
"finalhandler": "2.1.1",
"get-port": "5.1.1",
"json-schema-to-typescript": "15.0.4",
"lerna": "9.0.0",
"lerna": "9.0.3",
"log-symbols": "4.1.0",
"midnight-smoker": "8.0.0",
"mjpeg-consumer": "2.0.0",
"mjpeg-server": "0.3.1",
"mocha": "11.7.5",
"npm-run-all2": "8.0.4",
"prettier": "3.6.2",
"prettier": "3.7.4",
"rewiremock": "3.14.6",
"rimraf": "6.1.0",
"rimraf": "6.1.2",
"serve-static": "2.2.0",
"sinon": "21.0.0",
"sync-monorepo-packages": "1.0.2",
"teen_process": "3.0.2",
"teen_process": "3.0.4",
"ts-node": "10.9.2",
"tsd": "0.33.0",
"typescript": "5.9.3",
"typescript-eslint": "8.46.4",
"webdriverio": "9.20.0",
"typescript-eslint": "8.48.1",
"webdriverio": "9.21.0",
"ws": "8.18.3",
"yaml-js": "0.3.1"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.1.2](https://github.com/appium/appium/compare/appium@3.1.1...appium@3.1.2) (2025-12-04)
**Note:** Version bump only for package appium
## [3.1.1](https://github.com/appium/appium/compare/appium@3.1.0...appium@3.1.1) (2025-11-12)
@@ -0,0 +1,36 @@
---
authors:
- sai
- srini
date: 2025-11-25
---
# Announcing LambdaTest as Appium's Newest Development Partner
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
<!-- more -->
<div style="text-align:center;width:100%">
<a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
</a>
</div>
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
About LambdaTest
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
+19 -13
View File
@@ -4,7 +4,7 @@ title: Appium Server Security
The Appium team makes every effort to ensure the security of the Appium server. This is especially
important when Appium is run in a multitenant environment, or when multiple users are running
sessions on the same Appium server. In general, you can only safely enable all Appium's features if
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
all the following are true:
- You're running your own Appium server locally or within a protected internal network
@@ -12,18 +12,18 @@ all the following are true:
- You don't expose Appium's port(s) to the wider internet
But because many Appium users might not be able to guarantee such a safe environment, the Appium
team puts many features behind a security protection mechanism which forces system admins (the
people that are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
team puts many features behind a security protection mechanism, which forces system admins (the
people who are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
(Third-party driver and plugin authors can also [hide behaviour behind security
flags](../developing/build-drivers.md).)
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities;
this is the responsibility of the server admin who configures and launches the Appium server.
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities.
This is the responsibility of the server admin who configures and launches the Appium server.
## Security Server Args
The [Server CLI](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
Appium when starting it from the command line:
Appium, when starting it from the command line:
|<div style="width:10em">Parameter</div>|Description|
|---------------------------------------|-----------|
@@ -44,7 +44,7 @@ to the `bar` feature for all drivers.
## Insecure Features
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
Each Appium driver is responsible for its own security, and can create its own feature names. Thus,
you should read through the documentation for a particular driver to know which feature names it
might use. Here is an incomplete list of examples from some of Appium's official drivers:
@@ -53,10 +53,10 @@ might use. Here is an incomplete list of examples from some of Appium's official
|`get_server_logs`|Allows retrieving of Appium server logs via the Webdriver log interface|IOS, XCUITest, Android, UiAutomator2, Espresso|
|`adb_shell`|Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command|Android, UiAutomator2, Espresso|
|`record_audio`|Allow recording of host machine audio inputs|XCUITest|
|`execute_driver_script`| Allows to send a request which has multiple Appium commands.|Execute Driver Plugin|
|`execute_driver_script`| Allows sending a request that has multiple Appium commands.|Execute Driver Plugin|
Some insecure features operate on the server level, and do not require a driver session. Enabling
these features requires using the wildcard prefix:
Some insecure features operate on the server level and do not require a driver session. Enabling
these features require using the wildcard prefix:
|<div style="width:12em">Feature Name</div>|Description|
|------------|-----------|
@@ -73,17 +73,23 @@ appium --allow-insecure=first:foo
Turn on the `foo` feature for all drivers:
```bash
appium --allow-insecure=*:foo
appium --allow-insecure='*:foo'
```
Turn on the `foo` feature for all drivers _except_ `first`:
```bash
appium --allow-insecure=*:foo --deny-insecure=first:foo
appium --allow-insecure='*:foo' --deny-insecure=first:foo
```
Turn on all features _except_ `foo` for all drivers:
```bash
appium --relaxed-security --deny-insecure=*:foo
appium --relaxed-security --deny-insecure='*:foo'
```
Turn on multiple insecure features for specific drivers:
```bash
appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs
```
@@ -0,0 +1,34 @@
---
authors:
- sai
- srini
date: 2025-11-25
---
# Announcing LambdaTest as Appium's Newest Development Partner
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
<!-- more -->
<div style="text-align:center;width:100%"><a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
</a>
</div>
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
About LambdaTest
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
+19 -13
View File
@@ -4,7 +4,7 @@ title: Appium Server Security
The Appium team makes every effort to ensure the security of the Appium server. This is especially
important when Appium is run in a multitenant environment, or when multiple users are running
sessions on the same Appium server. In general, you can only safely enable all Appium's features if
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
all the following are true:
- You're running your own Appium server locally or within a protected internal network
@@ -12,18 +12,18 @@ all the following are true:
- You don't expose Appium's port(s) to the wider internet
But because many Appium users might not be able to guarantee such a safe environment, the Appium
team puts many features behind a security protection mechanism which forces system admins (the
people that are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
team puts many features behind a security protection mechanism, which forces system admins (the
people who are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
(Third-party driver and plugin authors can also hide behaviour behind security
flags.)
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities;
this is the responsibility of the server admin who configures and launches the Appium server.
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities.
This is the responsibility of the server admin who configures and launches the Appium server.
## Security Server Args
The [Server CLI](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
Appium when starting it from the command line:
Appium, when starting it from the command line:
| <div style="width:10em">Parameter</div> | Description |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -44,7 +44,7 @@ to the `bar` feature for all drivers.
## Insecure Features
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
Each Appium driver is responsible for its own security, and can create its own feature names. Thus,
you should read through the documentation for a particular driver to know which feature names it
might use. Here is an incomplete list of examples from some of Appium's official drivers:
@@ -53,10 +53,10 @@ might use. Here is an incomplete list of examples from some of Appium's official
| `get_server_logs` | Allows retrieving of Appium server logs via the Webdriver log interface | IOS, XCUITest, Android, UiAutomator2, Espresso |
| `adb_shell` | Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command | Android, UiAutomator2, Espresso |
| `record_audio` | Allow recording of host machine audio inputs | XCUITest |
| `execute_driver_script` | Allows to send a request which has multiple Appium commands. | Execute Driver Plugin |
| `execute_driver_script` | Allows sending a request that has multiple Appium commands. | Execute Driver Plugin |
Some insecure features operate on the server level, and do not require a driver session. Enabling
these features requires using the wildcard prefix:
Some insecure features operate on the server level and do not require a driver session. Enabling
these features require using the wildcard prefix:
| <div style="width:12em">Feature Name</div> | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------- |
@@ -73,17 +73,23 @@ appium --allow-insecure=first:foo
Turn on the `foo` feature for all drivers:
```bash
appium --allow-insecure=*:foo
appium --allow-insecure='*:foo'
```
Turn on the `foo` feature for all drivers _except_ `first`:
```bash
appium --allow-insecure=*:foo --deny-insecure=first:foo
appium --allow-insecure='*:foo' --deny-insecure=first:foo
```
Turn on all features _except_ `foo` for all drivers:
```bash
appium --relaxed-security --deny-insecure=*:foo
appium --relaxed-security --deny-insecure='*:foo'
```
Turn on multiple insecure features for specific drivers:
```bash
appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs
```
@@ -0,0 +1,34 @@
---
authors:
- sai
- srini
date: 2025-11-25
---
# Announcing LambdaTest as Appium's Newest Development Partner
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
<!-- more -->
<div style="text-align:center;width:100%"><a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
</a>
</div>
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
About LambdaTest
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
+19 -13
View File
@@ -4,7 +4,7 @@ title: Appium Server Security
The Appium team makes every effort to ensure the security of the Appium server. This is especially
important when Appium is run in a multitenant environment, or when multiple users are running
sessions on the same Appium server. In general, you can only safely enable all Appium's features if
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
all the following are true:
- You're running your own Appium server locally or within a protected internal network
@@ -12,18 +12,18 @@ all the following are true:
- You don't expose Appium's port(s) to the wider internet
But because many Appium users might not be able to guarantee such a safe environment, the Appium
team puts many features behind a security protection mechanism which forces system admins (the
people that are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
team puts many features behind a security protection mechanism, which forces system admins (the
people who are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
(Third-party driver and plugin authors can also hide behaviour behind security
flags.)
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities;
this is the responsibility of the server admin who configures and launches the Appium server.
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities.
This is the responsibility of the server admin who configures and launches the Appium server.
## Security Server Args
The [Server CLI](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
Appium when starting it from the command line:
Appium, when starting it from the command line:
| <div style="width:10em">Parameter</div> | Description |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -44,7 +44,7 @@ to the `bar` feature for all drivers.
## Insecure Features
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
Each Appium driver is responsible for its own security, and can create its own feature names. Thus,
you should read through the documentation for a particular driver to know which feature names it
might use. Here is an incomplete list of examples from some of Appium's official drivers:
@@ -53,10 +53,10 @@ might use. Here is an incomplete list of examples from some of Appium's official
| `get_server_logs` | Allows retrieving of Appium server logs via the Webdriver log interface | IOS, XCUITest, Android, UiAutomator2, Espresso |
| `adb_shell` | Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command | Android, UiAutomator2, Espresso |
| `record_audio` | Allow recording of host machine audio inputs | XCUITest |
| `execute_driver_script` | Allows to send a request which has multiple Appium commands. | Execute Driver Plugin |
| `execute_driver_script` | Allows sending a request that has multiple Appium commands. | Execute Driver Plugin |
Some insecure features operate on the server level, and do not require a driver session. Enabling
these features requires using the wildcard prefix:
Some insecure features operate on the server level and do not require a driver session. Enabling
these features require using the wildcard prefix:
| <div style="width:12em">Feature Name</div> | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------- |
@@ -73,17 +73,23 @@ appium --allow-insecure=first:foo
Turn on the `foo` feature for all drivers:
```bash
appium --allow-insecure=*:foo
appium --allow-insecure='*:foo'
```
Turn on the `foo` feature for all drivers _except_ `first`:
```bash
appium --allow-insecure=*:foo --deny-insecure=first:foo
appium --allow-insecure='*:foo' --deny-insecure=first:foo
```
Turn on all features _except_ `foo` for all drivers:
```bash
appium --relaxed-security --deny-insecure=*:foo
appium --relaxed-security --deny-insecure='*:foo'
```
Turn on multiple insecure features for specific drivers:
```bash
appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs
```
+52 -161
View File
@@ -1,200 +1,91 @@
---
title: How Does Appium Work?
title: Appium 如何工作?
---
As mentioned on the main page, Appium is an open-source project and ecosystem of related software,
designed to facilitate UI automation of many app platforms. With the release of Appium 2, Appium
has the following primary goals:[^1]
正如主页所述,Appium 是一个开源项目和相关软件生态系统,旨在促进多种应用平台的 UI 自动化。 随着 Appium 2 的发布,Appium 具有以下主要目标:[^1]
- Make platform-specific automation capabilities available under a cross-platform, standard API
- Allow easy access to this API from any programming language
- Provide tools to enable convenient community development of Appium extensions
- 在跨平台标准 API 下提供特定于平台的自动化功能
- 允许从任何编程语言轻松访问此 API
- 提供工具以便社区方便地开发 Appium 扩展
[^1]: To meet these primary goals, we also work with a set of secondary goals or methodology
principles, which we also encourage for Appium extension developers:
[^1]: 为实现这些主要目标,我们还遵循一套次要目标或方法原则,我们也鼓励 Appium 扩展开发者遵循这些原则:
- As far as possible, rely on (and contribute to) open source technology
- As far as possible, rely on vendor-provided tools for a given platform
- As far as possible, rely on automation tools that allow automation of unmodified apps (prefer
not to require the user to build in additional SDKs or software that introduce discrepancies
between the test version of the app and the production version)
- As far as possible, rely on existing standards instead of creating new ones
- 尽可能依赖(并贡献于)开源技术
- 尽可能依赖给定平台的供应商提供的工具
- 尽可能依赖不修改应用就能实现自动化(最好不要要求用户构建额外的 SDK 或软件,从而在测试版本和生产版本之间引入差异)的自动化工具
- 尽可能依赖现有标准而不是创建新标准
So, take any app platform you know about, like iOS or Android. Appium wants for there to be a way
for developers and testers to write UI automation code for that platform, according to a single,
unified API. Based on Appium's goals, we have a lot of questions to answer to make it all work:
所以,以您了解的任何应用平台为例,如 iOS 或 Android。 Appium 希望开发者测试人员能够为该平台编写 UI 自动化代码,根据单一的统一 API。 根据 Appium 的目标,我们有很多问题需要回答以使其全部工作:
- Which API should that "single, unified" API be?
- How do we map that API to automation behaviour for a specific platform?
- How do we make that API accessible via multiple popular programming languages?
- “单一统一”的 API 应该是什么?
- 我们如何将此 API 映射到特定平台的自动化行为?
- 我们如何使此 API 通过多种流行编程语言访问?
There's another, larger, question lurking in the background here too, given that there are more app
platforms out there than just iOS and Android:
这里还有另一个更大的问题,鉴于除了 iOS 和 Android 之外还有更多应用平台:
- How do we enable automation for _all_ the platforms?
- 我们如何为_所有_平台启用自动化?
Exploring Appium's answers to these questions may not be the quickest way to learn what Appium is,
but it is certainly a good one! So let's dive in.
探索 Appium 对这些问题的答案可能不是学习 Appium 是什么的最快方式,但它肯定是一个好方法! 所以让我们深入了解。
## Appium's choice of API
## Appium 的 API 选择
Appium is very fortunate to have been preceded by a technology which has been a long-standing
pioneer in the field of UI automation, namely [Selenium](https://selenium.dev). The goal of the
Selenium project has been to support UI automation of web browsers, and in this way we can think of
it as occupying a subset of Appium's goals. Along the way, Selenium (and, after they merged,
another project called WebDriver) developed a relatively stable API for browser automation.
Appium 非常幸运地继承了一个在 UI 自动化领域长期领先的技术,即 [Selenium](https://selenium.dev)。 Selenium 项目的目标是支持 Web 浏览器的 UI 自动化,因此我们可以将其视为占据 Appium 目标子集的一部分。 在此过程中,Selenium(以及后来合并的另一个名为 WebDriver 的项目)开发了一个相对稳定的浏览器自动化 API。
Over the years, Selenium worked with various web browser vendors and the [W3C](https://w3.org)
standards group to turn its API into an official web browser standard, called the WebDriver
specification. All the main browsers now
implement automation capabilities inline with the WebDriver spec, without the Selenium team having
to maintain any software that performs actual automation; standards for the win!
多年来,Selenium 与各种 Web 浏览器供应商和 [W3C](https://w3.org) 标准小组合作,将其 API 转变为官方 Web 浏览器标准,称为 [WebDriver 规范](https://w3c.github.io/webdriver/)。
所有主要浏览器现在都实现了符合 WebDriver 规范的自动化功能,而无需 Selenium 团队维护任何执行实际自动化的软件;标准获胜!
Appium's initial goals were to develop an automation standard for mobile apps (iOS and Android). We
could have made up something new, but in the spirit of joining forces and keeping standards, well,
standard, we decided to adopt the WebDriver spec as Appium's API.[^2] While user interaction on
websites and in mobile native apps are not entirely identical (with even greater differences once
we start to consider, for example, TV platforms controlled by simple remotes), the fact is that
most software UIs are pretty much the same. This means that the WebDriver spec provides automation
API primitives (finding elements, interacting with elements, loading pages or screens, etc...) that
more or less map to any platform.
Appium 的最初目标是为移动应用(iOS 和 Android)开发自动化标准。 我们本可以发明一些新的东西,但为了团结力量并保持标准的标准化,我们决定采用 WebDriver 规范作为 Appium 的 API。[^2] 虽然网站和移动原生应用的用户交互并不完全相同(一旦我们开始考虑例如由简单遥控器控制的电视平台,差异会更大),但事实是大多数软件 UI 都非常相似。 这意味着 WebDriver 规范提供了自动化 API 原语(查找元素、与元素交互、加载页面或屏幕等) 这些原语或多或少映射到任何平台。
[^2]: Technically, when Appium was first written, we were dealing with something older than the
WebDriver spec, called the JSON Wire Protocol. Since then, Appium continued to evolve along with
the W3C spec and is fully W3C-compliant.
[^2]: 从技术上讲,当 Appium 首次编写时,我们处理的是比 WebDriver 规范更古老的东西,称为 JSON Wire Protocol。 从那时起,Appium 继续与 W3C 规范一起演化,并完全符合 W3C 规范。
Of course, Appium wants to support the cases where user interaction _does_ differ from web to
mobile or web to TV, and so Appium also makes use of the built-in _extensibility_ of the WebDriver
spec. The result is that, no matter what platform you want to automate, when you use Appium, you
will do so using the standard WebDriver spec, with two caveats:
当然,Appium 希望支持用户交互从 Web 到移动或 Web 到电视确实不同的情况,因此 Appium 还利用 WebDriver 规范的内置_可扩展性_。 结果是,无论您想要自动化哪个平台,当您使用 Appium 时,您将使用标准 WebDriver 规范,但有两个注意事项:
- We might not have any way to support a particular WebDriver API command on a given platform, and
so some commands might be unsupported (for example, getting or setting cookies is not possible in
the world of native mobile app automation).
- We might support automation behaviours that go _beyond_ what's available in the WebDriver API
command list, though any such commands will be valid and spec-compliant extensions to the
WebDriver API.
- 我们可能无法在给定平台上支持特定的 WebDriver API 命令,因此某些命令可能不受支持(例如,在原生移动应用自动化世界中,获取或设置 cookie 是不可能的)。
- 我们可能支持超出 WebDriver API 命令列表的自动化行为,尽管任何此类命令将是有效的、符合规范的 WebDriver API 扩展。
How do you actually _use_ the WebDriver API, particularly in the context of Appium? We'll cover
that in the [section below](#universal-programming-language-access) on how Appium provides
universal programming language access. All you need to know for now is that the way Appium
introduces a universal UI automation interface is by implementing the WebDriver protocol.
您实际上如何_使用_ WebDriver API,特别是 Appium 的背景下? 我们将在下面的[部分](#universal-programming-language-access)中介绍 Appium 如何提供通用编程语言访问。 您现在只需要知道 Appium 通过实现 WebDriver 协议来引入通用 UI 自动化接口。
## Platform automation behaviour
## 平台自动化行为
The next question is, how does Appium map this protocol to automation behaviour on a wide range of
platforms? The trick is that, strictly speaking, Appium doesn't! It leaves this responsibility up
to a kind of software module called an Appium _driver_. There's a whole Driver
Introduction which you can read next, so we won't go into huge detail on how they
work for now.
下一个问题是,Appium 如何将此协议映射到广泛平台的自动化行为? 严格来说,Appium 没有! 它将此责任留给一种称为 Appium _驱动程序_ 的软件模块。 您可以阅读整个[驱动程序](./drivers.md)的介绍,所以我们现在不会深入细节。
What's important to understand at the moment is that a driver is kind of like a pluggable module
for Appium that gives Appium the power to automate a particular platform (or set of platforms,
depending on the goal of the driver). At the end of the day, a driver's responsibility is to simply
implement an Appium-internal interface representing the WebDriver protocol. How it implements this
interface is totally up to the driver, based on its strategy for making automation happen on
a specific platform. Typically, and with a lot more complexity and difficulty in the details,
a driver does this by relying on platform-specific automation technologies. For example, Apple
maintains an iOS automation technology called
[XCUITest](https://developer.apple.com/documentation/xctest/user_interface_tests). The Appium
driver that supports iOS app automation is called the XCUITest
Driver because ultimately what it does is
convert the WebDriver protocol to XCUITest library calls.
目前重要的是要理解驱动程序有点像 Appium 的可插拔模块,它赋予 Appium 自动化特定平台(或平台集,取决于驱动程序的目标)的能力。 最终,驱动程序的责任只是实现代表 WebDriver 协议的 Appium 内部接口。 它如何实现此接口完全取决于驱动程序,基于其在特定平台上实现自动化的策略。 通常,在细节上具有更多复杂性和难度,驱动程序通过依赖特定于平台的自动化技术来实现这一点。 例如,Apple 维护一种称为 [XCUITest](https://developer.apple.com/documentation/xctest/user_interface_tests) 的 iOS 自动化技术。 支持 iOS 应用自动化的 Appium 驱动程序称为 [XCUITest 驱动程序](https://github.com/appium/appium-xcuitest-driver),因为它最终所做的是将 WebDriver 协议转换为 XCUITest 库调用。
One of the reasons that drivers are independent, pluggable modules is that they work completely
differently from one another. The tools and requirements for building and using drivers for
different platforms are completely different. And so Appium lets you use just the drivers that you
need for your automation tasks. Choosing drivers and installing them so that you can use them with
your Appium instance is so important that Appium has its very own CLI for managing
drivers.
驱动程序是独立、可插拔模块的原因之一是它们彼此完全不同。 构建和使用不同平台的驱动程序的工具和要求完全不同。 因此,Appium 让您只使用您自动化任务所需的驱动程序。 选择驱动程序并安装它们以便与您的 Appium 实例一起使用非常重要,以至于 Appium 有自己的 [CLI 来管理驱动程序](../reference/cli/extensions.md)。
So, to answer our original question, the way that Appium provides access to automation capabilities
for a given platform is that the Appium team (or anyone else[^3]) writes a _driver_ for that
platform, implementing as much or little of the WebDriver protocol as desired. The driver can then
be installed by anyone using Appium.
因此,为了回答我们最初的问题,Appium 为给定平台提供自动化功能访问的方式是 Appium 团队(或任何人[^3])为该平台编写一个_驱动程序_,实现 WebDriver 协议的尽可能多或少的部分。 然后,任何使用 Appium 的人都可以安装驱动程序。
[^3]: You can build and share your own drivers! Check out Building
Drivers to learn more about how to develop drivers in Node.js
that can be used with Appium.
[^3]: 您可以构建和分享自己的驱动程序! 查看[构建驱动程序](../developing/build-drivers.md)以了解更多关于如何在 Node.js 中开发可与 Appium 一起使用的驱动程序的信息。
## Universal programming language access
## 通用编程语言访问
But what does it mean, or look like, to _use_ Appium, anyway? Since Appium is ultimately a Node.js
program, it _could_ have looked like importing Appium and its drivers as libraries into your own
Node.js programs. But that wouldn't meet Appium's goal of providing automation capabilities to
people using any popular programming language.
但使用 Appium 意味着什么,或者看起来像什么? 由于 Appium 最终是一个 Node.js 程序,它_可以_看起来像将 Appium 及其驱动程序作为库导入到您自己的 Node.js 程序中。 但这不会满足 Appium 的目标,即为使用任何流行编程语言的人提供自动化功能。
Luckily, the fact that Appium rode in on Selenium's coattails meant that we had a solution to this
problem from day one. You see, the WebDriver specification is actually an HTTP-based protocol,
meaning it is designed to be used over a network rather than within the memory of a single program.
幸运的是,Appium 继承 Selenium 的遗产意味着我们从一开始就有了这个问题的解决方案。 您看,WebDriver 规范实际上是一个基于 HTTP 的协议,这意味着它被设计为通过网络而不是单个程序的内存使用。
One of the main benefits of this "client-server" architecture is that it allows the automation
implementer (the thing doing the automation, in this case the 'server') to be completely distinct
from the automation runner (the thing defining what automation should be done, in what steps,
etc..., in this case the 'client'). Basically, all the "hard stuff" (actually figuring out how to
make automation happen on a given platform) can be handled in one place by the server, and "thin"
client libraries can be written in any programming language which simply encode HTTP requests to
the server in language-appropriate way. It's possible, in other words, to bring basic Appium
/ WebDriver capabilities to a new programming language relatively easily, assuming high-level HTTP
libraries exist, simply by coding up a basic HTTP client in that language.
这种“客户端-服务器”架构的主要好处之一是,它允许自动化实现者(执行自动化的事物,在这种情况下是“服务器”)与自动化运行者(定义应该做什么自动化、以什么步骤等的事物,在这种情况下是“客户端”)完全不同。 基本上,所有“困难的东西”(弄清楚如何在给定平台上实现自动化)可以在服务器的一个地方处理,“瘦”客户端库可以在任何编程语言中编写,这些库只需以适合语言的方式编码对服务器的 HTTP 请求。 换句话说,假设存在高级 HTTP 库,只需在该语言中编写基本的 HTTP 客户端,就可以相对容易地将基本的 Appium / WebDriver 功能引入新的编程语言。
There are a couple important takeaways here for you, the Appium user:
这里有几个重要的点供 Appium 用户了解:
- Appium is an _HTTP server_. It must run as a process on some computer for as long as you want to
be able to use it for automation. It must be accessible on the network to whichever computer you
want to use to run the automation from (whether that is the same machine or one across the
world).
- Unless you want to write raw HTTP calls or use cURL, using Appium for automation involves the use
of an [Appium Client](clients.md) in the language of your choice. The goal of each of these
clients is to encapsulate the WebDriver protocol so that rather than worrying about the protocol
itself, you can work with objects and methods that feel idiomatic for your language.
- The Appium server and the Appium client do _not_ need to be running on the same computer. You
simply need to be able to send HTTP requests from the client to the server over some network.
This greatly facilitates the use of cloud providers for Appium, since they can host the Appium
server and any related drivers and devices, and all you need to do is point your client script to
their secure endpoints.
- Appium 是一个_HTTP 服务器_。 只要您想使用它进行自动化,它必须在某台计算机上作为进程运行。 它必须在网络上可访问,以方便您想要运行自动化的任何计算机访问(无论是同一台机器还是世界另一端的机器)。
- 除非您想编写原始 HTTP 调用或使用 cURL,否则请使用您选择的语言的 [Appium 客户端](clients.md)进行自动化。 每个客户端的目标是将 WebDriver 协议封装,以便您不必担心协议本身,而是可以使用感觉适合您语言的对象和方法。
- Appium 服务器和 Appium 客户端_不需要_在同一台计算机上运行。 您只需能够通过某个网络从客户端向服务器发送 HTTP 请求。
这大大促进了云提供商对 Appium 的使用,因为他们可以托管 Appium 服务器以及任何相关驱动程序和设备,您只需将客户端脚本指向他们的安全端点。
And of course, none of this is about "testing" per se, purely about the use of Appium and its
client libraries for automation purposes. If you want to do automation for the purpose of
"testing", you'll likely want to enlist the help of test runners, test frameworks, and the like,
none of which need be related to Appium; one of the benefits of Appium's "universal accessibility"
is that it plays well with whatever set of tools you find most beneficial for your situation.
当然,这一切都不是关于“测试”本身,只是出于自动化目的使用 Appium 及其客户端库。 如果您想出于“测试”目的进行自动化,您可能希望利用测试运行器、测试框架等的帮助,这些都不需要与 Appium 相关;Appium“通用可访问性”的好处之一是它与您发现最适合您情况的任何工具集配合良好。
## Appium's huge scope
## Appium 的巨大范围
Appium's vision (automation of everything under a single API) is huge! Certainly, much bigger than
the team of core maintainers for the open source project. So how does Appium hope to achieve this
goal? Basically, by empowering the community to develop functionality on top of Appium as
a _platform_. This is what we call the Appium "ecosystem".
Appium 的愿景(在单一 API 下自动化一切)是巨大的! 当然,比开源项目的核心维护者团队大得多。 那么 Appium 如何希望实现这一目标? 基本上,通过授权社区在 Appium 之上作为_平台_开发功能。 这就是我们所谓的 Appium“生态系统”。
The Appium team does officially maintain a few drivers itself (for example, the XCUITest driver
that we spoke about earlier). But it cannot hope to have the platform-specific expertise or the
capacity to maintain drivers for many different platforms. But what we have done, particularly
beginning with Appium 2, is to provide tools to empower the community to join in our vision:
Appium 团队确实自己维护了一些驱动程序(例如,我们之前讨论的 XCUITest 驱动程序)。 但它无法拥有特定于平台的专业知识或维护许多不同平台的驱动程序的能力。 但我们所做的,特别是从 Appium 2 开始,是提供工具来授权社区加入我们的愿景:
- Anyone can create a driver simply by creating a Node.js module that conforms to the appropriate
conventions and implements any (sub|super)set of the WebDriver protocol. Creating a driver often
involves a minimal amount of code because the WebDriver protocol details are abstracted away, and
many helper libraries are available---the same libraries that power the Appium team's own
drivers.
- Sharing drivers with others is easy using the Appium driver CLI. There is no central authority.
Anyone can share drivers publicly or privately, for free or for sale. Drivers can be open or
closed source (though obviously we appreciate open source!).
- 任何人都可以通过创建一个符合适当约定并实现 WebDriver 协议的任何(子|超)集的 Node.js 模块来创建驱动程序。 创建驱动程序通常涉及最少的代码,因为 WebDriver 协议细节被抽象化,许多帮助库可用---这些库为 Appium 团队自己的驱动程序提供动力。
- 使用 Appium 驱动程序 CLI 与他人分享驱动程序很容易。 没有中央权威。
任何人都可以公开或私下分享驱动程序,免费或收费。 驱动程序可以是开源或闭源的(尽管我们欣赏开源!)。
Appium's vision of being a platform for development extends beyond the support of automation for
all app platforms. As a popular automation tool, there are many opportunities for integrating
Appium with all kinds of other tools and services. In addition, there are many feature ideas for
Appium, either as a core server or in its incarnation across various drivers, which the core team
will never have time to build. And so, with Appium 2, Appium has released a plugin system that
enables anyone to build and share modules that change how Appium works!
Appium 作为开发平台的愿景超越了对所有应用平台自动化支持。 作为一个流行的自动化工具,有许多机会将 Appium 与各种其他工具和服务集成。 此外,Appium 有许多功能想法,要么作为核心服务器,要么在其各种驱动程序中的化身,核心团队没有足够的时间构建。 因此,Appium 2 发布了一个插件系统,使任何人都可以构建和分享改变 Appium 工作方式的模块!
In the same way that drivers are easily shareable and consumable via the Appium driver CLI, plugins
can be published and consumed via a parallel [Plugin CLI](../reference/cli/extensions.md). Plugins
can do all sorts of things, for example adding the ability for Appium to find and interact with
screen regions based on a template image (as in the images). There are very few
limitations on what you can do with plugins, so you might also be interested in learning how to
[Build Plugins](../developing/build-plugins.md) in Node.js that can be used with Appium.
就像驱动程序可以通过 Appium 驱动程序 CLI 轻松分享和消费一样,插件可以通过[插件 CLI](../reference/cli/extensions.md)发布和消费。 插件可以做各种事情,例如添加 Appium 根据模板图像查找和与屏幕区域交互的能力(例如[图像插件](https://github.com/appium/appium/tree/master/packages/images-plugin))。 插件几乎没有限制,所以您可能也对学习如何在 Node.js 中[构建插件](../developing/build-plugins.md)以与 Appium 一起使用感兴趣。
So that's Appium: an extensible, universal interface for the UI automation of potentially
everything! Read on into some of the specific intro docs for more details, or check out the various
guides to dive into some more general concepts and features of Appium.
所以这就是 Appium:一个可扩展的、潜在一切的 UI 自动化通用接口! 继续阅读一些具体的介绍文档以获取更多细节,或查看各种指南以深入了解 Appium 的一些更一般概念和功能。
+22 -61
View File
@@ -2,57 +2,31 @@
hide:
- toc
title: Intro to Appium Clients
title: Appium 客户端简介
---
For all the reasons discussed in the [main Overview](./appium.md), Appium is based on the W3C
WebDriver specification. This means that
Appium implements a client-server architecture. The server (consisting of Appium itself along with
any drivers or plugins you are using for automation) is connected to the devices under test, and
is actually responsible for making automation happen on those devices. The client (driven by _you_,
the Appium test author) is responsible for sending commands to the server over the network, and
receiving responses from the server as a result. These responses can be used to tell whether
automation commands are successful, or might contain information that you queried about the state
of the application. This document is a conceptual introduction to the client side of this equation.
出于[概述](./appium.md)中讨论的所有原因,Appium 基于 [W3C WebDriver 规范](https://w3c.github.io/webdriver/)。 这意味着 Appium 实现了客户端-服务器架构。 服务器(由 Appium 本身以及您用于自动化的任何驱动程序或插件组成)连接到测试设备,并实际负责在这些设备上实现自动化。 客户端(由_您_驱动,Appium 测试作者)负责通过网络向服务器发送命令,并接收来自服务器的响应。 这些响应可用于判断自动化命令是否成功,或可能包含您查询的关于应用程序状态的信息。 本文档是对客户端方面的概念性介绍。
!!! info
```
For more about the server side of the equation (i.e., how does Appium actually control
devices?), check out our [Intro to Appium Drivers](./drivers.md). To skip to a list of links to
Appium client libraries, check out the [list of clients](../ecosystem/clients.md).
有关服务器端的信息(即 Appium 如何实际控制设备?),请查看我们的 [Appium 驱动程序简介](./drivers.md)。要跳转到 Appium 客户端库链接列表,请查看[客户端列表](../ecosystem/clients.md)。
```
What sorts of automation commands are available? That is up to the particular driver and plugins
that you are using in any given session. A standard set of commands would include, for example, the
following:
有哪些自动化命令可用? 那取决于您在任何给定会话中使用的特定驱动程序和插件。 一组标准命令可能包括以下内容:
- Find Element
- Click Element
- Get Page Source
- Take Screenshot
- 查找元素
- 点击元素
- 获取页面源代码
- 截取屏幕截图
If you look at these commands in the WebDriver specification, you'll notice that they are not
defined in terms of any particular programming language. They are not Java commands, or JavaScript
commands, or Python commands. Instead, they form part of an HTTP API which can be accessed from
within _any_ programming language (or none! you could just use cURL if you want).
如果您查看 WebDriver 规范中的这些命令,您会注意到它们不是以任何特定编程语言定义的。 它们不是 Java 命令、JavaScript 命令或 Python 命令。 相反,它们形成了可以通过_任何_编程语言访问的 HTTP API( 如果您愿意,您可以只使用 cURL)。
So, for example, the `Find Element` command corresponds to an HTTP `POST` request sent to the HTTP
endpoint `/session/:sessionid/element` (where in this case, `:sessionid` is a placeholder for the
unique session ID generated by the server in a previous call to `Create Session`).
例如,`查找元素`命令对应于发送到 HTTP 端点 `/session/:sessionid/element` 的 HTTP `POST` 请求(其中`:sessionid` 是服务器在之前 `创建会话` 调用中生成的唯一会话 ID 的占位符)。
This information is primarily useful for people developing technology that works with the WebDriver
spec. It's not particularly useful for people trying to write Appium or Selenium tests. When you
write an Appium test, you want to use a programming language you're familiar with. Luckily, there
exist a set of [Appium client libraries](../ecosystem/clients.md)[^1] that take care of the
responsibility of speaking HTTP to the Appium server. Instead, they expose a set of "native"
commands for a particular programming language, so that, to the test author, it just feels like
you're writing Python, or JavaScript, or Java.
此信息主要对开发与 WebDriver 规范一起工作的技术的人有用。 它对试图编写 Appium 或 Selenium 测试的人不是特别有用。 当您编写 Appium 测试时,您希望使用您熟悉的编程语言。 幸运的是,存在一组 [Appium 客户端库](../ecosystem/clients.md)[^1],它们负责向 Appium 服务器发起HTTP 的请求。 它们为特定编程语言公开了一组“原生”命令,以便对测试作者来说,它就像您在编写 Python、JavaScript 或 Java。
As an example, here's the same simple set of Appium commands in five different programming
languages, using the recommended Appium client binding for each language (note that this is not
working sample code including all appropriate imports; see each client library's instructions for
setup and command reference):
以下是使用 Appium 客户端在五种不同编程语言中实现相同的 Appium 命令集的示例(注意,这不是包含所有导入的工作示例代码;请参阅每个客户端库的设置和命令参考说明):
\=== "JavaScript (Webdriver.io)"
@@ -109,31 +83,18 @@ System.Console.WriteLine(driver.PageSource);
```
````
Each of these scripts, despite being in different languages, does the same thing under the hood:
尽管这些脚本使用不同的编程语言,但它们在底层做的事情是相同的:
1. Call `Find Element` with a `using` parameter of `xpath` and a `value` parameter expressing the
XPath query used to find an element. (If you're confused about these terms, you might find an
introduction to Appium or Selenium useful)
2. Call `Click Element` with the ID of the element found in the previous call.
3. Call `Get Element Text` with the ID of the same element, and print it to the console.
4. Call `Get Page Source` to retrieve the page/app source and print it to the console.
1. 调用 `Find Element`,使用 `using` 参数值为 `xpath`,以及 `value` 参数表达用于查找元素的 XPath 查询。 (如果你对这些术语感到困惑,可以参考 Appium 或 Selenium 的入门介绍)
2. 使用在上一次调用中找到的元素 ID 调用 `Click Element`。
3. 使用同一元素的 ID 调用 `Get Element Text`,并将其打印到控制台。
4. 调用 `Get Page Source` 来检索页面/应用程序源代码并将其打印到控制台。
The only other thing to keep in mind before choosing or using a client is that each client is
independently maintained. Just because a feature is available in one client, it doesn't mean it's
available in another client (though all clients support at least the standard W3C protocol plus any
common appium extensions). Just because one client has a nice set of helper functions, doesn't mean
another will. Some clients are kept very frequently up to date, and others are not! So when
thinking about choosing a library, the first consideration is the language you want to use, and the
second consideration is how full-featured and well-maintained the library is!
在选择或使用客户端之前,需要记住的另一件事是每个客户端都是独立维护的。 仅仅因为某个功能在一个客户端中可用,并不意味着它在另一个客户端中也可用(尽管所有客户端至少支持标准的 W3C 协议以及任何常见的 Appium 扩展)。 仅仅因为一个客户端有一套很好的辅助函数,并不意味着另一个客户端也会有。 有些客户端更新非常频繁,而其他客户端则不然! 因此,在考虑选择一个库时,首要考虑的是你想使用的语言,第二个考虑因素是该库的功能完善程度和维护情况!
To learn how to use an Appium client, visit that client's homepage to learn more. In many cases,
the Appium client for a given language is built _on top of_ the _Selenium_ client for that
language, and so certain Appium clients may only document the features which the Appium client
added on top of the Selenium client. All that to say, for a full reference, you may need to visit
both the Appium client documentation as well as the Selenium client documentation.
要学习如何使用 Appium 客户端,请访问该客户端的主页以了解更多信息。 在许多情况下,特定语言的 Appium 客户端是在该语言的 _Selenium_ 客户端之上构建的,因此某些 Appium 客户端可能只记录 Appium 客户端在 Selenium 客户端基础上添加的功能。 也就是说,要获得完整的参考,你可能需要访问 Appium 客户端文档以及 Selenium 客户端文档。
That's all you need to know about Appium clients! Head over to the
[Clients](../ecosystem/clients.md) page to check out the current list of clients.
这就是你需要了解的关于 Appium 客户端的全部内容! 前往 [客户端](../ecosystem/clients.md) 页面查看当前的客户端列表。
[^1]: These libraries are alternately called "clients", "client libraries", or "client bindings".
They all mean the same thing!
[^1]: 这些库也被称为"客户端"、"客户端库"或"客户端绑定"。
它们的意思都是一样的!
@@ -1,81 +1,64 @@
---
title: Install the UiAutomator2 Driver
title: 安装 UiAutomator2 驱动程序
---
You can't do much with Appium unless you have a [driver](../intro/drivers.md), which is an
interface that allows Appium to automate a particular platform.
除非您有[驱动程序](../intro/drivers.md),否则您无法使用 Appium 做太多事情,驱动程序是一个允许 Appium 自动化特定平台的接口。
!!! info
```
For this quickstart guide, we're going to be automating an app on the Android platform, because
the system requirements for Android automation via Appium are the same as for Appium itself
(whereas the iOS driver, for example, requires you to be using macOS).
对于这个快速入门指南,我们将在 Android 平台上自动化一个应用,因为通过 Appium 进行 Android 自动化的系统要求与 Appium 本身相同(而 iOS 驱动程序,则要求您使用 macOS)。
```
The driver we're going to use is called the UiAutomator2
Driver. It's worth visiting that driver's
documentation and bookmarking it, because it will be an invaluable reference down the line.
我们要使用的驱动程序称为 [UiAutomator2 驱动程序](https://github.com/appium/appium-uiautomator2-driver)。 请访问该驱动程序的文档并将其加入书签,因为它将成为未来宝贵的参考。
## Set up Android automation requirements
## 设置 Android 自动化要求
According to the driver, in addition to a working Appium server, we also need to set up the following:
根据驱动程序,除了工作 Appium 服务器,我们还需要设置以下内容:
### Android SDK
- The easiest way to set up the Android SDK requirements is by downloading [Android Studio](https://developer.android.com/studio).
We need to use its SDK manager (_Settings -> Languages & Frameworks -> Android SDK_)
to download the following items:
- Android SDK Platform (select whichever Android platform we want to automate, for example, API level 30)
- Android SDK Platform-Tools
- If you wish, you can also download these items without Android Studio:
- Android SDK Platform can be downloaded using `sdkmanager` included in [Android command-line tools](https://developer.android.com/studio#command-line-tools-only)
- [Android SDK Platform-Tools](https://developer.android.com/tools/releases/platform-tools)
- Set up the `ANDROID_HOME` environment variable to point to the directory where the Android SDK is
installed. You can usually find the path to this directory in the Android Studio SDK manager. It
will contain the `platform-tools` and other directories.
- 设置 Android SDK 的最简单方法是下载 [Android Studio](https://developer.android.com/studio)。
我们需要使用其 SDK 管理器(_设置 -> 语言和框架 -> Android SDK_)下载以下项目:
- Android SDK 平台(选择我们想要自动化的任何 Android 平台,例如 API 级别 30)
- Android SDK 平台工具
- 如果您愿意,您也可以在没有 Android Studio 的情况下下载这些项目:
- Android SDK 平台可以使用包含在 [Android 命令行工具](https://developer.android.com/studio#command-line-tools-only) 中的 `sdkmanager` 下载
- [Android SDK 平台工具](https://developer.android.com/tools/releases/platform-tools)
- 设置 `ANDROID_HOME` 环境变量指向安装 Android SDK 的目录。 您通常可以在 Android Studio SDK 管理器中找到此目录的路径。 它将包含 `platform-tools` 和其他目录。
### Java JDK
- Install the Java JDK (for the most recent Android API levels, JDK 9 is required, otherwise JDK
8 is required). You can download this from [Oracle](https://jdk.java.net/) or [Adoptium](https://adoptium.net/en-GB/temurin/releases/).
Make sure you get the JDK and not the JRE.
- Set up the `JAVA_HOME` environment variable to point to the JDK home directory. It will contain
the `bin`, `include`, and other directories.
- 安装 Java JDK(对于最新的 Android API 级别,需要 JDK 9,否则请用 JDK 8)。 您可以从 [Oracle](https://jdk.java.net/) 或 [Adoptium](https://adoptium.net/en-GB/temurin/releases/) 下载此软件。
确保您获得 JDK 而不是 JRE。
- 设置 `JAVA_HOME` 环境变量指向 JDK 主目录。 它将包含 `bin`、`include` 和其他目录。
### Prepare the Device
### 准备设备
- If using an emulator, use Android Studio to create and launch an Android Virtual Device (AVD).
You may need to download the system images for the API level of the emulator you want to
create. Using the AVD creation wizard in Android Studio is generally the easiest way to do all of
this.
- If using a real device, you should [set it up for development and enable USB Debugging](https://developer.android.com/studio/debug/dev-options).
- With the emulator or device connected, you can run `adb devices` (via the binary located at
`$ANDROID_HOME/platform-tools/adb`) to verify that your device shows up as connected.
- 如果使用模拟器,使用 Android Studio 创建和启动 Android 虚拟设备 (AVD)。
您可能需要下载要创建的模拟器的 API 级别的系统映像。 使用 Android Studio 中的 AVD 创建向导通常是完成所有这些的最简单方法。
- 如果使用真实设备,您应该为其设置[开发者模式并启用 USB 调试](https://developer.android.com/studio/debug/dev-options)。
- 连接模拟器或设备后,您可以运行 `adb devices`(adb位于 `$ANDROID_HOME/platform-tools/adb`)来验证您的设备是否显示为已连接。
Once your device shows up as connected in `adb`, and you've verified that the environment variables
are set up correctly, you should be good to go! If you ran into problems with any of these steps,
refer to the driver documentation, or the various Android or Java documentation sites as necessary.
一旦您的设备在 `adb` 中显示为已连接,并且您验证了环境变量设置正确,您应该准备好了! 如果您在这些步骤中的任何一个遇到问题,请参考驱动程序文档,或根据需要参考各种 Android 或 Java 文档站点。
Also, congratulations: whether or not you intended to, you now have the Android developer toolchain
set up on your system, so you can get busy making Android apps if you want!
恭喜:无论您是否打算这样做,您现在已经在系统上设置了 Android 开发者工具链,所以如果您愿意,可以开始制作 Android 应用!
## Install the driver itself
## 安装驱动程序本身
### Standard Install
### 标准安装
Like all Appium drivers, the UiAutomator2 driver is installed via the [Appium Extension CLI](../reference/cli/extensions.md).
Since UiAutomator2 is maintained by the core Appium team, it has an 'official' driver name
(`uiautomator2`), which makes the installation simpler.
像所有 Appium 驱动程序一样,UiAutomator 2 驱动程序通过 [Appium 扩展 CLI](../reference/cli/extensions.md) 安装。
由于 UiAutomator 2 由核心 Appium 团队维护,它有一个“官方”驱动程序名称(`uiautomator2`),这使得安装更简单。
Before installing, make sure your Appium server is _not_ running (if it is, quit it with _Ctrl-C_).
Then run the following command:
在安装之前,确保您的 Appium 服务器_未_运行(如果正在运行,请用 _Ctrl-C_ 退出)。
然后运行以下命令:
```bash
appium driver install uiautomator2
```
It should produce output that looks something like:
它应该产生看起来像这样的输出:
```
Attempting to find and install driver 'uiautomator2'
@@ -85,57 +68,45 @@ Driver uiautomator2@2.0.5 successfully installed
- platformNames: ["Android"]
```
Note how the installation process specifies what platforms is the driver valid for (in this case,
`Android`), and what automation name (the `appium:automationName` [capability](../guides/caps.md))
must be used to select this driver for use during an Appium session (in this case, `UiAutomator2`).
注意安装过程如何指定驱动程序的适用平台(在这里选 `Android`),以及必须用于在 Appium 会话期间选择此驱动程序的自动化名称(`appium:automationName` [能力](../guides/caps.md))(在这里选 `UiAutomator2`)。
!!! note
```
In this quickstart we have used the [Extension CLI](../reference/cli/extensions.md) to install the
UiAutomator2 driver, but if you are incorporating Appium into a Node.js project, you might
prefer to use `npm` to manage Appium and its connected drivers. To learn more about this
technique, visit the guide on [managing Appium extensions](../guides/managing-exts.md).
在这个快速入门中,我们使用了 [CLI扩展](../reference/cli/extensions.md) 来安装 UiAutomator 2 驱动程序,但如果您将 Appium 纳入 Node.js 项目,您可能更喜欢使用 `npm` 来管理 Appium 及其连接的驱动程序。要了解更多关于此技术的信息,请访问关于[管理 Appium 扩展](../guides/managing-exts.md)的指南。
```
### Batch Install
### 批量安装
You may want to use Appium with more than one driver. One way to accomplish this is to run
`appium driver install <driver-name>` for each individual driver, but you can also install multiple
drivers in one go:
您可能希望将 Appium 与多个驱动程序一起使用。 一种方法是为每个单独的驱动程序运行 `appium driver install <driver-name>`,但您也可以一次性安装多个驱动程序:
```
appium setup
```
Running this will install Appium's mobile-specific drivers: UiAutomator2, [XCUITest](https://appium.github.io/appium-xcuitest-driver/)
(only if running macOS), and [Espresso](https://github.com/appium/appium-espresso-driver).
运行此命令将安装 Appium 的移动端特定驱动程序:UiAutomator2、[XCUITest](https://appium.github.io/appium-xcuitest-driver/)(仅在运行 macOS 时),以及 [Espresso](https://github.com/appium/appium-espresso-driver)。
You can also use this command to batch install drivers for desktop applications or desktop browsers.
For more details on this, refer to the [Setup command documentation](../reference/cli/setup.md).
您也可以使用此命令批量安装桌面应用程序或桌面浏览器的驱动程序。
有关更多详细信息,请参考[设置命令文档](../reference/cli/setup.md)。
### Validating the Install
### 验证安装
The UiAutomator2 driver, like all official Appium drivers, comes with the Appium Doctor tool, which
allows validating whether all prerequisites have been set up correctly:
UiAutomator2 驱动程序,像所有官方 Appium 驱动程序一样,带有 Appium Doctor 工具,它允许验证是否所有先决条件都已正确设置:
```
appium driver doctor uiautomator2
```
This guide has focused on essential requirements, so Appium Doctor may suggest one or more optional
fixes. But if you see `0 required fixes needed`, that means everything is set up!
本指南专注于基本要求,因此 Appium Doctor 可能建议一个或多个可选修复。 但如果您看到 `0 required fixes needed`,那意味着一切都设置好了!
Now, start the Appium server again (run `appium`), and you should see that the newly-installed
driver is listed as available:
现在,再次启动 Appium 服务器(运行 `appium`),您应该看到新安装的驱动程序列为可用:
```
[Appium] Available drivers:
[Appium] - uiautomator2@2.0.5 (automationName 'UiAutomator2')
```
With the Android setup complete and the UiAutomator2 driver installed, you're ready to write your
first test! Now select your preferred language and give it a shot:
Android 设置完成并安装了 UiAutomator2 驱动程序,准备编写第一个测试吧! 现在选择您喜欢的语言并试试:
<div class="grid cards" markdown>
+1 -1
View File
@@ -1,7 +1,7 @@
import betterAjvErrors from '@sidvind/better-ajv-errors';
import {lilconfig} from 'lilconfig';
import _ from 'lodash';
import yaml from 'yaml';
import * as yaml from 'yaml';
import {getSchema, validate} from './schema/schema';
/**
+1 -1
View File
@@ -6,7 +6,7 @@ import B from 'bluebird';
import {env, fs} from '@appium/support';
import _ from 'lodash';
import path from 'path';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {CURRENT_SCHEMA_REV, DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
import {INSTALL_TYPE_NPM, INSTALL_TYPE_DEV} from './extension-config';
import {packageDidChange} from './package-changed';
+12 -12
View File
@@ -1,6 +1,6 @@
{
"name": "appium",
"version": "3.1.1",
"version": "3.1.2",
"description": "Automation for Apps.",
"keywords": [
"automation",
@@ -60,14 +60,14 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/base-driver": "^10.1.1",
"@appium/base-plugin": "^3.0.4",
"@appium/docutils": "^2.1.2",
"@appium/logger": "^2.0.2",
"@appium/base-driver": "^10.1.2",
"@appium/base-plugin": "^3.0.5",
"@appium/docutils": "^2.2.0",
"@appium/logger": "^2.0.3",
"@appium/schema": "^1.0.0",
"@appium/support": "^7.0.3",
"@appium/types": "^1.1.1",
"@sidvind/better-ajv-errors": "4.0.0",
"@appium/support": "^7.0.4",
"@appium/types": "^1.1.2",
"@sidvind/better-ajv-errors": "4.0.1",
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"argparse": "2.0.1",
@@ -77,18 +77,18 @@
"bluebird": "3.7.2",
"lilconfig": "3.1.3",
"lodash": "4.17.21",
"lru-cache": "11.2.2",
"lru-cache": "11.2.4",
"ora": "5.4.1",
"package-changed": "3.0.0",
"resolve-from": "5.0.0",
"semver": "7.7.3",
"source-map-support": "0.5.21",
"teen_process": "3.0.2",
"type-fest": "5.2.0",
"teen_process": "3.0.4",
"type-fest": "5.3.0",
"winston": "3.18.3",
"wrap-ansi": "7.0.0",
"ws": "8.18.3",
"yaml": "2.8.1"
"yaml": "2.8.2"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
@@ -1,5 +1,5 @@
{
"devDependencies": {
"webdriverio": "9.20.0"
"webdriverio": "9.21.0"
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
import {env, fs, npm, tempDir} from '@appium/support';
import path from 'node:path';
import resolveFrom from 'resolve-from';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {
DRIVER_TYPE,
EXT_SUBCOMMAND_INSTALL as INSTALL,
@@ -1,6 +1,6 @@
import {fs, tempDir} from '@appium/support';
import path from 'node:path';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {
CACHE_DIR_RELATIVE_PATH,
CURRENT_SCHEMA_REV,
@@ -3,7 +3,7 @@
import fs from 'fs';
// eslint-disable-next-line import/named
import {createSandbox} from 'sinon';
import YAML from 'yaml';
import * as YAML from 'yaml';
import * as schema from '../../lib/schema/schema';
import {resolveFixture, rewiremock} from '../helpers';
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [10.1.2](https://github.com/appium/appium/compare/@appium/base-driver@10.1.1...@appium/base-driver@10.1.2) (2025-12-04)
**Note:** Version bump only for package @appium/base-driver
## [10.1.1](https://github.com/appium/appium/compare/@appium/base-driver@10.1.0...@appium/base-driver@10.1.1) (2025-11-12)
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/base-driver",
"version": "10.1.1",
"version": "10.1.2",
"description": "Base driver class for Appium drivers",
"keywords": [
"automation",
@@ -44,25 +44,25 @@
"test:types": "tsd"
},
"dependencies": {
"@appium/support": "^7.0.3",
"@appium/types": "^1.1.1",
"@appium/support": "^7.0.4",
"@appium/types": "^1.1.2",
"@colors/colors": "1.6.0",
"async-lock": "1.4.1",
"asyncbox": "3.0.0",
"axios": "1.13.2",
"bluebird": "3.7.2",
"body-parser": "2.2.0",
"express": "5.1.0",
"body-parser": "2.2.1",
"express": "5.2.1",
"fastest-levenshtein": "1.0.16",
"http-status-codes": "2.3.0",
"lodash": "4.17.21",
"lru-cache": "11.2.2",
"lru-cache": "11.2.4",
"method-override": "3.0.0",
"morgan": "1.10.1",
"path-to-regexp": "8.3.0",
"serve-favicon": "2.5.1",
"source-map-support": "0.5.21",
"type-fest": "5.2.0"
"type-fest": "5.3.0"
},
"optionalDependencies": {
"spdy": "4.0.2"
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.0.5](https://github.com/appium/appium/compare/@appium/base-plugin@3.0.4...@appium/base-plugin@3.0.5) (2025-12-04)
**Note:** Version bump only for package @appium/base-plugin
## [3.0.4](https://github.com/appium/appium/compare/@appium/base-plugin@3.0.3...@appium/base-plugin@3.0.4) (2025-11-12)
**Note:** Version bump only for package @appium/base-plugin
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/base-plugin",
"version": "3.0.4",
"version": "3.0.5",
"description": "The base plugin used to create Appium plugins",
"keywords": [
"automation",
@@ -40,8 +40,8 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/base-driver": "^10.1.1",
"@appium/support": "^7.0.3"
"@appium/base-driver": "^10.1.2",
"@appium/support": "^7.0.4"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
+9
View File
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.0](https://github.com/appium/appium/compare/@appium/docutils@2.1.2...@appium/docutils@2.2.0) (2025-12-04)
### Features
* **docutils:** add 3 Material for MkDocs features ([#21784](https://github.com/appium/appium/issues/21784)) ([86d84b8](https://github.com/appium/appium/commit/86d84b8c6ae490271007a43dffdeaaca33b849c0))
## [2.1.2](https://github.com/appium/appium/compare/@appium/docutils@2.1.1...@appium/docutils@2.1.2) (2025-11-12)
**Note:** Version bump only for package @appium/docutils
+3
View File
@@ -75,8 +75,11 @@ theme:
- content.action.edit
- content.code.annotate
- content.code.copy
- content.footnote.tooltips
- content.tabs.link
- content.tooltips
- navigation.indexes
- navigation.path
- navigation.sections
- navigation.tabs
- navigation.top
+1 -1
View File
@@ -6,7 +6,7 @@
import {lilconfig, Loader} from 'lilconfig';
import _ from 'lodash';
import path from 'node:path';
import YAML from 'yaml';
import * as YAML from 'yaml';
import parser from 'yargs-parser';
import {hideBin} from 'yargs/helpers';
import {DEFAULT_LOG_LEVEL, LogLevelMap, NAME_BIN} from '../constants';
+1 -1
View File
@@ -9,7 +9,7 @@ import path from 'node:path';
import _pkgDir from 'pkg-dir';
import readPkg, {NormalizedPackageJson, PackageJson} from 'read-pkg';
import {JsonValue} from 'type-fest';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {
MESSAGE_PYTHON_MISSING,
NAME_MIKE,
+1 -1
View File
@@ -5,7 +5,7 @@
*/
import {NAME_MKDOCS_YML, PIP_ENV_VARS, REQUIREMENTS_TXT_PATH} from './constants';
import YAML from 'yaml';
import * as YAML from 'yaml';
import {exec} from 'teen_process';
import {Simplify} from 'type-fest';
import {DocutilsError} from './error';
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/docutils",
"version": "2.1.2",
"version": "2.2.0",
"description": "Documentation generation utilities for Appium and related projects",
"keywords": [
"automation",
@@ -42,13 +42,13 @@
],
"scripts": {
"test": "npm run test:unit",
"test:e2e": "echo \"No e2e tests for this package\"",
"test:e2e": "mocha --exit --timeout 60s --slow 30s \"./test/e2e/**/*.e2e.spec.ts\"",
"test:smoke": "node ./index.js",
"test:unit": "mocha \"./test/unit/**/*.spec.js\"",
"test:unit": "mocha \"./test/unit/**/*.spec.ts\"",
"start": "node ./build/lib/cli/index.js"
},
"dependencies": {
"@appium/support": "^7.0.3",
"@appium/support": "^7.0.4",
"chalk": "4.1.2",
"consola": "3.4.2",
"diff": "8.0.2",
@@ -57,9 +57,9 @@
"pkg-dir": "5.0.0",
"read-pkg": "5.2.0",
"source-map-support": "0.5.21",
"teen_process": "3.0.2",
"type-fest": "5.2.0",
"yaml": "2.8.1",
"teen_process": "3.0.4",
"type-fest": "5.3.0",
"yaml": "2.8.2",
"yargs": "18.0.0",
"yargs-parser": "22.0.0"
},
+1 -1
View File
@@ -1,5 +1,5 @@
mkdocs==1.6.1
mkdocs-git-revision-date-localized-plugin==1.5.0
mkdocs-material==9.6.23
mkdocs-material==9.7.0
mkdocs-redirects==1.2.2
mike==2.1.3
@@ -0,0 +1,319 @@
/**
* E2E tests for the `appium-docs build` and `init` commands
* @module
*/
import path from 'node:path';
import * as chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import * as YAML from 'yaml';
import yargs from 'yargs/yargs';
import {fs, tempDir} from '@appium/support';
import {buildSite} from '../../lib/builder';
import {init, initPython} from '../../lib/init';
import {stringifyYaml} from '../../lib/fs';
import {MkDocsYml} from '../../lib/model';
import {NAME_MKDOCS_YML, DEFAULT_SITE_DIR, NAME_PACKAGE_JSON, NAME_BIN} from '../../lib/constants';
import {build as buildCommand, init as initCommand, validate as validateCommand} from '../../lib/cli/command';
chai.use(chaiAsPromised);
const {expect} = chai;
/**
* Helper function to create a project directory with package.json
*/
async function createProjectDir(
testDir: string,
subdir: string,
packageJson: Record<string, any>
): Promise<string> {
const projectDir = path.join(testDir, subdir);
await fs.mkdirp(projectDir);
await fs.writeFile(
path.join(projectDir, NAME_PACKAGE_JSON),
JSON.stringify(packageJson, null, 2),
'utf8'
);
return projectDir;
}
/**
* Helper function to create a minimal mkdocs.yml file
*/
async function createMkdocsYml(projectDir: string, mkdocsYml: MkDocsYml): Promise<void> {
await fs.writeFile(path.join(projectDir, NAME_MKDOCS_YML), stringifyYaml(mkdocsYml), 'utf8');
}
/**
* Helper function to create a docs directory with a markdown file
*/
async function createDocsFile(projectDir: string, filename: string, content: string): Promise<void> {
const docsDir = path.join(projectDir, 'docs');
await fs.mkdirp(docsDir);
await fs.writeFile(path.join(docsDir, filename), content, 'utf8');
}
/**
* Helper function to ensure Python dependencies are installed
*/
async function ensurePythonDeps(projectDir: string, context: Mocha.Context): Promise<void> {
try {
await initPython({cwd: projectDir});
} catch {
context.skip();
}
}
/**
* Helper function to verify a site was built
*/
async function verifySiteBuilt(siteDir: string, expectedContent: string): Promise<void> {
const siteDirExists = await fs.exists(siteDir);
expect(siteDirExists).to.be.true;
const indexHtml = path.join(siteDir, 'index.html');
const indexHtmlExists = await fs.exists(indexHtml);
expect(indexHtmlExists).to.be.true;
const indexHtmlContent = await fs.readFile(indexHtml, 'utf8');
expect(indexHtmlContent).to.include(expectedContent);
}
/**
* Helper function to read and parse mkdocs.yml
*/
async function readMkdocsYml(projectDir: string): Promise<MkDocsYml> {
const mkdocsYmlPath = path.join(projectDir, NAME_MKDOCS_YML);
const mkdocsYmlContent = await fs.readFile(mkdocsYmlPath, 'utf8');
return YAML.parse(mkdocsYmlContent) as MkDocsYml;
}
describe('@appium/docutils build e2e', function () {
let testDir: string;
before(async function () {
// Create a temporary directory for the test
testDir = await tempDir.openDir();
});
after(async function () {
// Clean up the temporary directory
if (testDir) {
await fs.rimraf(testDir);
}
});
describe('buildSite', function () {
it('should build a site with mkdocs', async function () {
const projectDir = await createProjectDir(testDir, 'test1', {
name: 'test-docs',
version: '1.0.0',
description: 'Test documentation',
});
// Create a minimal mkdocs.yml
// For testing, we use a simple config without INHERIT to avoid path resolution issues
await createMkdocsYml(projectDir, {
site_name: 'Test Docs',
docs_dir: 'docs',
site_dir: DEFAULT_SITE_DIR,
theme: {
name: 'material',
},
plugins: ['search'],
});
await createDocsFile(projectDir, 'index.md', '# Test Documentation\n\nThis is a test page.\n');
await ensurePythonDeps(projectDir, this as Mocha.Context);
// Build the site
await buildSite({
mkdocsYml: path.join(projectDir, NAME_MKDOCS_YML),
cwd: projectDir,
});
// Verify the site was built
await verifySiteBuilt(path.join(projectDir, DEFAULT_SITE_DIR), 'Test Documentation');
});
it('should build a site with custom site-dir', async function () {
const customSiteDir = 'custom-site';
const projectDir = await createProjectDir(testDir, 'test2', {
name: 'test-docs-2',
version: '1.0.0',
description: 'Test documentation',
});
// Create a minimal mkdocs.yml
// For testing, we use a simple config without INHERIT to avoid path resolution issues
await createMkdocsYml(projectDir, {
site_name: 'Test Docs 2',
docs_dir: 'docs',
site_dir: customSiteDir,
theme: {
name: 'material',
},
plugins: ['search'],
});
await createDocsFile(projectDir, 'index.md', '# Test Documentation 2\n\nThis is another test page.\n');
await ensurePythonDeps(projectDir, this as Mocha.Context);
// Build the site with custom site-dir
const customSiteDirPath = path.join(projectDir, customSiteDir);
await buildSite({
mkdocsYml: path.join(projectDir, NAME_MKDOCS_YML),
siteDir: customSiteDirPath,
cwd: projectDir,
});
// Verify the site was built in the custom directory
await verifySiteBuilt(customSiteDirPath, 'Test Documentation 2');
});
});
describe('init', function () {
it('should scaffold mkdocs.yml file', async function () {
const projectDir = await createProjectDir(testDir, 'init-test', {
name: 'test-package',
version: '1.0.0',
description: 'Test package description',
repository: {
type: 'git',
url: 'https://github.com/testuser/test-package.git',
},
});
// Run init command (skip Python installation for faster test)
await init({
cwd: projectDir,
mkdocs: true,
python: false,
});
// Verify mkdocs.yml was created
const mkdocsYmlPath = path.join(projectDir, NAME_MKDOCS_YML);
expect(await fs.exists(mkdocsYmlPath)).to.be.true;
// Read and verify the content of mkdocs.yml
const mkdocsYml = await readMkdocsYml(projectDir);
// Verify expected fields are present
expect(mkdocsYml.INHERIT).to.equal('./node_modules/@appium/docutils/base-mkdocs.yml');
expect(mkdocsYml.docs_dir).to.equal('docs');
expect(mkdocsYml.site_dir).to.equal('site');
expect(mkdocsYml.site_name).to.equal('test-package');
expect(mkdocsYml.site_description).to.equal('Test package description');
// Repository URL may be normalized with "git+" prefix by read-pkg
expect(mkdocsYml.repo_url).to.include('github.com/testuser/test-package');
expect(mkdocsYml.repo_name).to.equal('testuser/test-package');
});
it('should scaffold mkdocs.yml with custom options', async function () {
const projectDir = await createProjectDir(testDir, 'init-custom-test', {
name: 'custom-package',
version: '2.0.0',
description: 'Custom package',
});
// Run init command with custom options
await init({
cwd: projectDir,
mkdocs: true,
python: false,
siteName: 'Custom Site Name',
repoUrl: 'https://github.com/custom/repo',
repoName: 'custom/repo',
siteDescription: 'Custom description',
});
// Verify mkdocs.yml was created
const mkdocsYmlPath = path.join(projectDir, NAME_MKDOCS_YML);
expect(await fs.exists(mkdocsYmlPath)).to.be.true;
// Read and verify the content
const mkdocsYml = await readMkdocsYml(projectDir);
// Verify custom values are used
expect(mkdocsYml.site_name).to.equal('Custom Site Name');
// Note: siteDescription from options should override package.json description
// If it doesn't work, it falls back to package description
expect(mkdocsYml.site_description).to.be.oneOf(['Custom description', 'Custom package']);
expect(mkdocsYml.repo_url).to.equal('https://github.com/custom/repo');
expect(mkdocsYml.repo_name).to.equal('custom/repo');
});
});
describe('CLI help', function () {
it('should print help when --help is passed', async function () {
let helpOutput = '';
// Create yargs instance similar to CLI
const y = yargs(['--help'])
.scriptName(NAME_BIN)
.command(buildCommand)
.command(initCommand)
.command(validateCommand)
.options({
verbose: {
type: 'boolean',
describe: 'Alias for --log-level=debug',
},
'log-level': {
alias: 'L',
choices: ['debug', 'info', 'warn', 'error', 'silent'],
describe: 'Sets the log level',
default: 'info',
},
config: {
alias: 'c',
type: 'string',
describe: 'Path to config file',
normalize: true,
nargs: 1,
requiresArg: true,
defaultDescription: '(discovered automatically)',
},
'no-config': {
type: 'boolean',
describe: 'Disable config file discovery',
},
})
.demandCommand(1)
.strict();
// Try getHelp first (returns a string, no I/O needed)
try {
const helpText = await y.getHelp();
helpOutput = helpText;
} catch {
// If getHelp doesn't work, use showHelp which writes to stderr by default
// Capture stderr since showHelp() writes to stderr by default
const originalStderrWrite = process.stderr.write.bind(process.stderr);
const mockStderrWrite = (chunk: any) => {
if (typeof chunk === 'string' || Buffer.isBuffer(chunk)) {
helpOutput += chunk.toString();
}
return true;
};
process.stderr.write = mockStderrWrite as typeof process.stderr.write;
try {
y.showHelp();
} finally {
process.stderr.write = originalStderrWrite;
}
}
// Verify help output contains expected content
expect(helpOutput).to.include(NAME_BIN);
expect(helpOutput).to.include('Commands:');
expect(helpOutput).to.include('build');
expect(helpOutput).to.include('init');
expect(helpOutput).to.include('validate');
expect(helpOutput).to.include('Options:');
expect(helpOutput).to.include('--help');
});
});
});
@@ -1,12 +1,12 @@
import {argify} from '../../lib/util';
import _ from 'lodash';
import * as chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
const {expect} = chai;
describe('argify', function () {
before(async function () {
const chai = await import('chai');
chai.should();
});
it('should create args from params', function () {
// deploy example
const version = '2.0';
@@ -29,7 +29,7 @@ describe('argify', function () {
),
version,
];
mikeArgs.should.eql([
expect(mikeArgs).to.eql([
'--config-file',
'/path/to/yml',
'--push',
@@ -45,3 +45,4 @@ describe('argify', function () {
]);
});
});
+2 -1
View File
@@ -4,12 +4,13 @@
"rootDir": ".",
"outDir": "build",
"checkJs": true,
"types": ["node", "mocha", "chai", "chai-as-promised"],
"paths": {
"@appium/support": ["../support"],
"@appium/types": ["../types"]
},
"strict": true
},
"include": ["./lib/**/*"],
"include": ["./lib/**/*", "./test/**/*"],
"references": [{"path": "../types"}, {"path": "../support"}]
}
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.5](https://github.com/appium/appium/compare/@appium/driver-test-support@1.0.4...@appium/driver-test-support@1.0.5) (2025-12-04)
**Note:** Version bump only for package @appium/driver-test-support
## [1.0.4](https://github.com/appium/appium/compare/@appium/driver-test-support@1.0.3...@appium/driver-test-support@1.0.4) (2025-11-12)
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/driver-test-support",
"version": "1.0.4",
"version": "1.0.5",
"description": "Test utilities for Appium drivers",
"keywords": [
"automation",
@@ -41,16 +41,16 @@
},
"types": "./build/lib/index.d.ts",
"dependencies": {
"@appium/types": "^1.1.1",
"@appium/types": "^1.1.2",
"axios": "1.13.2",
"bluebird": "3.7.2",
"chai": "6.2.0",
"chai": "6.2.1",
"chai-as-promised": "8.0.2",
"get-port": "5.1.1",
"lodash": "4.17.21",
"sinon": "21.0.0",
"source-map-support": "0.5.21",
"type-fest": "5.2.0"
"type-fest": "5.3.0"
},
"peerDependencies": {
"appium": "^3.0.0-beta.0",
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.0.5](https://github.com/appium/appium/compare/@appium/eslint-config-appium-ts@2.0.4...@appium/eslint-config-appium-ts@2.0.5) (2025-12-04)
### Bug Fixes
* **eslint-config-appium-ts:** update eslint-plugin-mocha to v11 ([#21722](https://github.com/appium/appium/issues/21722)) ([cabe2e5](https://github.com/appium/appium/commit/cabe2e53bc6d7b23cefc80334eb5d0aa89a72d4f))
## [2.0.4](https://github.com/appium/appium/compare/@appium/eslint-config-appium-ts@2.0.3...@appium/eslint-config-appium-ts@2.0.4) (2025-11-12)
**Note:** Version bump only for package @appium/eslint-config-appium-ts
+3 -3
View File
@@ -185,11 +185,11 @@ export default [
},
{
...mochaPlugin.configs.flat.recommended,
...mochaPlugin.configs.recommended,
name: 'Test Files',
files: ['**/test/**', '*.spec.*js', '-specs.*js', '*.spec.ts'],
rules: {
...mochaPlugin.configs.flat.recommended.rules,
...mochaPlugin.configs.recommended.rules,
/**
* Both `@ts-expect-error` and `@ts-ignore` are allowed to be used with impunity in tests.
* @remarks We often test things which explicitly violate types.
@@ -208,8 +208,8 @@ export default [
'mocha/no-exclusive-tests': 2,
'mocha/no-exports': 'off',
'mocha/no-mocha-arrows': 2,
'mocha/no-pending-tests': 'off',
'mocha/no-setup-in-describe': 'off',
'mocha/no-skipped-tests': 'off',
},
},
@@ -1,7 +1,7 @@
{
"name": "@appium/eslint-config-appium-ts",
"type": "module",
"version": "2.0.4",
"version": "2.0.5",
"description": "Shared ESLint config for Appium projects (TypeScript version)",
"keywords": [
"eslint",
@@ -29,14 +29,14 @@
"test:smoke": "exit 0"
},
"dependencies": {
"@eslint/compat": "1.4.1",
"@eslint/compat": "2.0.0",
"@eslint/js": "9.39.1",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-typescript": "4.4.4",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-mocha": "10.5.0",
"eslint-plugin-mocha": "11.2.0",
"eslint-plugin-promise": "7.2.1",
"typescript-eslint": "8.46.4"
"typescript-eslint": "8.48.1"
},
"peerDependencies": {
"eslint": "^9.0.0"
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.0.3](https://github.com/appium/appium/compare/@appium/execute-driver-plugin@5.0.2...@appium/execute-driver-plugin@5.0.3) (2025-12-04)
**Note:** Version bump only for package @appium/execute-driver-plugin
## [5.0.2](https://github.com/appium/appium/compare/@appium/execute-driver-plugin@5.0.1...@appium/execute-driver-plugin@5.0.2) (2025-10-08)
**Note:** Version bump only for package @appium/execute-driver-plugin
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/execute-driver-plugin",
"version": "5.0.2",
"version": "5.0.3",
"description": "Plugin for batching and executing Appium driver commands",
"keywords": [
"automation",
@@ -41,7 +41,7 @@
"bluebird": "3.7.2",
"lodash": "4.17.21",
"source-map-support": "0.5.21",
"webdriverio": "9.20.0"
"webdriverio": "9.21.0"
},
"peerDependencies": {
"appium": "^3.0.0-beta.0"
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.0.5](https://github.com/appium/appium/compare/@appium/fake-plugin@4.0.4...@appium/fake-plugin@4.0.5) (2025-12-04)
**Note:** Version bump only for package @appium/fake-plugin
## [4.0.4](https://github.com/appium/appium/compare/@appium/fake-plugin@4.0.3...@appium/fake-plugin@4.0.4) (2025-11-12)
**Note:** Version bump only for package @appium/fake-plugin
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/fake-plugin",
"version": "4.0.4",
"version": "4.0.5",
"description": "A fake Appium plugin",
"keywords": [
"automation",
@@ -39,8 +39,8 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/base-plugin": "^3.0.4",
"@appium/support": "^7.0.3",
"@appium/base-plugin": "^3.0.5",
"@appium/support": "^7.0.4",
"bluebird": "3.7.2",
"lodash": "4.17.21",
"source-map-support": "0.5.21"
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.0.4](https://github.com/appium/appium/compare/@appium/images-plugin@4.0.3...@appium/images-plugin@4.0.4) (2025-12-04)
**Note:** Version bump only for package @appium/images-plugin
## [4.0.3](https://github.com/appium/appium/compare/@appium/images-plugin@4.0.2...@appium/images-plugin@4.0.3) (2025-11-12)
**Note:** Version bump only for package @appium/images-plugin
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/images-plugin",
"version": "4.0.3",
"version": "4.0.4",
"description": "Plugin for working with images and image elements in Appium",
"keywords": [
"automation",
@@ -40,9 +40,9 @@
},
"dependencies": {
"@appium/opencv": "^4.0.3",
"@appium/support": "^7.0.3",
"@appium/support": "^7.0.4",
"lodash": "4.17.21",
"lru-cache": "11.2.2",
"lru-cache": "11.2.4",
"sharp": "0.34.5",
"source-map-support": "0.5.21"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.0.3](https://github.com/appium/appium/compare/@appium/logger@2.0.2...@appium/logger@2.0.3) (2025-12-04)
**Note:** Version bump only for package @appium/logger
## [2.0.2](https://github.com/appium/appium/compare/@appium/logger@2.0.1...@appium/logger@2.0.2) (2025-10-08)
**Note:** Version bump only for package @appium/logger
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/logger",
"version": "2.0.2",
"version": "2.0.3",
"author": "https://github.com/appium",
"description": "A Universal Logger For The Appium Ecosystem",
"repository": {
@@ -29,7 +29,7 @@
"dependencies": {
"console-control-strings": "1.1.0",
"lodash": "4.17.21",
"lru-cache": "11.2.2",
"lru-cache": "11.2.4",
"set-blocking": "2.0.0"
},
"license": "ISC",
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.4](https://github.com/appium/appium/compare/@appium/plugin-test-support@1.0.3...@appium/plugin-test-support@1.0.4) (2025-12-04)
**Note:** Version bump only for package @appium/plugin-test-support
## [1.0.3](https://github.com/appium/appium/compare/@appium/plugin-test-support@1.0.2...@appium/plugin-test-support@1.0.3) (2025-11-12)
**Note:** Version bump only for package @appium/plugin-test-support
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/plugin-test-support",
"version": "1.0.3",
"version": "1.0.4",
"description": "Testing utilities for Appium plugins",
"keywords": [
"automation",
@@ -41,11 +41,11 @@
"test:unit": "exit 0"
},
"dependencies": {
"@appium/types": "^1.1.1",
"@appium/types": "^1.1.2",
"get-port": "5.1.1",
"log-symbols": "4.1.0",
"source-map-support": "0.5.21",
"teen_process": "3.0.2"
"teen_process": "3.0.4"
},
"peerDependencies": {
"appium": "^3.0.0-beta.0",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.4](https://github.com/appium/appium/compare/@appium/storage-plugin@1.0.3...@appium/storage-plugin@1.0.4) (2025-12-04)
**Note:** Version bump only for package @appium/storage-plugin
## [1.0.3](https://github.com/appium/appium/compare/@appium/storage-plugin@1.0.2...@appium/storage-plugin@1.0.3) (2025-11-12)
**Note:** Version bump only for package @appium/storage-plugin
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/storage-plugin",
"version": "1.0.3",
"version": "1.0.4",
"description": "Server-side storage plugin for Appium",
"keywords": [
"automation",
@@ -41,12 +41,12 @@
"test:e2e": "mocha --timeout 20s --slow 10s \"./test/e2e/**/*.spec.*js\""
},
"dependencies": {
"@appium/support": "^7.0.3",
"@appium/support": "^7.0.4",
"async-lock": "1.4.1",
"bluebird": "3.7.2",
"lodash": "4.17.21",
"lru-cache": "11.2.2",
"rimraf": "6.1.0",
"lru-cache": "11.2.4",
"rimraf": "6.1.2",
"source-map-support": "0.5.21",
"ws": "8.18.3"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.0.4](https://github.com/appium/appium/compare/@appium/support@7.0.3...@appium/support@7.0.4) (2025-12-04)
**Note:** Version bump only for package @appium/support
## [7.0.3](https://github.com/appium/appium/compare/@appium/support@7.0.2...@appium/support@7.0.3) (2025-11-12)
+1 -2
View File
@@ -1,6 +1,6 @@
import _ from 'lodash';
import B from 'bluebird';
import yauzl from 'yauzl';
import * as yauzl from 'yauzl';
import archiver from 'archiver';
import {createWriteStream} from 'fs';
import path from 'path';
@@ -17,7 +17,6 @@ import {exec} from 'teen_process';
/**
* @type {(path: string, options?: yauzl.Options) => Promise<yauzl.ZipFile>}
*/
// eslint-disable-next-line import/no-named-as-default-member
const openZip = B.promisify(yauzl.open);
/**
* @type {(source: NodeJS.ReadableStream, destination: NodeJS.WritableStream) => Promise<NodeJS.WritableStream>}
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/support",
"version": "7.0.3",
"version": "7.0.4",
"description": "Support libs used across Appium packages",
"keywords": [
"automation",
@@ -41,9 +41,9 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/logger": "^2.0.2",
"@appium/tsconfig": "^1.1.0",
"@appium/types": "^1.1.1",
"@appium/logger": "^2.0.3",
"@appium/tsconfig": "^1.1.1",
"@appium/types": "^1.1.2",
"@colors/colors": "1.6.0",
"archiver": "7.0.1",
"axios": "1.13.2",
@@ -51,9 +51,9 @@
"bluebird": "3.7.2",
"bplist-creator": "0.1.1",
"bplist-parser": "0.3.2",
"form-data": "4.0.4",
"form-data": "4.0.5",
"get-stream": "6.0.1",
"glob": "11.0.3",
"glob": "13.0.0",
"jsftp": "2.1.3",
"klaw": "4.1.0",
"lockfile": "1.0.4",
@@ -71,10 +71,10 @@
"shell-quote": "1.8.3",
"source-map-support": "0.5.21",
"supports-color": "8.1.1",
"teen_process": "3.0.2",
"type-fest": "5.2.0",
"teen_process": "3.0.4",
"type-fest": "5.3.0",
"uuid": "13.0.0",
"which": "5.0.0",
"which": "6.0.0",
"yauzl": "3.2.0"
},
"optionalDependencies": {
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.0.4](https://github.com/appium/appium/compare/@appium/test-support@4.0.3...@appium/test-support@4.0.4) (2025-12-04)
**Note:** Version bump only for package @appium/test-support
## [4.0.3](https://github.com/appium/appium/compare/@appium/test-support@4.0.2...@appium/test-support@4.0.3) (2025-11-12)
**Note:** Version bump only for package @appium/test-support
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/test-support",
"version": "4.0.3",
"version": "4.0.4",
"description": "A collection of test utilities used across Appium packages",
"keywords": [
"automation",
@@ -45,7 +45,7 @@
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
},
"dependencies": {
"@appium/support": "^7.0.3",
"@appium/support": "^7.0.4",
"@colors/colors": "1.6.0",
"bluebird": "3.7.2",
"lodash": "4.17.21",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.1](https://github.com/appium/appium/compare/@appium/tsconfig@1.1.0...@appium/tsconfig@1.1.1) (2025-12-04)
**Note:** Version bump only for package @appium/tsconfig
## [1.1.0](https://github.com/appium/appium/compare/@appium/tsconfig@1.0.0...@appium/tsconfig@1.1.0) (2025-09-09)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/tsconfig",
"version": "1.1.0",
"version": "1.1.1",
"description": "Shared TypeScript Config for Appium",
"main": "tsconfig.json",
"keywords": [
@@ -32,7 +32,7 @@
"npm": ">=10"
},
"dependencies": {
"@tsconfig/node20": "20.1.6"
"@tsconfig/node20": "20.1.8"
},
"scripts": {
"test:smoke": "node tsconfig.json && node tsconfig.plugin.json"
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.2](https://github.com/appium/appium/compare/@appium/types@1.1.1...@appium/types@1.1.2) (2025-12-04)
**Note:** Version bump only for package @appium/types
## [1.1.1](https://github.com/appium/appium/compare/@appium/types@1.1.0...@appium/types@1.1.1) (2025-11-12)
**Note:** Version bump only for package @appium/types
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/types",
"version": "1.1.1",
"version": "1.1.2",
"description": "Various type declarations used across Appium",
"keywords": [
"automation",
@@ -38,10 +38,10 @@
"test:types": "tsd"
},
"dependencies": {
"@appium/logger": "^2.0.2",
"@appium/logger": "^2.0.3",
"@appium/schema": "^1.0.0",
"@appium/tsconfig": "^1.1.0",
"type-fest": "5.2.0"
"@appium/tsconfig": "^1.1.1",
"type-fest": "5.3.0"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.0.3](https://github.com/appium/appium/compare/@appium/universal-xml-plugin@2.0.2...@appium/universal-xml-plugin@2.0.3) (2025-12-04)
**Note:** Version bump only for package @appium/universal-xml-plugin
## [2.0.2](https://github.com/appium/appium/compare/@appium/universal-xml-plugin@2.0.1...@appium/universal-xml-plugin@2.0.2) (2025-11-12)
**Note:** Version bump only for package @appium/universal-xml-plugin
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/universal-xml-plugin",
"version": "2.0.2",
"version": "2.0.3",
"description": "Appium plugin for making XML source and XPath queries the same across iOS and Android",
"keywords": [
"automation",
@@ -38,7 +38,7 @@
},
"dependencies": {
"@xmldom/xmldom": "0.9.8",
"fast-xml-parser": "5.3.1",
"fast-xml-parser": "5.3.2",
"lodash": "4.17.21",
"source-map-support": "0.5.21",
"xpath": "0.0.34"
+3 -3
View File
@@ -249,8 +249,8 @@ function formatSlackMessage(pullRequests, from, to, generatedAt) {
const repoUrl = `https://github.com/${GITHUB_ORG}/${pr.repository}`;
// Format as simple markdown row with Slack-formatted links
// Column order changed to: index • author • title • repo • dates
return `${index + 1} • <${authorUrl}|${authorName}> • <${pr.html_url}|${prTitle}> • <${repoUrl}|${pr.repository}> • Created: ${createdDate} • Merged: ${mergedDate}`;
// Column order changed to: index • author • title • URL for the PR • repo • dates
return `${index + 1} • <${authorUrl}|${authorName}> • <${pr.html_url}|${prTitle}> • ${pr.html_url} • <${repoUrl}|${pr.repository}> • Created: ${createdDate} • Merged: ${mergedDate}`;
});
// Slack section text has a 3000 character limit. Keep under ~2900 to be safe.
@@ -361,4 +361,4 @@ async function main() {
* @property {string} commit.message - Pull request title
* @property {string} html_url - Pull request URL
* @property {string} repository - Repository name
*/
*/