diff --git a/.github/workflows/on-hold.yml b/.github/workflows/on-hold.yml index e4333cc30..39832a976 100644 --- a/.github/workflows/on-hold.yml +++ b/.github/workflows/on-hold.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check for "On Hold" label - uses: egmacke/action-check-label@v3 + uses: egmacke/action-check-label@v4 with: label: On Hold state: absent diff --git a/CONDUCT.md b/CONDUCT.md index f9ea64bb9..cb589f249 100644 --- a/CONDUCT.md +++ b/CONDUCT.md @@ -2,7 +2,7 @@ ### What is this code of conduct for? -Appium is a piece of technology, but **the core of the Appium community is the people in it**. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, socioeconomic status, religion (or lack thereof), or other marginalized aspect of comunity members. We expect all members of the Appium community to abide by this Code of Conduct whenever interacting in Appium venues (pull requests, GitHub issues, 1-1 or group chat, meetups, conferences, etc...) +Appium is a piece of technology, but **the core of the Appium community is the people in it**. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, socioeconomic status, religion (or lack thereof), or other marginalized aspect of community members. We expect all members of the Appium community to abide by this Code of Conduct whenever interacting in Appium venues (pull requests, GitHub issues, 1-1 or group chat, meetups, conferences, etc...) ### Examples of inappropriate behavior diff --git a/docs/payout.md b/docs/payout.md index 697ed426b..e645fe89a 100644 --- a/docs/payout.md +++ b/docs/payout.md @@ -8,7 +8,7 @@ This documentation is a note for the opencollective payout. 3. Type proper account name in `Who is being paid for this expense?` - The form depends on the target user 4. Select `Next` -5. Input expense info and complete the form. Then, the user will recieve the expense info. +5. Input expense info and complete the form. Then, the user will receive the expense info. - Expense title: ` contribution payout` - e.g. `2024-07 contribution payout` - Description in "Set invoice details" diff --git a/package-lock.json b/package-lock.json index 38fe41b1b..eefcf92e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ ], "devDependencies": { "@colors/colors": "1.6.0", - "@eslint/js": "9.25.1", + "@eslint/js": "9.27.0", "@tsconfig/node14": "14.1.3", "@types/archiver": "6.0.3", "@types/argparse": "2.0.17", @@ -22,7 +22,6 @@ "@types/bluebird": "3.5.42", "@types/chai": "5.2.1", "@types/chai-as-promised": "8.0.2", - "@types/diff": "7.0.2", "@types/express": "5.0.1", "@types/jsftp": "2.1.5", "@types/json-schema": "7.0.15", @@ -55,9 +54,9 @@ "conventional-changelog-conventionalcommits": "7.0.2", "cpy-cli": "5.0.0", "cross-env": "7.0.3", - "eslint": "9.25.1", - "eslint-config-prettier": "10.1.2", - "eslint-import-resolver-typescript": "4.3.4", + "eslint": "9.27.0", + "eslint-config-prettier": "10.1.5", + "eslint-import-resolver-typescript": "4.4.1", "eslint-plugin-import": "2.31.0", "eslint-plugin-mocha": "10.5.0", "eslint-plugin-promise": "7.2.1", @@ -69,21 +68,21 @@ "midnight-smoker": "8.0.0", "mjpeg-consumer": "2.0.0", "mjpeg-server": "0.3.1", - "mocha": "11.1.0", + "mocha": "11.5.0", "npm-run-all2": "6.2.6", "prettier": "3.5.3", - "rewiremock": "3.14.5", + "rewiremock": "3.14.6", "rimraf": "5.0.10", "serve-static": "1.16.2", "sinon": "20.0.0", "sync-monorepo-packages": "1.0.2", + "teen_process": "2.3.2", "ts-node": "10.9.2", "tsd": "0.32.0", "typescript": "5.8.3", - "typescript-eslint": "8.31.0", - "validate.js": "0.13.1", - "webdriverio": "9.12.7", - "ws": "8.18.1", + "typescript-eslint": "8.33.0", + "webdriverio": "9.14.0", + "ws": "8.18.2", "yaml-js": "0.3.1" }, "engines": { @@ -291,24 +290,33 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.3.0", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint-community/regexpp": { @@ -362,9 +370,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -431,12 +439,15 @@ "license": "MIT" }, "node_modules/@eslint/js": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", - "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", + "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -449,12 +460,12 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "levn": "^0.4.1" }, "engines": { @@ -2483,17 +2494,17 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.2.tgz", - "integrity": "sha512-i4Ez+s9oRWQbNjtI/3+jxr7OH508mjAKvza0ekPJem0ZtmsYHP3B5dq62+IaBHKaGCOuqJxXzvFLUhJvQ6jtsQ==", + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.5.tgz", + "integrity": "sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "debug": "^4.4.0", + "debug": "^4.4.1", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", - "semver": "^7.7.1", + "semver": "^7.7.2", "tar-fs": "^3.0.8", "yargs": "^17.7.2" }, @@ -2505,9 +2516,9 @@ } }, "node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2852,13 +2863,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/diff": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/diff/-/diff-7.0.2.tgz", - "integrity": "sha512-JSWRMozjFKsGlEjiiKajUjIJVKuKdE3oVy2DNtK+fUo8q82nhFZ2CPQwicAIkXrofahDXrWJ7mjelvZphMS98Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/eslint": { "version": "7.29.0", "dev": true, @@ -3194,20 +3198,20 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz", - "integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.0.tgz", + "integrity": "sha512-CACyQuqSHt7ma3Ns601xykeBK/rDeZa3w6IS6UtMQbixO5DWy+8TilKkviGDH6jtWCo8FGRKEK5cLLkPvEammQ==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/type-utils": "8.31.0", - "@typescript-eslint/utils": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/type-utils": "8.33.0", + "@typescript-eslint/utils": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3217,21 +3221,30 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "@typescript-eslint/parser": "^8.33.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz", - "integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.0.tgz", + "integrity": "sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4" }, "engines": { @@ -3246,14 +3259,15 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz", - "integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.0.tgz", + "integrity": "sha512-d1hz0u9l6N+u/gcrk6s6gYdl7/+pp8yHheRTqP6X5hVDKALEaTn8WfGiit7G511yueBEL3OpOEpD+3/MBdoN+A==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0" + "@typescript-eslint/tsconfig-utils": "^8.33.0", + "@typescript-eslint/types": "^8.33.0", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3263,16 +3277,49 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz", - "integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.0.tgz", + "integrity": "sha512-LMi/oqrzpqxyO72ltP+dBSP6V0xiUb4saY7WLtxSfiNEBI8m321LLVFU9/QDJxjDQG9/tjSqKz/E3380TEqSTw==", "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/utils": "8.31.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.0.tgz", + "integrity": "sha512-sTkETlbqhEoiFmGr1gsdq5HyVbSOF0145SYDJ/EQmXHtKViCaGvnyLqWFFHtEXoS0J1yU8Wyou2UGmgW88fEug==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.0.tgz", + "integrity": "sha512-lScnHNCBqL1QayuSrWeqAL5GmqNdVUQAAMTaCwdYEdWfIrSrOGzyLGRCHXcCixa5NK6i5l0AfSO2oBSjCjf4XQ==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/utils": "8.33.0", "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3287,9 +3334,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz", - "integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz", + "integrity": "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3300,19 +3347,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz", - "integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.0.tgz", + "integrity": "sha512-vegY4FQoB6jL97Tu/lWRsAiUUp8qJTqzAmENH2k59SJhw0Th1oszb9Idq/FyyONLuNqT1OADJPXfyUNOR8SzAQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/project-service": "8.33.0", + "@typescript-eslint/tsconfig-utils": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3350,15 +3399,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz", - "integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.0.tgz", + "integrity": "sha512-lPFuQaLA9aSNa7D5u2EpRiqdAUhzShwGg/nhpBlc4GR6kcTABttCuyjFs8BcEZ8VWrjCBof/bePhP3Q3fS+Yrw==", "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3373,12 +3422,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz", - "integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.0.tgz", + "integrity": "sha512-7RW7CMYoskiz5OOGAWjJFxgb7c5UNjTG292gYhWeOAcFmYCtVCSqjqSBj5zMhxbXo2JOW95YYrUWJfU0zrpaGQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.31.0", + "@typescript-eslint/types": "8.33.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -3402,9 +3451,9 @@ } }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.1.tgz", - "integrity": "sha512-KJfNZWh3ZzLVrIyQHcKf8vAzHHE4H7f6Huf07rdCwAWwfsvtGEYIYBDCEKfzfTDOMSR7J0AFsOUDEfOhJHGj7Q==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.8.tgz", + "integrity": "sha512-rsRK8T7yxraNRDmpFLZCWqpea6OlXPNRRCjWMx24O1V86KFol7u2gj9zJCv6zB1oJjtnzWceuqdnCgOipFcJPA==", "cpu": [ "arm64" ], @@ -3415,9 +3464,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.1.tgz", - "integrity": "sha512-Eepa8XBbiSaNC5w9lda8QtW9d4pO7oX9DEEoZkIRUh37G5dk7r7hquAG2v1wsr9UbDHikuPgUGS78CYYmcQPvA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.8.tgz", + "integrity": "sha512-16yEMWa+Olqkk8Kl6Bu0ltT5OgEedkSAsxcz1B3yEctrDYp3EMBu/5PPAGhWVGnwhtf3hNe3y15gfYBAjOv5tQ==", "cpu": [ "x64" ], @@ -3428,9 +3477,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.1.tgz", - "integrity": "sha512-xcm5adD2ArFkzvH8DZ1BBwi4p1os0D1lid+T6lPxLcopP1bI1gi/RTqBDp2a5bOWh/wjAIRqxO5Co8dY9ngz3A==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.8.tgz", + "integrity": "sha512-ST4uqF6FmdZQgv+Q73FU1uHzppeT4mhX3IIEmHlLObrv5Ep50olWRz0iQ4PWovadjHMTAmpuJAGaAuCZYb7UAQ==", "cpu": [ "x64" ], @@ -3441,9 +3490,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.1.tgz", - "integrity": "sha512-UK6CL/EaBGuu1+O/veX7PAXpjIJJgUcYmSow0CYcEzR5WBJakciPiuk2VA7lxGEFi8NdstwN/TNBGEcrfVi5UA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.8.tgz", + "integrity": "sha512-Z/A/4Rm2VWku2g25C3tVb986fY6unx5jaaCFpx1pbAj0OKkyuJ5wcQLHvNbIcJ9qhiYwXfrkB7JNlxrAbg7YFg==", "cpu": [ "arm" ], @@ -3454,9 +3503,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.1.tgz", - "integrity": "sha512-qOgInSOcVW35p5XoEUWRnVO5TzR268LnWyJUNoxeFZiXfPRSf/oIBFie3J3pkF5OteWO8Eg+gP/p291bJN9QVQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.8.tgz", + "integrity": "sha512-HN0p7o38qKmDo3bZUiQa6gP7Qhf0sKgJZtRfSHi6JL2Gi4NaUVF0EO1sQ1RHbeQ4VvfjUGMh3QE5dxEh06BgQQ==", "cpu": [ "arm" ], @@ -3467,9 +3516,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.1.tgz", - "integrity": "sha512-VOleS+xSSXNk2+7pMgcbZgqLjXGVczMJneLqCu7l+PQ9QtcZ0gVbj95vc3+mqEbrAue9Mve65CyQVJTNeUET5g==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.8.tgz", + "integrity": "sha512-HsoVqDBt9G69AN0KWeDNJW+7i8KFlwxrbbnJffgTGpiZd6Jw+Q95sqkXp8y458KhKduKLmXfVZGnKBTNxAgPjw==", "cpu": [ "arm64" ], @@ -3480,9 +3529,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.1.tgz", - "integrity": "sha512-dLpmqdK1Fxz12uFYrxg/HltL2mWaIHlYf/XARbrcmPDmGfrkhwEVi9iw5aNKY1ojSD/iNoISmWKS7HVkHy4ZFA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.8.tgz", + "integrity": "sha512-VfR2yTDUbUvn+e/Aw22CC9fQg9zdShHAfwWctNBdOk7w9CHWl2OtYlcMvjzMAns8QxoHQoqn3/CEnZ4Ts7hfrA==", "cpu": [ "arm64" ], @@ -3493,9 +3542,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.1.tgz", - "integrity": "sha512-xaVrau4Gmx/pRzCq3AFUT3cTEaK9Jj/PeEkOQweRczM8GdaQbp6kkxciZOP3ZJp1f2W3IkIuYkrV6Oz7z58zZg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.8.tgz", + "integrity": "sha512-xUauVQNz4uDgs4UJJiUAwMe3N0PA0wvtImh7V0IFu++UKZJhssXbKHBRR4ecUJpUHCX2bc4Wc8sGsB6P+7BANg==", "cpu": [ "ppc64" ], @@ -3506,9 +3555,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.1.tgz", - "integrity": "sha512-J38QcQPnfpN8H/6+3tTpgSu/w6qGHKlBpHfAKx+2sklYW/R4BLgXnhCEmkeyU3RFKQ0hmkzwAZ2U+fAiVDY+mw==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.8.tgz", + "integrity": "sha512-GqyIB+CuSHGhhc8ph5RrurtNetYJjb6SctSHafqmdGcRuGi6uyTMR8l18hMEhZFsXdFMc/MpInPLvmNV22xn+A==", "cpu": [ "riscv64" ], @@ -3519,9 +3568,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.1.tgz", - "integrity": "sha512-GfISZFM2r/z87oXpfLXDNoA51jMoVJa5oUxGX62/ZFNAXu6GzzgTwaaT7plq+II1BkID9gQG1hGOoHCwz2PClA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.8.tgz", + "integrity": "sha512-eEU3rWIFRv60xaAbtsgwHNWRZGD7cqkpCvNtio/f1TjEE3HfKLzPNB24fA9X/8ZXQrGldE65b7UKK3PmO4eWIQ==", "cpu": [ "riscv64" ], @@ -3532,9 +3581,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.1.tgz", - "integrity": "sha512-DSGpaQ8OWhdJPQNPEhG5+KeJOGAaGnfi8eKmAUYI/R0IPMUMrm64dTo/d68jdYVn9y7Cu53LIPM4k9UBzjCwGg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.8.tgz", + "integrity": "sha512-GVLI0f4I4TlLqEUoOFvTWedLsJEdvsD0+sxhdvQ5s+N+m2DSynTs8h9jxR0qQbKlpHWpc2Ortz3z48NHRT4l+w==", "cpu": [ "s390x" ], @@ -3545,9 +3594,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.1.tgz", - "integrity": "sha512-3U0mVIRMB82he3+MFH5cLMsTxqlr8Q5/g6Sz3MEbnET3+qJKqBa7zEbHWHEko4N04CSas8BUEr+L2UFRsCrFaQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.8.tgz", + "integrity": "sha512-GX1pZ/4ncUreB0Rlp1l7bhKAZ8ZmvDIgXdeb5V2iK0eRRF332+6gRfR/r5LK88xfbtOpsmRHU6mQ4N8ZnwvGEA==", "cpu": [ "x64" ], @@ -3558,9 +3607,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.1.tgz", - "integrity": "sha512-I8KcPBu0reYgzAjTe+5PJg7VXXjjHuAQzr8UfHV+H7xz5Cfgmnrdsa9LAZRg+SQlpjH0mO3QVFeRlaoDjmYwdQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.8.tgz", + "integrity": "sha512-n1N84MnsvDupzVuYqJGj+2pb9s8BI1A5RgXHvtVFHedGZVBCFjDpQVRlmsFMt6xZiKwDPaqsM16O/1isCUGt7w==", "cpu": [ "x64" ], @@ -3571,16 +3620,16 @@ ] }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.1.tgz", - "integrity": "sha512-VV1AVT5ikRtb2GMq+LfOHUMaZzkbua5PdAv97+L5gp6+5R49aCIAHFZMW3VNU0LYUHwn0WwzgFMQ7hVlHYX7MA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.8.tgz", + "integrity": "sha512-x94WnaU5g+pCPDVedfnXzoG6lCOF2xFGebNwhtbJCWfceE94Zj8aysSxdxotlrZrxnz5D3ijtyFUYtpz04n39Q==", "cpu": [ "wasm32" ], "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.9" + "@napi-rs/wasm-runtime": "^0.2.10" }, "engines": { "node": ">=14.0.0" @@ -3597,21 +3646,21 @@ } }, "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.9.tgz", - "integrity": "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz", + "integrity": "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.0", - "@emnapi/runtime": "^1.4.0", + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.1.tgz", - "integrity": "sha512-i6T6/GsTn0B8fthG7jkn/wFBrwJKBm4/V/bZB8j+FtrlW9nk0xL2IckBO6NuwaX2d47b7vMUTVMcG+CKPRmcMw==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.8.tgz", + "integrity": "sha512-vst2u8EJZ5L6jhJ6iLis3w9rg16aYqRxQuBAMYQRVrPMI43693hLP7DuqyOBRKgsQXy9/jgh204k0ViHkqQgdg==", "cpu": [ "arm64" ], @@ -3622,9 +3671,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.1.tgz", - "integrity": "sha512-d6Cy8VqTGT/ehavIek6XNi7ZVpKhyG0CXgYBPNNdZWI+7huy3KfQM2ME5pEKudkOLjtzEsbwWnNdCswpn6s/tg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.8.tgz", + "integrity": "sha512-yb3LZOLMFqnA+/ShlE1E5bpYPGDsA590VHHJPB+efnyowT776GJXBoh82em6O9WmYBUq57YblGTcMYAFBm72HA==", "cpu": [ "ia32" ], @@ -3635,9 +3684,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.1.tgz", - "integrity": "sha512-isaSSX0p2m4Fe9gjJZi+ga6yeRhej237QiC0vQVawsA1Xmr3updYoEEpB4F0LNVjmLUiLqxfmh8f68eGThYqtg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.8.tgz", + "integrity": "sha512-hHKFx+opG5BA3/owMXon8ypwSotBGTdblG6oda/iOu9+OEYnk0cxD2uIcGyGT8jCK578kV+xMrNxqbn8Zjlpgw==", "cpu": [ "x64" ], @@ -3648,15 +3697,15 @@ ] }, "node_modules/@wdio/config": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.12.6.tgz", - "integrity": "sha512-zlOJixJUHxeoyfIN/KdM797HwJj/oNgBaEdftgJARqbXt5AVZu18vJ3zljb+wzbY2M0pl7Y4+5OFH06WlDgQ+A==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.14.0.tgz", + "integrity": "sha512-mW6VAXfUgd2j+8YJfFWvg8Ba/7g1Brr6/+MFBpp5rTQsw/2bN3PBJsQbWpNl99OCgoS8vgc5Ykps5ZUEeffSVQ==", "dev": true, "license": "MIT", "dependencies": { "@wdio/logger": "9.4.4", - "@wdio/types": "9.12.6", - "@wdio/utils": "9.12.6", + "@wdio/types": "9.14.0", + "@wdio/utils": "9.14.0", "deepmerge-ts": "^7.0.3", "glob": "^10.2.2", "import-meta-resolve": "^4.0.0" @@ -3878,9 +3927,9 @@ } }, "node_modules/@wdio/types": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.12.6.tgz", - "integrity": "sha512-WzZhaN834du9wjqT/Go9qPyB7VkzV2bjr6pr06DrIzxIpJq/snWOv96C6OjJu8nmYNRjV769mAxyggBUf+sUoQ==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.14.0.tgz", + "integrity": "sha512-Zqc4sxaQLIXdI1EHItIuVIOn7LvPmDvl9JEANwiJ35ck82Xlj+X55Gd9NtELSwChzKgODD0OBzlLgXyxTr69KA==", "dev": true, "license": "MIT", "dependencies": { @@ -3891,9 +3940,9 @@ } }, "node_modules/@wdio/types/node_modules/@types/node": { - "version": "20.17.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.31.tgz", - "integrity": "sha512-quODOCNXQAbNf1Q7V+fI8WyErOCh0D5Yd31vHnKu4GkSztGQ7rlltAaqXhHhLl33tlVyUXs2386MkANSwgDn6A==", + "version": "20.17.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz", + "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3901,15 +3950,15 @@ } }, "node_modules/@wdio/utils": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.12.6.tgz", - "integrity": "sha512-JfI4CxBRQCOgToJeQNaZLv+wYNIGyJG1gqrpxUOvkrJvBgdOAmIu3dzlcKP/WviXlcxvwLQF2FK8bQVTjHv0fQ==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.14.0.tgz", + "integrity": "sha512-oJapwraSflOe0CmeF3TBocdt983hq9mCutLCfie4QmE+TKRlCsZz4iidG1NRAZPGdKB32nfHtyQlW0Dfxwn6RA==", "dev": true, "license": "MIT", "dependencies": { "@puppeteer/browsers": "^2.2.0", "@wdio/logger": "9.4.4", - "@wdio/types": "9.12.6", + "@wdio/types": "9.14.0", "decamelize": "^6.0.0", "deepmerge-ts": "^7.0.3", "edgedriver": "^6.1.1", @@ -4210,6 +4259,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, "engines": { "node": ">=6" } @@ -4257,17 +4307,6 @@ "node": ">=4" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/appium": { "resolved": "packages/appium", "link": true @@ -4898,13 +4937,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/bl": { "version": "4.1.0", "license": "MIT", @@ -5466,28 +5498,18 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/chownr": { @@ -6728,9 +6750,10 @@ } }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -6742,9 +6765,9 @@ "optional": true }, "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -7352,19 +7375,19 @@ } }, "node_modules/eslint": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", - "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", + "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", + "@eslint/js": "9.27.0", + "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -7412,13 +7435,16 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz", - "integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==", + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, "peerDependencies": { "eslint": ">=7.0.0" } @@ -7500,6 +7526,30 @@ "node": ">=8" } }, + "node_modules/eslint-import-context": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.6.tgz", + "integrity": "sha512-/e2ZNPDLCrU8niIy0pddcvXuoO2YrKjf3NAIX+60mHJBT4yv7mqCqvVdyCW2E720e25e4S/1OSVef4U6efGLFg==", + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash": "^0.0.5" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -7518,17 +7568,18 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.3.4.tgz", - "integrity": "sha512-buzw5z5VtiQMysYLH9iW9BV04YyZebsw+gPi+c4FCjfS9i6COYOrEWw9t3m3wA9PFBfqcBCqWf32qrXLbwafDw==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.1.tgz", + "integrity": "sha512-KHQnjMAn/Hbs1AcMs2YfJTeNoWsaOoMRvJUKr77Y2dv7jNOaT8/IJYlvfN/ZIwTxUsv2B6amwv7u9bt2Vl9lZg==", "license": "ISC", "dependencies": { - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.5", + "get-tsconfig": "^4.10.1", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.3" + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.2" }, "engines": { "node": "^16.17.0 || >=18.6.0" @@ -7551,9 +7602,9 @@ } }, "node_modules/eslint-import-resolver-typescript/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -8499,17 +8550,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.2", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/ftp-response-parser": { "version": "1.0.1", "dependencies": { @@ -8810,9 +8850,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -9305,7 +9345,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.1", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, "license": "BSD-2-Clause" }, @@ -9801,16 +9843,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.1.2", "license": "MIT", @@ -11314,11 +11346,6 @@ "version": "4.17.21", "license": "MIT" }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "license": "MIT" @@ -11338,28 +11365,6 @@ "version": "4.6.2", "license": "MIT" }, - "node_modules/lodash.some": { - "version": "4.6.0", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.template": { - "version": "4.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash._reinterpolate": "^3.0.0" - } - }, "node_modules/lodash.zip": { "version": "4.2.0", "license": "MIT" @@ -12315,24 +12320,24 @@ } }, "node_modules/mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", - "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.5.0.tgz", + "integrity": "sha512-VKDjhy6LMTKm0WgNEdlY77YVsD49LZnPSXJAaPNL9NRYQADxvORsyG1DIQY6v53BKTnlNbEE2MbVCDbnxr4K3w==", "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", + "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", @@ -12407,21 +12412,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/mocha/node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -12438,15 +12428,18 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha/node_modules/minipass": { @@ -12602,9 +12595,9 @@ } }, "node_modules/napi-postinstall": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.1.tgz", - "integrity": "sha512-3VK+GygwU4OMkBYdQLpRjxnt7idAsZAN5hnrWLHIAu4X+uO4uhqrIggKF1TacBV9OPUMwTb1sQQvwKRzfXLnQg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz", + "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==", "license": "MIT", "bin": { "napi-postinstall": "lib/cli.js" @@ -15013,13 +15006,16 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/redent": { @@ -15164,14 +15160,14 @@ } }, "node_modules/rewiremock": { - "version": "3.14.5", + "version": "3.14.6", + "resolved": "https://registry.npmjs.org/rewiremock/-/rewiremock-3.14.6.tgz", + "integrity": "sha512-hjpS7iQUTVVh/IHV4GE1ypg4IzlgVc34gxZBarwwVrKfnjlyqHJuQdsia6Ac7m4f4k/zxxA3tX285MOstdysRQ==", "dev": true, "license": "MIT", "dependencies": { "babel-runtime": "^6.26.0", "compare-module-exports": "^2.1.0", - "lodash.some": "^4.6.0", - "lodash.template": "^4.4.0", "node-libs-browser": "^2.1.0", "path-parse": "^1.0.5", "wipe-node-cache": "^2.1.2", @@ -15428,9 +15424,9 @@ "optional": true }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -15785,15 +15781,6 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/sinon/node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/sinon/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16554,9 +16541,9 @@ } }, "node_modules/teen_process": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.3.1.tgz", - "integrity": "sha512-duT4gPj7HxEYy+AR4bJ9MNwf8GMLpJd+sNRAK2PTx53FpCcaiXVft3ePZh3hO6PY8NFWZMxTC3ZAtxyztScEsw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.3.2.tgz", + "integrity": "sha512-eiYtJbYrMz5WbZL68u05qCgLMShPZhYKVewZFoyT6C2xvNdMfikCP7Nh0K3Phiy+H4bMZ8q5GtJROFcoYwQJmQ==", "license": "Apache-2.0", "dependencies": { "bluebird": "^3.7.2", @@ -16677,9 +16664,9 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "license": "MIT", "dependencies": { "fdir": "^6.4.4", @@ -17198,14 +17185,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.0.tgz", - "integrity": "sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.33.0.tgz", + "integrity": "sha512-5YmNhF24ylCsvdNW2oJwMzTbaeO4bg90KeGtMjUw0AGtHksgEPLRTUil+coHwCfiu4QjVJFnjp94DmU6zV7DhQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.31.0", - "@typescript-eslint/parser": "8.31.0", - "@typescript-eslint/utils": "8.31.0" + "@typescript-eslint/eslint-plugin": "8.33.0", + "@typescript-eslint/parser": "8.33.0", + "@typescript-eslint/utils": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17325,35 +17312,35 @@ } }, "node_modules/unrs-resolver": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.1.tgz", - "integrity": "sha512-jsXGehlxwxyetBCbABwgKB41xF1zhcnHYs9X16Cyx1aaWXFvqaXRJOpRgc/kB9zTBaSivwhFEHThoiu74PSU6w==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.8.tgz", + "integrity": "sha512-2zsXwyOXmCX9nGz4vhtZRYhe30V78heAv+KDc21A/KMdovGHbZcixeD5JHEF0DrFXzdytwuzYclcPbvp8A3Jlw==", "hasInstallScript": true, "license": "MIT", "dependencies": { - "napi-postinstall": "^0.2.1" + "napi-postinstall": "^0.2.2" }, "funding": { - "url": "https://github.com/sponsors/JounQin" + "url": "https://opencollective.com/unrs-resolver" }, "optionalDependencies": { - "@unrs/resolver-binding-darwin-arm64": "1.7.1", - "@unrs/resolver-binding-darwin-x64": "1.7.1", - "@unrs/resolver-binding-freebsd-x64": "1.7.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.7.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.7.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.7.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-x64-musl": "1.7.1", - "@unrs/resolver-binding-wasm32-wasi": "1.7.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.7.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.7.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.7.1" + "@unrs/resolver-binding-darwin-arm64": "1.7.8", + "@unrs/resolver-binding-darwin-x64": "1.7.8", + "@unrs/resolver-binding-freebsd-x64": "1.7.8", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.8", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.8", + "@unrs/resolver-binding-linux-arm64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-arm64-musl": "1.7.8", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-riscv64-musl": "1.7.8", + "@unrs/resolver-binding-linux-s390x-gnu": "1.7.8", + "@unrs/resolver-binding-linux-x64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-x64-musl": "1.7.8", + "@unrs/resolver-binding-wasm32-wasi": "1.7.8", + "@unrs/resolver-binding-win32-arm64-msvc": "1.7.8", + "@unrs/resolver-binding-win32-ia32-msvc": "1.7.8", + "@unrs/resolver-binding-win32-x64-msvc": "1.7.8" } }, "node_modules/upath": { @@ -17475,11 +17462,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/validate.js": { - "version": "0.13.1", - "dev": true, - "license": "MIT" - }, "node_modules/vary": { "version": "1.1.2", "license": "MIT", @@ -17602,19 +17584,19 @@ } }, "node_modules/webdriver": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.12.6.tgz", - "integrity": "sha512-Alz+JiaVW15b/Qy6zSmJeYXxvmtMIVpEAg7QDfCWqG9miZSKJYWwgWE3xoSrwYn5kTylUszqb17Pb5wyrj7YFw==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.14.0.tgz", + "integrity": "sha512-0mVjxafQ5GNdK4l/FVmmmXGUfLHCSBE4Ml2LG23rxgmw53CThAos6h01UgIEINonxIzgKEmwfqJioo3/frbpbQ==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "9.12.6", + "@wdio/config": "9.14.0", "@wdio/logger": "9.4.4", - "@wdio/protocols": "9.12.5", - "@wdio/types": "9.12.6", - "@wdio/utils": "9.12.6", + "@wdio/protocols": "9.14.0", + "@wdio/types": "9.14.0", + "@wdio/utils": "9.14.0", "deepmerge-ts": "^7.0.3", "undici": "^6.20.1", "ws": "^8.8.0" @@ -17624,9 +17606,9 @@ } }, "node_modules/webdriver/node_modules/@types/node": { - "version": "20.17.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.31.tgz", - "integrity": "sha512-quODOCNXQAbNf1Q7V+fI8WyErOCh0D5Yd31vHnKu4GkSztGQ7rlltAaqXhHhLl33tlVyUXs2386MkANSwgDn6A==", + "version": "20.17.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz", + "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -17650,9 +17632,9 @@ } }, "node_modules/webdriver/node_modules/@wdio/protocols": { - "version": "9.12.5", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.12.5.tgz", - "integrity": "sha512-i+yc0EZtZOh5fFuwHxvcnXeTXk2ZjFICRbcAxTNE0F2Jr4uOydvcAOw4EIIRmb9NWUSPf/bGZAA+4SEXmxmjUA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.14.0.tgz", + "integrity": "sha512-inJR+G8iiFrk8/JPMfxpy6wA7rvMIZFV0T8vDN1Io7sGGj+EXX7ujpDxoCns53qxV4RytnSlgHRcCaASPFcecQ==", "dev": true, "license": "MIT" }, @@ -17699,20 +17681,20 @@ } }, "node_modules/webdriverio": { - "version": "9.12.7", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.12.7.tgz", - "integrity": "sha512-HxpLQrFuadfE65dqh+Qc2pdvz18FbsdpdiZogy8VUBtxRanijbOsi4cV84ffGXab8Ownzu+bNBJuJjlTBDX00Q==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.14.0.tgz", + "integrity": "sha512-GP0p6J+yjcCXF9uXW7HjB6IEh33OKmZcLTSg/W2rnVYSWgsUEYPujKSXe5I8q5a99QID7OOKNKVMfs5ANoZ2BA==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "^20.11.30", "@types/sinonjs__fake-timers": "^8.1.5", - "@wdio/config": "9.12.6", + "@wdio/config": "9.14.0", "@wdio/logger": "9.4.4", - "@wdio/protocols": "9.12.5", + "@wdio/protocols": "9.14.0", "@wdio/repl": "9.4.4", - "@wdio/types": "9.12.6", - "@wdio/utils": "9.12.6", + "@wdio/types": "9.14.0", + "@wdio/utils": "9.14.0", "archiver": "^7.0.1", "aria-query": "^5.3.0", "cheerio": "^1.0.0-rc.12", @@ -17729,7 +17711,7 @@ "rgb2hex": "0.2.5", "serialize-error": "^11.0.3", "urlpattern-polyfill": "^10.0.0", - "webdriver": "9.12.6" + "webdriver": "9.14.0" }, "engines": { "node": ">=18.20.0" @@ -17770,9 +17752,9 @@ } }, "node_modules/webdriverio/node_modules/@wdio/protocols": { - "version": "9.12.5", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.12.5.tgz", - "integrity": "sha512-i+yc0EZtZOh5fFuwHxvcnXeTXk2ZjFICRbcAxTNE0F2Jr4uOydvcAOw4EIIRmb9NWUSPf/bGZAA+4SEXmxmjUA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.14.0.tgz", + "integrity": "sha512-inJR+G8iiFrk8/JPMfxpy6wA7rvMIZFV0T8vDN1Io7sGGj+EXX7ujpDxoCns53qxV4RytnSlgHRcCaASPFcecQ==", "dev": true, "license": "MIT" }, @@ -18216,9 +18198,9 @@ } }, "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -18481,14 +18463,14 @@ "ora": "5.4.1", "package-changed": "3.0.0", "resolve-from": "5.0.0", - "semver": "7.7.1", + "semver": "7.7.2", "source-map-support": "0.5.21", - "teen_process": "2.3.1", - "type-fest": "4.40.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", "winston": "3.17.0", "wrap-ansi": "7.0.0", - "ws": "8.18.1", - "yaml": "2.7.1" + "ws": "8.18.2", + "yaml": "2.8.0" }, "bin": { "appium": "index.js" @@ -18528,9 +18510,9 @@ "license": "ISC" }, "packages/appium/node_modules/type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -18560,15 +18542,15 @@ } }, "packages/appium/node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" } }, "packages/base-driver": { @@ -18594,7 +18576,7 @@ "path-to-regexp": "8.2.0", "serve-favicon": "2.5.0", "source-map-support": "0.5.21", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "engines": { "node": "^20.9.0 || >=22.11.0", @@ -18975,9 +18957,9 @@ } }, "packages/base-driver/node_modules/type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -19021,15 +19003,15 @@ "@appium/support": "^6.1.0", "chalk": "4.1.2", "consola": "3.4.2", - "diff": "7.0.0", + "diff": "8.0.02", "lilconfig": "3.1.3", "lodash": "4.17.21", "pkg-dir": "5.0.0", "read-pkg": "5.2.0", "source-map-support": "0.5.21", - "teen_process": "2.3.1", - "type-fest": "4.40.1", - "yaml": "2.7.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", + "yaml": "2.8.0", "yargs": "17.7.2", "yargs-parser": "21.1.1" }, @@ -19091,9 +19073,9 @@ } }, "packages/docutils/node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -19122,9 +19104,9 @@ } }, "packages/docutils/node_modules/type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -19134,15 +19116,15 @@ } }, "packages/docutils/node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" } }, "packages/driver-test-support": { @@ -19159,7 +19141,7 @@ "lodash": "4.17.21", "sinon": "20.0.0", "source-map-support": "0.5.21", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", @@ -19182,9 +19164,9 @@ } }, "packages/driver-test-support/node_modules/type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -19221,7 +19203,7 @@ "bluebird": "3.7.2", "lodash": "4.17.21", "source-map-support": "0.5.21", - "webdriverio": "9.12.7" + "webdriverio": "9.14.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", @@ -19825,7 +19807,7 @@ "@appium/support": "^6.1.0", "lodash": "4.17.21", "lru-cache": "10.4.3", - "sharp": "0.34.1", + "sharp": "0.34.2", "source-map-support": "0.5.21" }, "engines": { @@ -19938,7 +19920,7 @@ "bluebird": "3.7.2", "lodash": "4.17.21", "opencv-bindings": "4.5.5", - "sharp": "0.34.1", + "sharp": "0.34.2", "source-map-support": "0.5.21" }, "engines": { @@ -20022,7 +20004,7 @@ "get-port": "5.1.1", "log-symbols": "4.1.0", "source-map-support": "0.5.21", - "teen_process": "2.3.1" + "teen_process": "2.3.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", @@ -20074,7 +20056,7 @@ "lru-cache": "10.4.3", "rimraf": "5.0.10", "source-map-support": "0.5.21", - "ws": "8.18.1" + "ws": "8.18.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", @@ -20135,12 +20117,12 @@ "read-pkg": "5.2.0", "resolve-from": "5.0.0", "sanitize-filename": "1.6.3", - "semver": "7.7.1", + "semver": "7.7.2", "shell-quote": "1.8.2", "source-map-support": "0.5.21", "supports-color": "8.1.1", - "teen_process": "2.3.1", - "type-fest": "4.40.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", "uuid": "11.1.0", "which": "4.0.0", "yauzl": "3.2.0" @@ -20150,7 +20132,7 @@ "npm": ">=8" }, "optionalDependencies": { - "sharp": "0.34.1" + "sharp": "0.34.2" } }, "packages/support/node_modules/axios": { @@ -20315,9 +20297,9 @@ } }, "packages/support/node_modules/type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -20408,7 +20390,7 @@ "@appium/logger": "^1.7.0", "@appium/schema": "^0.8.1", "@appium/tsconfig": "^0.3.5", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", @@ -20416,9 +20398,9 @@ } }, "packages/types/node_modules/type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -20433,7 +20415,7 @@ "license": "Apache-2.0", "dependencies": { "@xmldom/xmldom": "0.9.8", - "fast-xml-parser": "5.2.1", + "fast-xml-parser": "5.2.3", "lodash": "4.17.21", "source-map-support": "0.5.21", "xpath": "0.0.34" @@ -20447,9 +20429,9 @@ } }, "packages/universal-xml-plugin/node_modules/fast-xml-parser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.1.tgz", - "integrity": "sha512-Kqq/ewnRACQ20e0BlQ5KqHRYWRBp7yv+jttK4Yj2yY+2ldgCoxJkrP1NHUhjypsJ+eQXlGJ/jebM3wa60s1rbQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.3.tgz", + "integrity": "sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==", "funding": [ { "type": "github", @@ -20458,16 +20440,16 @@ ], "license": "MIT", "dependencies": { - "strnum": "^2.0.5" + "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "packages/universal-xml-plugin/node_modules/strnum": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.0.5.tgz", - "integrity": "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", "funding": [ { "type": "github", @@ -20516,7 +20498,7 @@ "serve-favicon": "2.5.0", "source-map-support": "0.5.21", "spdy": "4.0.2", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "dependencies": { "accepts": { @@ -20778,9 +20760,9 @@ } }, "type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==" + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==" }, "type-is": { "version": "2.0.0", @@ -20807,15 +20789,15 @@ "@appium/support": "^6.1.0", "chalk": "4.1.2", "consola": "3.4.2", - "diff": "7.0.0", + "diff": "8.0.02", "lilconfig": "3.1.3", "lodash": "4.17.21", "pkg-dir": "5.0.0", "read-pkg": "5.2.0", "source-map-support": "0.5.21", - "teen_process": "2.3.1", - "type-fest": "4.40.1", - "yaml": "2.7.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", + "yaml": "2.8.0", "yargs": "17.7.2", "yargs-parser": "21.1.1" }, @@ -20847,9 +20829,9 @@ "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==" }, "diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==" + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==" }, "lilconfig": { "version": "3.1.3", @@ -20863,14 +20845,14 @@ } }, "type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==" + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==" }, "yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==" + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==" } } }, @@ -20886,7 +20868,7 @@ "lodash": "4.17.21", "sinon": "20.0.0", "source-map-support": "0.5.21", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "dependencies": { "axios": { @@ -20899,9 +20881,9 @@ } }, "type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==" + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==" } } }, @@ -20915,7 +20897,7 @@ "bluebird": "3.7.2", "lodash": "4.17.21", "source-map-support": "0.5.21", - "webdriverio": "9.12.7" + "webdriverio": "9.14.0" }, "dependencies": { "@puppeteer/browsers": { @@ -21311,7 +21293,7 @@ "@appium/support": "^6.1.0", "lodash": "4.17.21", "lru-cache": "10.4.3", - "sharp": "0.34.1", + "sharp": "0.34.2", "source-map-support": "0.5.21" }, "dependencies": { @@ -21394,7 +21376,7 @@ "bluebird": "3.7.2", "lodash": "4.17.21", "opencv-bindings": "4.5.5", - "sharp": "0.34.1", + "sharp": "0.34.2", "source-map-support": "0.5.21" }, "dependencies": { @@ -21457,7 +21439,7 @@ "get-port": "5.1.1", "log-symbols": "4.1.0", "source-map-support": "0.5.21", - "teen_process": "2.3.1" + "teen_process": "2.3.2" } }, "@appium/relaxed-caps-plugin": { @@ -21484,7 +21466,7 @@ "lru-cache": "10.4.3", "rimraf": "5.0.10", "source-map-support": "0.5.21", - "ws": "8.18.1" + "ws": "8.18.2" }, "dependencies": { "lru-cache": { @@ -21531,13 +21513,13 @@ "read-pkg": "5.2.0", "resolve-from": "5.0.0", "sanitize-filename": "1.6.3", - "semver": "7.7.1", - "sharp": "0.34.1", + "semver": "7.7.2", + "sharp": "0.34.2", "shell-quote": "1.8.2", "source-map-support": "0.5.21", "supports-color": "8.1.1", - "teen_process": "2.3.1", - "type-fest": "4.40.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", "uuid": "11.1.0", "which": "4.0.0", "yauzl": "3.2.0" @@ -21655,9 +21637,9 @@ } }, "type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==" + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==" }, "uuid": { "version": "11.1.0", @@ -21707,13 +21689,13 @@ "@appium/logger": "^1.7.0", "@appium/schema": "^0.8.1", "@appium/tsconfig": "^0.3.5", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "dependencies": { "type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==" + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==" } } }, @@ -21721,24 +21703,24 @@ "version": "file:packages/universal-xml-plugin", "requires": { "@xmldom/xmldom": "0.9.8", - "fast-xml-parser": "5.2.1", + "fast-xml-parser": "5.2.3", "lodash": "4.17.21", "source-map-support": "0.5.21", "xpath": "0.0.34" }, "dependencies": { "fast-xml-parser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.1.tgz", - "integrity": "sha512-Kqq/ewnRACQ20e0BlQ5KqHRYWRBp7yv+jttK4Yj2yY+2ldgCoxJkrP1NHUhjypsJ+eQXlGJ/jebM3wa60s1rbQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.3.tgz", + "integrity": "sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==", "requires": { - "strnum": "^2.0.5" + "strnum": "^2.1.0" } }, "strnum": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.0.5.tgz", - "integrity": "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==" } } }, @@ -21816,15 +21798,17 @@ } }, "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "requires": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "dependencies": { "eslint-visitor-keys": { - "version": "3.3.0" + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" } } }, @@ -21856,9 +21840,9 @@ "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==" }, "@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "requires": { "@types/json-schema": "^7.0.15" } @@ -21903,9 +21887,9 @@ } }, "@eslint/js": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", - "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==" + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", + "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==" }, "@eslint/object-schema": { "version": "2.1.6", @@ -21913,11 +21897,11 @@ "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==" }, "@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "requires": { - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "levn": "^0.4.1" } }, @@ -23129,24 +23113,24 @@ } }, "@puppeteer/browsers": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.2.tgz", - "integrity": "sha512-i4Ez+s9oRWQbNjtI/3+jxr7OH508mjAKvza0ekPJem0ZtmsYHP3B5dq62+IaBHKaGCOuqJxXzvFLUhJvQ6jtsQ==", + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.5.tgz", + "integrity": "sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==", "dev": true, "requires": { - "debug": "^4.4.0", + "debug": "^4.4.1", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", - "semver": "^7.7.1", + "semver": "^7.7.2", "tar-fs": "^3.0.8", "yargs": "^17.7.2" }, "dependencies": { "debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "requires": { "ms": "^2.1.3" @@ -23414,12 +23398,6 @@ "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true }, - "@types/diff": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/diff/-/diff-7.0.2.tgz", - "integrity": "sha512-JSWRMozjFKsGlEjiiKajUjIJVKuKdE3oVy2DNtK+fUo8q82nhFZ2CPQwicAIkXrofahDXrWJ7mjelvZphMS98Q==", - "dev": true - }, "@types/eslint": { "version": "7.29.0", "dev": true, @@ -23726,71 +23704,96 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz", - "integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.0.tgz", + "integrity": "sha512-CACyQuqSHt7ma3Ns601xykeBK/rDeZa3w6IS6UtMQbixO5DWy+8TilKkviGDH6jtWCo8FGRKEK5cLLkPvEammQ==", "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/type-utils": "8.31.0", - "@typescript-eslint/utils": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/type-utils": "8.33.0", + "@typescript-eslint/utils": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" + }, + "dependencies": { + "ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==" + } } }, "@typescript-eslint/parser": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz", - "integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.0.tgz", + "integrity": "sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ==", "requires": { - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/project-service": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.0.tgz", + "integrity": "sha512-d1hz0u9l6N+u/gcrk6s6gYdl7/+pp8yHheRTqP6X5hVDKALEaTn8WfGiit7G511yueBEL3OpOEpD+3/MBdoN+A==", + "requires": { + "@typescript-eslint/tsconfig-utils": "^8.33.0", + "@typescript-eslint/types": "^8.33.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz", - "integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.0.tgz", + "integrity": "sha512-LMi/oqrzpqxyO72ltP+dBSP6V0xiUb4saY7WLtxSfiNEBI8m321LLVFU9/QDJxjDQG9/tjSqKz/E3380TEqSTw==", "requires": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0" + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0" } }, + "@typescript-eslint/tsconfig-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.0.tgz", + "integrity": "sha512-sTkETlbqhEoiFmGr1gsdq5HyVbSOF0145SYDJ/EQmXHtKViCaGvnyLqWFFHtEXoS0J1yU8Wyou2UGmgW88fEug==", + "requires": {} + }, "@typescript-eslint/type-utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz", - "integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.0.tgz", + "integrity": "sha512-lScnHNCBqL1QayuSrWeqAL5GmqNdVUQAAMTaCwdYEdWfIrSrOGzyLGRCHXcCixa5NK6i5l0AfSO2oBSjCjf4XQ==", "requires": { - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/utils": "8.31.0", + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/utils": "8.33.0", "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" } }, "@typescript-eslint/types": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz", - "integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==" + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz", + "integrity": "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg==" }, "@typescript-eslint/typescript-estree": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz", - "integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.0.tgz", + "integrity": "sha512-vegY4FQoB6jL97Tu/lWRsAiUUp8qJTqzAmENH2k59SJhw0Th1oszb9Idq/FyyONLuNqT1OADJPXfyUNOR8SzAQ==", "requires": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/project-service": "8.33.0", + "@typescript-eslint/tsconfig-utils": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "dependencies": { "brace-expansion": { @@ -23812,22 +23815,22 @@ } }, "@typescript-eslint/utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz", - "integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.0.tgz", + "integrity": "sha512-lPFuQaLA9aSNa7D5u2EpRiqdAUhzShwGg/nhpBlc4GR6kcTABttCuyjFs8BcEZ8VWrjCBof/bePhP3Q3fS+Yrw==", "requires": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0" } }, "@typescript-eslint/visitor-keys": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz", - "integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.0.tgz", + "integrity": "sha512-7RW7CMYoskiz5OOGAWjJFxgb7c5UNjTG292gYhWeOAcFmYCtVCSqjqSBj5zMhxbXo2JOW95YYrUWJfU0zrpaGQ==", "requires": { - "@typescript-eslint/types": "8.31.0", + "@typescript-eslint/types": "8.33.0", "eslint-visitor-keys": "^4.2.0" }, "dependencies": { @@ -23839,90 +23842,90 @@ } }, "@unrs/resolver-binding-darwin-arm64": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.1.tgz", - "integrity": "sha512-KJfNZWh3ZzLVrIyQHcKf8vAzHHE4H7f6Huf07rdCwAWwfsvtGEYIYBDCEKfzfTDOMSR7J0AFsOUDEfOhJHGj7Q==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.8.tgz", + "integrity": "sha512-rsRK8T7yxraNRDmpFLZCWqpea6OlXPNRRCjWMx24O1V86KFol7u2gj9zJCv6zB1oJjtnzWceuqdnCgOipFcJPA==", "optional": true }, "@unrs/resolver-binding-darwin-x64": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.1.tgz", - "integrity": "sha512-Eepa8XBbiSaNC5w9lda8QtW9d4pO7oX9DEEoZkIRUh37G5dk7r7hquAG2v1wsr9UbDHikuPgUGS78CYYmcQPvA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.8.tgz", + "integrity": "sha512-16yEMWa+Olqkk8Kl6Bu0ltT5OgEedkSAsxcz1B3yEctrDYp3EMBu/5PPAGhWVGnwhtf3hNe3y15gfYBAjOv5tQ==", "optional": true }, "@unrs/resolver-binding-freebsd-x64": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.1.tgz", - "integrity": "sha512-xcm5adD2ArFkzvH8DZ1BBwi4p1os0D1lid+T6lPxLcopP1bI1gi/RTqBDp2a5bOWh/wjAIRqxO5Co8dY9ngz3A==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.8.tgz", + "integrity": "sha512-ST4uqF6FmdZQgv+Q73FU1uHzppeT4mhX3IIEmHlLObrv5Ep50olWRz0iQ4PWovadjHMTAmpuJAGaAuCZYb7UAQ==", "optional": true }, "@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.1.tgz", - "integrity": "sha512-UK6CL/EaBGuu1+O/veX7PAXpjIJJgUcYmSow0CYcEzR5WBJakciPiuk2VA7lxGEFi8NdstwN/TNBGEcrfVi5UA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.8.tgz", + "integrity": "sha512-Z/A/4Rm2VWku2g25C3tVb986fY6unx5jaaCFpx1pbAj0OKkyuJ5wcQLHvNbIcJ9qhiYwXfrkB7JNlxrAbg7YFg==", "optional": true }, "@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.1.tgz", - "integrity": "sha512-qOgInSOcVW35p5XoEUWRnVO5TzR268LnWyJUNoxeFZiXfPRSf/oIBFie3J3pkF5OteWO8Eg+gP/p291bJN9QVQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.8.tgz", + "integrity": "sha512-HN0p7o38qKmDo3bZUiQa6gP7Qhf0sKgJZtRfSHi6JL2Gi4NaUVF0EO1sQ1RHbeQ4VvfjUGMh3QE5dxEh06BgQQ==", "optional": true }, "@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.1.tgz", - "integrity": "sha512-VOleS+xSSXNk2+7pMgcbZgqLjXGVczMJneLqCu7l+PQ9QtcZ0gVbj95vc3+mqEbrAue9Mve65CyQVJTNeUET5g==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.8.tgz", + "integrity": "sha512-HsoVqDBt9G69AN0KWeDNJW+7i8KFlwxrbbnJffgTGpiZd6Jw+Q95sqkXp8y458KhKduKLmXfVZGnKBTNxAgPjw==", "optional": true }, "@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.1.tgz", - "integrity": "sha512-dLpmqdK1Fxz12uFYrxg/HltL2mWaIHlYf/XARbrcmPDmGfrkhwEVi9iw5aNKY1ojSD/iNoISmWKS7HVkHy4ZFA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.8.tgz", + "integrity": "sha512-VfR2yTDUbUvn+e/Aw22CC9fQg9zdShHAfwWctNBdOk7w9CHWl2OtYlcMvjzMAns8QxoHQoqn3/CEnZ4Ts7hfrA==", "optional": true }, "@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.1.tgz", - "integrity": "sha512-xaVrau4Gmx/pRzCq3AFUT3cTEaK9Jj/PeEkOQweRczM8GdaQbp6kkxciZOP3ZJp1f2W3IkIuYkrV6Oz7z58zZg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.8.tgz", + "integrity": "sha512-xUauVQNz4uDgs4UJJiUAwMe3N0PA0wvtImh7V0IFu++UKZJhssXbKHBRR4ecUJpUHCX2bc4Wc8sGsB6P+7BANg==", "optional": true }, "@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.1.tgz", - "integrity": "sha512-J38QcQPnfpN8H/6+3tTpgSu/w6qGHKlBpHfAKx+2sklYW/R4BLgXnhCEmkeyU3RFKQ0hmkzwAZ2U+fAiVDY+mw==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.8.tgz", + "integrity": "sha512-GqyIB+CuSHGhhc8ph5RrurtNetYJjb6SctSHafqmdGcRuGi6uyTMR8l18hMEhZFsXdFMc/MpInPLvmNV22xn+A==", "optional": true }, "@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.1.tgz", - "integrity": "sha512-GfISZFM2r/z87oXpfLXDNoA51jMoVJa5oUxGX62/ZFNAXu6GzzgTwaaT7plq+II1BkID9gQG1hGOoHCwz2PClA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.8.tgz", + "integrity": "sha512-eEU3rWIFRv60xaAbtsgwHNWRZGD7cqkpCvNtio/f1TjEE3HfKLzPNB24fA9X/8ZXQrGldE65b7UKK3PmO4eWIQ==", "optional": true }, "@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.1.tgz", - "integrity": "sha512-DSGpaQ8OWhdJPQNPEhG5+KeJOGAaGnfi8eKmAUYI/R0IPMUMrm64dTo/d68jdYVn9y7Cu53LIPM4k9UBzjCwGg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.8.tgz", + "integrity": "sha512-GVLI0f4I4TlLqEUoOFvTWedLsJEdvsD0+sxhdvQ5s+N+m2DSynTs8h9jxR0qQbKlpHWpc2Ortz3z48NHRT4l+w==", "optional": true }, "@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.1.tgz", - "integrity": "sha512-3U0mVIRMB82he3+MFH5cLMsTxqlr8Q5/g6Sz3MEbnET3+qJKqBa7zEbHWHEko4N04CSas8BUEr+L2UFRsCrFaQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.8.tgz", + "integrity": "sha512-GX1pZ/4ncUreB0Rlp1l7bhKAZ8ZmvDIgXdeb5V2iK0eRRF332+6gRfR/r5LK88xfbtOpsmRHU6mQ4N8ZnwvGEA==", "optional": true }, "@unrs/resolver-binding-linux-x64-musl": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.1.tgz", - "integrity": "sha512-I8KcPBu0reYgzAjTe+5PJg7VXXjjHuAQzr8UfHV+H7xz5Cfgmnrdsa9LAZRg+SQlpjH0mO3QVFeRlaoDjmYwdQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.8.tgz", + "integrity": "sha512-n1N84MnsvDupzVuYqJGj+2pb9s8BI1A5RgXHvtVFHedGZVBCFjDpQVRlmsFMt6xZiKwDPaqsM16O/1isCUGt7w==", "optional": true }, "@unrs/resolver-binding-wasm32-wasi": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.1.tgz", - "integrity": "sha512-VV1AVT5ikRtb2GMq+LfOHUMaZzkbua5PdAv97+L5gp6+5R49aCIAHFZMW3VNU0LYUHwn0WwzgFMQ7hVlHYX7MA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.8.tgz", + "integrity": "sha512-x94WnaU5g+pCPDVedfnXzoG6lCOF2xFGebNwhtbJCWfceE94Zj8aysSxdxotlrZrxnz5D3ijtyFUYtpz04n39Q==", "optional": true, "requires": { - "@napi-rs/wasm-runtime": "^0.2.9" + "@napi-rs/wasm-runtime": "^0.2.10" }, "dependencies": { "@emnapi/runtime": { @@ -23935,45 +23938,45 @@ } }, "@napi-rs/wasm-runtime": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.9.tgz", - "integrity": "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz", + "integrity": "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==", "optional": true, "requires": { - "@emnapi/core": "^1.4.0", - "@emnapi/runtime": "^1.4.0", + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" } } } }, "@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.1.tgz", - "integrity": "sha512-i6T6/GsTn0B8fthG7jkn/wFBrwJKBm4/V/bZB8j+FtrlW9nk0xL2IckBO6NuwaX2d47b7vMUTVMcG+CKPRmcMw==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.8.tgz", + "integrity": "sha512-vst2u8EJZ5L6jhJ6iLis3w9rg16aYqRxQuBAMYQRVrPMI43693hLP7DuqyOBRKgsQXy9/jgh204k0ViHkqQgdg==", "optional": true }, "@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.1.tgz", - "integrity": "sha512-d6Cy8VqTGT/ehavIek6XNi7ZVpKhyG0CXgYBPNNdZWI+7huy3KfQM2ME5pEKudkOLjtzEsbwWnNdCswpn6s/tg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.8.tgz", + "integrity": "sha512-yb3LZOLMFqnA+/ShlE1E5bpYPGDsA590VHHJPB+efnyowT776GJXBoh82em6O9WmYBUq57YblGTcMYAFBm72HA==", "optional": true }, "@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.1.tgz", - "integrity": "sha512-isaSSX0p2m4Fe9gjJZi+ga6yeRhej237QiC0vQVawsA1Xmr3updYoEEpB4F0LNVjmLUiLqxfmh8f68eGThYqtg==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.8.tgz", + "integrity": "sha512-hHKFx+opG5BA3/owMXon8ypwSotBGTdblG6oda/iOu9+OEYnk0cxD2uIcGyGT8jCK578kV+xMrNxqbn8Zjlpgw==", "optional": true }, "@wdio/config": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.12.6.tgz", - "integrity": "sha512-zlOJixJUHxeoyfIN/KdM797HwJj/oNgBaEdftgJARqbXt5AVZu18vJ3zljb+wzbY2M0pl7Y4+5OFH06WlDgQ+A==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.14.0.tgz", + "integrity": "sha512-mW6VAXfUgd2j+8YJfFWvg8Ba/7g1Brr6/+MFBpp5rTQsw/2bN3PBJsQbWpNl99OCgoS8vgc5Ykps5ZUEeffSVQ==", "dev": true, "requires": { "@wdio/logger": "9.4.4", - "@wdio/types": "9.12.6", - "@wdio/utils": "9.12.6", + "@wdio/types": "9.14.0", + "@wdio/utils": "9.14.0", "deepmerge-ts": "^7.0.3", "glob": "^10.2.2", "import-meta-resolve": "^4.0.0" @@ -24117,18 +24120,18 @@ } }, "@wdio/types": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.12.6.tgz", - "integrity": "sha512-WzZhaN834du9wjqT/Go9qPyB7VkzV2bjr6pr06DrIzxIpJq/snWOv96C6OjJu8nmYNRjV769mAxyggBUf+sUoQ==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.14.0.tgz", + "integrity": "sha512-Zqc4sxaQLIXdI1EHItIuVIOn7LvPmDvl9JEANwiJ35ck82Xlj+X55Gd9NtELSwChzKgODD0OBzlLgXyxTr69KA==", "dev": true, "requires": { "@types/node": "^20.1.0" }, "dependencies": { "@types/node": { - "version": "20.17.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.31.tgz", - "integrity": "sha512-quODOCNXQAbNf1Q7V+fI8WyErOCh0D5Yd31vHnKu4GkSztGQ7rlltAaqXhHhLl33tlVyUXs2386MkANSwgDn6A==", + "version": "20.17.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz", + "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==", "dev": true, "requires": { "undici-types": "~6.19.2" @@ -24137,14 +24140,14 @@ } }, "@wdio/utils": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.12.6.tgz", - "integrity": "sha512-JfI4CxBRQCOgToJeQNaZLv+wYNIGyJG1gqrpxUOvkrJvBgdOAmIu3dzlcKP/WviXlcxvwLQF2FK8bQVTjHv0fQ==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.14.0.tgz", + "integrity": "sha512-oJapwraSflOe0CmeF3TBocdt983hq9mCutLCfie4QmE+TKRlCsZz4iidG1NRAZPGdKB32nfHtyQlW0Dfxwn6RA==", "dev": true, "requires": { "@puppeteer/browsers": "^2.2.0", "@wdio/logger": "9.4.4", - "@wdio/types": "9.12.6", + "@wdio/types": "9.14.0", "decamelize": "^6.0.0", "deepmerge-ts": "^7.0.3", "edgedriver": "^6.1.1", @@ -24334,7 +24337,8 @@ "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==" + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true }, "ansi-escapes": { "version": "4.3.2", @@ -24359,13 +24363,6 @@ "color-convert": "^1.9.0" } }, - "anymatch": { - "version": "3.1.3", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, "appium": { "version": "file:packages/appium", "requires": { @@ -24390,14 +24387,14 @@ "ora": "5.4.1", "package-changed": "3.0.0", "resolve-from": "5.0.0", - "semver": "7.7.1", + "semver": "7.7.2", "source-map-support": "0.5.21", - "teen_process": "2.3.1", - "type-fest": "4.40.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", "winston": "3.17.0", "wrap-ansi": "7.0.0", - "ws": "8.18.1", - "yaml": "2.7.1" + "ws": "8.18.2", + "yaml": "2.8.0" }, "dependencies": { "axios": { @@ -24420,9 +24417,9 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "type-fest": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", - "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==" + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==" }, "ws": { "version": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", @@ -24430,9 +24427,9 @@ "requires": {} }, "yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==" + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==" } } }, @@ -24868,9 +24865,6 @@ "write-file-atomic": "^5.0.0" } }, - "binary-extensions": { - "version": "2.2.0" - }, "bl": { "version": "4.1.0", "requires": { @@ -25266,16 +25260,11 @@ } }, "chokidar": { - "version": "3.5.3", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" } }, "chownr": { @@ -26089,9 +26078,9 @@ "version": "1.2.0" }, "detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==" }, "detect-node": { "version": "2.1.0", @@ -26100,9 +26089,9 @@ "optional": true }, "diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==" }, "diff-sequences": { "version": "29.4.3", @@ -26512,18 +26501,18 @@ } }, "eslint": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", - "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", + "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", + "@eslint/js": "9.27.0", + "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -26628,9 +26617,9 @@ } }, "eslint-config-prettier": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz", - "integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==", + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "requires": {} }, "eslint-formatter-pretty": { @@ -26682,6 +26671,15 @@ } } }, + "eslint-import-context": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.6.tgz", + "integrity": "sha512-/e2ZNPDLCrU8niIy0pddcvXuoO2YrKjf3NAIX+60mHJBT4yv7mqCqvVdyCW2E720e25e4S/1OSVef4U6efGLFg==", + "requires": { + "get-tsconfig": "^4.10.1", + "stable-hash": "^0.0.5" + } + }, "eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -26701,22 +26699,23 @@ } }, "eslint-import-resolver-typescript": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.3.4.tgz", - "integrity": "sha512-buzw5z5VtiQMysYLH9iW9BV04YyZebsw+gPi+c4FCjfS9i6COYOrEWw9t3m3wA9PFBfqcBCqWf32qrXLbwafDw==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.1.tgz", + "integrity": "sha512-KHQnjMAn/Hbs1AcMs2YfJTeNoWsaOoMRvJUKr77Y2dv7jNOaT8/IJYlvfN/ZIwTxUsv2B6amwv7u9bt2Vl9lZg==", "requires": { - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.5", + "get-tsconfig": "^4.10.1", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.3" + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.2" }, "dependencies": { "debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "requires": { "ms": "^2.1.3" } @@ -27253,10 +27252,6 @@ "version": "1.0.0", "dev": true }, - "fsevents": { - "version": "2.3.2", - "optional": true - }, "ftp-response-parser": { "version": "1.0.1", "requires": { @@ -27451,9 +27446,9 @@ } }, "get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "requires": { "resolve-pkg-maps": "^1.0.0" } @@ -27794,7 +27789,9 @@ } }, "http-cache-semantics": { - "version": "4.1.1", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true }, "http-deceiver": { @@ -28123,12 +28120,6 @@ "has-bigints": "^1.0.1" } }, - "is-binary-path": { - "version": "2.1.0", - "requires": { - "binary-extensions": "^2.0.0" - } - }, "is-boolean-object": { "version": "1.1.2", "requires": { @@ -29143,10 +29134,6 @@ "lodash": { "version": "4.17.21" }, - "lodash._reinterpolate": { - "version": "3.0.0", - "dev": true - }, "lodash.clonedeep": { "version": "4.5.0" }, @@ -29162,25 +29149,6 @@ "lodash.merge": { "version": "4.6.2" }, - "lodash.some": { - "version": "4.6.0", - "dev": true - }, - "lodash.template": { - "version": "4.5.0", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, "lodash.zip": { "version": "4.2.0" }, @@ -29292,7 +29260,7 @@ "requires": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", - "http-cache-semantics": "4.1.1", + "http-cache-semantics": "4.2.0", "is-lambda": "^1.0.1", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", @@ -29822,23 +29790,23 @@ } }, "mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", - "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.5.0.tgz", + "integrity": "sha512-VKDjhy6LMTKm0WgNEdlY77YVsD49LZnPSXJAaPNL9NRYQADxvORsyG1DIQY6v53BKTnlNbEE2MbVCDbnxr4K3w==", "requires": { - "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", + "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", @@ -29880,16 +29848,6 @@ "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" - }, - "dependencies": { - "minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "requires": { - "brace-expansion": "^2.0.1" - } - } } }, "jackspeak": { @@ -29902,9 +29860,9 @@ } }, "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "requires": { "brace-expansion": "^2.0.1" } @@ -30022,9 +29980,9 @@ } }, "napi-postinstall": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.1.tgz", - "integrity": "sha512-3VK+GygwU4OMkBYdQLpRjxnt7idAsZAN5hnrWLHIAu4X+uO4uhqrIggKF1TacBV9OPUMwTb1sQQvwKRzfXLnQg==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz", + "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==" }, "natural-compare": { "version": "1.4.0" @@ -31611,10 +31569,9 @@ } }, "readdirp": { - "version": "3.6.0", - "requires": { - "picomatch": "^2.2.1" - } + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==" }, "redent": { "version": "3.0.0", @@ -31704,13 +31661,13 @@ "version": "1.0.4" }, "rewiremock": { - "version": "3.14.5", + "version": "3.14.6", + "resolved": "https://registry.npmjs.org/rewiremock/-/rewiremock-3.14.6.tgz", + "integrity": "sha512-hjpS7iQUTVVh/IHV4GE1ypg4IzlgVc34gxZBarwwVrKfnjlyqHJuQdsia6Ac7m4f4k/zxxA3tX285MOstdysRQ==", "dev": true, "requires": { "babel-runtime": "^6.26.0", "compare-module-exports": "^2.1.0", - "lodash.some": "^4.6.0", - "lodash.template": "^4.4.0", "node-libs-browser": "^2.1.0", "path-parse": "^1.0.5", "wipe-node-cache": "^2.1.2", @@ -31872,9 +31829,9 @@ "optional": true }, "semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==" }, "send": { "version": "0.19.0", @@ -32124,11 +32081,6 @@ "supports-color": "^7.2.0" }, "dependencies": { - "diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==" - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32669,9 +32621,9 @@ } }, "teen_process": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.3.1.tgz", - "integrity": "sha512-duT4gPj7HxEYy+AR4bJ9MNwf8GMLpJd+sNRAK2PTx53FpCcaiXVft3ePZh3hO6PY8NFWZMxTC3ZAtxyztScEsw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.3.2.tgz", + "integrity": "sha512-eiYtJbYrMz5WbZL68u05qCgLMShPZhYKVewZFoyT6C2xvNdMfikCP7Nh0K3Phiy+H4bMZ8q5GtJROFcoYwQJmQ==", "requires": { "bluebird": "^3.7.2", "lodash": "^4.17.21", @@ -32762,9 +32714,9 @@ } }, "tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "requires": { "fdir": "^6.4.4", "picomatch": "^4.0.2" @@ -33094,13 +33046,13 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==" }, "typescript-eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.0.tgz", - "integrity": "sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.33.0.tgz", + "integrity": "sha512-5YmNhF24ylCsvdNW2oJwMzTbaeO4bg90KeGtMjUw0AGtHksgEPLRTUil+coHwCfiu4QjVJFnjp94DmU6zV7DhQ==", "requires": { - "@typescript-eslint/eslint-plugin": "8.31.0", - "@typescript-eslint/parser": "8.31.0", - "@typescript-eslint/utils": "8.31.0" + "@typescript-eslint/eslint-plugin": "8.33.0", + "@typescript-eslint/parser": "8.33.0", + "@typescript-eslint/utils": "8.33.0" } }, "uglify-js": { @@ -33172,28 +33124,28 @@ "version": "1.0.0" }, "unrs-resolver": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.1.tgz", - "integrity": "sha512-jsXGehlxwxyetBCbABwgKB41xF1zhcnHYs9X16Cyx1aaWXFvqaXRJOpRgc/kB9zTBaSivwhFEHThoiu74PSU6w==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.8.tgz", + "integrity": "sha512-2zsXwyOXmCX9nGz4vhtZRYhe30V78heAv+KDc21A/KMdovGHbZcixeD5JHEF0DrFXzdytwuzYclcPbvp8A3Jlw==", "requires": { - "@unrs/resolver-binding-darwin-arm64": "1.7.1", - "@unrs/resolver-binding-darwin-x64": "1.7.1", - "@unrs/resolver-binding-freebsd-x64": "1.7.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.7.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.7.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.7.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.7.1", - "@unrs/resolver-binding-linux-x64-musl": "1.7.1", - "@unrs/resolver-binding-wasm32-wasi": "1.7.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.7.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.7.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.7.1", - "napi-postinstall": "^0.2.1" + "@unrs/resolver-binding-darwin-arm64": "1.7.8", + "@unrs/resolver-binding-darwin-x64": "1.7.8", + "@unrs/resolver-binding-freebsd-x64": "1.7.8", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.8", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.8", + "@unrs/resolver-binding-linux-arm64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-arm64-musl": "1.7.8", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-riscv64-musl": "1.7.8", + "@unrs/resolver-binding-linux-s390x-gnu": "1.7.8", + "@unrs/resolver-binding-linux-x64-gnu": "1.7.8", + "@unrs/resolver-binding-linux-x64-musl": "1.7.8", + "@unrs/resolver-binding-wasm32-wasi": "1.7.8", + "@unrs/resolver-binding-win32-arm64-msvc": "1.7.8", + "@unrs/resolver-binding-win32-ia32-msvc": "1.7.8", + "@unrs/resolver-binding-win32-x64-msvc": "1.7.8", + "napi-postinstall": "^0.2.2" } }, "upath": { @@ -33282,10 +33234,6 @@ "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", "dev": true }, - "validate.js": { - "version": "0.13.1", - "dev": true - }, "vary": { "version": "1.1.2" }, @@ -33370,27 +33318,27 @@ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" }, "webdriver": { - "version": "9.12.6", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.12.6.tgz", - "integrity": "sha512-Alz+JiaVW15b/Qy6zSmJeYXxvmtMIVpEAg7QDfCWqG9miZSKJYWwgWE3xoSrwYn5kTylUszqb17Pb5wyrj7YFw==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.14.0.tgz", + "integrity": "sha512-0mVjxafQ5GNdK4l/FVmmmXGUfLHCSBE4Ml2LG23rxgmw53CThAos6h01UgIEINonxIzgKEmwfqJioo3/frbpbQ==", "dev": true, "requires": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "9.12.6", + "@wdio/config": "9.14.0", "@wdio/logger": "9.4.4", - "@wdio/protocols": "9.12.5", - "@wdio/types": "9.12.6", - "@wdio/utils": "9.12.6", + "@wdio/protocols": "9.14.0", + "@wdio/types": "9.14.0", + "@wdio/utils": "9.14.0", "deepmerge-ts": "^7.0.3", "undici": "^6.20.1", "ws": "^8.8.0" }, "dependencies": { "@types/node": { - "version": "20.17.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.31.tgz", - "integrity": "sha512-quODOCNXQAbNf1Q7V+fI8WyErOCh0D5Yd31vHnKu4GkSztGQ7rlltAaqXhHhLl33tlVyUXs2386MkANSwgDn6A==", + "version": "20.17.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz", + "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==", "dev": true, "requires": { "undici-types": "~6.19.2" @@ -33409,9 +33357,9 @@ } }, "@wdio/protocols": { - "version": "9.12.5", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.12.5.tgz", - "integrity": "sha512-i+yc0EZtZOh5fFuwHxvcnXeTXk2ZjFICRbcAxTNE0F2Jr4uOydvcAOw4EIIRmb9NWUSPf/bGZAA+4SEXmxmjUA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.14.0.tgz", + "integrity": "sha512-inJR+G8iiFrk8/JPMfxpy6wA7rvMIZFV0T8vDN1Io7sGGj+EXX7ujpDxoCns53qxV4RytnSlgHRcCaASPFcecQ==", "dev": true }, "ansi-regex": { @@ -33438,19 +33386,19 @@ } }, "webdriverio": { - "version": "9.12.7", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.12.7.tgz", - "integrity": "sha512-HxpLQrFuadfE65dqh+Qc2pdvz18FbsdpdiZogy8VUBtxRanijbOsi4cV84ffGXab8Ownzu+bNBJuJjlTBDX00Q==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.14.0.tgz", + "integrity": "sha512-GP0p6J+yjcCXF9uXW7HjB6IEh33OKmZcLTSg/W2rnVYSWgsUEYPujKSXe5I8q5a99QID7OOKNKVMfs5ANoZ2BA==", "dev": true, "requires": { "@types/node": "^20.11.30", "@types/sinonjs__fake-timers": "^8.1.5", - "@wdio/config": "9.12.6", + "@wdio/config": "9.14.0", "@wdio/logger": "9.4.4", - "@wdio/protocols": "9.12.5", + "@wdio/protocols": "9.14.0", "@wdio/repl": "9.4.4", - "@wdio/types": "9.12.6", - "@wdio/utils": "9.12.6", + "@wdio/types": "9.14.0", + "@wdio/utils": "9.14.0", "archiver": "^7.0.1", "aria-query": "^5.3.0", "cheerio": "^1.0.0-rc.12", @@ -33467,7 +33415,7 @@ "rgb2hex": "0.2.5", "serialize-error": "^11.0.3", "urlpattern-polyfill": "^10.0.0", - "webdriver": "9.12.6" + "webdriver": "9.14.0" }, "dependencies": { "@types/node": { @@ -33492,9 +33440,9 @@ } }, "@wdio/protocols": { - "version": "9.12.5", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.12.5.tgz", - "integrity": "sha512-i+yc0EZtZOh5fFuwHxvcnXeTXk2ZjFICRbcAxTNE0F2Jr4uOydvcAOw4EIIRmb9NWUSPf/bGZAA+4SEXmxmjUA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.14.0.tgz", + "integrity": "sha512-inJR+G8iiFrk8/JPMfxpy6wA7rvMIZFV0T8vDN1Io7sGGj+EXX7ujpDxoCns53qxV4RytnSlgHRcCaASPFcecQ==", "dev": true }, "@wdio/repl": { @@ -33800,9 +33748,9 @@ } }, "ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", "requires": {} }, "xmlbuilder": { diff --git a/package.json b/package.json index 3dae8b2f0..c8b856705 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ }, "devDependencies": { "@colors/colors": "1.6.0", - "@eslint/js": "9.25.1", + "@eslint/js": "9.27.0", "@tsconfig/node14": "14.1.3", "@types/argparse": "2.0.17", "@types/archiver": "6.0.3", @@ -94,7 +94,6 @@ "@types/bluebird": "3.5.42", "@types/chai": "5.2.1", "@types/chai-as-promised": "8.0.2", - "@types/diff": "7.0.2", "@types/express": "5.0.1", "@types/jsftp": "2.1.5", "@types/json-schema": "7.0.15", @@ -127,9 +126,9 @@ "conventional-changelog-conventionalcommits": "7.0.2", "cpy-cli": "5.0.0", "cross-env": "7.0.3", - "eslint": "9.25.1", - "eslint-config-prettier": "10.1.2", - "eslint-import-resolver-typescript": "4.3.4", + "eslint": "9.27.0", + "eslint-config-prettier": "10.1.5", + "eslint-import-resolver-typescript": "4.4.1", "eslint-plugin-import": "2.31.0", "eslint-plugin-mocha": "10.5.0", "eslint-plugin-promise": "7.2.1", @@ -141,21 +140,21 @@ "midnight-smoker": "8.0.0", "mjpeg-consumer": "2.0.0", "mjpeg-server": "0.3.1", - "mocha": "11.1.0", + "mocha": "11.5.0", "npm-run-all2": "6.2.6", "prettier": "3.5.3", - "rewiremock": "3.14.5", + "rewiremock": "3.14.6", "rimraf": "5.0.10", "serve-static": "1.16.2", "sinon": "20.0.0", "sync-monorepo-packages": "1.0.2", + "teen_process": "2.3.2", "ts-node": "10.9.2", "tsd": "0.32.0", "typescript": "5.8.3", - "typescript-eslint": "8.31.0", - "validate.js": "0.13.1", - "webdriverio": "9.12.7", - "ws": "8.18.1", + "typescript-eslint": "8.33.0", + "webdriverio": "9.14.0", + "ws": "8.18.2", "yaml-js": "0.3.1" }, "engines": { @@ -172,6 +171,6 @@ "ajv-formats": { "ajv": "8.17.1" }, - "http-cache-semantics": "4.1.1" + "http-cache-semantics": "4.2.0" } } diff --git a/packages/appium/docs/en/developing/config-system.md b/packages/appium/docs/en/developing/config-system.md index cd2497759..ef970a177 100644 --- a/packages/appium/docs/en/developing/config-system.md +++ b/packages/appium/docs/en/developing/config-system.md @@ -42,7 +42,7 @@ to its documentation for more information about the search paths. Additionally, support for config files written in YAML via the package [`yaml`](https://npm.im/yaml). If a config file is found and successfully [validated](#validation), the result will be merged with -a set of defaults and any additionall CLI arguments. CLI arguments have precedence over config +a set of defaults and any additional CLI arguments. CLI arguments have precedence over config files, and config files have precedence over defaults. ## Validation @@ -203,7 +203,7 @@ desired. Any property defined in the schema having type `array` will _automatically_ uses the `csv` transformer. Likewise, a property having type `object` will use the `json` transformer. It's conceivable that `array` may want to use the `json` transformer, but otherwise, the presence of - the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not stricly + the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not strictly necessary. The adapter (remember the adapter?) creates a pipeline function including a special "CSV diff --git a/packages/appium/docs/en/quickstart/test-dotnet.md b/packages/appium/docs/en/quickstart/test-dotnet.md index 940616f88..201028e24 100644 --- a/packages/appium/docs/en/quickstart/test-dotnet.md +++ b/packages/appium/docs/en/quickstart/test-dotnet.md @@ -1,105 +1,105 @@ ---- -hide: - - toc - -title: Write a Test (.NET) ---- - -The [Appium .NET Client](https://github.com/appium/dotnet-client/) is -an official Appium client in C#. This driver is an extension of the Selenium C# client. It has all the functionalities of the regular driver, but add Appium-specific methods on top of this. The driver is available on the public NuGet Gallery as [Appium.WebDriver](https://www.nuget.org/packages/Appium.WebDriver/). - -Now, we get inside the directory and create a new [NUnit](https://nunit.org/) project. We will also add the references to the Appium.Net driver, and other dependencies. - -```bash -cd dotnet-client -dotnet new nunit --name appiumtest - -cd appiumtest - -# This will install the latest 5.x version -dotnet add package Appium.WebDriver --prerelease -dotnet add package Newtonsoft.Json --version 13.0.3 -``` - -Once this is done, your project should have a placeholder file `UnitTest1.cs`. We will replace the code to include the OpenQA namespaces, an initialization of the driver, and the actual test. - -```C# title="UnitTest1.cs" -using OpenQA.Selenium; -using OpenQA.Selenium.Appium; -using OpenQA.Selenium.Appium.Android; -using OpenQA.Selenium.Appium.Enums; - -namespace appiumtest; - -public class Tests -{ - private AndroidDriver _driver; - - [OneTimeSetUp] - public void SetUp() - { - var serverUri = new Uri(Environment.GetEnvironmentVariable("APPIUM_HOST") ?? "http://127.0.0.1:4723/"); - var driverOptions = new AppiumOptions() { - AutomationName = AutomationName.AndroidUIAutomator2, - PlatformName = "Android", - DeviceName = "Android Emulator", - }; - - driverOptions.AddAdditionalAppiumOption("appPackage", "com.android.settings"); - driverOptions.AddAdditionalAppiumOption("appActivity", ".Settings"); - // NoReset assumes the app com.google.android is preinstalled on the emulator - driverOptions.AddAdditionalAppiumOption("noReset", true); - - _driver = new AndroidDriver(serverUri, driverOptions, TimeSpan.FromSeconds(180)); - _driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10); - } - - [OneTimeTearDown] - public void TearDown() - { - _driver.Dispose(); - } - - [Test] - public void TestBattery() - { - _driver.StartActivity("com.android.settings", ".Settings"); - _driver.FindElement(By.XPath("//*[@text='Battery']")).Click(); - } -} -``` - -!!! note - - It's not within the scope of this guide to give a complete run-down on the dotnet client - library or everything that's happening here, so we'll leave the code itself unexplained in - detail for now. You may want to read up particularly on Appium - [Capabilities](../guides/caps.md) in addition to familiarizing yourself with the - [dotnet client driver documentation](https://github.com/appium/dotnet-client/) for a fuller explanation - of the various API commands you see and what their purpose is. - -Basically, this code is doing the following: - -1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what -kind of thing you want to automate. Some of these parameters can be overriden using environment variables. -1. Starting an Appium session on the built-in Android settings app. -1. Finding the "Battery" list item and clicking it. -1. Ending the Appium session. - -That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server -running in another terminal session, otherwise you'll get an error about not being able to connect -to one. Then, you can execute the script: - -```bash -dotnet test - -# Example output: -# Starting test execution, please wait... -# A total of 1 test files matched the specified pattern. - -# Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: 323 ms - appiumtest.dll (net7.0) -``` - -If all goes well, you'll see the Settings app open up and navigate to the "Battery" view in the emulator before the app closes again. - -Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore. +--- +hide: + - toc + +title: Write a Test (.NET) +--- + +The [Appium .NET Client](https://github.com/appium/dotnet-client/) is +an official Appium client in C#. This driver is an extension of the Selenium C# client. It has all the functionalities of the regular driver, but add Appium-specific methods on top of this. The driver is available on the public NuGet Gallery as [Appium.WebDriver](https://www.nuget.org/packages/Appium.WebDriver/). + +Now, we get inside the directory and create a new [NUnit](https://nunit.org/) project. We will also add the references to the Appium.Net driver, and other dependencies. + +```bash +cd dotnet-client +dotnet new nunit --name appiumtest + +cd appiumtest + +# This will install the latest 5.x version +dotnet add package Appium.WebDriver --prerelease +dotnet add package Newtonsoft.Json --version 13.0.3 +``` + +Once this is done, your project should have a placeholder file `UnitTest1.cs`. We will replace the code to include the OpenQA namespaces, an initialization of the driver, and the actual test. + +```C# title="UnitTest1.cs" +using OpenQA.Selenium; +using OpenQA.Selenium.Appium; +using OpenQA.Selenium.Appium.Android; +using OpenQA.Selenium.Appium.Enums; + +namespace appiumtest; + +public class Tests +{ + private AndroidDriver _driver; + + [OneTimeSetUp] + public void SetUp() + { + var serverUri = new Uri(Environment.GetEnvironmentVariable("APPIUM_HOST") ?? "http://127.0.0.1:4723/"); + var driverOptions = new AppiumOptions() { + AutomationName = AutomationName.AndroidUIAutomator2, + PlatformName = "Android", + DeviceName = "Android Emulator", + }; + + driverOptions.AddAdditionalAppiumOption("appPackage", "com.android.settings"); + driverOptions.AddAdditionalAppiumOption("appActivity", ".Settings"); + // NoReset assumes the app com.google.android is preinstalled on the emulator + driverOptions.AddAdditionalAppiumOption("noReset", true); + + _driver = new AndroidDriver(serverUri, driverOptions, TimeSpan.FromSeconds(180)); + _driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10); + } + + [OneTimeTearDown] + public void TearDown() + { + _driver.Dispose(); + } + + [Test] + public void TestBattery() + { + _driver.StartActivity("com.android.settings", ".Settings"); + _driver.FindElement(By.XPath("//*[@text='Battery']")).Click(); + } +} +``` + +!!! note + + It's not within the scope of this guide to give a complete run-down on the dotnet client + library or everything that's happening here, so we'll leave the code itself unexplained in + detail for now. You may want to read up particularly on Appium + [Capabilities](../guides/caps.md) in addition to familiarizing yourself with the + [dotnet client driver documentation](https://github.com/appium/dotnet-client/) for a fuller explanation + of the various API commands you see and what their purpose is. + +Basically, this code is doing the following: + +1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what +kind of thing you want to automate. Some of these parameters can be overridden using environment variables. +1. Starting an Appium session on the built-in Android settings app. +1. Finding the "Battery" list item and clicking it. +1. Ending the Appium session. + +That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server +running in another terminal session, otherwise you'll get an error about not being able to connect +to one. Then, you can execute the script: + +```bash +dotnet test + +# Example output: +# Starting test execution, please wait... +# A total of 1 test files matched the specified pattern. + +# Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: 323 ms - appiumtest.dll (net7.0) +``` + +If all goes well, you'll see the Settings app open up and navigate to the "Battery" view in the emulator before the app closes again. + +Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore. diff --git a/packages/appium/docs/en/sponsors.md b/packages/appium/docs/en/sponsors.md index a773f951a..a6e73f685 100644 --- a/packages/appium/docs/en/sponsors.md +++ b/packages/appium/docs/en/sponsors.md @@ -44,16 +44,17 @@ contributors! ## Silver Sponsors - + [Become a Silver Sponsor](https://opencollective.com/appium/contribute/silver-sponsor-72876/checkout?interval=month&amount=250&contributeAs=me) ## Bronze Sponsors [Become a Bronze Sponsor](https://opencollective.com/appium/contribute/sponsors-70690/checkout?interval=month&amount=100&contributeAs=me) diff --git a/packages/appium/docs/ja/blog/.authors.yml b/packages/appium/docs/ja/blog/.authors.yml new file mode 100644 index 000000000..b6f9d4f3c --- /dev/null +++ b/packages/appium/docs/ja/blog/.authors.yml @@ -0,0 +1,19 @@ +authors: + jlipps: + name: 'Jonathan Lipps' + description: 'Appium project lead. Learn more about Jonathan at https://jlipps.com' + avatar: 'https://gravatar.com/avatar/fdaadd825d92709bcf7fe76dffa12c40681c6108c67bcddf19478b2d00e3794b.jpg' + slug: 'jlipps' + url: 'https://jlipps.com' + srini: + name: 'Srinivasan Sekar' + description: 'Appium Maintainer' + avatar: 'https://avatars.githubusercontent.com/u/8896549?v=4' + slug: 'srini' + url: 'https://srini.codes' + sai: + name: 'Sai krishna' + description: 'Appium Maintainer' + avatar: 'https://avatars.githubusercontent.com/u/4045041?v=4' + slug: 'sai' + url: 'https://saikrishna.tech' diff --git a/packages/appium/docs/ja/blog/index.md b/packages/appium/docs/ja/blog/index.md index c58f16c50..ace656eba 100644 --- a/packages/appium/docs/ja/blog/index.md +++ b/packages/appium/docs/ja/blog/index.md @@ -1,2 +1,2 @@ -# Blog +# Appium Blog diff --git a/packages/appium/docs/ja/blog/posts/announcing-appiumconf2024.md b/packages/appium/docs/ja/blog/posts/announcing-appiumconf2024.md new file mode 100644 index 000000000..f3fa6d1be --- /dev/null +++ b/packages/appium/docs/ja/blog/posts/announcing-appiumconf2024.md @@ -0,0 +1,45 @@ +--- +authors: + - srini + - sai +date: 2024-07-13 +--- + +# Appium Conf 2024: Call for Proposals Now Open! + +We're thrilled to announce that Appium Conf is back and going online for 2024! This is the official Appium conference where you can learn all about what's new in Appium 2.0 and explore the latest in automating tests for devices, mobile apps, and desktop applications. + + + +
+ + Appium Conf logo + +
+ +## Mark Your Calendars: September 13, 2024 + +Join us on September 13, 2024, for a full day of inspiring and practical talks from the Appium team and the world's top mobile testing and automation experts. With Appium 2.0 now well-established, this is your opportunity to dive deep and learn how to maximize its potential. + +## Why Attend Appium Conf 2024? + +1. **Gain Insights**: Hear interesting insights and inspiring case studies from global experts and the core Appium team. +2. **Improve Your Strategy**: Gain valuable knowledge to enhance your own automation strategy. +3. **Network**: Make connections with Appium users from around the globe. +4. **Learn from Specialists**: Benefit from Appium specialists' expertise on a variety of topics. + +## Call for Proposals: Share Your Knowledge! + +We're looking for a diverse range of speakers from around the globe who are eager to share innovative ideas and use-cases of mobile test automation. If you have experience with Appium and insights that could benefit the community of test practitioners, we want to hear from you! + +Don't miss this chance to contribute to the Appium community and showcase your expertise on a global stage. + +## How to Submit Your Proposal + +Visit our website at [https://appiumconf.com/](https://appiumconf.com/) and Submit a Proposal. We're excited to see your innovative ideas and experiences with Appium! + +## Stay Tuned + +Keep an eye on our website and social media channels for updates on the conference schedule, keynote speakers, and more exciting details about Appium Conf 2024. + +Join us in shaping the future of mobile and device test automation. Submit your proposal today and be part of this exciting event! \ No newline at end of file diff --git a/packages/appium/docs/ja/blog/posts/announcing-browserstack-as-strategic-partner.md b/packages/appium/docs/ja/blog/posts/announcing-browserstack-as-strategic-partner.md new file mode 100644 index 000000000..9e97df30b --- /dev/null +++ b/packages/appium/docs/ja/blog/posts/announcing-browserstack-as-strategic-partner.md @@ -0,0 +1,46 @@ +--- +authors: + - jlipps +date: 2024-06-10 +--- + +# Announcing BrowserStack as Appium's Strategic Partner + +We have another exciting announcement for you! As part of our recently-announced sponsorship and +contributor compensation +program, +we are obviously in need of significant funding to support giving back to our contributor +community. We are therefore extremely happy to announce one of our brand new exclusive Strategic Partners: BrowserStack! + + + +
+ + + + +
+ +BrowserStack has long been recognized in the industry as having extensive support for Appium, +allowing you to run functional and visual regression tests for your native and hybrid apps at scale +across a variety of devices and platforms. + +As a token of this collaboration, BrowserStack is extending a special premium access of +BrowserStack App Automate product to Appium users. Discover more about this special offer at +[browserstack.com](https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium&utm_term=partannouncement) + +With the decision to come on board as Strategic Partner, BrowserStack is making a huge investment +in Appium and the Appium community. BrowserStack is very interested in supporting the development +of the Appium contributor base, and is proud to be a key part of our contributor compensation +scheme. Without Strategic Partners like BrowserStack, we would not be able to maintain such +a program! We welcome them with gratitude! + +**About BrowserStack** + +BrowserStack is the world’s leading software testing platform powering over two million tests every +day across 19 global data centers. BrowserStack helps Tesco, Shell, NVIDIA, Discovery, Wells Fargo, +and over 50,000 customers deliver quality software at speed by moving testing to their Cloud. +BrowserStack’s platform provides instant access to 20,000+ real mobile devices on a highly reliable +cloud infrastructure that effortlessly scales as testing needs grow. With BrowserStack, Dev and QA +teams can move fast while delivering an amazing experience for every customer. diff --git a/packages/appium/docs/ja/blog/posts/announcing-headspin-as-development-partner.md b/packages/appium/docs/ja/blog/posts/announcing-headspin-as-development-partner.md new file mode 100644 index 000000000..07434fa20 --- /dev/null +++ b/packages/appium/docs/ja/blog/posts/announcing-headspin-as-development-partner.md @@ -0,0 +1,47 @@ +--- +authors: + - jlipps +date: 2024-06-06 +--- + +# Announcing HeadSpin as Appium's Development Partner + +Recently, we announced a new [sponsorship and contributor compensation program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/) for the Appium +project. As part of this program, we felt it was important to have a place to recognize those +companies who make an extremely valuable kind of contribution to the project: dedicated maintainer +time. Appium only survives because of the tireless efforts of the core maintainers, and some of us +are only able to do this work because it is donated on behalf of our day jobs. We're therefore very +excited to announce our first Development Partner: HeadSpin! + + + +
+ +
+ +HeadSpin is a real device performance and UX analysis cloud, with full support for Appium. When you +run your Appium tests on HeadSpin, you get access to comprehensive performance reports about your +app, including potential network, system resource, or user experience issues. HeadSpin supports +a variety of complex testing modes, including hooking up your own devices to the cloud, injecting +and receiving video and audio to/from devices, working with media (streaming) platforms, and more. + +HeadSpin has been one of the Appium project's biggest supporters for a long time, and currently +employs two of Appium's core maintainers, donating a significant portion of their time towards the +development, maintenance, support, and leadership of open source Appium repos. HeadSpin has also +worked hard towards Appium's vision of a robust Appium ecosystem, contributing several +HeadSpin-maintained Appium drivers and plugins to the community: + +- A [Roku TV driver](https://github.com/headspinio/appium-roku-driver) +- A [Tizen TV driver](https://github.com/headspinio/appium-tizen-tv-driver/) +- A [LG webOS TV driver](https://github.com/headspinio/appium-lg-webos-driver/) +- A [Unity game automation plugin](https://github.com/headspinio/appium-altunity-plugin) + +These are all free and open source Appium components that HeadSpin has donated to the community +with the goal of fostering collaboration in these areas of media app automation. + +Looking to the future, HeadSpin plans to continue supporting Appium in significant ways, both as +a Development Partner and a significant contributor to the Appium ecosystem. The Appium project is +deeply indebted to HeadSpin for all of its support, and is proud to take this moment to recognize +HeadSpin as our first official Development Partner! diff --git a/packages/appium/docs/ja/blog/posts/announcing-sauce-labs-as-strategic-partner.md b/packages/appium/docs/ja/blog/posts/announcing-sauce-labs-as-strategic-partner.md new file mode 100644 index 000000000..b7e2762a7 --- /dev/null +++ b/packages/appium/docs/ja/blog/posts/announcing-sauce-labs-as-strategic-partner.md @@ -0,0 +1,36 @@ +--- +authors: + - jlipps +date: 2024-06-10 +--- + +# Announcing Sauce Labs as Appium's Strategic Partner + +The good news surrounding our new sponsorship and contributor compensation +program +just keeps coming! Effective immediately we are fortunate and excited to be able to welcome a new Strategic Partner to +the Appium project: Sauce Labs! + + + +
+ +
+ +Sauce Labs has a long history of support for the Appium project. In fact, Appium was initially +incubated at Sauce Labs under the direction of [@jlipps](https://github.com/jlipps), in the early +days of mobile automation. Sauce Labs always envisioned Appium as being a project for and by the +community, and cemented this perspective in 2016 with the donation of Appium to the JS Foundation +(now the [OpenJS Foundation](https://openjsf.org/)). To this day, developers associated with Sauce +Labs continue to help maintain various parts of the Appium project. + +Now, Sauce Labs is making a further commitment to support Appium financially as a way to enable +our new contributor compensation program. We're very excited about this program as a vehicle for +getting more people involved in Appium's development and maintenance. With the help of Strategic +Partners like Sauce Labs, our project will be better able to meet the needs of our constantly +growing userbase, and attract new developers (like you?) to build the Appium ecosystem together. +Needless to say, we are extremely grateful for Sauce Labs's support! + +**About Sauce Labs** + +Sauce Labs is the leader in continuous quality. Our Platform for Test helps organizations transform software testing from a chore to a competitive advantage. With decades of expertise and deep roots in the Selenium and Appium open source communities, high performing software teams use our platform to execute any testing workload across thousands of different devices, browsers, and operating systems—anywhere, any time, and at any scale. For more information, please visit [saucelabs.com](https://saucelabs.com). diff --git a/packages/appium/docs/ja/blog/posts/announcing-sponsorship-program.md b/packages/appium/docs/ja/blog/posts/announcing-sponsorship-program.md new file mode 100644 index 000000000..41e58d434 --- /dev/null +++ b/packages/appium/docs/ja/blog/posts/announcing-sponsorship-program.md @@ -0,0 +1,48 @@ +--- +authors: + - jlipps +date: 2024-05-14 +--- + +# Announcing Appium's Sponsorship Program + +Over the last several months, the Appium team has been working on a sponsorship program that is +designed to help give back to Appium's contributors as well as to recognize important partner +individuals or companies in the industry. This program is now officially launching! Let's dive into +some of the details. + + + +First of all, the details and fine print will always be available at Appium's Governance +document, which outlines how the +project is run, who makes project decisions, etc... This document will be kept up to date with the +latest details of the program, so that's the place to bookmark for reference! + +As of now, Appium has opened up sponsorship opportunities via our OpenCollective +page. OpenCollective is a service which allows people to donate +to open source groups. We've defined a number of giving tiers for donations, within a very wide +range, and welcome any financial amount with gratitude! Based on the donation tier, sponsorship +comes with a variety of benefits, including recognition at different places in the Appium repo, +docs, and website. In addition to financial sponsorship, the project has decided to recognize +significant donations of project leadership and maintenance efforts from companies who have +invested heavily into Appium with their employees' time (we call these "Development Partners"). + +What will the project do with the funds raised through this sponsorship program? We aim to give it +all back to the Appium community! With the details again available at our [Governance document](https://github.com/appium/appium/blob/master/GOVERNANCE.md), +we have implemented a scheme very much inspired by our friends at [WebdriverIO](https://webdriver.io/blog/2024/02/15/new-contributor-stipend-program) (thanks WDIO +friends!) There are three groups of contributors to Appium that this scheme supports: (1) project +maintainers (those who devote consistent time to leading the project), (2) project contributors +(anyone in the wider community that contributes code or documentation), and (3) upstream projects +(other open source projects Appium relies heavily on to work well). Each month, the funds raised +via sponsorship will be distributed in different amounts to each of these groups. So if you +make a valuable contribution to Appium moving forward, you'll be eligible to get some cash as +a thank-you! (You'll need to have your own OpenCollective account in good standing to receive +funds). + +We're very excited about this new program, and hope that it helps existing and new contributors to +feel even better about donating their time to making Appium better. And of course, none of this +would be possible without the amazing Partners and Sponsors we hope to attract! On that note, stay +tuned over the next few weeks as we unveil some of our initial program launch Partners! And if you +or your company would like to participate by supporting Appium financially, you are most welcome. +Just head over to our OpenCollective page and choose the tier that reflects your desired +contribution level. diff --git a/packages/appium/docs/ja/blog/posts/hello-world.md b/packages/appium/docs/ja/blog/posts/hello-world.md new file mode 100644 index 000000000..109a1ca29 --- /dev/null +++ b/packages/appium/docs/ja/blog/posts/hello-world.md @@ -0,0 +1,15 @@ +--- +authors: + - jlipps +date: 2024-03-07 +--- + +# Hello World! + +This is the first post in the Appium blog. There's not much to see here yet. We're creating this +space so we can make announcements or post other news, or information about events, that don't +really fit inside the documentation itself. + + + +Stay tuned for more! diff --git a/packages/appium/docs/ja/cli/args.md b/packages/appium/docs/ja/cli/args.md new file mode 100644 index 000000000..6aab0066a --- /dev/null +++ b/packages/appium/docs/ja/cli/args.md @@ -0,0 +1,70 @@ +--- +hide: + - toc +title: Server Command-Line Arguments +--- + +To start the Appium server, you may either run `appium` or `appium server`. The `server` subcommand +is considered to be the default, so if you omit it, Appium will interpret this as your request to +run the Appium server. + +The invocation of `appium` (or `appium server`) can take a number of arguments, which are detailed +below. + +!!! note + +``` +All of these arguments can be set via a [Configuration File](../guides/config.md) instead if +you want. Any arguments set on the command line will override any arguments found in +a configuration file. +``` + +|
Argument
| Description | Type |
Default
| Aliases | +| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------ | ------- | +| `--address` | IP address to listen on | string | `0.0.0.0` | `-a` | +| `--allow-cors` | Whether the Appium server should allow web browser connections from any host | boolean | `false` | | +| `--allow-insecure` | Set which [insecure features](../guides/security.md) are allowed to run in this server's sessions. Most features are defined on a driver level; see driver documentation for more details. Individual features can be overridden by `--deny-insecure`. Has no effect in combination with `--relaxed-security`. | array | `[]` | | +| `--base-path` | Base path to use as the prefix for all webdriver routes running on the server | string | `""` | `-pa` | +| `--callback-address` | Callback IP address (default: same as `--address`) | string | | `-ca` | +| `--callback-port` | Callback port (default: same as `--port`) (Value must be between `1` and `65535`) | integer | `4723` | `-cp` | +| `--config` | Path to an [Appium configuration JSON file](../guides/config.md) | string | | | +| `--debug-log-spacing` | Add exaggerated spacing in logs to help with visual inspection | boolean | `false` | | +| `--default-capabilities` | Set the default desired capabilities, which will be set on each session unless overridden by received capabilities. If a string, a path to a JSON file containing the capabilities, or raw JSON. | object | | `-dc` | +| `--deny-insecure` | Set which [insecure features](../guides/security.md) are not allowed to run in this server's sessions. Most features are defined on a driver level; see driver documentation for more details. Since all insecure features are disabled by default, this argument has no effect without either `--allow-insecure` or `--relaxed-security`, and is applied after both. | array | `[]` | | +| `--driver` | Driver-specific configuration. Keys should correspond to driver package names | object | | | +| `--drivers-import-chunk-size` | The maximum amount of drivers that could be imported in parallel on server startup | number | `3` | | +| `--keep-alive-timeout` | Number of seconds the Appium server should apply as both the keep-alive timeout and the connection timeout for all requests. Setting this to `0` disables the timeout. | integer | `600` | `-ka` | +| `--request-timeout` | Number of seconds the Appium server should apply for receiving the entire HTTP request from the client. A value of 0 disables the timeout. Set it to a non-zero value to protect against potential Denial-of-Service attacks in case the server is deployed without a reverse proxy in front. HTTP requests that are running longer than allowed by this timeout would be rejected with the status code 408. | integer | `3600` | | +| `--local-timezone` | Use local timezone for timestamps | boolean | `false` | | +| `--log` | Also send log output to this file | string | | `-g` | +| `--log-filters` | One or more log filtering rules | array | | | +| `--log-level` | Log level (console[:file]) (Value must be one of: `info`, `info:debug`, `info:info`, `info:warn`, `info:error`, `warn`, `warn:debug`, `warn:info`, `warn:warn`, `warn:error`, `error`, `error:debug`, `error:info`, `error:warn`, `error:error`, `debug`, `debug:debug`, `debug:info`, `debug:warn`, `debug:error`) | string | `debug` | | +| `--log-format` | Log format (Value must be to one of: `text`, `json`, `pretty_json`). If logs are printed as JSON then the text coloring is always disabled. | string | `text` | | +| `--log-no-colors` | Do not use color in console output | boolean | `false` | | +| `--log-timestamp` | Show timestamps in console output | boolean | `false` | | +| `--long-stacktrace` | Add long stack traces to log entries. Recommended for debugging only. | boolean | `false` | | +| `--no-perms-check` | Skip various permission checks on the server startup | boolean | `false` | | +| `--nodeconfig` | Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself | string | | | +| `--plugin` | Plugin-specific configuration. Keys should correspond to plugin package names | object | | | +| `--plugins-import-chunk-size` | The maximum amount of plugins that could be imported in parallel on server startup | number | `7` | | +| `--port` | Port to listen on (Value must be between `1` and `65535`) | integer | `4723` | `-p` | +| `--relaxed-security` | Allow all [insecure features](../guides/security.md). Only use this if all clients are in a trusted network and could not potentially break out of the session sandbox. Specific features can be overridden by using `--deny-insecure`. | boolean | `false` | | +| `--session-override` | Enables session override (clobbering) | boolean | `false` | | +| `--ssl-cert-path` | Absolute path to the `.cert` file if TLS is used. Must be provided together with `--ssl-key-path`. See the [SSL/TLS/SPDY Support guide](../guides/tls.md) for details | string | | | +| `--ssl-key-path` | Absolute path to the `.key` file if TLS is used. Must be provided together with `--ssl-cert-path`. See the [SSL/TLS/SPDY Support guide](../guides/tls.md) for details | string | | | +| `--strict-caps` | Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device | boolean | `false` | | +| `--tmp` | Absolute path to directory Appium can use to manage temp files | string | Windows: `C:\Windows\Temp`
Others: `/tmp` | | +| `--trace-dir` | Absolute path to directory Appium can use to save iOS instrument traces | string | `/appium-instruments` | | +| `--use-drivers` | A list of drivers to activate. By default, all installed drivers will be activated. | array | `[]` | | +| `--use-plugins` | A list of plugins to activate. To activate all plugins, the value should be an array with a single item `"all"`. | array | `[]` | | +| `--webhook` | Also send log output to this http listener | string | | `-G` | + +The following arguments are used for information retrieval, after which the server will automatically exit. They are therefore meant for reference or debug purposes. + +|
Argument
| Description | Alias | +| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| `--help` | Print instructions on using the Appium command-line. This argument can also be used for any Appium subcommands. | `-h` | +| `--show-build-info` | Print detailed information on the Appium server version | | +| `--show-config` | Print the current Appium server configuration details | | +| `--show-debug-info` | Print information on the current environment: details about the operating system, Node.js, and Appium itself | | +| `--version` | Print the Appium server version | `-v` | diff --git a/packages/appium/docs/ja/cli/env-vars.md b/packages/appium/docs/ja/cli/env-vars.md new file mode 100644 index 000000000..2c028837a --- /dev/null +++ b/packages/appium/docs/ja/cli/env-vars.md @@ -0,0 +1,23 @@ +--- +hide: + - toc +title: Server Environment Variables +--- + +The primary way of configuring the Appium server is via [Command-Line Arguments](./args.md). However, some more +advanced features are toggled or configured via environment variables. To set environment +variables, refer to the documentation for your operating system and terminal. These are the +environment variables that the Appium server understands: + +| Variable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `APPIUM_HOME` | By default, Appium creates a directory called `.appium` in the home directory for your system user. You can adjust the directory with this variable, as detailed in the [Managing Extensions](../guides/managing-exts.md) guide. | +| `APPIUM_TMP_DIR` | By default, Appium uses a random temporary directory for many of its operations. If you wish to use a specific directory, you may do so by including an absolute path as the value of this variable. The behaviour is equivalent to using the `--tmp` CLI arg. | +| `APPIUM_PREFER_SYSTEM_UNZIP` | Set to `0` or `false` to request that Appium not use the `unzip` binary included on your system for unzipping downloaded apps or other artifacts. Instead it will use a JS-based unzip library. This could help on some systems with non-existent or non-standard `unzip` commands. Note that if unzipping fails using the system library, the fallback library will be attempted in any case, so setting this env var merely saves time in the event you know the system unzip will fail. | +| `APPIUM_HOST` | Same as the `--address` CLI arg | +| `APPIUM_PORT` | Same as the `--port` CLI arg | +| `APPIUM_RELOAD_EXTENSIONS` | Set to `1` to cause Appium to re-require extensions when new sessions are created. This is mostly useful for [building extensions](../developing/build-drivers.md) | +| `APPIUM_OMIT_PEER_DEPS` | Adds `--omit=peer` to all the NPM commands run internally by Appium. Mostly an internal feature. | +| `APPIUM_APPS_CACHE_MAX_AGE` | Allows to set the maximum age (in minutes) for [cached applications](../guides/caching.md). The default value is `60 * 24` (24 hours). Do not set it to a lower number than the duration of a single session startup. | +| `APPIUM_APPS_CACHE_MAX_ITEMS` | Allows to set the maximum amount of [cached applications](../guides/caching.md). The default value is `1024`. Do not set it to a lower number than the amount of apps in all parallel sessions per process. | +| `APPIUM_APPS_CACHE_IGNORE_URL_QUERY` | If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys. See the corresponding [feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713) for more details. Disabled by default. | diff --git a/packages/appium/docs/ja/cli/extensions.md b/packages/appium/docs/ja/cli/extensions.md new file mode 100644 index 000000000..2d41ef79d --- /dev/null +++ b/packages/appium/docs/ja/cli/extensions.md @@ -0,0 +1,228 @@ +--- +title: Extension Command-Line Usage +--- + +Appium allows for the flexible installation and management of various _extensions_, such as _drivers_ +(which provide Appium with the capability to automate a given platform) and _plugins_ (which can +augment or alter the way individual Appium commands work). For a conceptual understanding of these +entities, please review the [Introduction](../intro/index.md). + +Management of drivers and plugins is handled by Appium's Extension CLI (command-line interface). + +!!! note + +``` +This reference uses placeholders to refer to various options. Anywhere you see one of these +placeholders in the reference, ensure you replace it with the correct type of actual content. +``` + +| Placeholder | Meaning | +| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `` | "Extension type". It should be either `driver` or `plugin`. All the Extension CLI commands can be used with either drivers or plugins, so you must specify which type of extension will be used | +| `` | "Extension name". This is the short name of the extension found in a call to `appium list`. This is distinct from the NPM package name of the extension or, in general, the "install spec" of the extension. | +| `` | "Install specification". This refers to the string used to indicate what extension Appium should install. | +| `` | This refers to the method that Appium should use to install an extension. | + +## Commands + +All Extension CLI commands begin with `appium `, i.e., either `appium driver` or `appium +plugin`. + +All Extension CLI commands can take an optional `--json` argument, which will return the result of +the command as a machine-readable JSON string rather than the standard output, which is colourized +and tuned for human consumption. + +### `doctor` + +Run doctor checks for the given extension, which validate whether the extension has its prerequisites +configured correctly. Note that not all extensions include doctor checks. See the +[Building Doctor Checks](../developing/build-doctor-checks.md) tutorial for more details on +how to create them. + +Usage: + +``` +appium doctor +``` + +Required arguments: + +- ``: must be `driver` or `plugin` +- ``: the name of the extension whose doctor checks you want to run + +Optional arguments: + +- `--json`: return the result in JSON format + +Example (run doctor checks for the UiAutomator2 driver): + +``` +appium driver doctor uiautomator2 +``` + +### `install` + +Install an extension. If successful, respond with the short name of the extension which can be used +in other invocations of the Extension CLI. If the extension is a driver, also note which platforms +may be used with the driver. + +Usage: + +``` +appium install [--source=] [--package=] [--json] +``` + +Required arguments: + +- ``: must be `driver` or `plugin` +- ``: this is the name, location, and/or version of the extension you want to + install. Its possible values are dependent on the `` (see below). + +Optional arguments: + +- `--source`: this directs Appium where to find your extension. See below for a table of possible + source types and corresponding install specification. +- `--package`: when `` is `git` or `github`, `--package` is required. It should be + the Node.js package name of the extension. Without this information, Appium will not be able to + find the installed package. +- `--json`: return the result in JSON format + +| Install source type | Behaviour | +| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| None | This is the default behaviour when no `--source` is used. In this case, Appium will look at `` and match it against the name of extensions available when running `appium list`, i.e., against the officially recognized extension names. If found, it will install that extension at the latest version via NPM | +| `npm` | Install an extension based on its NPM package name. Here, `` must be the NPM package name with any additional NPM installation modifiers, like version (see below) | +| `github` | Install an extension via a GitHub spec of the form `/` | +| `git` | Install an extension via a Git URL (e.g., `git+ssh://git-host.com/repo.git`) | +| `local` | Install an extension via a local path. This must be a path to the directory where the Node.js package information for the driver is located. | + +#### NPM-based `` + +When Appium is installing an extension via NPM (as is the case when `--source` is either omitted or +set to `npm`), the `` can be complex, and can include any kind of information allowed +by `npm install`: + +- `[@scope]/` +- `[@scope]/@` +- `[@scope]/@` +- `[@scope]/@` + +#### Examples + +- Install the latest XCUITest driver: + + ``` + appium driver install xcuitest + ``` + +- Install the XCUITest driver at version 4.11.1: + + ``` + appium driver install xcuitest@4.11.1 + ``` + +- Install the `beta` version of the `@appium/fake-driver` from NPM: + + ``` + appium driver install --source=npm @appium/fake-driver@beta + ``` + +- Install a locally-developed plugin: + + ``` + appium plugin install --source=local /path/to/my/plugin + ``` + +### `list` + +List installed and available extensions. "Available" extensions include those which are officially +recognized by the Appium team, but you are not limited to installing only the extensions displayed +in this list. + +Usage: + +``` +appium list [--installed] [--updates] [--json] +``` + +Required arguments: + +- ``: must be `driver` or `plugin` + +Optional arguments: + +- `--installed`: show only installed extensions, not installed plus available extensions +- `--updates`: for extensions installed via NPM, display a message if there are any updates +- `--json`: return the result in JSON format + +### `run` + +Run a script included in an extension package. Extension authors can include runnable scripts that +assist with setup or perform other tasks. These scripts are given names (called the `` +in this reference) by extension authors and will generally be documented in extension +documentation. + +Usage: + +``` +appium run [--json] [script-args] +``` + +Required arguments: + +- ``: must be `driver` or `plugin` +- ``: the name of the extension whose script you want to run +- ``: the name of the script the extension has published + +Optional arguments: + +- `script-args`: any arguments that Appium does not interpret as belonging to its own set of + arguments will be passed along to the extension script +- `--json`: return the result in JSON format + +Example (run the `reset` script included with the UiAutomator2 driver): + +``` +appium driver run uiautomator2 reset +``` + +### `update` + +Update one or more extensions that have been installed via NPM. By default, Appium will not +automatically update any extension past a major version boundary, so as to prevent +unintended breaking changes. + +Usage: + +``` +appium update [--unsafe] [--json] +``` + +Required arguments: + +- ``: must be `driver` or `plugin` +- ``: the name of the extension to update, or the string `installed` (which will update + all installed extensions) + +Optional arguments: + +- `--unsafe`: direct Appium to go ahead and update past a major version boundary +- `--json`: return the result in JSON format + +### `uninstall` + +Remove an installed extension. + +Usage: + +``` +appium uninstall [--json] +``` + +Required arguments: + +- ``: must be `driver` or `plugin` +- ``: the name of the extension to uninstall + +Optional arguments: + +- `--json`: return the result in JSON format diff --git a/packages/appium/docs/ja/cli/index.md b/packages/appium/docs/ja/cli/index.md new file mode 100644 index 000000000..cc0f74ba8 --- /dev/null +++ b/packages/appium/docs/ja/cli/index.md @@ -0,0 +1,25 @@ +--- +hide: + - toc +title: Command-Line Overview +--- + +Appium provides a command-line executable (`appium`), which will likely be your main way of interacting with +the Appium server. This section of the Appium documentation describes how to use this executable. + +To start off, you can run `appium -v` or `appium --version` to return the installed version, +or run `appium -h` or `appium --help` to return the help message. + +The main `appium` executable provides the following subcommands: + +1. `appium server` (or simply `appium`) - launch an Appium server + - [See here for accepted arguments](./args.md) + - For advanced features, [see here for accepted environment variables](./env-vars.md) +2. `appium driver` - manage Appium drivers + - [See here for details](./extensions.md) +3. `appium plugin` - manage Appium plugins + - [See here for details](./extensions.md) +4. `appium setup` - batch install a preset of drivers and plugins + - [See here for details](./setup.md) + +Like the main command, you can also run each subcommand with the `-h` or `--help` flag to learn more about it. diff --git a/packages/appium/docs/ja/cli/setup.md b/packages/appium/docs/ja/cli/setup.md new file mode 100644 index 000000000..ef95b2a57 --- /dev/null +++ b/packages/appium/docs/ja/cli/setup.md @@ -0,0 +1,33 @@ +--- +hide: + - toc +title: Setup Command-Line Usage +--- + +The `setup` command aims to simplify the initial procedure of setting up Appium. It allows to install +multiple extensions (drivers/plugins) in one go, without the need to run +`appium install ` multiple times. + +The command has several presets that can be used to install different sets of extensions. +The presets are as follows: + +| Preset | Installation Command | Included Drivers | Included Plugins | +| ------------------- | --------------------------------------- | ------------------------------------------ | ---------------- | +| Mobile | `appium setup mobile` or `appium setup` | `uiautomator2`, `xcuitest`[^1], `espresso` | `images` | +| Desktop application | `appium setup desktop` | `mac2`[^1], `windows`[^2] | `images` | +| Desktop browser | `appium setup browser` | `safari`[^1], `gecko`, `chromium` | `images` | + +Attempting to install a preset while already having one or more of its included extensions installed +will only install the missing extensions. + +Refer to the [Ecosystem documentation](../ecosystem/index.md) to learn more about the extensions +listed above. + +This commands also supports the functionality that allows to fully reset your Appium server +deployment if you experience various configuration issues, +for example, due to a failed upgrade attempt from an older Appium version, on server startup. +By running `appium setup reset` the server would uninstall all installed drivers, plugins and their related manifest files from the currently used Appium home folder. + +[^1]: Only installed if the host machine is running macOS. + +[^2]: Only installed if the host machine is running Windows. diff --git a/packages/appium/docs/ja/commands/base-driver.md b/packages/appium/docs/ja/commands/base-driver.md new file mode 100644 index 000000000..d236308ff --- /dev/null +++ b/packages/appium/docs/ja/commands/base-driver.md @@ -0,0 +1,580 @@ +# Driver: base-driver + +### `createSession` + +`POST` **`/session`** + +Historically the first two arguments were reserved for JSONWP capabilities. +Appium 2 has dropped the support of these, so now we only accept capability +objects in W3C format and thus allow any of the three arguments to represent +the latter. + +**`See`** + +[https://w3c.github.io/webdriver/#new-session](https://w3c.github.io/webdriver/#new-session) + + + +#### Parameters + +| Name | Type | Description | +| :---------------------- | :---------------------------------------------- | :----------------------------------------------------------------------------------------------------- | +| `desiredCapabilities?` | `W3CDriverCaps`<`C`\> | the new session capabilities | +| `requiredCapabilities?` | `W3CDriverCaps`<`C`\> | another place the new session capabilities could be sent (typically left undefined) | +| `capabilities?` | `W3CDriverCaps`<`C`\> | another place the new session capabilities could be sent (typically left undefined) | + +#### Response + +`CreateResult` + +The capabilities object representing the created session + +### `deleteSession` + +`DELETE` **`/session/:sessionId`** + +Returns capabilities for the session and event history (if applicable) + + + +#### Response + +`SingularSessionData`<`C`, `SessionData`\> + +A session data object + +### `getSession` + +`GET` **`/session/:sessionId`** + +Returns capabilities for the session and event history (if applicable). + +!!! warning "Deprecated" + +``` +Please use `getAppiumSessionCapabilities` to get the session capabilities. +Please use `getLogEvents` to get event history. +``` + + + +#### Response + +`SingularSessionData`<`C`, `SessionData`\> + +A session data object + +### `getAppiumSessionCapabilities` + +`GET` **`/session/:sessionId/appium/capabilities`** + +Returns capabilities for the session. + + + +#### Response + +`AppiumSessionCapabilities` + +A session data object + +### `findElement` + +`POST` **`/session/:sessionId/element`** + +Find a UI element given a locator strategy and a selector, erroring if it can't be found + +**`See`** + +[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :------- | :--------------------------------------------------------------------- | +| `using` | `string` | the locator strategy | +| `value` | `string` | the selector to combine with the strategy to find the specific element | + +#### Response + +`Element`<`string`\> + +The element object encoding the element id which can be used in element-related +commands + +### `findElementFromElement` + +`POST` **`/session/:sessionId/element/:elementId/element`** + +Find a UI element given a locator strategy and a selector, erroring if it can't be found. Only +look for elements among the set of descendants of a given element + +**`See`** + +[https://w3c.github.io/webdriver/#find-element-from-element](https://w3c.github.io/webdriver/#find-element-from-element) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :------- | :--------------------------------------------------------------------- | +| `using` | `string` | the locator strategy | +| `value` | `string` | the selector to combine with the strategy to find the specific element | + +#### Response + +`Element`<`string`\> + +The element object encoding the element id which can be used in element-related +commands + +### `findElementFromShadowRoot` + +`POST` **`/session/:sessionId/shadow/:shadowId/element`** + +Find an element from a shadow root + +**`See`** + +[https://w3c.github.io/webdriver/#find-element-from-shadow-root](https://w3c.github.io/webdriver/#find-element-from-shadow-root) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :------- | :---------------------------------------------------------------------- | +| `using` | `string` | the locator strategy | +| `value` | `string` | the selector to combine with the strategy to find the specific elements | + +#### Response + +`Element`<`string`\> + +The element inside the shadow root matching the selector + +### `findElements` + +`POST` **`/session/:sessionId/elements`** + +Find a a list of all UI elements matching a given a locator strategy and a selector + +**`See`** + +[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :------- | :---------------------------------------------------------------------- | +| `using` | `string` | the locator strategy | +| `value` | `string` | the selector to combine with the strategy to find the specific elements | + +#### Response + +`Element`<`string`\>[] + +A possibly-empty list of element objects + +### `findElementsFromElement` + +`POST` **`/session/:sessionId/element/:elementId/elements`** + +Find a a list of all UI elements matching a given a locator strategy and a selector. Only +look for elements among the set of descendants of a given element + +**`See`** + +[https://w3c.github.io/webdriver/#find-elements-from-element](https://w3c.github.io/webdriver/#find-elements-from-element) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :------- | :---------------------------------------------------------------------- | +| `using` | `string` | the locator strategy | +| `value` | `string` | the selector to combine with the strategy to find the specific elements | + +#### Response + +`Element`<`string`\>[] + +A possibly-empty list of element objects + +### `findElementsFromShadowRoot` + +`POST` **`/session/:sessionId/shadow/:shadowId/elements`** + +Find elements from a shadow root + +**`See`** + +[https://w3c.github.io/webdriver/#find-element-from-shadow-root](https://w3c.github.io/webdriver/#find-element-from-shadow-root) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :------- | :---------------------------------------------------------------------- | +| `using` | `string` | the locator strategy | +| `value` | `string` | the selector to combine with the strategy to find the specific elements | + +#### Response + +`Element`<`string`\>[] + +A possibly empty list of elements inside the shadow root matching the selector + +### `getLog` + +`POST` **`/session/:sessionId/log`** + +Get the log for a given log type. + +!!! warning "Deprecated" + +``` +Please use the `/session/:sessionId/se/log` endpoint instead +``` + + + +#### Parameters + +| Name | Type | Description | +| :----- | :------- | :------------------------------------------------------------------------------------------------- | +| `type` | `string` | Name/key of log type as defined in ILogCommands.supportedLogTypes. | + +#### Response + +`any` + +### `getLog` + +`POST` **`/session/:sessionId/se/log`** + +Get the log for a given log type. + + + +#### Parameters + +| Name | Type | Description | +| :----- | :------- | :------------------------------------------------------------------------------------------------- | +| `type` | `string` | Name/key of log type as defined in ILogCommands.supportedLogTypes. | + +#### Response + +`any` + +### `getLogEvents` + +`POST` **`/session/:sessionId/appium/events`** + +Get a list of events that have occurred in the current session + + + +#### Parameters + +| Name | Type | Description | +| :------ | :--------------------------------------------------------------------------- | :-------------------------------------------------------- | +| `type?` | `string` \\| `string`[] | filter the returned events by including one or more types | + +#### Response + +`EventHistory` \| `Record`<`string`, `number`\> + +The event history for the session + +### `getLogTypes` + +`GET` **`/session/:sessionId/log/types`** + +Get available log types as a list of strings + +!!! warning "Deprecated" + +``` +Please use the `/session/:sessionId/se/log/types` endpoint instead +``` + + + +#### Response + +`string`[] + +### `getLogTypes` + +`GET` **`/session/:sessionId/se/log/types`** + +Get available log types as a list of strings + + + +#### Response + +`string`[] + +### `getPageSource` + +`GET` **`/session/:sessionId/source`** + +Get the current page/app source as HTML/XML + +**`See`** + +[https://w3c.github.io/webdriver/#get-page-source](https://w3c.github.io/webdriver/#get-page-source) + + + +#### Response + +`string` + +The UI hierarchy in a platform-appropriate format (e.g., HTML for a web page) + +### `getSessions` + +`GET` **`/sessions`** + +Get data for all sessions running on an Appium server + + + +#### Response + +A list of session data objects. +Each session data object will be returned with `id` and the session's capabilities as `capabilities` keys like an example below: + +```json +[ + { + "id":"ba30c6da-c266-4734-8ddb-c16f5bb53e16", + "capabilities":{ "platformName":"ios","browserName":"safari","automationName":"xcuitest","platformVersion":"17.2","deviceName":"iPhone 15" } + }, + { + "id":"1441110c-1ece-4e45-abbf-ebf404f45f0a", + "capabilities":{ "platformName":"ios","browserName":"safari","automationName":"xcuitest","platformVersion":"17.0","deviceName":"iPhone 14" } + }, + ... +] +``` + +### `getSettings` + +`GET` **`/session/:sessionId/appium/settings`** + +Update the session's settings dictionary with a new settings object + + + +#### Response + +`null` + +### `updateSettings` + +`POST` **`/session/:sessionId/appium/settings`** + +Update the session's settings dictionary with a new settings object + + + +#### Parameters + +| Name | Type | Description | +| :--------- | :--------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | +| `settings` | `Settings` | A key-value map of setting names to values. Settings not named in the map will not have their value adjusted. | + +#### Response + +`null` + +### `getStatus` + +`GET` **`/status`** + +**`Summary`** + +Retrieve the server's current status. + +**`Description`** + +Returns information about whether a remote end is in a state in which it can create new sessions and can additionally include arbitrary meta information that is specific to the implementation. + +The readiness state is represented by the ready property of the body, which is false if an attempt to create a session at the current time would fail. However, the value true does not guarantee that a New Session command will succeed. + +Implementations may optionally include additional meta information as part of the body, but the top-level properties ready and message are reserved and must not be overwritten. + + + +#### Examples + + + +##### JavaScript + + + +```js +// webdriver.io example +await driver.status(); +``` + + + +##### Python + + + +```python +driver.get_status() +``` + + + +##### Java + + + +```java +driver.getStatus(); +``` + + + +##### Ruby + + + +```ruby +# ruby_lib example +remote_status + +# ruby_lib_core example +@driver.remote_status +``` + + + + + +#### Response + +`Object` + +### `getTimeouts` + +`GET` **`/session/:sessionId/timeouts`** + +Set the various timeouts associated with a session + +**`See`** + +[https://w3c.github.io/webdriver/#set-timeouts](https://w3c.github.io/webdriver/#set-timeouts) + + + +#### Response + +`null` + +### `timeouts` + +`POST` **`/session/:sessionId/timeouts`** + +Set the various timeouts associated with a session + +**`See`** + +[https://w3c.github.io/webdriver/#set-timeouts](https://w3c.github.io/webdriver/#set-timeouts) + + + +#### Parameters + +| Name | Type | Description | +| :---------- | :--------------------- | :--------------------------------------------------------------------------------- | +| `type?` | `string` | used only for the old (JSONWP) command, the type of the timeout | +| `ms?` | `string` \\| `number` | used only for the old (JSONWP) command, the ms for the timeout | +| `script?` | `number` | the number in ms for the script timeout, used for the W3C command | +| `pageLoad?` | `number` | the number in ms for the pageLoad timeout, used for the W3C command | +| `implicit?` | `string` \\| `number` | the number in ms for the implicit wait timeout, used for the W3C command | + +#### Response + +`null` + +### `implicitWait` + +`POST` **`/session/:sessionId/timeouts/implicit_wait`** + +Set the implicit wait timeout + +!!! warning "Deprecated" + +``` +Please use the `/session/:sessionId/timeouts` endpoint instead +``` + +Use `timeouts` instead + + + +#### Parameters + +| Name | Type | Description | +| :--- | :--------------------- | :---------------- | +| `ms` | `string` \\| `number` | the timeout in ms | + +#### Response + +`null` + +### `logCustomEvent` + +`POST` **`/session/:sessionId/appium/log_event`** + +Add a custom-named event to the Appium event log + + + +#### Parameters + +| Name | Type | Description | +| :------- | :------- | :-------------------------------------------------------------------------- | +| `vendor` | `string` | the name of the vendor or tool the event belongs to, to namespace the event | +| `event` | `string` | the name of the event itself | + +#### Response + +`null` + +### `reset` + +`POST` **`/session/:sessionId/appium/app/reset`** + +Reset the current session (run the delete session and create session subroutines) + +!!! warning "Deprecated" + +``` +Please use each driver's launch, activate, terminate or cleanup method. +``` + +Use explicit session management commands instead + + + +#### Response + +`null` diff --git a/packages/appium/docs/ja/commands/execute-driver-plugin.md b/packages/appium/docs/ja/commands/execute-driver-plugin.md new file mode 100644 index 000000000..d1df48e92 --- /dev/null +++ b/packages/appium/docs/ja/commands/execute-driver-plugin.md @@ -0,0 +1,22 @@ +# Plugin: execute-driver + +### `executeDriverScript` + +`POST` **`/session/:sessionId/appium/execute_driver`** + +Implementation of a command within a plugin + +At minimum, `D` must be `ExternalDriver`, but a plugin can be more narrow about which drivers it supports. + + + +#### Parameters + +| Name | Type | +| :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `script` | [script: string, scriptType: string, timeoutMs: number] | +| `type?` | [script: string, scriptType: string, timeoutMs: number] | + +#### Response + +`unknown` diff --git a/packages/appium/docs/ja/commands/images-plugin.md b/packages/appium/docs/ja/commands/images-plugin.md new file mode 100644 index 000000000..97b1a47ce --- /dev/null +++ b/packages/appium/docs/ja/commands/images-plugin.md @@ -0,0 +1,89 @@ +# Plugin: images + +### `compareImages` + +`POST` **`/session/:sessionId/appium/compare_images`** + +#### Parameters + +| Name | Type | +| :--------- | :---------------------------------------------------------- | +| `mode` | `any`[] | +| `options?` | `any`[] | + +#### Response + +`ComparisonResult` + +### `findElement` + +`POST` **`/session/:sessionId/element`** + +Find a UI element given a locator strategy and a selector, erroring if it can't be found + +**`See`** + +[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :---- | :--------------------------------------------------------------------- | +| `using` | `any` | the locator strategy | +| `value` | `any` | the selector to combine with the strategy to find the specific element | + +#### Response + +`any` + +The element object encoding the element id which can be used in element-related +commands + +### `findElements` + +`POST` **`/session/:sessionId/elements`** + +Find a a list of all UI elements matching a given a locator strategy and a selector + +**`See`** + +[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :---- | :---------------------------------------------------------------------- | +| `using` | `any` | the locator strategy | +| `value` | `any` | the selector to combine with the strategy to find the specific elements | + +#### Response + +`any` + +A possibly-empty list of element objects + +### `performActions` + +`POST` **`/session/:sessionId/actions`** + +If the actions contains image elements as origin, convert them to viewport coordinates before sending it to the external driver + +**`See`** + +[https://w3c.github.io/webdriver/#perform-actions](https://w3c.github.io/webdriver/#perform-actions) + + + +#### Parameters + +| Name | Type | Description | +| :-------- | :----------------- | :--------------------------- | +| `actions` | `ActionSequence[]` | an array of action sequences | + +#### Response + +`null` diff --git a/packages/appium/docs/ja/commands/index.md b/packages/appium/docs/ja/commands/index.md new file mode 100644 index 000000000..ec94ff42c --- /dev/null +++ b/packages/appium/docs/ja/commands/index.md @@ -0,0 +1,26 @@ +--- +hide: + - toc +title: Intro to Commands +--- + +Here you can find various commands exposed by the main Appium module through its base driver, as +well as the commands available in several plugins. + +!!! note + +``` +The Appium base driver only exposes a few commands, as it is not meant to be used on its own. +Please refer to the documentation of your [Appium driver](../ecosystem/drivers.md) to learn +about the commands it exposes, and then check your [Appium client](../ecosystem/clients.md) +documentation for the exact syntax of that command. +``` + +The command listings can be found here: + +- [Base Driver](./base-driver.md) +- [Execute Driver Plugin](./execute-driver-plugin.md) +- [Images Plugin](./images-plugin.md) +- [Relaxed Caps Plugin](./relaxed-caps-plugin.md) +- [Storage Plugin](./storage-plugin.md) +- [Universal XML Plugin](./universal-xml-plugin.md) diff --git a/packages/appium/docs/ja/commands/relaxed-caps-plugin.md b/packages/appium/docs/ja/commands/relaxed-caps-plugin.md new file mode 100644 index 000000000..bc57d6e17 --- /dev/null +++ b/packages/appium/docs/ja/commands/relaxed-caps-plugin.md @@ -0,0 +1,27 @@ +# Plugin: relaxed-caps + +### `createSession` + +`POST` **`/session`** + +Start a new automation session + +**`See`** + +[https://w3c.github.io/webdriver/#new-session](https://w3c.github.io/webdriver/#new-session) + + + +#### Parameters + +| Name | Type | Description | +| :---------------------- | :---- | :----------------------------------------------------------------------------------------------------- | +| `desiredCapabilities?` | `any` | the new session capabilities | +| `requiredCapabilities?` | `any` | another place the new session capabilities could be sent (typically left undefined) | +| `capabilities?` | `any` | another place the new session capabilities could be sent (typically left undefined) | + +#### Response + +`any` + +The capabilities object representing the created session diff --git a/packages/appium/docs/ja/commands/storage-plugin.md b/packages/appium/docs/ja/commands/storage-plugin.md new file mode 100644 index 000000000..df5e413f9 --- /dev/null +++ b/packages/appium/docs/ja/commands/storage-plugin.md @@ -0,0 +1,113 @@ +# Plugin: storage + +!!! tip + + All these commands can be invoked without creating a session, allowing you to + prepare your test environment in advance. + +### `addStorageItem` + +`POST` **`/storage/add`** + +Add a new file to the storage + +#### Parameters + +| Name | Type | Description | +| :----- | :------- | :--------------------------------------------------------------------------------------------- | +| `name` | `string` | the name used to save the file (must not include path separator characters) | +| `sha1` | `string` | SHA1 hash of the file to be uploaded | + +#### Example + +```bash +curl -X POST --header "Content-Type: application/json" --data '{"name":"app.ipa","sha1":"ccc963411b2621335657963322890305ebe96186"}' http://127.0.0.1:4723/storage/add +``` + +#### Response + +`AddRequestResult` + +A JSON object in the following format: + +```json +{ + "ws": { + "stream": "/storage/add/ccc963411b2621335657963322890305ebe96186/stream", + "events": "/storage/add/ccc963411b2621335657963322890305ebe96186/events" + }, + "ttlMs": 300000 +} +``` + +| Name | Type | Description | +| :---------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------- | +| `ws.stream` | `string` | the pathname of the streaming web socket used to upload the file content | +| `ws.events` | `string` | the pathname of the events web socket used to notify about upload success or a failure | +| `ttlMs` | `number` | the amount of milliseconds both web sockets will be kept active before they expire, or a file payload would be successfully uploaded | + +### `listStorageItems` + +`GET` **`/storage/list`** + +List all files present in the storage + +#### Example + +```bash +curl http://127.0.0.1:4723/storage/list +``` + +#### Response + +`List` + +A list of items, where each item has the following properties: + +| Name | Type | Description | +| :----- | :------- | :---------------------------------------------- | +| `name` | `string` | the name of the file in the storage | +| `path` | `string` | full path to the file on the remote file system | +| `size` | `number` | file size in bytes | + +### `deleteStorageItem` + +`POST` **`/storage/delete`** + +Deletes a file in the storage with the specified name + +#### Parameters + +| Name | Type | Description | +| :----- | :------- | :--------------------------------- | +| `name` | `string` | the name of the file to be deleted | + +#### Example + +```bash +curl -X POST --header "Content-Type: application/json" --data '{"name":"app.ipa"}' http://127.0.0.1:4723/storage/delete +``` + +#### Response + +`boolean` + +`false` if the file does not exist in the storage, or `true` upon successful file deletion + +### `resetStorage` + +`POST` **`/storage/reset`** + +Deletes all uploaded files and stops any incomplete uploads. +If the `APPIUM_STORAGE_KEEP_ALL` flag is enabled, all uploaded files will be preserved, +and only the incomplete uploads will be stopped. + +#### Example + +```bash +curl -X POST http://127.0.0.1:4723/storage/reset +``` + +#### Response + +`undefined` diff --git a/packages/appium/docs/ja/commands/universal-xml-plugin.md b/packages/appium/docs/ja/commands/universal-xml-plugin.md new file mode 100644 index 000000000..a7e02de13 --- /dev/null +++ b/packages/appium/docs/ja/commands/universal-xml-plugin.md @@ -0,0 +1,68 @@ +# Plugin: universal-xml + +### `findElement` + +`POST` **`/session/:sessionId/element`** + +Find a UI element given a locator strategy and a selector, erroring if it can't be found + +**`See`** + +[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :---------------------------------------------------------- | :------------------- | +| `using` | `any`[] | the locator strategy | + +#### Response + +`any` + +The element object encoding the element id which can be used in element-related +commands + +### `findElements` + +`POST` **`/session/:sessionId/elements`** + +Find a a list of all UI elements matching a given a locator strategy and a selector + +**`See`** + +[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements) + + + +#### Parameters + +| Name | Type | Description | +| :------ | :---------------------------------------------------------- | :------------------- | +| `using` | `any`[] | the locator strategy | + +#### Response + +`any` + +A possibly-empty list of element objects + +### `getPageSource` + +`GET` **`/session/:sessionId/source`** + +Get the current page/app source as HTML/XML + +**`See`** + +[https://w3c.github.io/webdriver/#get-page-source](https://w3c.github.io/webdriver/#get-page-source) + + + +#### Response + +`string` + +The UI hierarchy in a platform-appropriate format (e.g., HTML for a web page) diff --git a/packages/appium/docs/ja/contributing.md b/packages/appium/docs/ja/contributing.md new file mode 100644 index 000000000..730e63999 --- /dev/null +++ b/packages/appium/docs/ja/contributing.md @@ -0,0 +1,161 @@ +--- +hide: + - navigation +title: Contributing to Appium +--- + +The Appium project would not exist without the many contributions of code, documentation, +maintenance, and support from companies and volunteers. As such, we welcome contributions! + +There are a lot of different ways to help the project - see below for everything you can do and the +processes to follow for each contribution method. Note that no matter how you contribute, your +participation is governed by our [Code of Conduct](https://github.com/appium/appium/blob/master/CONDUCT.md). + +## Join the Discussion Forum + +You don't need to know the internals of Appium to be able to contribute! If you have experience with +using Appium and feel like sharing your knowledge with others, consider helping out users on the +Appium forums at [discuss.appium.io](https://discuss.appium.io/). Hop on over and see if there are +any questions that you can answer. + +## Report Bugs or Feature Requests + +If you've encountered a bug, or have a cool feature in mind that you think Appium should support, +make sure to let us know at our [GitHub issue tracker](https://github.com/appium/appium/issues). +Please use the appropriate issue form template when creating your issue. + +## Triage Issues + +In addition to creating issues, you can also help us investigate already reported issues. All you +need is enough familiarity with Appium to try and reproduce bugs. + +You can get started by checking our [GitHub issue tracker](https://github.com/appium/appium/issues) +for issues with labels such as `Needs Triage` or `Needs Info`, and leaving relevant comments: + +- If the issue is a duplicate, drop a link to the original issue +- If the user has not provided enough information (such as Appium logs), ask them for more details +- If you can reproduce the problem on your own environment, provide all the information that you think + would help us track down the cause of the issue + +For further information on triaging Appium issues (for any Appium project repository), please contact +any member of the [Technical Committee](https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee). + +## Contribute Code + +We are always open to pull requests for improving the Appium code or documentation! + +!!! info + +``` +Developer information may not be kept up to date as frequently as user-facing information, or +it may be most relevant in its current form on the online repository, not in this published +version. Make sure to check the repo or discuss with maintainers. We would be glad to help +new contributors get started! +``` + +Start by cloning the repository (we recommend [forking](https://github.com/appium/appium/fork) +it first): + +```sh +git clone https://github.com/appium/appium.git +cd appium +``` + +!!! info + +``` +If you are VS Code user, you can easily check out the project using [Runme](https://runme.dev/api/runme?repository=https%3A%2F%2Fgithub.com%2Fappium%2Fappium.git&fileToOpen=packages%2Fappium%2Fdocs%2Fen%2Fcontributing%2Findex.md). +``` + +Install dependencies: + +```sh +npm install +``` + +From here on there are several things you can do. + +Build the project: + +```sh +npm run build +``` + +Build the project and watch for changes: + +```sh +npm run dev +``` + +Start the locally built Appium server: + +```sh +npm start +``` + +Run various tests: + +```sh +npm run lint +npm run test:unit +npm run test:types +npm run test:smoke +npm run test:e2e +npm run test:quick # unit and types +npm run test:slow # everything +``` + +You can also run tests for specific workspaces, e.g.: + +```sh +export APPIUM_WORKSPACE=@appium/base-driver +npm run test:unit -w $APPIUM_WORKSPACE +``` + +### Documentation + +The documentation for this project is [available in the project repository itself](https://github.com/appium/appium/tree/master/packages/appium/docs). +It is contained in Markdown files, which are built by our documentation system in the +`@appium/docutils` module. This module is based on [MkDocs](https://www.mkdocs.org/) and therefore +requires [Python](https://www.python.org/) to be installed on your system. + +Install Python dependencies: + +```sh +npm run install-docs-deps +``` + +After making your changes, you can run the documentation server in dev mode: + +```sh +npm run dev:docs +``` + +You can then view the documentation at `http://127.0.0.1:8000/docs/en`. + +## Translating Appium Documentation + +The process of Appium documents localization into languages other than English is automated and is done via +the [Crowdin Translations Management System](https://crowdin.com). Do not edit any translated documents +directly in the GitHub Appium repository as they are going to be replaced with ones exported from Crowdin +during an upcoming sync. + +### Where To Start + +If you would like to contribute to the translation of Appium documents into your language then simply join +the translators group for the [Appium Documentation](https://crowdin.com/project/appium-documentation) +Crowdin project, and start translating documents there. If you see that your language is missing from +the list of available Crowdin languages then simply let us know by creating an +[issue](https://github.com/appium/appium/issues). + +### Source Language Updates + +Changes in documents are synchronized to Crowdin automatically via the `Update Crowdin English Docs` GitHub action. +This action is triggered automatically as soon as there are any changes under `packages/appium/docs/en/**.md` +or `packages/appium/docs/mkdocs-en.yml`. + +### Fetching Translated Documents + +In order to fetch translated files from Crowdin to the GitHub repository it is necessary to trigger +the `Sync Crowdin Docs Translations` action. This action should also automatically create a PR with +corresponding translated resources included. diff --git a/packages/appium/docs/ja/developing/build-docs.md b/packages/appium/docs/ja/developing/build-docs.md new file mode 100644 index 000000000..dd2637e69 --- /dev/null +++ b/packages/appium/docs/ja/developing/build-docs.md @@ -0,0 +1,86 @@ +--- +title: Building Documentation +--- + +Once you've [built a driver](./build-drivers.md) or [built a plugin](./build-plugins.md) for Appium, +you will hopefully want to document how that extension works for your users. The most basic way of +doing this is to write up a quick `README.md` and keep it in the root of your project's repository. +However, this can involve a lot of effort. + +The Appium project has built tools to help with this, and we've packaged up these tools so our +ecosystem developers building drivers and plugins can _also_ use them. The best way to get going +with these tools is probably to look at an existing Appium driver repo to see how it's done, for +example the [XCUITest driver repo](https://github.com/appium/appium-xcuitest-driver). But this guide +will outline the basic approach. + +### Conceptual architecture + +Appium settled on [MkDocs](https://www.mkdocs.org/) as a Markdown-based documentation site +generator. It uses a Python toolchain (and not Node.js), but it turned out to be the best option +for our purposes. You can adjust this, but by default Appium's utilities also assume that you'll be +using the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) theme/extension for +MkDocs. + +In order to make different versions of your docs available (one for each minor release of your +extension, typically), we also bundle [Mike](https://github.com/jimporter/mike). + +From here, building a basic docs site is as easy as collecting your Markdown files together and +defining how you want them to be organized. + +### Prerequisites + +To take advantage of Appium's documentation utilities, you'll need to install: + +- [Python v3+](https://www.python.org/downloads/) +- [pip](https://pip.pypa.io/en/stable/installation/) (this may be installed automatically with Python) +- The `@appium/docutils` package: + + ```bash + npm install --save-dev @appium/docutils + ``` + +### Initializing an Extension for Building Docs + +To prepare your extension for generating documentation, run the following command: + +```bash +npx appium-docs init +``` + +This will: + +1. Create a `tsconfig.json` if one does not already exist. This is necessary even if your extension + is not written in TypeScript. +2. Create a `mkdocs.yml` with the necessary configuration for MkDocs. + +### Documenting Your Extension + +At this point, you can begin documenting your extension. By default, MkDocs will look for Markdown +files in the `docs` directory. You can therefore create your Markdown documentation files, place +them in `docs`, and add links to these files in `mkdocs.yml`. + +Refer to the [MkDocs documentation](https://www.mkdocs.org/user-guide/writing-your-docs/) for +information on how to organize and structure your documentation. + +### Building the Docs + +At this point, you can use the `appium-docs` CLI tool. Run this tool with no arguments to get the +full help output and see all the available subcommands and parameters. Here are a few usage +examples: + +```bash +# Generate reference and build the mkdocs site into the site dir +npx appium-docs build + +# Same as build, but host the docs on a local dev server +# and watch for changes and rebuild when files change +npx appium-docs build --serve + +# Build the docs and deploy them with mike versioning to the docs-site branch +# using the included commit message. +# This is particularly useful for pushing content to a GitHub pages branch! +npx appium-docs build \ + --deploy \ + -b docs-site \ + -m 'docs: auto-build docs for appium-xcuitest-driver@%s' +``` diff --git a/packages/appium/docs/ja/developing/build-doctor-checks.md b/packages/appium/docs/ja/developing/build-doctor-checks.md new file mode 100644 index 000000000..a6e18d0b7 --- /dev/null +++ b/packages/appium/docs/ja/developing/build-doctor-checks.md @@ -0,0 +1,141 @@ +--- +title: Building Doctor Checks +--- + +The idea of Appium Doctor is to assist users with driver or plugin preconditions setup. Sometimes such +preconditions might be quite complicated and require non-trivial technical knowledge. Doctor checks, +which are vanilla Node.js class instances written by extension authors, simplify +the setup process by automating diagnostics and possible fixes for the found issues. These checks +might also be interactive to ensure better usage experience. + +This tutorial is supposed to be used by plugin or driver authors that would like to help their users +to deal with complicated setup or configuration steps. + +## Adding Doctor Checks + +### Typing Requirements + +The term `Doctor Check` literally describes a single javascript class instance that implements the +[IDoctorCheck interface](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts). +The interface defines the following methods and properties: + +- `diagnose(): Promise`: Contains the code to diagnose a possible issue +- `fix(): Promise`: Either fixes the actual problem if `hasAutofix()` returns true or + returns a string description for possible manual fixes. If this method throws an exception named + `FixSkippedError` and `hasAutofix()` returns true then the result of the method invocation + is going to be ignored. +- `hasAutofix(): boolean`: Whether calling `fix()` would resolve the found issue +- `isOptional(): boolean`: Whether the found issue can be ignored and is not a showstopper +- `log: AppiumLogger`: May be used for logging. This property may be assigned + by the instance itself or by the Appium server if it is left unassigned. + +The `DoctorCheckResult` object returned by the `diagnose()` method must contain the following properties: + +- `ok: boolean`: Whether the diagnosis found no issues +- `optional: boolean`: Whether the diagnosed issue is safe to ignore +- `message: string`: The text message describing the diagnostic result + +### Manifest Requirements + +A single extension may export multiple Doctor checks to Appium. In order for these checks to be properly +picked up by the server CLI after the corresponding extension is installed they might be listed in the +package .json manifest under the `appium.doctor.checks` section similar to the definition below: + +```json + // ... + "appium": { + "driverName": "fake", + "automationName": "Fake", + "platformNames": [ + "Fake" + ], + "mainClass": "FakeDriver", + "schema": "./build/lib/fake-driver-schema.js", + "scripts": { + "fake-error": "./build/lib/scripts/fake-error.js", + "fake-success": "./build/lib/scripts/fake-success.js", + "fake-stdin": "./build/lib/scripts/fake-stdin.js" + }, + "doctor": { + "checks": [ + "./doctor/fake1.js", + "./doctor/fake2.js" + // ... + ] + } + }, + // ... +``` + +Also, it makes sense to include the [@appium/types](https://www.npmjs.com/package/@appium/types) import +to the package dev dependencies. + +### Implementation Example + +The below example is a "raw" Node.JS implementation that does not use any transpilation: + +```js +const {fs, doctor} = require('@appium/support'); + +/** @satisfies {import('@appium/types').IDoctorCheck} */ +class EnvVarAndPathCheck { + /** + * @param {string} varName + */ + constructor(varName) { + this.varName = varName; + } + + async diagnose() { + const varValue = process.env[this.varName]; + if (typeof varValue === 'undefined') { + return doctor.nok(`${this.varName} environment variable is NOT set!`); + } + + if (await fs.exists(varValue)) { + return doctor.ok(`${this.varName} is set to: ${varValue}`); + } + + return doctor.nok(`${this.varName} is set to '${varValue}' but this is NOT a valid path!`); + } + + async fix() { + return ( + `Make sure the environment variable ${this.varName} is properly configured for the Appium server process` + ); + } + + hasAutofix() { + return false; + } + + isOptional() { + return false; + } +} + +const androidHomeCheck = new EnvVarAndPathCheck('ANDROID_HOME'); + +module.exports = {androidHomeCheck}; + +/** + * @typedef {import('@appium/types').DoctorCheckResult} CheckResult + */ +``` + +This file could be saved as `doctor/android-home-check.js` and then added to the package.json manifest +as + +```json + // ... + "appium": { + // ... + "doctor": { + "checks": [ + "./doctor/android-home-check.js", + ] + } + // ... + }, + // ... +``` diff --git a/packages/appium/docs/ja/developing/build-drivers.md b/packages/appium/docs/ja/developing/build-drivers.md new file mode 100644 index 000000000..91cfc487d --- /dev/null +++ b/packages/appium/docs/ja/developing/build-drivers.md @@ -0,0 +1,866 @@ +--- +title: Building Drivers +--- + +Appium wants to make it easy for anyone to develop their own automation drivers as part of the +Appium ecosystem. This guide will explain what's involved and how you can accomplish various driver +development tasks using the tools Appium provides. This guide assumes you (1) are a competent user of +Appium, (2) are a competent Node.js developer, and (3) that you have read and understood the +[Driver Intro](../intro/drivers.md). + +If that describes you, great! This guide will get you started. + +## Before you create your driver + +Before you get to work implementing your driver, it's important to have a few things sorted out. +For example, you need to know what your driver will do. Which platform is it trying to expose +WebDriver automation for? + +Appium doesn't magically give you the power to automate any platform. All it does is give you a set +of convenient tools for implementing the WebDriver Protocol. So if you want to create, for example, +a driver for a new app platform, you'll need to know how to automate apps on that platform _without Appium_. + +This usually means that you need to be very familiar with app development for a given platform. And +it usually means that you will rely on tools or SDKs provided by the platform vendor. + +Basically, if you can't answer the question **"how would I launch, remotely trigger behaviours, and +read state from an app on this platform?" then you're not quite ready to write an Appium driver**. +Make sure you do the research to feel comfortable that there _is_ a path forward. Once there is, +coding it up and making it available as an Appium driver should be the easy part! + +## Other drivers to reference + +One of the greatest things about building an Appium driver is that there are already a number of +open source Appium drivers which you can look at for reference. There is +a [fake-driver](https://github.com/appium/appium/tree/master/packages/fake-driver) sample driver which +does basically nothing other than showcase some of the things described in this guide. + +And of course, all of Appium's official drivers are open source and available in repositories at +the project's GitHub organization. So if you ever find yourself asking, "how does a driver do X?", +read the code for these drivers! Also don't be afraid to ask questions of the Appium developers if +you get stuck; we're always happy to help make sure the driver development experience is a good +one! + +## Basic requirements for Appium drivers + +These are the things your driver _must_ do (or be), if you want it to be a valid Appium driver. + +### Node.js package with Appium extension metadata + +All Appium drivers are fundamentally Node.js packages, and therefore must have a valid +`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in Node.js so it can be loaded by Appium. + +Your `package.json` must include `appium` as a `peerDependency`. The requirements for the +dependency versions should be as loose as possible (unless you happen to know your driver will only +work with certain versions of Appium). For Appium 2, for example, this would look something like +`^2.0.0`, declaring that your driver works with any version of Appium that starts with 2.x. + +Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension +metadata'): + +```json +{ + ..., + "appium": { + "driverName": "fake", + "automationName": "Fake", + "platformNames": [ + "Fake" + ], + "mainClass": "FakeDriver" + }, + ... +} +``` + +The required subfields are: + +- `driverName`: this should be a short name for your driver. +- `automationName`: this should be the string users will use for their `appium:automationName` + capability to tell Appium to use _your_ driver. +- `platformNames`: this is an array of one or more platform names considered valid for your driver. + When a user sends in the `platformName` capability to start a session, it must be included in + this list for your driver to handle the session. Known platform name strings include: `iOS`, + `tvOS`, `macOS`, `Windows`, `Android`. +- `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a + class which extends Appium's `BaseDriver` (see below). + +### Extend Appium's `BaseDriver` class + +Ultimately, your driver is much easier to write because most of the hard work of implementing the +WebDriver protocol and handling certain common logic is taken care of already by Appium. This is +all encoded up as a class which Appium exports for you to use, called `BaseDriver`. It is exported +from `appium/driver`, so you can use one of these styles to import it and create your _own_ class +that extends it: + +```js +import {BaseDriver} from 'appium/driver'; +// or: const {BaseDriver} = require('appium/driver'); + +export class MyDriver extends BaseDriver { +} +``` + +### Make your driver available + +That's basically it! With a Node.js package exporting a driver class and with correct Appium +extension metadata, you've got yourself an Appium driver! Now it doesn't _do_ anything, but you can +load it up in Appium, start and stop sessions with it, etc... + +To make it available to users, you could publish it via NPM. When you do so, your driver will be +installable via the Appium CLI: + +``` +appium driver install --source=npm +``` + +It's a good idea to test your driver first, of course. One way to see how it works within Appium is +to install it locally first: + +``` +appium driver install --source=local /path/to/your/driver +``` + +### Developing your driver + +How you develop your driver is up to you. It is convenient, however, to run it from within Appium +without having to do lots of publishing and installing. The most straightforward way to do this is +to include the most recent version of Appium as a `devDependency`, and then also your own driver, +like this: + +```json +{ + "devDependencies": { + ..., + "appium": "^2.0.0", + "your-driver": "file:.", + ... + } +} +``` + +Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your driver is +listed as a dependency alongside it, it will be automatically "installed" and available. You can +design your e2e tests this way, or if you're writing them in Node.js, you can simply import +Appium's start server methods to handle starting and stopping the Appium server in Node. (TODO: +reference an implementation of this in one of the open source drivers when ready). + +Another way to do local development with an existing Appium server install is to simply install +your driver locally: + +``` +appium driver install --source=local /path/to/your/driver/dev/dir +``` + +### Refreshing your driver during development + +When the Appium server starts, it loads your driver into memory. Changes to your driver code will +not take effect until the next time the Appium server starts. Simply starting a new session is not +sufficient to cause your driver's code to be reloaded. + +However, you can set the `APPIUM_RELOAD_EXTENSIONS` environment variable to `1` to request that +Appium clear its module cache and reload extensions whenever a new session is requested. This may +obviate the need to restart the server when you make code changes to your driver. + +## Standard driver implementation ideas + +These are things you will probably find yourself wanting to do when creating a driver. + +### Set up state in a constructor + +If you define your own constructor, you'll need to call `super` to make sure all the standard state +is set up correctly: + +```js +constructor(...args) { + super(...args); + // now do your own thing +} +``` + +The `args` parameter here is the object containing all the CLI args used to start the Appium +server. + +### Define and validate accepted capabilities + +You can define your own capabilities and basic validation for them. Users will always be able to +send in capabilities that you don't define, but if they send in capabilities you have explicitly +defined, then Appium will validate that they are of the correct type (and will check for the +presence of required capabilities). + +If you want to turn capability validation off entirely, set `this.shouldValidateCaps` to `false` in +your constructor. + +To give Appium your validation constraints, set `this.desiredCapConstraints` to a validation object +in your constructor. Validation objects can be somewhat complex. Here's an example from the +UiAutomator2 driver: + +```js +{ + app: { + presence: true, + isString: true + }, + automationName: { + isString: true + }, + browserName: { + isString: true + }, + launchTimeout: { + isNumber: true + }, +} +``` + +### Start a session and read capabilities + +Appium's `BaseDriver` already implements the `createSession` command, so you don't have to. However +it's very common to need to perform your own startup actions (launching an app, running some +platform code, or doing different things based on capabilities you have defined for your driver). +So you'll probably end up overriding `createSession`. You can do so by defining the method in your +driver: + +```js +async createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) { + const [sessionId, caps] = super.createSession(w3cCaps); + // do your own stuff here + return [sessionId, caps]; +} +``` + +For legacy reasons, your function will receive old-style JSON Wire Protocol desired and required +caps as the first two arguments. Given that the old protocol isn't supported anymore and clients +have all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion +about what `otherDriverData` is about, see the section below on concurrent drivers). + +You'll want to make sure to call `super.createSession` in order to get the session ID as well as +the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps` +locally here would have no effect other than changing what the user sees in the create session +response). + +So that's it! You can fill out the middle section with whatever startup logic your driver requires. + +### End a session + +If your driver requires any cleanup or shutdown logic, it's best to do it as part of overriding the +implementation of `deleteSession`: + +```js +async deleteSession() { + // do your own cleanup here + // don't forget to call super! + await super.deleteSession(); +} +``` + +It's very important not to throw any errors here if possible so that all parts of session cleanup +can succeed! + +### Access capabilities and CLI args + +You'll often want to read parameters the user has set for the session, whether as CLI args or as +capabilities. The easiest way to do this is to access `this.opts`, which is a merge of all options, +from the CLI or from capabilities. So for example to access the `appium:app` capability, you could +simply get the value of `this.opts.app`. + +If you care about knowing whether something was sent in as a CLI arg _or_ a capability, you can +access the `this.cliArgs` and `this.caps` objects explicitly. + +In all cases, the `appium:` capability prefix will have been stripped away by the time you are +accessing values here, for convenience. + +### Implement WebDriver classic commands + +You handle WebDriver commands by implementing functions in your driver class. Each member of the +WebDriver Protocol, plus the various Appium extensions, has a corresponding function that you +implement if you want to support that command in your driver. The best way to see which commands +Appium supports and which method you need to implement for each command is to look at Appium's +[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js). +Each route object in this file tells you the command name as well as the parameters you'd expect to +receive for that command. + +Let's take this block for example: + +```js +'/session/:sessionId/url': { + GET: {command: 'getUrl'}, + POST: {command: 'setUrl', payloadParams: {required: ['url']}}, +} +``` + +Here we see that the route `/session/:sessionId/url` is mapped to two commands, one for a `GET` +request and one for a `POST` request. If we want to allow our driver to change the "url" (or +whatever that might mean for our driver), we can therefore implement the `setUrl` command, knowing +it will take the `url` parameter: + +```js +async setUrl(url) { + // your implementation here +} +``` + +A few notes: + +- all command methods should be `async` functions or otherwise return a `Promise` +- you don't need to worry about protocol encoding/decoding. You will get JS objects as params, and + can return JSON-serializable objects in response. Appium will take care of wrapping it up in the + WebDriver protocol response format, turning it into JSON, etc... +- all session-based commands receive the `sessionId` parameter as the last parameter +- all element-based commands receive the `elementId` parameter as the second-to-last parameter +- if your driver doesn't implement a command, users can still try to access the command, and will + get a `501 Not Yet Implemented` response error. + +### Implement WebDriver BiDi commands + +[WebDriver BiDi](https://w3c.github.io/webdriver-bidi) is a newer version of the WebDriver spec +which is implemented over Websockets instead of HTTP. As an Appium driver author you can take +advantage of Appium's BiDi support without having to know anything about the BiDi protocol or +Websockets. Implementing handlers for BiDi commands works just the same as implementing handlers +for WebDriver classic commands (described in the previous section). You simply define a method on +your driver of the appropriate name, and it will be called when the BiDi command is requested by +the client. To see which specific names you should use for BiDi commands, have a look at +[bidi-commands.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.js) + +You are not limited to BiDi commands that are defined in the official BiDi specification. If you +wish to define new commands, you may do so; you just need to tell Appium about them! See +[below](#extend-the-existing-protocol-with-new-commands) for more information. + +### Implement element finding + +Element finding is a special command implementation case. You don't actually want to override +`findElement` or `findElements`, even though those are what are listed in `routes.js`. Appium does +a lot of work for you if instead you implement this function: + +```js +async findElOrEls(strategy, selector, mult, context) { + // find your element here +} +``` + +Here's what gets passed in: + +- `strategy` - a string, the locator strategy being used +- `selector` - a string, the selector +- `mult` - boolean, whether the user has requested one element or all elements matching the + selector +- `context` - (optional) if defined, will be a W3C Element (i.e., a JS object with the W3C element + identifier as the key and the element ID as the value) + +And you need to return one of the following: + +- a single W3C element (an object as described above) +- an array of W3C elements + +Note that you can import that W3C web element identifier from `appium/support`: + +```js +import {util} from 'appium/support'; +const { W3C_WEB_ELEMENT_IDENTIFIER } = util; +``` + +What you do with elements is up to you! Usually you end up keeping a cache map of IDs to actual +element "objects" or whatever the equivalent is for your platform. + +### Define valid locator strategies + +Your driver might only support a subset of the standard WebDriver locator strategies, or it might +add its own custom locator strategies. To tell Appium which strategies are considered valid for +your driver, create an array of strategies and assign it to `this.locatorStrategies`: + +```js +this.locatorStrategies = ['xpath', 'custom-strategy']; +``` + +Appium will throw an error if the user attempts to use any strategies other than the allowed ones, +which enables you to keep your element finding code clean and deal with only the strategies you +know about. + +By default, the list of valid strategies is empty, so if your driver isn't simply proxying to +another WebDriver endpoint, you'll need to define some. The protocol-standard locator strategies +are defined [here](https://www.w3.org/TR/webdriver/#locator-strategies). + +### Throw WebDriver-specific errors + +The WebDriver spec defines a set of error +codes to accompany command responses if an +error occurred. Appium has created error classes for each of these codes, so you can throw the +appropriate error from inside a command, and it will do the right thing in terms of the protocol +response to the user. To get access to these error classes, import them from `appium/driver`: + +``` +import {errors} from 'appium/driver'; + +throw new errors.NoSuchElementError(); +``` + +### Log messages to the Appium log + +You can always use `console.log`, of course, but Appium provides a nice logger for you as +`this.log` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log +levels). If you want to create an Appium logger outside of a driver context (say in a script or +helper file), you can always construct your own too: + +```js +import {logging} from 'appium/support'; +const log = logging.getLogger('MyDriver'); +``` + +## Further possibilities for Appium drivers + +These are things your driver _can_ do to take advantage of extra driver features or do its job more +conveniently. + +### Add a schema for custom command line arguments + +You can add custom CLI args if you want your driver to receive data from the command line when the +Appium server is started (for example, ports that a server administrator should set that should not +be passed in as capabilities. + +To define CLI arguments (or configuration properties) for the Appium server, your extension must provide a _schema_. In +the `appium` property of your extension's `package.json`, add a `schema` property. This will either +a) be a schema itself, or b) be a path to a schema file. + +The rules for these schemas: + +- Schemas must conform to [JSON Schema Draft-07](https://ajv.js.org/json-schema.html#draft-07). +- If the `schema` property is a path to a schema file, the file must be in JSON or JS (CommonJS) format. +- Custom `$id` values are unsupported. To use `$ref`, provide a value relative to the schema root, e.g., `/properties/foo`. +- Known values of the `format` keyword are likely supported, but various other keywords may be unsupported. If you find a keyword that is unsupported which you need to use, please [ask for support](https://github.com/appium/appium/issues/new) or send a PR! +- The schema must be of type `object` (`{"type": "object"}`), containing the arguments in a `properties` keyword. Nested properties are unsupported. + +Example: + +```json +{ + "type": "object", + "properties": { + "test-web-server-port": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "The port to use for the test web server" + }, + "test-web-server-host": { + "type": "string", + "description": "The host to use for the test web server", + "default": "sillyhost" + } + } +} +``` + +The above schema defines two properties which can be set via CLI argument or configuration file. If +this extension is a _driver_ and its name is "horace", the CLI args would be +`--driver-horace-test-web-server-port` and `--driver-horace-test-web-server-host`, respectively. +Alternatively, a user could provide a configuration file containing: + +```json +{ + "server": { + "driver": { + "horace": { + "test-web-server-port": 1234, + "test-web-server-host": "localhorse" + } + } + } +} +``` + +### Add driver scripts + +Sometimes you might want users of your driver to be able to run scripts outside the context of +a session (for example, to run a script that pre-builds aspects of your driver). To support this, +you can add a map of script names and JS files to the `scripts` field within your Appium extension +metadata. So let's say you've created a script in your project that lives in a `scripts` directory +in your project, named `driver-prebuild.js`. Then you could add a `scripts` field like this: + +```json +{ + "scripts": { + "prebuild": "./scripts/driver-prebuild.js" + } +} +``` + +Now, assuming your driver is named `mydriver`, users of your driver can run `appium driver run +mydriver prebuild`, and your script will execute. + +### Proxy commands to another WebDriver implementation + +A very common design architecture for Appium drivers is to have some kind of platform-specific +WebDriver implementation that the Appium driver interfaces with. For example, the Appium +UiAutomator2 driver interfaces with a special (Java-based) server running on the Android device. In +webview mode, it also interfaces with Chromedriver. + +If you find yourself in this situation, it is extremely easy to tell Appium that your driver is +just going to be proxying WebDriver commands straight to another endpoint. + +First, let Appium know that your driver _can_ proxy by implementing the `canProxy` method: + +```js +canProxy() { + return true; +} +``` + +Next, tell Appium which WebDriver routes it should _not_ attempt to proxy (there often end up being +certain routes that you don't want to forward on): + +```js +getProxyAvoidList() { + return [ + ['POST', new RegExp('^/session/[^/]+/appium')] + ]; +} +``` + +The proxy avoidance list should be an array of arrays, where each inner array has an HTTP method as +its first member, and a regular expression as its second. If the regular expression matches the +route, then the route will not be proxied and instead will be handled by your driver. In this +example, we are avoiding proxying all `POST` routes that have the `appium` prefix. + +Next, we have to set up the proxying itself. The way to do this is to use a special class from +Appium called `JWProxy`. (The name means "JSON Wire Proxy" and is related to a legacy +implementation of the protocol). You'll want to create a `JWProxy` object using the details required to +connect to the remote server: + +```js +// import {JWProxy} from 'appium/driver'; + +const proxy = new JWProxy({ + server: 'remote.server', + port: 1234, + base: '/', +}); + +this.proxyReqRes = proxy.proxyReqRes.bind(proxy); +this.proxyCommand = proxy.command.bind(proxy); +``` + +Here we are creating a proxy object and assigning some of its methods to `this` under the names +`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget +this step! The `JWProxy` has a variety of other options which you can check out in the source code, +as well. (TODO: publish options as API docs and link here). + +Finally, we need a way to tell Appium when the proxy is active. For your driver it might always +be active, or it might only be active when in a certain context. You can define the logic as an +implementation of `proxyActive`: + +```js +proxyActive() { + return true; // or use custom logic +} +``` + +With those pieces in play, you won't have to reimplement anything that's already implemented by the +remote endpoint you're proxying to. Appium will take care of all the proxying for you. + +### Proxy BiDi commands to another BiDi implementation + +All of the above about proxying WebDriver commands is conceptually also valid for proxying BiDi +commands specifically. In order to enable BiDi proxying, you need to implement `get bidiProxyUrl` +on your driver. This should return a Websocket URL which is the address of the upstream socket you +want BiDi commands to be proxied to. + +The intended pattern here is for you to start a session on the upstream implementation, check +whether it has an active BiDi socket in the returned capabilities (e.g., the `webSocketUrl` +capability), and then to set an internal field to that value, so that it can be returned by `get +bidiProxyUrl`. Once all this is in place, Appium will proxy BiDi commands from the client straight +to the upstream connection. + +### Extend the existing protocol with new commands + +You may find that the existing commands don't cut it for your driver. If you want to expose +behaviours that don't map to any of the existing commands, you can create new commands in one of +three ways: + +1. Extending the classic WebDriver protocol and creating client-side plugins to access the extensions via the classic HTTP interface +2. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface +3. Overloading the Execute Script command by defining Execute + Methods + +If you want to follow the first path, you can direct Appium to recognize new methods and add them +to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap` +static variable in your driver class to an object of the same form as Appium's `routes.js` object. +For example, here is the `newMethodMap` for the `FakeDriver` example driver: + +```js +static newMethodMap = { + '/session/:sessionId/fakedriver': { + GET: {command: 'getFakeThing'}, + POST: {command: 'setFakeThing', payloadParams: {required: ['thing']}}, + }, + '/session/:sessionId/fakedriverargs': { + GET: {command: 'getFakeDriverArgs'}, + }, +}; +``` + +In this example we're adding a few new routes and a total of 3 new commands. For more examples of +how to define commands in this way, it's best to have a look through `routes.js`. Now all you need +to do is implement the command handlers in the same way you'd implement any other Appium command. + +The downside of this way of adding new commands is that people using the standard Appium clients +won't have nice client-side functions designed to target these endpoints. So you would need to +create and release client-side plugins for each language you want to support (directions or +examples can be found at the relevant client docs). + +The second way of adding new commands is adding them as BiDi commands (accessed via the BiDi +websocket interface, rather than the classic HTTP interface). BiDi commands come in two parts: +a "module", which is basically a container or namespace, and a "command", which is the name of your +new command. + +As with the first method, you teach Appium to recognize your new BiDi commands by adding a static +field to your driver class, called `newBidiCommands`. It has a format similar to `newMethodMap`. +Basically it encapsulates information about the BiDi module, BiDi command name, reference to your +driver instance method that will handle the command, and required and optional parameters. Here's +an example of a `newBidiCommands` as implemented on an imaginary driver: + +```js +static newBidiCommands = { + 'appium:video': { + startFramerateCapture: { + command: 'startFrameCap', + params: { + required: ['videoSource'], + optional: ['showOnScreen'], + } + }, + stopFramerateCapture: { + command: 'stopFrameCap', + }, + } +}; +``` + +In this imaginary example, we have defined two new BiDi commands: +`appium:video.startFramerateCapture` and `appium:video.stopFramerateCapture`. Note first of all +that, because we are defining a custom BiDi command, we should include a 'vendor prefix' (in this +case, `appium:`, though you should pick something that represents your project). The first command +takes a required and an optional parameter, and the second does not. When combined with generic +BiDi support in your driver (see [the section on BiDi](#implement-webdriver-bidi-commands) above), +and given an implementation of the appropriate methods on your driver (e.g. `startFrameCap` and +`stopFrameCap` in this example), clients would be able to send these BiDi commands using whatever +mechanism normally exists for doing so in the client library. + +An alternative to these other ways of doing things is to overload a command which all WebDriver clients +have access to already: Execute Script. Appium provides some a convenient tool for making this +easy. Let's say you are building a driver for stereo system called `soundz`, and you wanted to +create a command for playing a song by name. You could expose this to your users in such a way that +they call something like: + +```js +// webdriverio example. Calling webdriverio's `executeScript` command is what trigger's Appium's +// Execute Script command handler +driver.executeScript('soundz: playSong', [{song: 'Stairway to Heaven', artist: 'Led Zeppelin'}]); +``` + +Then in your driver code you can define the static property `executeMethodMap` as a mapping of +script names to methods on your driver. It has the same basic form as `newMethodMap`, described +above. Once `executeMethodMap` is defined, you'll also need to implement the Execute Script command +handler, which according to Appium's routes mapping is called `execute`. The implementation can +call a single helper function, `this.executeMethod`, which takes care of looking at the script and +arguments the user sent in and routing it to the correct custom handler you've defined. Here's an +example: + +```js +static executeMethodMap = { + 'soundz: playSong', { + command: 'soundzPlaySong', + params: {required: ['song', 'artist'], optional: []}, + } +} + +async soundzPlaySong(song, artist) { + // play the song based on song and artist details +} + +async execute(script, args) { + return await this.executeMethod(script, args); +} +``` + +A couple notes about this system: + +1. The arguments array sent via the call to Execute Script must contain only zero or one element(s). The + first item in the list is considered to be the parameters object for your method. These parameters + will be parsed, validated, and then applied to your overload method in the order specified in + `executeMethodMap` (the order specified in the `required` parameters list, followed by the + `optional` parameters list). I.e., this framework assumes only a single actual argument sent in via + Execute Script (and this argument should be an object with keys/values representing the + parameters your execute method expects). +2. Appium does not automatically implement `execute` (the Execute Script handler) for you. You may + wish, for example, to only call the `executeMethod` helper function when you're not in proxy + mode! +3. The `executeMethod` helper will reject with an error if a script name doesn't match one of the + script names defined as a command in `executeMethodMap`, or if there are missing parameters. + +One of the nice things about the Execute Method strategy is that methods implemented in this way +will be available via the classic or BiDi interfaces (since they will result in the same Appium +handlers being called). + +### Build Appium Doctor checks + +Your users can run `appium driver doctor ` to run installation and health checks. Visit +the [Building Doctor Checks](./build-doctor-checks.md) guide for more information on this +capability. + +### Implement handling of Appium settings + +Appium users can send parameters to your driver via CLI args as well as via capabilities. But these +cannot change during the course of a test, and sometimes users want to adjust parameters mid-test. +Appium has a [Settings](../guides/settings.md) API for this purpose. + +To support settings in your own driver, first of all define `this.settings` to be an instance of +the appropriate class, in your constructor: + +```js +// import {DeviceSettings} from 'appium/driver'; + +this.settings = new DeviceSettings(); +``` + +Now, you can read user settings any time simply by calling `this.settings.getSettings()`. This will +return a JS object where the settings names are keys and have their corresponding values. + +If you want to assign some default settings, or run some code on your end whenever settings are +updated, you can do both of these things as well. + +```js +constructor() { + const defaults = {setting1: 'value1'}; + this.settings = new DeviceSettings(defaults, this.onSettingsUpdate.bind(this)); +} + +async onSettingsUpdate(key, value) { + // do anything you want here with key and value +} +``` + +### Emit BiDi events + +With the WebDriver BiDi protocol, clients can subscribe to arbitrary events which can be sent +asynchronously to the client over the BiDi socket connection. As an Appium driver author you don't +need to worry about event subscription. If you want to emit an event with a certain method name and +payload, it's as easy as using the built-in event emitter with the `bidiEvent` event. + +As an +example, let's say our driver wants to periodically emit CPU load information. We could define an +event called `system.cpu`, and a payload that looks like `{load: 0.97}` to signify 97% CPU usage. +Whenever we want, our driver can simply call the following code (assuming we have the current load +in `this.currentCpuLoad`): + +```js +this.eventEmitter.emit('bidiEvent', { + method: 'appium:system.cpu', + params: {load: this.currentCpuLoad}, +}) +``` + +Now, if the client has subscribed to the `system.cpu` event, it will be notified with the load +whenever the driver emits it. + +### Make itself aware of resources other concurrent drivers are using + +Let's say your driver uses up some system resources, like ports. There are a few ways to make sure +that multiple simultaneous sessions don't use the same resources: + +1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc) +2. Just always use free resources (find a new random port for each session) +3. Have each driver express what resources it is using, then examine currently-used resources from + other drivers when a new session begins. + +To support this third strategy, you can implement `get driverData` in your driver to return what +sorts of resources your driver is currently using, for example: + +```js +get driverData() { + return {specialPort: 1234, specialFile: /path/to/file} +} +``` + +Now, when a new session is started on your driver, the `driverData` response from any other +simultaneously running drivers (of the same type) will also be included, as the last parameter of +the `createSession` method: + +```js +async createSession(jwpCaps, reqCaps, w3cCaps, driverData) +``` + +You can dig into this `driverData` array to see what resources other drivers are using to help +determine which ones you want to use for this particular session. + +!!! warning + +``` +Be careful here, since `driverData` is only passed between sessions of a single running Appium +server. There's nothing to stop a user from running multiple Appium servers and requesting your +driver simultaneously on each of them. In this case, you won't be able to ensure independence +of resources via `driverData`, so you might consider using file-based locking mechanisms or +something similar. +``` + +!!! warning + +``` +It's also important to note you will only receive `driverData` for other instances of *your* +driver. So unrelated drivers also running may still be using some system resources. In general +Appium doesn't provide any features for ensuring unrelated drivers don't interfere with one +another, so it's up to the drivers to allow users to specify resource locations or addresses to +avoid clashes. +``` + +### Log events to the Appium event timeline + +Appium has an [Event Timing API](../guides/event-timing.md) which allows users to get timestamps +for certain server-side events (like commands, startup milestones, etc...) and display them on +a timeline. The feature basically exists to allow introspection of timing for internal events to +help with debugging or running analysis on Appium driver internals. You can add your own events to +the event log: + +```js +this.logEvent(name); +``` + +Simply provide a name for the event and it will be added at the current time, and made accessible +as part of the event log for users. + +### Hide behaviour behind security flags + +Appium has a feature-flag based [security model](../guides/security.md) that allows driver authors +to hide certain features behind security flags. What this means is that if you have a feature you +deem insecure and want to require server admins to opt in to it, you can require that they enable +the feature by adding it to the `--allow-insecure` list or turning off server security entirely. + +To support the check within your own driver, you can call `this.isFeatureEnabled(featureName)` to +determine whether a feature of the given name has been enabled. Or, if you want to simply +short-circuit and throw an error if the feature isn't enabled, you can call +`this.assertFeatureEnabled(featureName)`. + +### Use a temp dir for files + +If you want to use a temporary directory for files your driver creates that are not important to +keep around between computer or server restarts, you can simply read from `this.opts.tmpDir`. This +reads the temporary directory location from `@appium/support`, potentially overridden by a CLI +flag. I.e., it's safer than writing to your own temporary directory because the location here plays +nicely with possible user configuration. `this.opts.tmpDir` is a string, the path to the dir. + +### Deal with unexpected shutdowns or crashes + +Your driver might run into a situation where it can't continue operating normally. For example, it +might detect that some external service has crashed and nothing will work anymore. In this case, it +can call `this.startUnexpectedShutdown(err)` with an error object including any details, and Appium +will attempt to gracefully handle any remaining requests before shutting down the session. + +If you want to perform some of your own cleanup logic when you encounter this condition, you can +either do so immediately before calling `this.startUnexpectedShutdown`, or you can attach a handler +to the unexpected shutdown event and run your cleanup logic "out of band" so to speak: + +```js +this.onUnexpectedShutdown(handler) +``` + +`handler` should be a function which receives an error object (representing the reason for the +unexpected shutdown). diff --git a/packages/appium/docs/ja/developing/build-plugins.md b/packages/appium/docs/ja/developing/build-plugins.md new file mode 100644 index 000000000..31628a628 --- /dev/null +++ b/packages/appium/docs/ja/developing/build-plugins.md @@ -0,0 +1,520 @@ +--- +title: Building Plugins +--- + +This is a high-level guide for developing Appium plugins, which is not something most Appium users +need to know or care about. If you are not familiar with Appium plugins yet from a user +perspective, check out the [list of plugins](../ecosystem/plugins.md) to play around with some and get +an idea of the sorts of things that plugins can do. Plugins are a powerful system for augmenting +Appium's functionality or changing the way Appium works. They can be distributed to other Appium +users and can extend Appium's ecosystem in all kinds of interesting ways! (There is also +a significant amount of overlap here with developing Appium drivers, so you may also want to check +out the [building drivers](./build-drivers.md) guide for further inspiration.) + +## Before you create your plugin + +Before creating your plugin, it's good to have a general idea of what you want your plugin to +accomplish and whether it will be possible to implement it given the restrictions of the Appium +platform. Reading through this guide will help you understand what's possible. In general, Appium's +plugin system is extremely powerful and no attempts have been made to artificially limit what's +possible with them (which is a main reason that all plugins are opt-in by the system administrator +responsible for starting the Appium server---plugins are powerful and should only be used when +explicitly trusted!). + +## Other plugins to reference + +There are a wide variety of open source Appium plugins available for perusal. It's definitely +recommended to explore the code for some other plugins before embarking on writing your own. The +Appium team maintains a set of official plugins in the Appium GitHub +repo. Links to other open source plugins can be found in the +[Plugin list](../ecosystem/plugins.md) + +## Basic requirements for plugins + +These are the things your plugin _must_ do (or be), if you want it to be a valid Appium plugin. + +### Node.js package with Appium extension metadata + +All Appium plugins are fundamentally Node.js packages, and therefore must have a valid +`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in +Node.js so it can be loaded by Appium. + +Your `package.json` must include `appium` as a `peerDependency`. The requirements for the +dependency versions should be as loose as possible (unless you happen to know your plugin will only +work with certain versions of Appium). For Appium 2, for example, this would look something like +`^2.0.0`, declaring that your plugin works with any version of Appium that starts with 2.x. + +Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension +metadata'): + +```` +```json +{ + ..., + "appium": { + "pluginName": "fake", + "mainClass": "FakePlugin" + }, + ... +} +``` +```` + +The required subfields are: + +- `pluginName`: this should be a short name for your plugin. +- `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a + class which extends Appium's `BasePlugin` (see below). + +### Extend Appium's `BasePlugin` class + +Ultimately, your plugin is much easier to write because most of the hard work of defining patterns +for overriding commands is done for you. This is +all encoded up as a class which Appium exports for you to use, called `BasePlugin`. It is exported +from `appium/plugin`, so you can use one of these styles to import it and create your _own_ class +that extends it: + +```js +import {BasePlugin} from 'appium/plugin'; +// or: const {BasePlugin} = require('appium/plugin'); + +export class MyPlugin extends BasePlugin { + // class methods here +} +``` + +!!! note + +``` +In all the code samples below, whenever we reference an example method, it is assumed +that it is defined _within_ the class, though this is not explicitly written, for the sake of +clarity and space. +``` + +### Make your plugin available + +That's basically it! With a Node.js package exporting a plugin class and with correct Appium +extension metadata, you've got yourself an Appium plugin! Now it doesn't _do_ anything, but you can +load it up in Appium, activate it, etc... + +To make it available to users, you could publish it via NPM. When you do so, your plugin will be +installable via the Appium CLI: + +``` +appium plugin install --source=npm +``` + +It's a good idea to test your plugin first, of course. One way to see how it works within Appium is +to install it locally first: + +``` +appium plugin install --source=local /path/to/your/plugin +``` + +And of course, plugins must be "activated" during Appium server start, so make sure you direct your +users to do so: + +``` +appium --use-plugins=plugin-name +``` + +### Developing your plugin + +How you develop your plugin is up to you. It is convenient, however, to run it from within Appium +without having to do lots of publishing and installing. The most straightforward way to do this is +to include the most recent version of Appium as a `devDependency` (although its being already +included as a `peerDependency` is sufficient in newer versions of NPM), and then also your own plugin, +like this: + +```json +{ + "devDependencies": { + ..., + "appium": "^2.0.0", + "your-plugin": "file:.", + ... + } +} +``` + +Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your plugin is +listed as a dependency alongside it, it will be automatically "installed" and available. You can +design your e2e tests this way, or if you're writing them in Node.js, you can simply import +Appium's start server methods to handle starting and stopping the Appium server in Node. + +Of course, you can always install it locally as described above as well. + +Anytime you make changes to your plugin code, you'll need to restart the Appium server to make sure +it picks up the latest code. As with drivers, you can set the `APPIUM_RELOAD_EXTENSIONS` +environment variable if you wish Appium to try to re-require your plugin module when a new session +starts. + +## Standard plugin implementation ideas + +These are things you will probably find yourself wanting to do when creating a plugin. + +### Set up state in a constructor + +If you define your own constructor, you'll need to call `super` to make sure all the standard state +is set up correctly: + +```js +constructor(...args) { + super(...args); + // now do your own thing +} +``` + +The `args` parameter here is the object containing all the CLI args used to start the Appium +server. + +### Intercept and handle specific Appium commands + +This is the most normal behavior for Appium plugins -- to modify or replace the execution of one or +more commands that would normally be handled by the active driver. To override the default command +handling, you need to implement `async` methods in your class with the same name as the Appium +commands to be handled (just exactly how drivers themselves are +implemented). Curious what command names there +are? They are defined in the Appium base driver's +[routes.js](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js) file, +and of course you can add more as defined in the next section. + +Each command method is sent the following arguments: + +1. `next`: This is a reference to an `async` function which encapsulates the chain of behaviors which would take place if this plugin were not handling the command. You can choose to call the next behavior in the chain at any point in your logic (by making sure to include `await next()` somewhere), or not. If you don't, it means the default behavior (or any plugins registered after this one) won't be run. +2. `driver`: This is the object representing the driver handling the current session. You have access to it for any work you need to do, for example calling other driver methods, checking capabilities or settings, etc... +3. `...args`: A spread array with any arguments that have been applied to the command by the user. + +For example, if we wanted to override the `setUrl` command to simply add some extra logging on top, +we would implement as follows: + +```js +async setUrl(next, driver, url) { + this.log(`Let's get the page source for some reason before navigating to '${url}'!`); + await driver.getPageSource(); + const result = await next(); + this.log(`We can also log after the original behaviour`); + return result; +} +``` + +### Intercept and handle _all_ Appium commands + +You might find yourself in a position where you want to handle _all_ commands, in order to inspect +payloads to determine whether or not to act in some way. If so, you can implement `async handle`, +and any command that is not handled by one of your named methods will be handled by this method +instead. It takes the following parameters (with all the same semantics as above): + +1. `next` +2. `driver` +3. `cmdName` - string representing the command being run +4. `...args` + +For example, let's say we want to log timing for all Appium commands as part of a plugin. We could +do this by implementing `handle` in our plugin class as follows: + +```js +async handle(next, driver, cmdName, ...args) { + const start = Date.now(); + try { + const result = await next(); + } finally { + const elapsedMs = Date.now() - start; + this.log(`Command '${cmdName}' took ${elapsedMs}`); + } + return result; +} +``` + +### Working with driver proxies + +There is a bit of a gotcha with handling Appium commands. Appium drivers have the ability to turn +on a special 'proxy' mode, wherein the Appium server process takes a look at incoming URLs, and +decides whether to forward them on to some upstream WebDriver server. It could happen that +a command which a plugin wants to handle is designated as a command which is being proxied to an +upstream server. In this case, we might run into a problem, because the plugin never gets a chance to +handle that command! The way Appium handles this is as follows: + +1. When a command comes in, before deciding whether to proxy the command, the main protocol handler + checks to see whether a plugin would handle the command. +2. If a plugin would _not_ handle the command--all proceeds as normal, and the request is either + proxied or not, based on the driver's proxy mode. +3. If a plugin _would_ handle the command, then the proxy behavior is skipped for the time being, + and wrapped up as the `next` function sent to the plugin. So if you have a command handler in + your plugin, and you want to be sure that the default driver proxying _does_ take place, then + simply `await next()` instead of (or in addition to) whatever your plugin handler is doing. + +### Throw WebDriver-specific errors + +The WebDriver spec defines a set of error +codes to accompany command responses if an +error occurred. Appium has created error classes for each of these codes, so you can throw the +appropriate error from inside a command, and it will do the right thing in terms of the protocol +response to the user. To get access to these error classes, import them from `appium/driver`: + +```js +import {errors} from 'appium/driver'; + +throw new errors.NoSuchElementError(); +``` + +### Log messages to the Appium log + +You can always use `console.log`, of course, but Appium provides a nice logger for you as +`this.logger` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log +levels). If you want to create an Appium logger outside of a plugin context (say in a script or +helper file), you can always construct your own too: + +```js +import {logging} from 'appium/support'; +const log = logging.getLogger('MyPlugin'); +``` + +## Further possibilities for Appium plugins + +These are things your plugin _can_ do to take advantage of extra plugin features or do its job more +conveniently. + +### Add a schema for custom command line arguments + +You can add custom CLI args if you want your plugin to receive data from the command line when the +Appium server is started (for example, ports that a server administrator should set that should not +be passed in as capabilities). + +This works largely the same for plugins as it does for drivers, so for more details have a look at +the equivalent section in the building drivers +doc. + +The only difference is that to construct the CLI argument name, you prefix it with +`--plugin-`. So for example, if you have a plugin named `pluggo` and a CLI arg defined with +the name `electro-port`, you can set it when starting Appium via `--plugin-pluggo-electro-port`. + +Setting args via a configuration file is also supported, as it is for drivers, but under the +`plugin` field instead. For example: + +```json +{ + "server": { + "plugin": { + "pluggo": { + "electro-port": 1234 + } + } + } +} +``` + +### Add plugin scripts + +Sometimes you might want users of your plugin to be able to run scripts outside the context of +a session (for example, to run a script that pre-builds aspects of your plugin). To support this, +you can add a map of script names and JS files to the `scripts` field within your Appium extension +metadata. So let's say you've created a script in your project that lives in a `scripts` directory +in your project, named `plugin-prebuild.js`. Then you could add a `scripts` field like this: + +```json +{ + "scripts": { + "prebuild": "./scripts/plugin-prebuild.js" + } +} +``` + +Now, assuming your plugin is named `myplugin`, users of your plugin can run `appium plugin run +myplugin prebuild`, and your script will execute. + +### Add new Appium commands + +If you want to offer functionality that doesn't map to any of the existing commands supported by +drivers, you can create new commands in one of two ways, just as is possible for drivers: + +1. Extending the WebDriver protocol and creating client-side plugins to access the extensions +2. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface +3. Overloading the Execute Script command by defining Execute + Methods + +#### Extending the HTTP Protocol + +If you want to follow the first path, you can direct Appium to recognize new methods and add them +to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap` +static variable in your driver class to an object of the same form as Appium's `routes.js` object. +For example, here is part of the `newMethodMap` for the `FakePlugin` example driver: + +```js +static newMethodMap = { + '/session/:sessionId/fake_data': { + GET: {command: 'getFakeSessionData', neverProxy: true}, + POST: { + command: 'setFakeSessionData', + payloadParams: {required: ['data']}, + neverProxy: true, + }, + }, + '/session/:sessionId/fakepluginargs': { + GET: {command: 'getFakePluginArgs', neverProxy: true}, + }, +}; +``` + +!!! note + +``` +If you're using TypeScript, static member objects like these should be defined `as const`. +``` + +In this example we're adding a few new routes and a total of 3 new commands. For more examples of +how to define commands in this way, it's best to have a look through `routes.js`. Now all you need +to do is implement the command handlers in the same way you'd implement any other Appium command. + +Note also the special `neverProxy` key for commands; this is generally a good idea to set to `true` +for plugins, since your plugin might be active for a driver that is put into proxy mode but hasn't +bothered to decline proxying for these (new and therefore unknown) commands. Setting `neverProxy` +to `true` here will cause Appium to never proxy these routes and therefore ensure your plugin +handles them, even if a driver is in proxy mode. + +The downside of adding new commands via `newMethodMap` is that people using the standard Appium +clients won't have nice client-side functions designed to target these endpoints. So you would need +to create and release client-side plugins for each language you want to support (directions or +examples can be found at the relevant client docs). + +#### Extending the BiDi Protocol + +You can also make new commands accessible via the WebDriver BiDi (WebSocket-based) protocol. BiDi +commands come in two parts: a "module", which is basically a container or namespace, and +a "command", which is the name of your new command. + +As with the first method, you teach Appium to recognize your new BiDi commands by adding a static +field to your driver class, called `newBidiCommands`. It has a format similar to `newMethodMap`. +Basically it encapsulates information about the BiDi module, BiDi command name, reference to your +driver instance method that will handle the command, and required and optional parameters. Here's +an example of a `newBidiCommands` as implemented on an imaginary driver: + +```js +static newBidiCommands = { + 'appium:video': { + startFramerateCapture: { + command: 'startFrameCap', + params: { + required: ['videoSource'], + optional: ['showOnScreen'], + } + }, + stopFramerateCapture: { + command: 'stopFrameCap', + }, + } +}; +``` + +In this imaginary example, we have defined two new BiDi commands: `appium:video.startFramerateCapture` and +`appium:video.stopFramerateCapture`. The first command takes a required and an optional parameter, and the +second does not. When you have implemented the `startFrameCap` and `stopFrameCap` methods on your +plugin class, they will be called whenever the BiDi commands are triggered by a client. The +signatures for these methods would look as follows: + +```js +async startFrameCap(next: () => Promise, driver: DriverClass, videoSource: string, showOnScreen: boolean): Promise; +async stopFrameCap(next: () => Promise, driver: DriverClass): Promise; +``` + +As with adding or overriding existing HTTP protocol commands, these methods are injected with +a `next` parameter and a `driver` parameter. The `driver` object represents the driver currently +owning the session, and calling `await next()` will execute/return the behavior that would execute +were the plugin not active (i.e., the driver's own handling of that method, or the chain of +commands executed with the same name by other active plugins). + +Note that, currently, if a driver has BiDi proxying turned on, plugins will not be able to override +BiDi methods handled by the proxy. Also note that since these are custom BiDi commands, our module +name should include a vendor prefix (we chose `appium:`, but you can/should choose something that +makes sense for your extension). + +#### Overloading Execute Script + +An alternative to these ways of doing things is to overload a command which all WebDriver clients +have access to already: Execute Script. Make sure to read the section on adding new +commands in +the Building Drivers guide to understand the way this works in general. The way it works with +plugins is only slightly different. Let's look at an example taken from Appium's `fake-plugin`: + +```js +static executeMethodMap = { + 'fake: plugMeIn': { + command: 'plugMeIn', + params: {required: ['socket']}, + }, +}; + +async plugMeIn(next, driver, socket) { + return `Plugged in to ${socket}`; +} + +async execute(next, driver, script, args) { + return await this.executeMethod(next, driver, script, args); +} +``` + +We have three important components shown here which make this system work, all of which are defined +inside the plugin class: + +1. The `executeMethodMap`, defined in just the same way as for drivers +2. The implementation of the command method as defined in `executeMethodMap` (in this case, + `plugMeIn`) +3. The overriding/handling of the `execute` command. Just like any plugin command handlers, the + first two arguments are `next` and `driver`, followed by the script name and args. `BasePlugin` + implements a helper method which we can simply call with all of these arguments. + +Overriding Execute Methods from drivers works as you'd expect: if your plugin defines an Execute +Method with the same name as that of a driver, your command (in this case `plugMeIn`) will be +called first. You can choose to run the driver's original behaviour via `next` if you want. + +### Emit BiDi Events + +Your plugin can emit custom BiDi events in exactly the same way as Appium +drivers. + +### Build Appium Doctor checks + +Your users can run `appium plugin doctor ` to run installation and health checks. Visit +the [Building Doctor Checks](./build-doctor-checks.md) guide for more information on this +capability. + +### Update the Appium server object + +You probably don't normally need to update the Appium server object (which is an +[Express](https://expressjs.com/) server having already been +[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js) +in a variety of ways). But, for example, you could add new Express middleware to the server to +support your plugin's requirements. To update the server you must implement the `static async +updateServer` method in your class. This method takes three parameters: + +- `expressApp`: the Express app object +- `httpServer`: the Node HTTP server object +- `cliArgs`: a map of the CLI args used to start the Appium server + +You can do whatever you want with them inside the `updateServer` method. You might want to +reference how these objects are created and worked with in the BaseDriver code, so that you know +you're not undoing or overriding anything standard and important. But if you insist, you can, with +results you'll need to test! Warning: this should be considered an advanced feature and requires +knowledge of Express, as well as the care not to do anything that could affect the operation of +other parts of the Appium server! + +### Handle unexpected session shutdown + +When developing a plugin you may want to add some cleanup logic for when a session ends. You would +naturally do this by adding a handler for `deleteSession`. This works in most cases, except when +the session does not finish cleanly. Appium sometimes determines that a session has finished +unexpectedly, and in these situations, Appium will look for a method called `onUnexpectedShutdown` +in your plugin class, which will be called (passing the current session driver as the first +parameter, and the error object representing the cause of the shutdown as the second), giving you +an opportunity to take any steps that might be necessary to clean up from the session. For example, +keeping in mind that the function is not `await`ed you could implement something like this: + +```js +async onUnexpectedShutdown(driver, cause) { + try { + // do some cleanup + } catch (e) { + // log any errors; don't allow anything to be thrown as they will be unhandled rejections + } +} +``` diff --git a/packages/appium/docs/ja/developing/config-system.md b/packages/appium/docs/ja/developing/config-system.md new file mode 100644 index 000000000..9ca0efcc1 --- /dev/null +++ b/packages/appium/docs/ja/developing/config-system.md @@ -0,0 +1,468 @@ +--- +title: Appium's Config System +--- + +Appium 2 supports [configuration files](../guides/config.md). A configuration file is intended to +have (nearly) 1:1 parity with command-line arguments. An end user can supply Appium 2 with +a configuration file, CLI args, or both (the args have precedence over the config file). + +This document will be a technical overview of how the configuration system works. It is intended +for Appium contributors, but will also explain the system's fundamental features. + +## Reading a Config File + +A config file is a JSON, JavaScript, or YAML file which can be validated against a schema. By +default, this file will be named `.appiumrc.{json,js,yaml,yml}` and should be in the root of the +project which depends upon `appium`. Other filenames and locations are supported via the `--config ` flag. For obvious reasons, the `config` argument is disallowed within config files. + +In lieu of a separate file, configuration can be embedded in a project's `package.json` using the +`appiumConfig` property, e.g.,: + +```json +{ + "appiumConfig": { + "server": { + "port": 12345 + } + } +} +``` + +When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js` +will call into `lib/config-file.js` to load and/or search for a configuration file and in +`package.json`. + +!!! note + +``` +It is not an error if configuration isn't found! +``` + +The [`lilconfig`](https://npm.im/lilconfig) package provides the search & load functionality; refer +to its documentation for more information about the search paths. Additionally, Appium provides +support for config files written in YAML via the package [`yaml`](https://npm.im/yaml). + +If a config file is found and successfully [validated](#validation), the result will be merged with +a set of defaults and any additional CLI arguments. CLI arguments have precedence over config +files, and config files have precedence over defaults. + +## Validation + +The same system is used for _both_ validation of config files _and_ command-line arguments. + +The package [`ajv`](https://npm.im/ajv) provides validation. Of course, to make `ajv` validate +anything, it must be provided a _schema_. + +The _base_ schema is a JSON Schema +Draft-7-compliant object exported by +`lib/schema/appium-config-schema.js`. This schema defines configuration _native to Appium_, and +only concerns its behavior as a _server_; it does not define configuration for any other +functionality (e.g., the `plugin` or `driver` subcommands). + +!!! warning + +``` +Note that this file is the _base_ schema; this will become painfully relevant. +``` + +This file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is +especially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files. + +It is more straightforward to explain how config files are validated, so we'll start there. + +### Validating Config Files + +When a config file is found (`lib/config-file.js`), it will call the `validate` function exported +from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to +validate the data against the schema that Appium has provided it. + +If the config file is invalid, errors will be generated to be displayed to the user. Finally, the +`init` function will detect these errors, display them, and the process will exit. + +I hope that made sense, because this is the easy part. + +### Validating CLI Arguments + +As mentioned earlier, the same system is used for validating both config files and CLI arguments. + +Totally not judging, but Appium uses [`argparse`](https://npm.im/argparse) for its CLI argument +parsing. This package, and others like it, provides an API to define the arguments a command-line +Node.js script accepts, and will ultimately return an object representation of the user-supplied +arguments. + +Just as the schema defines what's allowed in a config file, it also defines what's allowed on the +command-line. + +#### Defining CLI Arguments via Schema + +CLI arguments must be _defined_ before their values can be validated. + +A JSON schema isn't a natural fit for defining CLI args--it needs some grease to make it work--but +it's close enough that we can do so with an adapter and some custom metadata. + +In `lib/cli/parser.js`, there's a wrapper around `argparse`'s `ArgumentParser`; it's called (wait +for it)... `ArgParser`. The wrapper exists because we're doing some custom things with `argparse`, +but is has nothing to do with the schema directly. + +An `ArgParser` instance is created and its `parseArgs()` method is called with the raw CLI +arguments. The definition of the accepted arguments comes from `lib/cli/args.js` in part--here, all +of the arguments _not_ intended for use with the `server` subcommand are hard-coded (e.g., the +`driver` subcommand and _its_ subcommands). `args.js` also contains a function `getServerArgs()`, +which in turn calls into `toParserArgs` in `lib/schema/cli-args.js`. `lib/schema/cli-args.js` can +be considered the "adapter" layer between `argparse` and the schema. + +`toParserArgs` uses the `flattenSchema` function exported by `lib/schema/schema.js`, which +"squashes" the schema into a key/value representation. Then, `toParserArgs` iterates over each +key/value pair and "converts" it into a suitable `ArgumentOption` object for final handoff to +`ArgParser`. + +This adapter (`cli-args.js`) is where most of the mess is hidden; let's explore this rat's nest +a bit further. + +##### CLI & Schema Incongruities + +The conversion algorithm (see function `subSchemaToArgDef` in `lib/schema/cli-args.js`) is mostly +just hacks and special cases neatly packed into a function. Things that don't cleanly map from +`argparse` to a JSON schema include, but are not limited to: + +- A schema cannot natively express "store the value of `--foo=` in a property called `bar`" in a schema (this corresponds to the `ArgumentOption['dest']` prop). +- A schema cannot natively express aliases; e.g., `--verbose` can also be `-v` +- A schema `enum` is not restricted to multiple types, but `argparse`'s equivalent `ArgumentOption['choices']` prop _is_ +- A schema does not know about `argparse`'s concept of "actions" (note that Appium is not currently using custom actions--though it did, and it could again). +- `argparse` has no native type for `email`, `hostname`, `ipv4`, `uri` etc., and the schema does +- Schema validation only _validates_, it does not perform translation, transformation, or coercion (mostly). `argparse` allows this. +- Schemas allow the `null` type, for whatever reason. Ever pass `null` on the CLI? +- `argparse` does not understand anything other than primitives; no objects, arrays, etc., and certainly not arrays of a particular type. + +All of the above cases and others are handled by the adapter. + +!!! warning + +``` +Some decisions made in the adapter were arrived at via coin toss. If you are curious about why +something is the way it is, it's likely that it had to do _something_. +``` + +Let's look more closely at handling types. + +#### Argument Types via `ajv` + +While `argparse` allows consumers, via its API, to define the _type_ of various arguments (e.g., +a string, number, boolean flag, etc.), Appium mostly avoids these built-in types. _Why is that?_ +Well: + +1. We already know the type of an argument, because we've defined it in a schema. +2. `ajv` provides validation against a schema. +3. A schema allows for greater expression of types, allowed values, etc., than `argparse` can provide natively. +4. The expressiveness of a schema allows for better error messaging. + +To that end, the adapter eschews `argparse`'s built-in types (see allowed string values of +`ArgumentOption['type']`) and instead abuses the ability to provide a _function_ as a `type`. The +exception is _boolean_ flags, which do not have a `type`, but rather `action: 'store_true'`. The +world may never know why. + +##### Types as Functions + +When a `type` is a function, the function performs both validation _and_ coercion (if necessary). +So what are these functions? + +> Note: `type` is _omitted_ (and thus _not_ a function) from the `ArgumentOption` if the property +> type is `boolean`, and is instead provided an `action` property of `store_true`. Yes, this is +> weird. No, I don't know why. + +Well... it depends upon the schema. But generally speaking, we create a _pipeline_ of functions, +each corresponding to a keyword in the schema. Let's take the example of the `port` argument. In +lieu of asking the OS which ports the `appium`-running user can bind to, this argument is expected +to be an integer between 1 and 65535. This turns out to be two functions which we combine into +a pipeline: + +1. Convert the value to an integer, if possible. Because _every value in `process.argv` is a string_, we must coerce if we want a number. +2. Use `ajv` to validate the integer against the schema for `port`. A schema lets us define a range via the `minimum` and `maximum` keywords. Read more about how this works in + +Much like the config file validation, if errors are detected, Appium nicely tells the end-user and +the process exits w/ some help text. + +For other arguments which are naturally of non-primitive types, things are not so straightforward. + +##### Transformers + +Remember how `argparse` doesn't understand arrays? What if the most ergonomic way to express +a value is, in fact, an array? + +Well, Appium can't accept an array on the CLI, even though it can accept one in the config file. +But Appium _can_ accept a comma-delimited string (a CSV "line"). Or a string filepath referring to +a file which _contains_ a delimited list. Either way: by the time the value gets out of the +argument parser, it should be an array. + +And as mentioned above, the native facilities of a JSON schema cannot express this. However, it's +possible to define a _custom keyword_ which Appium can then detect and handle accordingly. So +that's what Appium does. + +In this case, a custom keyword `appiumCliTransformer` is registered with `ajv`. The value of +`appiumCliTransformer` (at the time of this writing) can be `csv` or `json`. In the base schema +file, `appium-config-schema.js`, Appium uses `appiumCliTransformer: 'csv'` if this behavior is +desired. + +!!! note + +``` +Any property defined in the schema having type `array` will _automatically_ uses the `csv` +transformer. Likewise, a property having type `object` will use the `json` transformer. It's +conceivable that `array` may want to use the `json` transformer, but otherwise, the presence of +the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not stricly +necessary. +``` + +The adapter (remember the adapter?) creates a pipeline function including a special "CSV +transformer" (transformers are defined in `lib/schema/cli-transformers.js`), and uses this function +as the `type` property of the `ArgumentOption` passed into `argparse`. In this case, the `type: +'array'` in the schema is ignored. + +!!! note + +``` +The config file doesn't _need_ to perform any complex transformation of values, because it +naturally allows Appium to define exactly what it expects. So Appium does no post-processing of +config file values. +``` + +Properties that do not need this special treatment use `ajv` directly for validation. How this +works requires some explanation, so that's next. + +#### Validation of Individual Arguments via `ajv` + +When we think of a JSON schema, we tend to think, "I have this JSON file and I want to validate it +against the schema". That's valid, and in fact Appium does just that with config files! However, +Appium does not do this when validating arguments. + +!!! note + +``` +During implementation, I was tempted to mash all of the arguments together into +a config-file-like data structure and then validate it all at once. I think that would have +been _possible_, but since an object full of CLI arguments is a flat key/value structure and +the schema is not, this seemed like trouble. +``` + +Instead, Appium validates a value against a specific property _within_ the schema. To do this, it +maintains a mapping between a CLI argument definition and its corresponding property. The mapping +itself is a `Map` with a unique identifier for the argument as the key, and an `ArgSpec` +(`lib/schema/arg-spec.js`) object as the value. + +An `ArgSpec` object stores the following metadata: + +| Property Name | Description | +| --------------- | -------------------------------------------------------------------------------------------------------- | +| `name` | Canonical name of the argument, corresponding to the property name in the schema. | +| `extType?` | `driver` or `plugin`, if appropriate | +| `extName?` | Extension name, if appropriate | +| `ref` | Computed `$id` of the property in the schema | +| `arg` | Argument as accepted on CLI, without leading dashes | +| `dest` | Property name in parsed arguments object (as returned by `argparse`'s `parse_args()`) | +| `defaultValue?` | Value of the `default` keyword in schema, if appropriate | + +When a schema is [finalized](#schema-finalization), the `Map` is populated with `ArgSpec` objects +for all known arguments. + +So when the adapter is creating the pipeline of functions for the argument's `type`, it already has +an `ArgSpec` for the argument. It creates a function which calls `validate(value, ref)` (in +`lib/schema/schema.js`) where `value` is whatever the user provided, and `ref` is the `ref` +property of the `ArgSpec`. The concept is that `ajv` can validate using _any_ `ref` it knows about; +each property in a schema can be referenced by this `ref` whether it's defined or not. To help +visualize, if a schema is: + +```json +{ + "$id": "my-schema.json", + "type": "object", + "properties": { + "foo": { + "type": "number" + } + } +} +``` + +The `ref` of `foo` would be `my-schema.json#/properties/foo`. Assuming our `Ajv` instance knows +about this `my-schema.json`, then we can call its `getSchema(ref)` method (which has a `schema` +property, but is a misnomer nonetheless) to get a validation function; `validate(value, ref)` in +`schema.js` calls this validation function. + +!!! note + +``` +The schema spec says a schema author can supply an explicit `$id` keyword to override this; +it's unsupported by Appium at this time. If needed, extension authors must carefully use `$ref` +without custom `$id`s. It's highly unlikely an extension would have a schema so complicated as +to need this, however; Appium itself doesn't even use `$ref` to define its own properties! +``` + +Next, let's take a look at how Appium loads schemas. This actually happens _before_ any argument +validation. + +## Schema Loading + +Let's ignore extensions for a moment, and start with the base schema. + +When something first imports the `lib/schema/schema.js` module, an instance of an `AppiumSchema` is +created. This is a singleton, and its methods are exported from the module (all of which are bound +to the instance). + +The constructor does very little; it instantiates an `Ajv` instance and configures it with Appium's +[custom keywords](#custom-keyword-reference) and adds support for the `format` keyword via the +[ajv-formats](https://npm.im/ajv-formats) module. + +Otherwise, the `AppiumSchema` instance does not interact with the `Ajv` instance until its +`finalize()` method (exported as `finalizeSchema()`) is called. When this method is called, we're +saying "we are not going to add any more schemas; go ahead and create `ArgSpec` objects and +register schemas with `ajv`". + +When does finalization happen? Well: + +1. When the `appium` executable begins, it _checks for and configures extensions_ (hand-wave) in `APPIUM_HOME`. +2. Only then does it start to think about arguments--it instantiates an `ArgParser`, which (as you'll recall) runs the adapter to convert the schema to arguments. +3. _Finalization happens here_--when creating the parser. Appium need the schema(s) to be registered with `ajv` in order to create validation functions for arguments. +4. Thereafter, Appium parses the arguments with the `ArgParser`. +5. Finally, decides what to do with the returned object. + +Without extensions, `finalize()` still knows about the Appium base schema +(`appium-config-schema.js`), and just registers that. However, step 1. above is doing a _lot of +work_, so let's look at how extensions come into play. + +## Extension Support + +One of the design goals of this system is the following: + +_An extension should be able to register custom CLI arguments with the Appium, and a user should be +able to use them like any other argument_. + +Previously, Appium 2 accepted arguments in this manner (via `--driverArgs`), but validation was +hand-rolled and required extension implementors to use a custom API. It also required the user to +awkwardly pass a JSON string as the configuration on the command-line. Further, no contextual help +(via `--help`) existed for these arguments. + +Now, by providing a schema for its options, a driver or plugin can register CLI arguments and +config file schemas with Appium. + +To register a schema, an extension must provide the `appium.schema` property in its `package.json`. +The value may be a schema or a path to a schema. If the latter, the schema should be JSON or +a CommonJS module (ESM not supported at this time, nor is YAML). + +For any property in this schema, the property will appear as a CLI argument of the form +`----`. For example, if the `fake` driver provides +a property `foo`, the argument will be `--driver-fake-foo`, and will show in `appium server --help` +like any other CLI argument. + +The corresponding property in a config file would be +`server...`, e.g.: + +```json +{ + "server": { + "driver": { + "fake": { + "foo": "bar" + } + } + } +} +``` + +The naming convention described above avoids problems of one extension type having a name conflict +with a different extension type. + +!!! note + +``` +While an extension can provide aliases via `appiumCliAliases`, "short" flags are disallowed, +since all arguments from extensions are prefixed with `----`. +The extension name and argument name will be kebab-cased for the CLI, according to [Lodash's +rules](https://lodash.com/docs/4.17.15#kebabCase) around kebab-casing. +``` + +The schema object will look much like Appium's base schema, but it will only have top-level +properties (nested properties are currently unsupported). Example: + +```json +{ + "title": "my rad schema for the cowabunga driver", + "type": "object", + "properties": { + "fizz": { + "type": "string", + "default": "buzz", + "$comment": "corresponds to CLI --driver-cowabunga-fizz" + } + } +} +``` + +As written in a user's config file, this would be the `server.driver.cowabunga.fizz` property. + +When extensions are loaded, the `schema` property is verified and the schema is registered with the +`AppiumSchema` (it is _not_ registered with `Ajv` until `finalize()` is called). + +During finalization, each registered schema is added to the `Ajv` instance. The schema is assigned +an `$id` based on the extension type and name (which overrides whatever the extension provides, if +anything). Schemas are also forced to disallowed unknown arguments via the `additionalProperties: +false` keyword. + +Behind the scenes, the base schema has `driver` and `plugin` properties which are objects. When +finalized, a property is added to each--corresponding to an extension name--and the value of this +property is a reference to the `$id` of a property in the extension schema. For example, the +`server.driver` property will look like this: + +```json +{ + "driver": { + "cowabunga": { + "$ref": "driver-cowabunga.json" + } + } +} +``` + +This is why we call it the "base" schema--it is _mutated_ when extensions provide schemas. The +extension schemas are kept separately, but the _references_ are added to the schema before it's +ultimately added to `ajv`. This works because an `Ajv` instance understands references _from_ any +schema it knows about _to_ any schema it knows about. + +!!! note + +``` +This makes it impossible to provide a complete static schema for Appium _and_ the installed +extensions (as of Nov 5 2021). A static `.json` schema _is_ generated from the base (via a Gulp +task), but it does not contain any extension schemas. The static schema also has uses beyond +Appium; e.g., IDEs can provide contextual error-checking of config files this way. Let's solve +this? +``` + +Just like how we look up the reference ID of a particular argument in the base schema, validation +of arguments from extensions happens the exact same way. If the `cowabunga` driver has the schema +ID `driver-cowabunga.json`, then the `fizz` property can be referenced from any schema registered +with `ajv` via `driver-cowabunga.json#/properties/fizz`. "Base" schema arguments begin with +`appium.json#properties/` instead. + +## Development Environment Support + +During the flow of development, a couple extra tasks have been automated to maintain the base +schema: + +- As a post-transpilation step, a `lib/appium-config.schema.json` gets generated from +- `lib/schema/appium-config-schema.js` (in addition to its CJS counterpart generated by Babel). +- This file is under version control. It ends up being _copied_ to +- `build/lib/appium-config.schema.json` in this step. A pre-commit hook (see +- `scripts/generate-schema-declarations.js` in the root monorepo) generates +- a `types/appium-config-schema.d.ts` from the above JSON file. The types in `types/types.d.ts` +- depend upon this file. This file is under version control. + +## Custom Keyword Reference + +Keywords are defined in `lib/schema/keywords.js`. + +- `appiumCliAliases`: allows a schema to express aliases (e.g., a CLI argument can be `--verbose` or `-v`). This is an array of strings. Strings shorter than three (3) characters will begin with a single dash (`-`) instead of a double-dash (`--`). Note that any argument provided by an extension will begin with a double-dash, because these are required to have the `----` prefix. +- `appiumCliDest`: allows a schema to specify a custom property name in the post-`argprase` arguments objects. If not set, this becomes a camelCased string. +- `appiumCliDescription`: allows a schema to override the description of the argument when displayed on the command-line. This is useful paired with `appiumCliTransformer` (or `array`/`object`-typed properties), since there's a substantial difference between what a CLI-using user can provide vs. what a config-file-using user can provide. +- `appiumCliTransformer`: currently a choice between `csv` and `json`. These are custom functions which post-process a value. They are not used when loading & validating config files, but the idea should be that they result in the same object you'd get if you used whatever the config file wanted (e.g., an array of strings). `csv` is for comma-delimited strings and CSV files; `json` is for raw JSON strings and `.json` files. +- `appiumCliIgnore`: If `true`, do not support this property on the CLI. +- `appiumDeprecated`: If `true`, the property is considered "deprecated", and will be displayed as such to the user (e.g., in the `--help` output). Note the JSON Schema draft-2019-09 introduces a new keyword `deprecated` which we should use instead if upgrading to this metaschema. When doing so, `appiumDeprecated` should itself be marked as `deprecated`. diff --git a/packages/appium/docs/ja/developing/index.md b/packages/appium/docs/ja/developing/index.md new file mode 100644 index 000000000..670d79c8d --- /dev/null +++ b/packages/appium/docs/ja/developing/index.md @@ -0,0 +1,17 @@ +--- +hide: + - toc +title: Intro to Development +--- + +Appium 2 is built with a modular structure, which means that Appium extensions (drivers and plugins) +are decoupled from the main Appium module, and you only need to install the extensions that you +want to use. This modular structure also unlocks the ability to develop entirely new extensions! + +This section of the Appium documentation is intended to help aspiring developers with creating their +own Appium extension: + +- For creating a driver, see the [Build Drivers](./build-drivers.md) page +- For creating a plugin, take a look at the [Build Plugins](build-plugins.md) page +- Drivers and plugins both need documentation, so check out the [Build Documentation](./build-docs.md) page +- For creating a doctor check, see the [Building Doctor Checks](./build-doctor-checks.md) page diff --git a/packages/appium/docs/ja/developing/sensitive.md b/packages/appium/docs/ja/developing/sensitive.md new file mode 100644 index 000000000..c6cc3c0a2 --- /dev/null +++ b/packages/appium/docs/ja/developing/sensitive.md @@ -0,0 +1,48 @@ +--- +hide: + - toc +title: Masking Sensitive Log Data +--- + +Since Appium server version 2.18.0 there is a possibility to mask sensitive +values in logs. The below tutorial explains how to use this feature in third-party +extensions. + +## Why It Might Be Useful + +It is the right call to hide sensitive information, like passwords, tokens, etc. +from server logs, so it does not accidentally leak if these logs end up in wrong hands. +Appium server already provides a way to manipulate logs records via +[filtering](../guides/log-filters.md), although it has its own limitations. +The current approach is more sophisticated though, and requires some fine-tuning +on the driver/plugin side. + +## How To + +The assumption is that your extension uses the standard built-in +[@appium/logger](https://www.npmjs.com/package/@appium/logger). +In order to get some value in logs replaced by a generic mask it is necessary: + +- Change the logging expression to wrap sensitive values and format them, for example: + + ```js + this.log.info(`Value: ${value}`); + ``` + + becomes + + ```js + import {logger} from '@appium/support'; + + this.log.info('Value: %s', logger.markSensitive(value)); + ``` + + The formatting happens via the standard Node.js's + [util.format](https://nodejs.org/api/util.html#utilformatformat-args) API. + +- While sending the appropriate server request, where this log line is used and should be masked, + add the custom header `X-Appium-Is-Sensitive` with its value set to `1` or `true` (case-insensitive). + Without such header the above log value is not going to be masked. + This way it is possible to conditionally mask log records depending on which + request is being handled by the extension if the log expression is used in the + common section. diff --git a/packages/appium/docs/ja/ecosystem/clients.md b/packages/appium/docs/ja/ecosystem/clients.md new file mode 100644 index 000000000..a83b5338b --- /dev/null +++ b/packages/appium/docs/ja/ecosystem/clients.md @@ -0,0 +1,44 @@ +--- +hide: + - toc +title: Appium Clients +--- + +You need a client to write and run Appium scripts. You'll want to become very +familiar with your client documentation (as well as the documentation of any Selenium client that +the Appium client depends on) since that will be your primary interface to Appium. + +To learn more about clients, read our [Client Intro](../intro/clients.md). + +### Official Clients + +These clients are currently maintained by the Appium team: + +| Client | Language | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| [Appium Java client](https://github.com/appium/java-client) | Java | +| [Appium Python client](https://github.com/appium/python-client) | Python | +| [Appium Ruby Core client](https://github.com/appium/ruby_lib_core) (Recommended)
[Appium Ruby client](https://github.com/appium/ruby_lib) | Ruby | +| [Appium .NET client](https://github.com/appium/dotnet-client) | C# | + +### Other Clients + +These clients are not maintained by the Appium team and can be used with other languages: + +| Client | Language | +| ---------------------------------------------------------------------------------------------------- | ----------------------- | +| [WebdriverIO](https://webdriver.io/docs/appium) | Node.js | +| [Nightwatch.js](https://nightwatchjs.org/guide/mobile-app-testing/introduction.html) | Node.js | +| [RobotFramework](https://github.com/serhatbolsu/robotframework-appiumlibrary) | DSL | +| [multicatch's appium-client](https://github.com/multicatch/appium-client) | Rust | +| [SwiftAppium](https://github.com/milcgroup/swiftappium) | Swift | + +In general, any W3C WebDriver spec-compatible client will also integrate well with Appium, though +some Appium-specific commands may not be implemented in other clients. + +!!! note + +``` +If you maintain an Appium client that you would like to be listed in the Appium docs, feel free +to make a PR to add it to this section with a link to the documentation for the client. +``` diff --git a/packages/appium/docs/ja/ecosystem/drivers.md b/packages/appium/docs/ja/ecosystem/drivers.md new file mode 100644 index 000000000..11282e29f --- /dev/null +++ b/packages/appium/docs/ja/ecosystem/drivers.md @@ -0,0 +1,54 @@ +--- +hide: + - toc +title: Appium Drivers +--- + +You can't use Appium without at least one driver! Click on the link for each driver to see the +specific installation instructions and documentation for that driver. + +Generally, drivers can be installed using their listed installation key, with the following command: + +``` +appium driver install +``` + +To learn more about drivers, check out the [Driver Intro](../intro/drivers.md). + +### Official Drivers + +These drivers are currently maintained by the Appium team: + +| Driver | Installation Key | Platform(s) | Mode(s) | +| -------------------------------------------------------------------- | ---------------- | ------------------------------ | -------------------------- | +| [Chromium](https://github.com/appium/appium-chromium-driver) | `chromium` | macOS, Windows, Linux | Web | +| [Espresso](https://github.com/appium/appium-espresso-driver) | `espresso` | Android | Native | +| [Gecko](https://github.com/appium/appium-geckodriver) | `gecko` | macOS, Windows, Linux, Android | Web | +| [Mac2](https://github.com/appium/appium-mac2-driver) | `mac2` | macOS | Native | +| [Safari](https://github.com/appium/appium-safari-driver) | `safari` | macOS, iOS | Web | +| [UiAutomator2](https://github.com/appium/appium-uiautomator2-driver) | `uiautomator2` | Android | Native, Hybrid, Web | +| [Windows](https://github.com/appium/appium-windows-driver) | `windows` | Windows | Native | +| [XCUITest](https://github.com/appium/appium-xcuitest-driver) | `xcuitest` | iOS | Native, Hybrid, Web | + +### Other Drivers + +These drivers are not maintained by the Appium team and can be used to target additional platforms: + +| Driver | Installation Key | Platform(s) | Mode(s) | Supported By | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------------------- | -------------------------- | ------------------------------------- | +| [Flutter](https://github.com/appium/appium-flutter-driver) | `--source=npm appium-flutter-driver` | iOS, Android | Native | Community | +| [Flutter Integration](https://github.com/AppiumTestDistribution/appium-flutter-integration-driver) | `--source=npm appium-flutter-integration-driver` | iOS, Android | Native | Community / `@AppiumTestDistribution` | +| [LG WebOS](https://github.com/headspinio/appium-lg-webos-driver) | `--source=npm appium-lg-webos-driver` | LG TV | Web | HeadSpin | +| [Linux](https://github.com/fantonglang/appium-linux-driver) | `--source=npm @stdspa/appium-linux-driver` | Linux | Native | `@fantonglang` | +| [Roku](https://github.com/headspinio/appium-roku-driver) | `--source=npm @headspinio/appium-roku-driver` | Roku | Native | HeadSpin | +| [Tizen](https://github.com/Samsung/appium-tizen-driver) | `--source=npm appium-tizen-driver` | Android | Native | Community / Samsung | +| [TizenTV](https://github.com/headspinio/appium-tizen-tv-driver) | `--source=npm appium-tizen-tv-driver` | Samsung TV | Web | HeadSpin | +| [Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver) | `--source=npm appium-youiengine-driver` | iOS, Android, macOS, Linux, tvOS | Native | Community / You.i | +| [NovaWindows](https://github.com/AutomateThePlanet/appium-novawindows-driver) | `--source=npm appium-novawindows-driver` | Windows | Native | Community / Automate The Planet | + +!!! note + +``` +If you maintain an Appium driver that you would like to be listed in the Appium docs, feel free +to make a PR to add it to this section with a link to the driver documentation. +``` diff --git a/packages/appium/docs/ja/ecosystem/index.md b/packages/appium/docs/ja/ecosystem/index.md new file mode 100644 index 000000000..72e71c860 --- /dev/null +++ b/packages/appium/docs/ja/ecosystem/index.md @@ -0,0 +1,44 @@ +--- +hide: + - toc +title: Ecosystem Overview +--- + +Appium has a wide ecosystem of related software and tools. This section of the Appium documentation +aims to compile a listing of various officially-supported and community-supported Appium projects: + +
+ +- :material-car: **Drivers** + + --- + + Link Appium to your test device + + [:octicons-arrow-right-24: View all drivers](./drivers.md) + +- :octicons-code-16: **Clients** + + --- + + Link Appium to your automation code + + [:octicons-arrow-right-24: View all clients](./clients.md) + +- :fontawesome-solid-plug: **Plugins** + + --- + + Modify and extend Appium functionality + + [:octicons-arrow-right-24: View all plugins](./plugins.md) + +- :material-wrench: **Tools** + + --- + + Interact with Appium in other ways + + [:octicons-arrow-right-24: View all tools](./tools.md) + +
\ No newline at end of file diff --git a/packages/appium/docs/ja/ecosystem/plugins.md b/packages/appium/docs/ja/ecosystem/plugins.md new file mode 100644 index 000000000..5d0d640aa --- /dev/null +++ b/packages/appium/docs/ja/ecosystem/plugins.md @@ -0,0 +1,48 @@ +--- +hide: + - toc +title: Appium Plugins +--- + +Plugins offer various ways to extend or modify Appium's behaviour. They are _completely optional_ +and are not needed for standard automation functionality, but you may find them to be useful +for more specialised automation workflows. + +Generally, plugins can be installed using their listed installation key, with the following command: + +``` +appium plugin install +``` + +### Official Plugins + +These plugins are are currently maintained by the Appium team: + +|
Plugin
|
Installation Key
| Description | +| --------------------------------------------------------------------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| [Execute Driver](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin) | `execute-driver` | Run entire batches of commands in a single call to the Appium server | +| [Images](https://github.com/appium/appium/tree/master/packages/images-plugin) | `images` | Image matching and comparison features | +| [Relaxed Caps](https://github.com/appium/appium/tree/master/packages/relaxed-caps-plugin) | `relaxed-caps` | Relax Appium's requirement for vendor prefixes on capabilities | +| [Storage](https://github.com/appium/appium/tree/master/packages/storage-plugin) | `storage` | Server-side storage with client-side management | +| [Universal XML](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin) | `universal-xml` | Instead of the standard XML format for iOS and Android, use an XML definition that is the same across both platforms | + +### Other Plugins + +These plugins are not maintained by the Appium team and can provide additional functionality: + +|
Plugin
|
Installation Key
| Description |
Supported By
| +| ---------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------ | +| [AltUnity](https://github.com/headspinio/appium-altunity-plugin) | `--source=npm appium-altunity-plugin` | Target Unity games and apps for automation with a new context, via the AltUnityTester framework | HeadSpin | +| [Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm) | `--source=npm appium-device-farm` | Manage and create driver sessions on connected Android devices and iOS simulators | `@AppiumTestDistribution` | +| [Gestures](https://github.com/AppiumTestDistribution/appium-gestures-plugin) | `--source=npm appium-gestures-plugin` | Perform basic gestures using W3C Actions | `@AppiumTestDistribution` | +| [Interceptor](https://github.com/AppiumTestDistribution/appium-interceptor-plugin) | `--source=npm appium-interceptor` | Intercept and mock API requests and responses | `@AppiumTestDistribution` | +| [OCR](https://github.com/jlipps/appium-ocr-plugin) | `--source=npm appium-ocr-plugin` | Find elements via OCR text | `@jlipps` | +| [Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin) | `--source=npm appium-reporter-plugin` | Generate standalone consolidated HTML reports with screenshots | `@AppiumTestDistribution` | +| [Wait](https://github.com/AppiumTestDistribution/appium-wait-plugin) | `--source=npm appium-wait-plugin` | Manage global element wait timeouts | `@AppiumTestDistribution` | + +!!! note + +``` +If you maintain an Appium plugin that you would like to be listed in the Appium docs, feel free +to make a PR to add it to this section with a link to the documentation for the plugin. +``` diff --git a/packages/appium/docs/ja/ecosystem/tools.md b/packages/appium/docs/ja/ecosystem/tools.md new file mode 100644 index 000000000..f2fae2e18 --- /dev/null +++ b/packages/appium/docs/ja/ecosystem/tools.md @@ -0,0 +1,41 @@ +--- +hide: + - toc +title: Appium-Related Tools +--- + +There are several Appium tools that have been created to to assist with things not directly related +to testing, such as Appium installation, test development, and more. + +### [Appium Inspector](https://appium.github.io/appium-inspector/latest/) + +Appium has a graphical client which can be used to inspect application screenshots, view the +application hierarchy, run Appium commands, record app interactions, and more. It is very useful +for Appium test development. + +Find downloads and more information on its GitHub page: [Appium Inspector](https://github.com/appium/appium-inspector) + +### Appium Doctor + +Appium Doctor is a command-line tool built into Appium drivers and plugins. +The command is expected to be used to validate whether a driver or plugin has all of its prerequisites and other environment details set up correctly +if the driver/plugin author implemented the `doctor` command. + +For example, `uiautomator2` driver provides the `doctor` command below. + +``` +appium driver doctor uiautomator2 +``` + +It shows no result if the driver/plugin author did not implement them. + +More information on this command can be found in the [Command-Line Usage documentation](../cli/extensions.md#doctor). +For driver/plugin developers, please read [Building Doctor Checks](../developing/build-doctor-checks.md). + +### Other Tools + +These tools are not maintained by the Appium team and can be used to assist with other problems: + +| Name | Description | Supported By | +| ------------------------------------------------------------------------------ | ----------------------------------------------------- | ------------------------- | +| [appium-installer](https://github.com/AppiumTestDistribution/appium-installer) | Help set up an Appium environment for Android and iOS | `@AppiumTestDistribution` | diff --git a/packages/appium/docs/ja/guides/branch-testing.md b/packages/appium/docs/ja/guides/branch-testing.md new file mode 100644 index 000000000..062463202 --- /dev/null +++ b/packages/appium/docs/ja/guides/branch-testing.md @@ -0,0 +1,57 @@ +--- +title: Local Validation Of Extension PRs +--- + +Sometimes it might be necessary to validate if a remote driver or a plugin PR works for the particular local +environment before it is merged or published. This tutorial describes how to achieve that. + +## Requirements + +- Recent LTS version of NodeJS. Check [Node.js main page](https://nodejs.org) for the download link. +- Recent version of the Appium server. Use the following commands to ensure you have + the latest version installed: `npm uninstall appium` and `npm install -g appium`. +- [Git](https://git-scm.com/) should be available locally. + +## Installation + +- [Check out](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally) the PR locally. + There is also an option (although it is less flexible, because you won't be able to easily fetch + any changes to this PR later) to simply [download](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives) and unzip the sources + locally. If you choose the later option then no `git` tool would be necessary. +- Navigate to the local driver or plugin folder and run `npm i` from that folder. +- Make sure you don't have the given driver or plugin already installed. Use the `appium driver uninstall ` + or `appium plugin uninstall ` CLI in order to delete any leftovers. The value of + ``/`` depends on the actual driver or plugin name the PR has been prepared for. + If you are not sure which name you need to use then check the content of the `package.json` manifest, + which must be always located under the root folder of the fetched sources. You should be looking for + the `"appium" -> "driverName"` entry value there. +- Change the current folder to the one, which is NOT the driver/plugin folder root or its subfolder. + Also, make sure your current working folder does not contain any extra `package.json` file. If + it does then simply navigate to any other folder that does not. +- Run the following command in order to link the driver/plugin sources to the Appium server: + `appium driver install --source=local ` or + `appium plugin install --source=local `. +- Stop the Appium server if it is running and start it again (`appium server --use-drivers=`) + to check the list of loaded drivers. If the linking succeeded then you must see the driver name and the path to its + parent folder in the server logs. In case of a plugin it is required to explicitly request + this plugin to be loaded upon server startup: `appium server --use-plugins=`. + +## Update + +After you have tested the PR and there are issues it might be necessary to update the local branch with +the recent changes from Git. Follow the next steps for that: + +- Navigate to the parent folder of your local driver/plugin and run `git pull`. +- Stop Appium server if it is running. +- Run `npm i` in the parent folder of your local driver/plugin to rebuild it and update any dependencies if necessary. +- Start Appium server again similarly to how this is done in the corresponding [Installation](#installation) step above. + +## Switching Back To a Stable Release + +After the PR is merged there is no need to use the local plugin/driver deployment anymore, and it makes sense +to switch back to the package managed by NPM. Follow the next steps for that: + +- Unlink the installed driver/plugin from the server by running `appium driver uninstall ` or + `appium plugin uninstall `. +- Delete the local source folder (`rm -rf `). +- Install the driver or the plugin from NPM. Check the component README in order to find a proper command for that. diff --git a/packages/appium/docs/ja/guides/caching.md b/packages/appium/docs/ja/guides/caching.md new file mode 100644 index 000000000..7297e3e6d --- /dev/null +++ b/packages/appium/docs/ja/guides/caching.md @@ -0,0 +1,78 @@ +--- +title: Caching of Application Bundles +--- + +Appium's base driver provides a feature which enables caching of application builds provided, for example, +as `app` capability value or to endpoints similar to the `installApp` one. This article explains common caching +principles, so you could create more performant and efficient test suite execution strategies. + +## Why Caching Is Necessary + +Mobile application bundles could reach hundreds of megabytes is size. This could become a serious +performance issue if a test suite is executed, and it is necessary to fetch/extract the same application +bundle for each test. + +## What Is Cached + +Caching could be applied to application bundles generated by +[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.js#L107) helper call. +Inherited drivers can customize their caching logic by providing own `onPostProcess` +(or both `inDownload` and `onPostProcess`) property definition, but the general +rule of thumb is that we need to cache locally all application bundles need to be downloaded and/or extracted +first before they could be actually installed on the device under test. On iOS, for example, these are `.ipa` or +`.zip` compressed application bundles, or .`aab` on Android. + +## Caching of Remote Application Bundles + +In order to validate whether an app bundle downloaded from the given URL could be (re)used from the cache the following +steps are applied: + +1. The script checks if the given URL is already present in the cache. + If yes then it tries to fetch previously remembered + [Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified) + or [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) header values for it. +2. If `ETag` value is present then it is put into + [If-None-Match request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match). + Else if `Last-Modified` header value is present then it is put into + [If-Modified-Since request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since). + Otherwise, no caching is applied. +3. If the response status is equal to `304` then the previously cached binary is used, + otherwise the cached entry is reset and refreshed. + +## Caching of Local Application Bundles + +It only makes sense to cache application bundles if they need some preprocessing before being installed on the device under test. +For example, on iOS `.ipa` bundles must be unzipped, because the system installer only works with `.app` folders. + +1. The script verifies if the given bundle path is already present in the cache. If the bundle was not in the cache yet + then it gets preprocessed and added there. +2. The script validates the hashsum of the bundle and compares it to the previously stored one. If hash sums don't match + then the cached item gets deleted and the preprocessing of the bundle repeats. + +## How The Cache File System Is Configured + +The cache where the base driver keeps all application bundles is located in the system temp folder. It is configured +on per-process basis, so each test session initialized in scope of the same Appium server process takes advantages +of it. It is a [LRU Cache](https://www.npmjs.com/package/lru-cache) with the following limitations: + +- Max items: 1024. You may customize it by providing a new value to + the [APPIUM_APPS_CACHE_MAX_ITEMS](../cli/env-vars.md) environment variable. + Do not set it to a lower number than the amount of apps in all parallel sessions per process. +- Max time to live (TTL) for each entry: 24 hours. + You may customize it by providing a new value to the + [APPIUM_APPS_CACHE_MAX_AGE](../cli/env-vars.md) environment variable. + Do not set it to a lower number than the duration of a single session startup. +- TTL is refreshed for each entry upon access +- By default the full application URL is used as cache key. You may change this behavior + by enabling the [APPIUM_APPS_CACHE_IGNORE_URL_QUERY](../cli/env-vars.md) environment variable. + If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys. + See the corresponding [feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713) + for more details. + +!!! warning + +``` +Note: The cache root folder is set up for automatic deletion on Appium process termination. This would only +work if Appium server is killed with `SIGINT` or `SIGTERM`. If `SIGKILL` is used then no cache cleanup +would be performed. +``` diff --git a/packages/appium/docs/ja/guides/caps.md b/packages/appium/docs/ja/guides/caps.md new file mode 100644 index 000000000..9f881e8c3 --- /dev/null +++ b/packages/appium/docs/ja/guides/caps.md @@ -0,0 +1,284 @@ +--- +title: Session Capabilities +--- + +"Capabilities" is the name given to the set of parameters used to start an Appium session. The +information in the set describes what sort of "capabilities" you want your session to have, for +example, a certain mobile operating system or a certain version of a device. Capabilities are +represented as key-value pairs, with values allowed to be any valid JSON type, including +other objects. + +The W3C WebDriver spec's [section on Capabilities](https://w3c.github.io/webdriver/#capabilities) +identifies a small set of 10 standard capabilities, including the following: + +| Capability Name | Type | Description | +| ---------------- | -------- | ---------------------------------------------- | +| `browserName` | `string` | The name of the browser to launch and automate | +| `browserVersion` | `string` | The specific version of the browser | +| `platformName` | `string` | The type of platform hosting the browser | + +## Common Appium Capabilities + +Appium understands these browser-focused capabilities, but introduces a number of additional +capabilities. According to the WebDriver spec, any +non-standard "extension capabilities" must include a namespace prefix (signifying the vendor +introducing the capability), ending in a `:`. Appium's vendor prefix is +`appium:`, and so any Appium-specific capabilities must include this prefix. Depending on which +client you are using, the prefix may be added automatically or in conjunction with certain +interfaces, but it is always a good practice to explicitly include it for clarity. + +Here is a list of all the globally-recognized Appium capabilities: + +!!! info + +``` +Individual drivers and plugins can support other capabilities, so refer to their documentation +for lists of specific capability names. Some drivers may also not support all of these capabilities +``` + +|
Capability
| Type | Required? | Description | +| ---------------------------------------- | --------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `platformName` | `string` | yes | The type of platform hosting the app or browser | +| `appium:automationName` | `string` | yes | The name of the Appium driver to use | +| `browserName` | `string` | no | The name of the browser to launch and automate, if the driver supports web browsers as a special case | +| `appium:app` | `string` | no | The path to an installable application | +| `appium:deviceName` | `string` | no | The name of a particular device to automate, e.g., `iPhone 14` (currently only actually useful for specifying iOS simulators, since in other situations it's typically recommended to use a specific device id via the `appium:udid` capability). | +| `appium:platformVersion` | `string` | no | The version of a platform, e.g., for iOS, `16.0` | +| `appium:newCommandTimeout` | `number` | no | The number of seconds the Appium server should wait for clients to send commands before deciding that the client has gone away and the session should shut down. `60` seconds by default. Setting it to zero disables the timer. | +| `appium:noReset` | `boolean` | no | If true, instruct an Appium driver to avoid its usual reset logic during session start and cleanup (default `false`) | +| `appium:fullReset` | `boolean` | no | If true, instruct an Appium driver to augment its usual reset logic with additional steps to ensure maximum environmental reproducibility (default `false`) | +| `appium:eventTimings` | `boolean` | no | If true, instruct an Appium driver to collect [Event Timings](./event-timing.md) (default `false`) | +| `appium:printPageSourceOnFindFailure` | `boolean` | no | If true, collect the page source and print it to the Appium log whenever a request to find an element fails (default `false`) | + +Some drivers place more complex constraints on capabilities as a group. For example, while the +`appium:app` and `browserName` capabilities are listed above as optional, if you want to launch +a session with a specific app, the XCUITest driver requires that at least one of `appium:app`, +`browserName`, or `appium:bundleId` are included in the capabilities (otherwise it will not know +what app to install and/or launch and will simply open a session on the home screen). Each driver +will document how it interprets these capabilities and any other platform-specific requirements. + +!!! note + +``` +Capabilities are like parameters used when starting a session. After the capabilities are sent +and the session is started, they cannot be changed. If a driver supports updating aspects of +its behaviour in the course of a session, it will provide a [Setting](./settings.md) for this +purpose instead of, or in addition to, a capability. +``` + +Each Appium client has its own way of constructing capabilities and starting a session. For +examples of doing this in each client library, head to the [Ecosystem](../ecosystem/index.md) page +and click through to the appropriate client documentation. + +## BiDi Protocol Support + +Appium supports [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol since base–driver 9.5.0. +The actual behavior depends on individual drivers while the Appium and the baseーdriver support the protocol. +Please make sure if a driver supports the protocol and what kind of commands/events it supports in the documentation. + +| Capability Name | Type | Description | +| --------------- | --------- | ------------------------------------------------------- | +| `webSocketUrl` | `boolean` | To enable BiDi protocol in the session. | + +## Using `appium:options` to Group Capabilities + +If you use a lot of `appium:` capabilities in your tests, it can get a little repetitive. You can +combine all capabilities as an object value of a single `appium:options` capability instead, in +which case you don't need to use prefixes on the capabilities inside the object. For example: + +```json +{ + "platformName": "iOS", + "appium:options": { + "automationName": "XCUITest", + "platformVersion": "16.0", + "app": "/path/to/your.app", + "deviceName": "iPhone 12", + "noReset": true + } +} +``` + +Note that constructing a capability value which is itself an object differs by language; refer to +your client documentation for further examples on how to achieve this. + +!!! warning + +``` +If you include the same capabilities both inside and outside of `appium:options`, the values +inside of `appium:options` take precedence. +``` + +## Always-Match and First-Match Capabilities + +The W3C spec allows clients to give the Appium server some flexibility in the kind of session it +creates in response to a new session request. This is through the concept of "always-match" and +"first-match" capabilities: + +- Always-match capabilities consist of a single set of capabilities, every member of which must + be satisfied by the server in order for the new session request to proceed. +- First-match capabilities consist of an array of capability sets. Each set is merged with the + always-match capabilities, and the first set that the server knows how to handle will be the set + that is used to start the session. + +!!! note + +``` +Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or +a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for +a more in-depth description of how capabilities are processed. +``` + +In practice, use of first-match capabilities is not necessary or recommended for use with Appium. +Instead, we recommend that you define the explicit set of capabilities you want the Appium +server to handle. These will be encoded as the always-match capabilities, and the array of +first-match capabilities will be empty. + +That being said, Appium _does_ understand always-match and first-match capabilities as +defined in the W3C spec, so if you use these features, Appium will work as expected. The process of +defining always-match and first-match capabilities is unique to each client library, so refer to +the documentation for your client library to see examples of how it works. + +## Special Notes for Cloud Providers + +!!! warning + +``` +This section is not intended for end-users of Appium; it is intended for developers building +Appium-compatible cloud services. +``` + +When managing an Appium cloud, your users may wish to target various independent versions of Appium +drivers and plugins. It is of course up to each service provider how they wish to implement the +discovery, installation, and availability of any official or third party drivers or plugins. But +the Appium team does provide several suggestions, for consistency across the industry. _These are +recommendations only,_ and not a standard, but adopting it will help users to navigate the increased +complexity that working with Appium 2 in a cloud environment may bring. + +### Suggested capabilities + +In addition to the standard `platformName`, `appium:deviceName`, `appium:automationName`, and +`appium:platformVersion`, we recommend adopting the capability `$cloud:appiumOptions`, where the +label `$cloud` is not meant to be interpreted literally but instead should be replaced by your +vendor prefix (so for HeadSpin it would be `headspin`, Sauce Labs it would be `sauce`, and +BrowserStack it would be `browserstack`, to name just a few examples). The `$cloud:appiumOptions` +capability would itself be a JSON object, with the following internal keys: + +|
Capability
| Usage | Example | +| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `version` | The version of the Appium server that is used to host and manage drivers. If omitted, the behavior is left up to the provider, but the recommendation would be to provide the latest official version. | `2.0.0` | +| `automationVersion` | The version of the driver (as specified by `appium:automationName`) that should be used. | `1.55.2` | +| `automation` | The name of a custom driver to use (see below for more info). This would override `appium:automationName` and `$cloud:automationVersion`. | `{"name": "@org/custom-driver", "source": "github", "package": "custom-driver"}` | +| `plugins` | The list of plugins (and potentially versions of plugins) that should be activated (see below for more info). | `["images", "universal-xml"]` | + +### Basic example + +Appium extensions (drivers and plugins) have a set of properties that specify where they can be +installed from. Cloud providers are obviously under no obligation to provide support for +arbitrarily specified extensions, seeing as these may represent untrusted code running in a managed +environment. In the case where arbitrary extensions are not supported, the `appium:automationName`, +`$cloud:automationVersion`, and `$cloud:appiumPlugins` capabilities should be sufficient. See the +following JSON object representing capabilities for a session: + +```json +{ + "platformName": "iOS", + "appium:platformVersion": "14.4", + "appium:deviceName": "iPhone 11", + "appium:app": "Some-App.app.zip", + "appium:automationName": "XCUITest", + "$cloud:appiumOptions": { + "version": "2.0.0", + "automationVersion": "3.52.0", + "plugins": ["images"] + } +} +``` + +This set of capabilities requests an Appium 2+ server supporting the XCUITest driver at version +`3.52.0`, and the `images` plugin active. This set is easy for a cloud provider to verify. The +cloud provider can obviously do anything it wants in response to these capabilities, including +downloading Appium and driver and plugin packages on the fly, or erroring out if the versions +requested are not in a supported set, or if the plugin is not supported, etc... + +### Basic example with `appium:options` + +The previous example still looks a bit disorganized, so of course we also recommend that cloud +providers support the `appium:options` capability as detailed above, which could turn the previous +set of capabilities into the following: + +```json +{ + "platformName": "iOS", + "appium:options": { + "platformVersion": "14.4", + "deviceName": "iPhone 11", + "app": "Some-App.app.zip", + "automationName": "XCUITest" + }, + "$cloud:appiumOptions": { + "version": "2.0.0", + "automationVersion": "3.52.0", + "plugins": ["images"] + } +} +``` + +### Extension objects + +Some service providers may wish to dynamically allow access to all of the features of the Appium +2 CLI, including downloading arbitrary drivers and plugins. To represent these extensions, we can +define special JSON "extension objects", with the following keys: + +- `name`: the name of the extension. This would be an `npm` package name (if downloading from `npm`), + or a `git` or GitHub spec (if downloading from a `git` server or GitHub). +- `version`: the version of the extension, e.g., the `npm` package version or `git` SHA. +- (optional) `source`: a denotation of where the extension can be downloaded from. It is recommended + to support the following values: `appium`, `npm`, `git`, `github`. Here, `appium` means "Appium's + own official list", and should be the default value if this key is not included. +- (optional) `package`: when downloading extensions from `git` or GitHub, the `npm` package name of + the extension must also be provided. This is optional for non-`git` sources. + +Since each session is handled by a single driver, the `$cloud:appiumOptions`/`$automation` +capability could be used with an extension object value to denote this driver, for example: + +```json +{ + "$cloud:appiumOptions": { + "automation": { + "name": "git+https://some-git-host.com/custom-driver-project.git", + "version": "some-git-sha", + "source": "git", + "package": "driver-npm-package-name" + } + } +} +``` + +And since sessions can handle multiple plugins, each value in the list of `$cloud:appiumPlugins` +could also be an extension object rather than a string, so that specific versions could be +requested: + +```json +{ + "$cloud:appiumOptions": { + "plugins": [{ + "name": "images", + "version": "1.1.0" + }, { + "name": "my-github-org/my-custom-plugin", + "version": "a83f2e", + "source": "github", + "package": "custom-plugin" + }] + } +} +``` + +These serve as illustrative examples for the recommendations here. Of course, it is up to the +service providers to implement the handling of these capabilities at their front end / load +balancer, to perform any error checking, or to actually run any of the `appium driver` or `appium +plugin` CLI commands that support the end user's request. This section is merely a suggestion as to +how service providers might design their user-facing capabilities API in a way which in principle +supports all of the capabilities that Appium itself would provide to the end user if they were +running Appium on their own. diff --git a/packages/appium/docs/ja/guides/config.md b/packages/appium/docs/ja/guides/config.md new file mode 100644 index 000000000..91535b239 --- /dev/null +++ b/packages/appium/docs/ja/guides/config.md @@ -0,0 +1,102 @@ +--- +title: The Appium Config File +--- + +Instead of passing arguments on the command line to Appium, you may add them to a special config +file. Appium will read values from this config file when it runs. (Please note that CLI arguments +have _precedence_ over configuration files; if a value is set in a config file _and_ via CLI +argument, the CLI argument is preferred.) + +## Supported Config File Formats + +You can store your config data in the following kinds of files: + +- JSON +- YAML +- JS (a JavaScript file exporting a JS object) +- CJS (the same as above; the extension is for common JS) + +!!! warning + +``` +Note: Configuration files in ESM format are not currently supported. +``` + +## Supported Config File Locations + +Configuration files can be named anything, but the following filenames will be automatically +discovered and loaded by Appium: + +- `.appiumrc.json` (recommended) +- `.appiumrc.yaml` +- `.appiumrc.yml` +- `.appiumrc.js` +- `.appiumrc.cjs` +- `appium.config.js` +- `appium.config.cjs` +- `.appiumrc` (which is considered to be JSON) + +Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium` +property in your `package.json` and it will be automatically discovered. + +### Config File Search + +Appium will search _up_ the directory tree from the current working directory for one of these +files. If it reaches the current user's home directory or filesystem root, it will stop looking. + +To specify a _custom_ location for your config file, use `appium --config /path/to/config/file`. + +#### Configuration File Format + +First, you might want to look at some examples: + +- [Appium Configuration - JSON](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.json) +- [Appium Configuration - YAML](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.yaml) +- [Appium Configuration - JS](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.js) + +A description of the format is available, as well: + +- [Appium Configuration File JSON Schema](https://github.com/appium/appium/blob/master/packages/schema/lib/appium-config.schema.json) +- [TypeScript declarations for Appium Configuration](https://github.com/appium/appium/blob/master/packages/types/lib/config.ts) + +To describe in words, the config file will have a root `server` property, and all arguments are +child properties. For certain properties which must be supplied on the command-line as +comma-delimited lists, JSON strings, and/or external filepaths, these instead will be of their +"native" type. For example, `--use-plugins ` needs `` to be comma-delimited string +or path to a delimited file. However, the config file just wants an array, e.g.,: + +```json +{ + "server": { + "use-plugins": ["my-plugin", "some-other-plugin"] + } +} +``` + +## Configuring extensions (drivers and plugins) + +For `driver`-and-`plugin`-specific configuration, these live under the `server.driver` and +`server.plugin` properties, respectively. Each driver or plugin will have its own named property, +and the values of any specific configuration it provides are under this. For example: + +```json +{ + "server": { + "driver": { + "xcuitest": { + "webkit-debug-proxy-port": 5400 + } + } + } +} +``` + +!!! note + +``` +The above configuration corresponds to the `--driver-xcuitest-webkit-debug-proxy-port` CLI argument. +``` + +All properties are case-sensitive and will be in +[kebab-case](https://en.wikipedia.org/wiki/Naming_convention_\(programming\)#Delimiter-separated_words). +For example, `callback-port` is allowed, but `callbackPort` is not. diff --git a/packages/appium/docs/ja/guides/context.md b/packages/appium/docs/ja/guides/context.md new file mode 100644 index 000000000..8e79e621a --- /dev/null +++ b/packages/appium/docs/ja/guides/context.md @@ -0,0 +1,43 @@ +--- +hide: + - toc +title: Managing Contexts +--- + +A common feature of many app platforms is the ability for developers to embed web content inside of +the platform-native app frame. This allows developers to leverage web technologies or existing web +content for some or all of the app functionality. However, the additional complexity of mixing +"modes" within a single application can make it difficult for automation tools that are designed to +target the "native" elements and behaviours. + +Appium provides a set of APIs for working with different app modes, called "contexts", that Appium +drivers can implement if they support automation commands in these different modes. There are three +basic commands that Appium has added to the W3C WebDriver spec for this purpose: + +| Command Name | Method/Route | Params | Description | Returns | +| --------------------- | --------------------------- | ------------------------------------ | --------------------------------------------- | --------------- | +| `Get Contexts` | `GET /session/:id/contexts` | | Get a list of the available contexts | `array` | +| `Get Current Context` | `GET /session/:id/context` | | Get the name of the active context | `string` | +| `Set Context` | `POST /session/:id/context` | `name` (`string`) | Switch into the context with the given `name` | `null` | + +This API is flexible enough to handle a variety of semantic interpretations on the part of the +driver. For example, the XCUITest driver includes two kinds of contexts: the native app context and +any active webviews, as one context per webview. A call to `Get Contexts` will return the list of +names, which you as a test author can sift through and use to switch into the appropriate context. +As another example, the Appium Altunity +Plugin introduces the concept of a `UNITY` +context, which encapsulates all the plugin's specific behaviour to ensure that when outside of the +`UNITY` context, the active driver's usual command implementations are used. + +It is important to note that a call to `Get Contexts` will always contain at least one context, +conventionally but not necessarily named `NATIVE_APP`. This is the default active context. + +Depending on the type of context you're in, the operation of the driver might change. The XCUITest +driver, when targeting a webview context, will not run its typical routines for finding and +interacting with elements. Instead, it will run a different set of routines appropriate to web +elements. This might have a variety of consequences, like supporting a different set of locator +strategies. + +The command names in the table above are generic references to the commands and not code examples. +For examples of how to access the Context API in the language-specific client libraries, please +visit the documentation for a given library. diff --git a/packages/appium/docs/ja/guides/event-timing.md b/packages/appium/docs/ja/guides/event-timing.md new file mode 100644 index 000000000..5c678cb99 --- /dev/null +++ b/packages/appium/docs/ja/guides/event-timing.md @@ -0,0 +1,81 @@ +--- +hide: + - toc +title: Retrieving Event Timings +--- + +Appium comes with the ability to retrieve timing information about startup +information and command length. This is an advanced feature that is controlled +by the use of the `appium:eventTimings` capability (set it to `true` to log event +timings). + +With this capability turned on, the `POST /session/:id/appium/events` response (i.e., +the response to `driver.logs.events` or similar, depending on client) will be +decorated with an `events` property. This is the structure of that `events` +property: + +``` +{ + "": [, ...], + "commands": [ + { + "cmd": "", + "startTime": , + "endTime": + }, + ... + ] +} +``` + +In other words, the `events` property has 2 kinds of properties of its own: + +- Properties which are the names of event types +- The `commands` property + +Properties which are names of event types correspond to an array of timestamps +when that event happened. It's an array because events might happen multiple +times in the course of a session. Examples of event types include: + +- `newSessionRequested` +- `newSessionStarted` + +(Individual drivers will define their own event types, so we do not have an +exhaustive list to share here. It's best to actually get one of these responses +from a real session to inspect the possible event types.) + +The `commands` property is an array of objects. Each object has the name of the +Appium-internal command (for example `click`), as well as the time the command +started processing and the time it finished processing. + +With this data, you can calculate the time between events, or a strict timeline +of events, or statistical information about average length of a certain type of +command, and so on. + +You can only receive data about events that have happened when you make the +call to `/session/:id/appium/events`, so the best time to get data about an entire session is +right before quitting it. + +The Appium team maintains an event timings parser tool that can be used to +generate various kinds of reports from event timings output: +[appium/appium-event-parser](https://github.com/appium/appium-event-parser). + +!!! note + +``` +In the past, events were available as a part of `GET /session/:id` response +``` + +## Add a custom event + +!!! warning "TODO" + +``` +The links to the commands in the following paragraph do not yet work since these docs are under +construction. +``` + +You can add custom events that will show up in the event timings data. You can send a custom event +name to the Appium server using the [Log Event API](#TODO), and the server will store the +timestamp. The [Get Events](#TODO) command can be used to retrieve named events' timestamps later +on. diff --git a/packages/appium/docs/ja/guides/execute-methods.md b/packages/appium/docs/ja/guides/execute-methods.md new file mode 100644 index 000000000..8692b2cee --- /dev/null +++ b/packages/appium/docs/ja/guides/execute-methods.md @@ -0,0 +1,141 @@ +--- +hide: + - toc +title: Execute Methods +--- + +Because the scope of commands implemented in Appium drivers is broader than the scope of commands +defined by the W3C WebDriver spec, Appium needs a way for these "extended" commands to be accessible +by client libraries. There are two main strategies for this: + +1. Appium drivers define new W3C-compatible API routes, and Appium clients are updated to include + support for those new routes. +2. Appium drivers define so-called "Execute Methods" which provide new functionality by + overloading the existing `Execute Script` command which is already available in any WebDriver- + based client library (including all Selenium and Appium clients). + +There are pros and cons for each strategy, but it is ultimately up to the extension author to +decide how they wish implement new commands. + +This guide is designed to specifically help you understand the "Execute Method" strategy. This +pattern is commonly used in official Appium drivers and other third-party extensions. +Here's an example of how the `Execute Script` command is designed to work in the world of WebDriver +and browser automation: + +\=== "JS (WebDriverIO)" + +```` +```js +await driver.executeScript('return arguments[0] + arguments[1]', [3, 4]) +``` +```` + +\=== "Java" + +```` +```java +JavascriptExecutor jsDriver = (JavascriptExecutor) driver; +jsDriver.executeScript("return arguments[0] + arguments[1]", 3, 4); +``` +```` + +\=== "Python" + +```` +```py +driver.execute_script('return arguments[0] + arguments[1]', 3, 4) +``` +```` + +\=== "Ruby" + +```` +```rb +driver.execute_script 'return arguments[0] + arguments[1]', 3, 4 +``` +```` + +\=== "C#" + +```` +```dotnet +((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0] + arguments[1]", 3, 4); +``` +```` + +What's happening here is that we are defining a snippet of Javascript (technically, +a function body) to be executed within the web browser. The client can send arguments which are +serialized, sent over HTTP, and finally provided to the function as parameters. In this example, +we are essentially defining an addition function. The return value of the `Execute Script` command +is whatever the return value of the Javascript snippet is! In the case of this example, that value +would be the number `7` (`3` + `4`). + +Each client library has its own way of calling the command and providing any arguments to the script +function, but the function itself—the snippet—is always a string and is the same across all languages. + +In the world of Appium, we are usually not automating a web browser, which means this command is +not particularly useful. But it _is_ useful as a way to encode the name of an arbitrary command and +to provide parameters. For example, the XCUITest +Driver has implemented a command that lets a client +terminate a running application if you know the ID (the `bundleId`) of the app. The way that the +driver makes this command available is via the Execute Method `mobile: terminateApp`. Instead of +providing a JavaScript function to the "Execute Script" command, the user provides a _known string_ +as defined by the driver. The only other thing a client needs to know is the set of +parameters for the method, which are documented by the driver. In this case, we have a parameter +named `bundleId`, whose value should be a string encoding the ID of the app to terminate. Here is +how this Execute Method would be called: + +\=== "JS (WebDriverIO)" + +```` +```js +await driver.executeScript('mobile: terminateApp', [{bundleId: 'com.my.app'}]) +``` +```` + +\=== "Java" + +```` +```java +JavascriptExecutor jsDriver = (JavascriptExecutor) driver; +jsDriver.executeScript("mobile: terminateApp", ImmutableMap.of("bundleId", "com.my.app")); +``` +```` + +\=== "Python" + +```` +```py +driver.execute_script('mobile: terminateApp', {'bundleId': 'com.my.app'}) +``` +```` + +\=== "Ruby" + +```` +```rb +driver.execute_script 'mobile: terminateApp', { bundleId: 'com.my.app' } +``` +```` + +\=== "C#" + +```` +```dotnet +((IJavaScriptExecutor)driver).ExecuteScript("mobile: terminateApp", + new Dictionary { { "bundleId", "com.my.app" } }); + +``` +```` + +There are two important differences in using Appium Execute Methods from vanilla Selenium +Javascript execution: + +1. The script string is just a command name; it will be provided by the driver documentation +2. The standard way to provide parameters is as a _single_ object with keys representing parameter + names and values representing parameter values. So in this case, we had to specify both the + parameter name (`bundleId`) as the key of the parameters object, and the parameter value + (`com.my.app`) as the value for that key. A driver can define parameters as _required_ or _optional_. + +Of course, always refer to the documentation for the particular Execute Method in case the author +has made any alterations to the standard access method. diff --git a/packages/appium/docs/ja/guides/grid.md b/packages/appium/docs/ja/guides/grid.md new file mode 100644 index 000000000..3133bc775 --- /dev/null +++ b/packages/appium/docs/ja/guides/grid.md @@ -0,0 +1,166 @@ +--- +title: Appium and Selenium Grid +--- + +## Using Selenium Grid 4+ + +The +[relay](https://www.selenium.dev/documentation/grid/configuration/toml_options/#relaying-commands-to-a-service-endpoint-that-supports-webdriver) +feature in Grid 4 allows you to proxy Appium requests to an Appium server instance. Here is +an example walkthrough of how you would connect two different Appium instances to a Selenium Grid. + +### Define the Appium configs + +Each Appium instance should have a config file that can be easily updated. It should contain any +information which needs to be unique to that particular server (e.g., ports its drivers should use +that others should not). We are going to have 2 Appium servers, so we will need 2 config files: + +```yaml +# appium1.yml +server: + port: 4723 + use-drivers: + - xcuitest + default-capabilities: + wdaLocalPort: 8100 + mjpegServerPort: 9100 + mjpegScreenshotUrl: "http://localhost:9100" +``` + +In the above YAML config file, we specify the Appium server port, the driver used, and parameters +for the driver that will be sent in as default capabilities. Our goal is to ensure that any other +drivers running on this host will not compete with system ports or other resources. The second +config file could look like the following, where we simply adjust a few ports to prevent clashes: + +```yaml +# appium2.yml +server: + port: 4733 + use-drivers: + - xcuitest + default-capabilities: + wdaLocalPort: 8110 + mjpegServerPort: 9110 + mjpegScreenshotUrl: "http://localhost:9110" +``` + +### Define the Grid node configs + +We will be launching one Grid "node" per Appium server, to manage relaying commands and determining +capacity and online status, etc... So we should have one config file per Grid node as well. Each +node config should include the address of the Appium server it will target, as well as a list of +capability "configs" it should accept to relay a session request to Appium. Here is what the config +could look like for the two nodes: + +```toml +# node1.toml +[server] +port = 5555 + +[node] +detect-drivers = false + +[relay] +url = "http://localhost:4723" +status-endpoint = "/status" +configs = [ + "1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 13\", \"appium:automationName\": \"XCUITest\"}" +] +``` + +```toml +# node2.toml +[server] +port = 5565 + +[node] +detect-drivers = false + +[relay] +url = "http://localhost:4733" +status-endpoint = "/status" +configs = [ + "1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 12\", \"appium:automationName\": \"XCUITest\"}" +] +``` + +Note that each node config also specifies a different port itself for the node to run on. + +### Putting it together + +The Grid nodes aren't enough--you'll also want a Grid "hub" that acts as a load balancer and +manager for all the nodes. So in the end we'll have 5 processes running at once: 2 Appium servers, +2 Grid nodes, and 1 Grid hub. It's best to run each of these in a separate terminal window to avoid +confusion of logs. Here is how you'd start each process: + +0. `appium --config appium1.yml` +1. `appium --config appium2.yml` +2. `java -jar /path/to/selenium.jar node --config node1.toml` +3. `java -jar /path/to/selenium.jar node --config node2.toml` +4. `java -jar /path/to/selenium.jar hub` + +Once you wait a few moments for the nodes to detect their Appium servers, and to register with the +hub, you'll be able to send all your Appium traffic via the single hub endpoint (defaulting to +`http://localhost:4444`). + +And of course, you're able to link up Appium servers and nodes running on different machines in +your network to form a larger grid. + +## Using Selenium Grid 3 + +It is possible to register your Appium server with a local [Selenium Grid 3](https://www.selenium.dev/documentation/legacy/selenium_3/grid_3/) +([setup docs](https://www.selenium.dev/documentation/legacy/grid_3/setting_up_your_own_grid/)) instance by using the +`--nodeconfig` server argument. + +```bash +appium server --nodeconfig /path/to/nodeconfig.json --base-path=/wd/hub +``` + +In the referenced config file you have to define the `browserName`, `version` and `platform` +capabilities and based on these parameters the grid will re-direct your test to the right device. +You will also need to configure your host details and the Selenium Grid details. For a full list of +all parameters and descriptions see +[here](https://www.selenium.dev/documentation/legacy/selenium_3/grid_setup/). + +Once you start the Appium server it will register with the grid, and you will see your device on +the grid console page: + +`http://**\**:**\**/grid/console` + +### Example Grid Node Configuration JSON + +```json +{ + "capabilities": + [ + { + "browserName": "", + "version":"", + "maxInstances": 1, + "platform":"" + } + ], + "configuration": + { + "cleanUpCycle":2000, + "timeout":30000, + "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy", + "url":"http://:/wd/hub", + "host": "", + "port": , + "maxSession": 1, + "register": true, + "registerCycle": 5000, + "hubPort": , + "hubHost": "", + "hubProtocol": "" + } +} +``` + +If `url`, `host`, and `port` are not given, the config will be auto updated to point to +`localhost:`. + +If your Appium server is running on a different machine to your Selenium Grid server, make sure you +use an external name/IP address in your `host` and `url` configuration; `localhost` and `127.0.0.1` +will prevent Selenium Grid from connecting correctly. diff --git a/packages/appium/docs/ja/guides/headers.md b/packages/appium/docs/ja/guides/headers.md new file mode 100644 index 000000000..4c09392c8 --- /dev/null +++ b/packages/appium/docs/ja/guides/headers.md @@ -0,0 +1,17 @@ +--- +title: Header Handling +--- + +# Header Handling + +## Request ID Tracking + +Appium supports setting the request ID for each request through the `x-request-id` header. This is useful for tracing requests through your system, especially in environments where multiple services are involved or when debugging across different requests. + +### Using `x-request-id` + +When making requests to Appium, you can include an `x-request-id` header with a unique identifier. This ID will be: + +- Used to track the request through Appium's logging system +- Preserved across the entire request lifecycle +- Generated automatically (as a UUID) if not provided diff --git a/packages/appium/docs/ja/guides/log-filters.md b/packages/appium/docs/ja/guides/log-filters.md new file mode 100644 index 000000000..54fb7aa2b --- /dev/null +++ b/packages/appium/docs/ja/guides/log-filters.md @@ -0,0 +1,86 @@ +--- +title: Filtering the Appium Log +--- + +Sometimes it might be necessary to hide sensitive information, like passwords, device identifiers, +hashes, etc..., from the server log. Appium makes it possible to ensure such information is +redacted in logs via the `--log-filters` command line argument. This argument allows you to provide +the path to a special config file, containing one or more log obfuscation rules. + +## Config Format + +The filtering config must be one of: + +- a path to a valid JSON file containing an array of filtering rules +- a `log-filters` entry in an [Appium Config](./config.md) file, with the rules array inline + +Each rule is an object with a set of predefined properties. The following rule properties are +supported: + +- `pattern`: A valid Javascript RegExp pattern to replace. Must be a valid non-empty pattern. +- `text`: A simple non-empty exact text match to replace. Either this property or the above one must + be provided. `pattern` has priority over `text` if both are provided. +- `flags`: Regular expression flags for the given pattern. Supported flags are the same as for the + standard JavaScript [RegExp constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2). + Note that the `g` (global matching) flag is always enabled. +- `replacer`: The replacer value to use. By default it is `**SECURE**`. Empty values are allowed. + +### Config Examples + +Replace all occurrences of `my.magic.app` string with the default replacer: + +```json +[ + { + "text": "my.magic.app" + } +] +``` + +Replace all occurrences of `my.magic.` string with a custom replacer (case insensitive): + +```json +[ + { + "pattern": "my\\.magic\\.\\w", + "flags": "i", + "replacer": "***" + } +] +``` + +Replace all occurrences of `my.magic.` and/or `your.magic` strings with a custom +replacer (case insensitive): + +```json +[ + { + "pattern": "my\\.magic\\.\\w+", + "flags": "i", + "replacer": "***" + }, + { + "pattern": "your\\.magic", + "flags": "i", + "replacer": "***" + } +] +``` + +Truncate all log lines to max 15 chars (advanced): + +```json +[ + { + "pattern": "(.{1,15}).*", + "flags": "s", + "replacer": "$1" + } +] +``` + +### Config Errors Handling + +If any of the config rules contains invalid items (such as empty/invalid pattern, empty rule, etc.) +then Appium will print the detailed report about collected errors and will fail to start until +these errors are addressed. diff --git a/packages/appium/docs/ja/guides/managing-exts.md b/packages/appium/docs/ja/guides/managing-exts.md new file mode 100644 index 000000000..2f14d85e5 --- /dev/null +++ b/packages/appium/docs/ja/guides/managing-exts.md @@ -0,0 +1,89 @@ +--- +title: Managing Drivers and Plugins +--- + +To do anything useful with Appium, you need to have at least one [Driver](../intro/drivers.md) +installed, otherwise Appium won't know how to automate anything. There is an entire +[Ecosystem](../ecosystem/index.md) of drivers and plugins out there! + +This guide helps explain how to manage these drivers and plugins. There are +two basic strategies: using Appium's extension CLI interface, or managing extensions yourself in an +`npm`-based project. + +!!! note + +``` +Other package managers are not currently supported. +``` + +## Using Appium's Extension CLI + +With Appium's [Extension CLI](../cli/extensions.md), you let Appium manage drivers and plugins for +you. You will use CLI commands to tell Appium which extensions you would like to install, update, +or remove. Here's an example of how you might install a driver using the CLI: + +```bash +appium driver install xcuitest +``` + +This command will install the latest version of the +[XCUITest Driver](https://github.com/appium/appium-xcuitest-driver). The Extension CLI comes with a variety +of commands and parameters; see the documentation for that command for all the specifics. + +The all-important question when Appium is managing your extensions for you is: where are they installed? +Appium manages extensions in a directory specified by the `APPIUM_HOME` environment variable. You +can set that variable to anything you like, and Appium will manage its extensions there. You can +therefore also use the `APPIUM_HOME` environment variable to manage different sets of extensions, +for example if you want to have the same driver installed at conflicting versions: + +```bash +APPIUM_HOME=/path/to/home1 appium driver install xcuitest@4.11.1 +APPIUM_HOME=/path/to/home2 appium driver install xcuitest@4.11.2 +``` + +Running these commands will result in two separate `APPIUM_HOME` directories being created and +populated with the corresponding version of the XCUITest driver. You can then use the same +environment variables to direct Appium which version to use on launch: + +```bash +APPIUM_HOME=/path/to/home1 appium # use xcuitest driver 4.11.1 +APPIUM_HOME=/path/to/home2 appium # use xcuitest driver 4.11.2 +``` + +You don't need to set `APPIUM_HOME` if you don't want to! By default, Appium will set `APPIUM_HOME` +to the directory `.appium` in your user home directory. + +These installed packages will be managed by `extensions.yaml` in `$APPIUM_HOME/node_modules/.cache/appium/extensions.yaml`. + +## Do-It-Yourself with `npm` + +Because Appium and Appium drivers are Node.js programs, if you are integrating your Appium scripts +into your own Node.js project, there is an alternative way to manage drivers and plugins: via `npm`, +like any other dependency. Basically, whenever you run Appium, if you have not explicitly set +`APPIUM_HOME`, it will: + +1. Try to determine whether the _current directory_ is inside an `npm` package. +2. If so, it will check whether `appium` is a dependency (dev, prod, or peer) in the project's + `package.json` +3. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will ignore load + drivers and plugins defined in that `package.json` file instead. + +This means you are freely able to add Appium drivers and plugins as regular package dependencies or +dev dependencies. For example, if your project has a `package.json` which includes the following: + +```json +{ + "devDependencies": { + "appium": "^2.0.0", + "appium-xcuitest-driver": "^4.11.1" + } +} +``` + +Then, if you run `npx appium` inside your project, Appium will detect that it is a dependency of +the project, and will load the XCUITest driver which is also listed as a dev dependency for the +project. + +This strategy is _only_ recommended if you are already using `npm` for your project. +Otherwise, it is recommended that you use Appium's Extension CLI and, if necessary, adjust +`APPIUM_HOME` to change the location of stored extensions. diff --git a/packages/appium/docs/ja/guides/migrating-1-to-2.md b/packages/appium/docs/ja/guides/migrating-1-to-2.md index 5ee753f06..cc407c83f 100644 --- a/packages/appium/docs/ja/guides/migrating-1-to-2.md +++ b/packages/appium/docs/ja/guides/migrating-1-to-2.md @@ -1,295 +1,281 @@ --- -title: Appium 1.xからAppium 2.xへ移行する +title: Appium 2 へ移行する --- - -このドキュメントは既にAppium 1.xを利用している人がAppium 2.xに移行するための手引きです。 -破壊的変更(breaking changes)の一覧や、実行環境・テストコードをAppium 2.0互換にするための方法が含まれます。 +このドキュメントは既にAppium 1 を利用している人がAppium 2 に移行するための手引きです。 破壊的変更の一覧や、実行環境・テストコードをAppium 2 互換にするための方法が含まれます。 - +Appium 2 is the biggest Appium release in over 5 years. It is _not_ focused on changing the +automation behavior for any particular platform, but instead re-envisions Appium into an +_ecosystem_ of automation tools: - - -!!! note - - Appiumは継続的に開発されているため、このドキュメントはAppiumドライバーやプラグインに関して情報古い可能性があります。 - -## Appium 2.0の概要 - - - -Appium 2.0は過去5年間におけるAppiumのリリース野中で最も大きなリリースです。Appium 2.0の主要な変更は特定のプラットフォームに対する自動化された動作に関するものでは**ありません**。Appium 2.0はAppiumをドライバー(drivers)(あるプラットフォームに対する自動化を支援するためのプロジェクト)とプラグイン(plugins)(Appiumの動作を上書き、代替、拡張、もしくは追加するためのプロジェクト)という容易に実装、共有できる**仕組みを提供するプラットフォーム**として再考しています。 - - +- The core Appium module retains only platform-agnostic functionality +- Functionality for automating specific platforms is moved to separate _driver_ modules +- Functionality for altering/extending Appium is moved to separate _plugin_ modules 同時に、Appiumプロジェクトは多くの古くなったり非推奨となっている機能や依存を取り除こうとしています。 - - -これらに合わせて、Appiumのインストール方法、ドライバーやフィーチャーの管理、プロトコルサポートに関していくつかの破壊的変更をが導入されます。詳細は以下になります。 - - +Since Appium 2 is a major architectural change, ^^we do not recommend directly updating your +Appium 1 installations to Appium 2^^. Instead, please uninstall Appium 1 first, and only install +Appium 2 afterwards. ## 破壊的変更 - +### Drivers Installed Separately -以下では破壊的変更と、何をする必要があるのかを示します。 +When installing Appium 1, all available drivers would be installed alongside the main Appium +server. In Appium 2, due to its modular structure, this is no longer the case - by default, +installing it only installs the core Appium server, without any drivers. - +When it comes to installing Appium 2 drivers, there are several approaches you can take: - -### :bangbang: 初期設定のbase path - - - - -Appium 1.xでは、AppiumサーバーのURLは`http://localhost:4723/wd/hub`でした。この`/wd/hub`であるbase pathはSelenium 1からSelenium 2へ移行した時の名残であり、今となっては何ら意味を持ちません。そのため、初期設定のbase pathは`/`となります。もしあたなが以前の挙動を保持したいのであれば、以下の通りにAppiumサーバを起動してください。 - -``` -appium --base-path=/wd/hub -``` - - - -この設定は[Config file](https://appium.io/docs/en/latest/guides/config/)からでも可能です。 - - -### :bangbang: ドライバーのインストール - - - -Appium 1.xをインストールしたとき、全ての入手可能なドライバーはAppiumサーバーと合わせてインストールされていました。しかしAppium 2.0では異なります。Appium 2.0のインストール(例えば `npm i -g appium` を実行した時)は単にAppiumサーバーのみをインストールし、ドライバーはインストールされません。ドライバーをインストールするためには新しい[Appium拡張コマンドラインインタフェース(Appium extension CLI)](https://appium.io/docs/en/latest/cli/extensions/)を使わなければいけません。例えば、最新のXCUITestとUiAutomator2ドライバーをインストールする場合、Appiumをインストールしたのちに次のコマンドを実行する必要があります。 - -```bash -appium driver install uiautomator2 # installs the latest driver version -appium driver install xcuitest@4.12.2 # installs a specific driver version -``` - - - -これにより、ドライバーがインストールされ、利用可能になります。このCLIはいろいろな機能を提供しているので、CLIのドキュメントを確認してみてください。もしCI上で実行したり、いくつかのドライバーをAppiumと一緒にインストールしたい場合、以下のようなフラグを利用することが可能です。 +- Add the `--drivers` flag when installing Appium, for example: ```bash npm i -g appium --drivers=xcuitest,uiautomator2 ``` - - -これはAppiumと2つのドライバーを、1つのコマンドでインストールします。もしセットアップで何らかの問題が発生した場合、既存のAppium 1.xを`npm uninstall -g appium`で削除してみてください。 - -### :bangbang: ドライバーがインストールされるパス - - - -Appium 1.xをインストールしたとき、全ての入手可能なドライバーは主要なAppiumサーバーと合わせてインストールされていました。 -そのパスは`/path/to/appium/node_modules`です。 -例えば、手動でWebDriverAgentをビルドするための`appium-webdriveragent`パッケージは、`/path/to/appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`でした。 - -Appium 2.0では、このような依存関係を環境変数 `APPIUM_HOME` にインストールします。デフォルトのパスは `~/.appium` です。 -そのため、XCUITestドライバーパッケージをインストールすると、`appium-webdriveragent` へのパスは `$APPIUM_HOME/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent` となります。 - -### :bangbang: Chromeドライバーのインストールフラグ - - -Appium 1.xでは、以下のコマンドラインフラグを使って、(例えばUiAutomator2ドライバーの一部として)Chromedriverをインストールする方法の変更が可能でした。 - -* `--chromedriver-skip-install` -* `--chromedriver-version` -* `--chromedriver-cdnurl` - - -Appium 2.0では必要なドライバーだけインストールするようになり、またこれらのフラグはnpmの設定フラグとして実装されたため、これらのコマンドラインフラグは機能しません。代わりに、ドライバーのインストール時に以下の環境変数を使用してください: - -* `APPIUM_SKIP_CHROMEDRIVER_INSTALL` -* `CHROMEDRIVER_VERSION` -* `CHROMEDRIVER_CDNURL` - -例: +- Use the [Appium Extension CLI](../cli/extensions.md), for example: ```bash -APPIUM_SKIP_CHROMEDRIVER_INSTALL=1 appium driver install uiautomator2 +appium driver install uiautomator2 ``` -### :bangbang: ドライバー特有のコマンドラインオプション +- Use the [Appium Setup CLI command](../cli/setup.md) (added in Appium `2.6`), for example: - -Appium 1.xでは、特定のドライバに特化したコマンドラインオプションは、すべてAppiumサーバーに中継されていました。 -そのため、例えば`--chromedriver-executable`は、UiAutomator2ドライバーで使用する特定のChromedriverバージョンの場所を設定するためにAppiumで使用できるCLIパラメータでした。 +```bash +appium setup mobile +``` - -Appium 2.xでは、すべてのドライバーとプラットフォーム固有の CLI パラメータは、それらのドライバー自体が管理するかたちに移行しました。これらにアクセスするには、引数の前に拡張機能の種類 (`driver` または `plugin`) と拡張機能の名前を付ける必要があります。例えば、`--chromedriver-executable` は `--driver-uiautomator2-chromedriver-executable` となります。 +Check the [Managing Drivers and Plugins guide](./managing-exts.md) for more information. -### :bangbang: ドライバー特有の自動化コマンド +!!! info "Actions Needed" - +``` +When installing Appium 2, use one of the above approaches for installing your desired drivers +``` -特定のドライバーにのみ関係するコマンドの定義は、そのドライバーの実装に移行しました。 -例えば、`pressKeyCode`はUiAutomator2ドライバー特有のものなので、現在ではそのドライバーのみが解釈できます。 -実際には、適切なドライバーがインストールされていない場合に発生するエラーの種類が変わります。 -以前は、ドライバーが未実装のコマンドを実行すると `501 Not Yet Implemented` というエラーが返却されていました。 -現在では、コマンドを実装していないドライバーがアクティブでない場合、主Appiumサーバーはそのコマンドは定義されていないと処理し、`404 Not Found` エラーを返却します。 +### Driver Installation Path Changed -### :bangbang: Driver updates +When installing Appium 1, all available drivers would be installed as dependencies of the main +Appium server, in `/path/to/appium/node_modules`. 例えば、手動でWebDriverAgentをビルドするための`appium-webdriveragent`は、`/path/to/appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`でした。 - +In Appium 2, drivers (and plugins) are installed at the path defined by the `APPIUM_HOME` +environment variable, whose default value is `~/.appium`. So, `appium-webdriveragent` would now be +located at `$APPIUM_HOME/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`. -以前は、iOSやAndroidに関わるドライバーの更新を入手するために、Appiumの新しいリリースにそれらの更新が組み込まれるのを待ち、Appiumのバージョンを更新していました。 -Appium 2.xでは、AppiumサーバーとAppiumドライバーは各々にバージョンが管理され、別々にリリースされます。 -つまりドライバーは独自のリリース周期で、新しいAppiumサーバーのリリースを待つのではなく、その都度更新を適用することができます。 +!!! info "Actions Needed" -ドライバーの更新をCLIでチェックする方法: +``` +If your code uses paths to Appium driver files, update it to use the `APPIUM_HOME` environment +variable +``` + +### Drivers Updated Separately + +In Appium 1, in order to get updates to your drivers, you would simply wait for those updates to be +rolled into a new release of Appium, and then update your Appium version. With Appium 2, since the +server and drivers are separate packages, they can release new versions independently from each +other - this means that you no longer need to wait for a new Appium server release, but can install +the latest driver versions right away. + +Checking for driver updates is done by using the [Appium Extension CLI](../cli/extensions.md): ```bash appium driver list --updates ``` - - 更新が入手可能であれば、任意のドライバーに対して `update` コマンドを実行することができます。 ```bash -appium driver update xcuitest +appium driver list --updates ``` - - -(更新コマンドの詳しい説明は [Extension CLI](https://appium.io/docs/en/latest/cli/extensions/#update) を確認してください。) - - - -Appium サーバー自体を更新するには、これまでと同じように `npm i -g appium` を実行します。現在、Appiumサーバーの新しいバージョンをインストールしても、ドライバーはそのままなので、プロセス全体がより迅速になります。 - - - -最新のバージョンではなく、特定のバージョンに更新したい場合は、`update`の代わりに`install`サブコマンドを使ってドライバをアンインストールし、希望のバージョンをインストールしてください。 +Updating the Appium server itself is the same as before: ```bash -appium driver uninstall xcuitest -appium driver install xcuitest@4.11.1 +npm update -g appium ``` -### :bangbang: プロトコルの変更 +However, in Appium 2 this process is a lot quicker, since drivers are no longer bundled with the +server package. - +!!! info "Actions Needed" -AppiumのAPIは[W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/)に基づいており、何年もこのプロトコルをサポートしています。 -W3C WebDriver Protocolがウェブ標準として設計される以前は、SeleniumとAppiumの両方で他のプロトコルが使用されていました。それは、「JSONWP」(JSON Wire Protocol)と「MJSONWP」(Mobile JSON Wire Protocol)です。 -W3Cプロトコルと(M)JSONWPプロトコルはいくつか異なる点があります。 +``` +Make sure to use the [Appium Extension CLI](../cli/extensions.md) to manage your drivers +``` - +### Deprecated Packages No Longer Supported -Appium 2.0までは、古いSelenium/Appiumクライアントが新しいAppiumサーバーと通信できるように、Appiumは両方のプロトコルをサポートしていました。今後、古いプロトコルのサポートは削除されます。 +The Appium 1 ecosystem included several drivers, clients and other packages that had since been +deprecated and replaced with newer packages. Appium 2 no longer includes support for these packages, +and it is recommended to migrate to the following replacements: -### :bangbang: Capabilitiesはベンダープレフィックスを使用しなければならない +| Appium 1 Package | Replacement in Appium 2 | +| ------------------ | -------------------------------------------------------------------------- | +| iOS Driver | [XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/latest/) | +| UiAutomator Driver | [UiAutomator2](https://github.com/appium/appium-uiautomator2-driver/) | +| `wd` Client | [WebdriverIO Client](https://webdriver.io/) | +| Appium Desktop | [Appium Inspector](https://github.com/appium/appium-inspector) | - +!!! info "Actions Needed" -古いプロトコルと新しいプロトコルの大きな違いのひとつは、Capabilitiesのフォーマットにあります。以前は "desired capabilities" と呼ばれていましたが、現在は単に "capabilities" と呼ばれ、非標準の機能にはいわゆる "vendor prefix" が要求されるようになりました。標準として組み込まれているcapabilitiesは [WebDriver Protocol spec](https://www.w3.org/TR/webdriver/#capabilities) に記載されており、`browserName` や `platformName` などのよく使われるcapabilitiesが含まれています。 +``` +If you are using any of the aforementioned package(s), migrate to their recommended replacement(s) +``` - +### Default Server Base Path Changed -これらの標準として組み込まれているcapabilitiesはそのまま使用され続けます。それ以外のすべてのcapabilitiesは、その名前に"vendor prefix"を 含まなければなりません。"vendor prefix"は、`appium:` のように、コロンが続く文字列です。Appiumのほとんどのcapabilitiesは、標準として組み込まれているcapabilitiesではないため、"vendor prefix"を含める必要があります(ドキュメントで指示がない限り、`appium:` を使用することを推奨します)。 -例えば、 +In Appium 1, the default Appium server URL was `http://localhost:4723/wd/hub`, where the `/wd/hub` +part (the base path) was a legacy convention from Selenium 1. Appium 2 changes the default base +path to `/`, therefore the default server URL is now `http://localhost:4723/`. -- `appium:app` -- `appium:noReset` -- `appium:deviceName` +!!! info "Actions Needed" - +``` +In your test scripts, change the base path of the target server URL from `/wd/hub` to `/`. +Alternatively, you can retain the Appium 1 base path by launching Appium with the +`--base-path=/wd/hub` [command-line argument](../cli/args.md). +``` -この要件は、Appium 2.0をターゲットにしているテストスイートにとって破壊的な変更になるかもしれませんし、ならないかもしれません。 -アップデートされたAppiumクライアント(少なくとも Appium チームによってメンテナンスされているもの)を使用している場合、クライアントは自動的にすべての必要なcapabilitiesに `appium:` 接頭辞を追加します。新しいバージョンの[Appium Inspector](https://github.com/appium/appium-inspector)も同様です。クラウドベースのAppiumプロバイダもこれを行うかもしれません。 -そのため、もしあなたが使っていcapabilitiesに vendor prefix がない旨のメッセージが表示された場合は、この方法で問題を解決することができます。 +### Server Port 0 No Longer Supported - +In Appium 1, it was possible to specify `--port 0` during server startup, which had the effect of +starting Appium on a random free port. Appium 2 no longer allows this, and requires port values to +be `1` or higher. If you wish to start Appium on a random port, you must now take care of this on +your own prior to launching the server. -これに関連して、W3CプロトコルをサポートしていないWebDriverクライアントを使用してAppiumセッションを開始することはできなくなります(WDライブラリに関するこの趣旨のコメントは以下を参照してください)。 +!!! info "Actions Needed" - +``` +If you are launching Appium with `--port 0`, change the port number value to `1` or higher +``` -みなさんの活動を少し楽にするために、Appiumに関連する全てのcapabilitiesを一つのオブジェクトにまとめるオプション(`appium:options`)も導入しました。通常、`appium:`接頭辞を付けるものを、この1つのcapabilityにまとめることができます。以下は `appium:options` を使ってSafariブラウザ上でiOSセッションを開始する例(JSON)です: +### Driver-Specific CLI Options Changed +Appium 1 では、特定のドライバに特化したコマンドラインオプションは、すべてAppiumサーバーに中継されていました。 So, for example, `--chromedriver-executable` was a CLI parameter you could use to +set the Chromedriver location for the UiAutomator2 driver. + +In Appium 2, all driver-specific CLI options have been moved to the drivers themselves. However, +depending on the driver, these options may now need to be passed in another way: + +- Some options can still be passed as different CLI flags, for example: + +```bash +appium --webdriveragent-port=5000 # Appium 1 +appium --driver-xcuitest-webdriveragent-port=5000 # Appium 2 +``` + +- Some options can now be passed as environment variables, for example: + +```bash +appium --chromedriver-version=100 # Appium 1 +CHROMEDRIVER_VERSION=100 appium # Appium 2 +``` + +- Some options can now be passed as [capabilities](https://appium.io/docs/en/latest/guides/caps/), + for example: + +``` +appium --chromedriver-executable=/path/to/chromedriver # Appium 1 +{"appium:chromedriverExecutable": "/path/to/chromedriver"} # Appium 2 +``` + +!!! info "Actions Needed" + +``` +If you are using driver-specific CLI options, refer to that driver's documentation for how to +apply them in Appium 2 +``` + +### Filepaths No Longer Supported for Some CLI Options + +In Appium 1, some server command-line options could be invoked by passing a filepath as their +value, and Appium would then parse the contents of that file as the actual value for that option. +There were four options that supported this: + +- `--nodeconfig` +- `--default-capabilities` +- `--allow-insecure` +- `--deny-insecure` + +Appium 2 no longer attempts to parse the contents of filepaths passed to these options, and offers +two ways to specify the value for these options: + +- As strings, directly on the command line + - `--nodeconfig` / `--default-capabilities`: JSON string + - `--allow-insecure` / `--deny-insecure`: comma-separated list +- In the [Appium Configuration file](./config.md) + +!!! info "Actions Needed" + +``` +If you are using any of the aforementioned CLI options with a filepath value, update your code +to pass the file contents either directly or through the Appium config file +``` + +### Old Protocols Dropped + +AppiumのAPIは[W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/)に基づいており、何年もこのプロトコルをサポートしています。 Before this protocol was designed as a web standard, the +[JSON Wire Protocol](https://www.selenium.dev/documentation/legacy/json_wire_protocol/) (JSONWP) +and [Mobile JSON Wire Protocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) +(MJSONWP) were used instead. + +In Appium 1, all of these protocols were supported, so that older Selenium/Appium clients could +still communicate with newer Appium servers. Appium 2 removes support for JSONWP/MJSONWP and is now +only compatible with the W3C WebDriver Protocol. + +!!! info "Actions Needed" + +``` +Make sure you are using Selenium/Appium clients compatible with the W3C WebDriver Protocol +``` + +### Capabilities Require Vendor Prefix + +In Appium 1, in order to create a session, you had to specify certain desired capabilities, which +would indicate session parameters, e.g. the driver you want to use. Appium 2 retains this behavior +and continues to accept desired capabilities (now renamed simply to 'capabilities'), but as part of +the W3C WebDriver Protocol specification, all non-standard capabilities are now required to use a +vendor prefix. + +The list of standard capabilities is described in the [WebDriver Protocol specification](https://www.w3.org/TR/webdriver/#capabilities), +and includes a few commonly used capabilities like `browserName` and `platformName`. All other +capabilities must now start with the vendor name and a colon (the vendor prefix), for example, +`moz:` or `goog:`. Since most of Appium's capabilities go beyond the standard W3C capabilities, +all of them must include the `appium:` prefix (unless specified otherwise): + +``` +deviceName # Appium 1 +appium:deviceName # Appium 2 +``` + +This requirement may or may not be a breaking change for your test suites. Up-to-date versions of +official Appium clients and the Appium Inspector will automatically add the `appium:` prefix to all +non-standard capabilities, and the same may apply to cloud-based Appium providers. + +Additionally, if you are starting a session with multiple Appium-specific capabilities (which will +likely be the case), it may seem repetitive to add the `appium:` prefix to each individual +capability. To avoid this, you can optionally group up all these capabilities under a single object +capability, `appium:options`, for example: + +\=== "Default Approach" + +```` +```json +{ + "platformName": "iOS", + "browserName": "Safari", + "appium:platformVersion": "14.4", + "appium:deviceName": "iPhone 11", + "appium:automationName": "XCUITest" +} +``` +```` + +\=== "With `appium:options`" + +```` ```json { "platformName": "iOS", @@ -301,188 +287,117 @@ On a related note, it will no longer be possible to start Appium sessions using } } ``` +```` - +ケイパビリティの詳細については、[Capabilities Guide](./caps.md)をご覧ください。 -(もちろん、`appium:options`のような構造化されたcapabilityや、`goog:chromeOptions`のような構造化されたcapabilityは、クライアントによって作成方法が異なります。) +!!! info "Actions Needed" -!!! note +``` +Add the `appium:` prefix to all Appium-specific capabilities used in your tests, or wrap them +inside an `appium:options` object +``` - `appium:options`で表示されるcapabilityは、オブジェクトのトップレベルで表示される同名のcapabilityを上書きします。 - (新しい `appium:options` 構文のサポートは、クラウドプロバイダによって異なる場合があります。) +### Advanced Features Moved to Plugins - +One of the design goals for Appium 2 is to extract non-core features into special extensions called +[plugins](../ecosystem/plugins.md). Two such features of Appium 1 have been moved to plugins, and +are no longer bundled with Appium 2: -ケイパビリティの詳細については、[Capabilities Guide](https://appium.io/docs/en/latest/guides/caps/)をご覧ください。 +| Feature | Plugin Name | +| ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| Image-related features (comparison, search by image, etc...) | [`images`](https://github.com/appium/appium/tree/master/packages/images-plugin) | +| The Execute Driver Script feature | [`execute-driver`](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin) | -### :bangbang: 削除されたコマンド +!!! info "Actions Needed" - +```` +If you were using the image-related features and/or the execute driver script feature in Appium +1, first install their plugin(s): +``` +appium plugin install images +appium plugin install execute-driver +``` +Afterwards, make sure to activate the plugin(s) upon launching the Appium server: +``` +appium --use-plugins=images,execute-driver +``` +```` -ドライバの実装に移行したコマンドに加え、旧JSON Wireプロトコルの一部であり、W3Cプロトコルの一部ではないコマンドは使用できなくなりました: +### Endpoint Changes - +A few server endpoints used in Appium 1 were accepting old or unused parameters. Appium 2 removes +support for these parameters. The following is a list of these changed endpoints, along with the +parameters they no longer accept, as well as the parameters they continue to accept in Appium 2. -- TODO(これらのコマンドは特定・削除中であり、完了次第ここに更新されます) +- `POST /session/:sessionId/appium/device/gsm_signal` + - :octicons-x-24: `signalStrengh` + - :octicons-check-24: `signalStrength` +- `POST /session/:sessionId/appium/element/:elementId/value` + - :octicons-x-24: `value` + - :octicons-check-24: `text` +- `POST /session/:sessionId/appium/element/:elementId/replace_value` + - :octicons-x-24: `value` + - :octicons-check-24: `text` - +!!! info "Actions Needed" -最新のAppiumやSeleniumクライアントを使用している場合、これらにアクセスすることはできないため、どのような破壊的変更もまずはクライアント側に現れるはずです。 +``` +Check your Appium client documentation for the methods using these endpoints, and adjust your +code to only use the accepted parameters +``` -### :bangbang: 画像解析機能をプラグインに移行 +### Internal Packages Renamed - +In Appium 1, the internal dependency packages were each located in their own repository. Appium 2 +moves to a monorepo structure and therefore renames many of these packages, for example: -Appium 2.0の設計目標の1つは、非コア機能を[plugins](https://appium.io/docs/en/latest/ecosystem/plugins/)と呼ばれる特別な拡張機能に移行することです。これにより、ダウンロード時間やシステム設定が追加で必要となる機能を選択して利用できるようになります。Appiumの様々な画像関連機能(画像比較、画像による要素の検索など)は、[images](https://github.com/appium/appium/tree/master/packages/images-plugin)という公式にサポートされているプラグインに移動されました。 +``` +appium-base-driver # Appium 1 +@appium/base-driver # Appium 2 +``` - +!!! info "Actions Needed" -これらの画像関連メソッドを使用する場合、以下の2つのことを行う必要があります。 - - - - -1. プラグインをインストールする: `appium plugin install images`. -2. コマンドラインで指定したプラグインリストにプラグインを含めることで、プラグインを実行できる状態でAppiumサーバーを起動する。例:`appium --use-plugins=images` - - - -画像関連のコマンドはクライアント側でも削除されるため、これらの機能にアクセスするには、プラグインのREADMEにあるクライアント側プラグインのインストールの指示に従う必要があります。 - -### :bangbang: Execute Driver Scriptコマンドがプラグインに移動 - - - -高度なExecute Driver Script機能(WebdriverIOスクリプトを送信して、クライアントからコマンドごとに実行するのではなく、サーバー上で完全に実行させる機能)はプラグインに移動しました。この機能を使い続けるには以下の方法を使用してください: - - - -1. プラグインをインストールする: `appium plugin install execute-driver`. -2. コマンドラインで指定したプラグインリストにプラグインを含めることで、プラグインを実行できる状態でAppiumサーバーを起動する。例:`appium --use-plugins=execute-driver` - -### :bangbang: `--nodeconfig` `--default-capabilities ` `--allow-insecure` `--deny-insecure`での外部ファイルのサポート終了 - - - -これらのオプションはコマンドラインで文字列として指定できます(`--nodeconfig`の場合はJSON文字列、`--allow-insecure`と`--deny-insecure`の場合はカンマ区切りの文字列リスト)。コマンドラインで指定する引数は、引用符で囲むかエスケープする必要があります。 - - - -これらのオプションを提供するために推奨される方法は、[Configuration File](#configuration-files)を使うことです。 - - - -つまり、JSON Appium configファイルを使用している場合、単純に "nodeconfig" JSON ファイルの内容を `server.nodeconfig` プロパティの値にカット&ペーストすることができます。 以前 `--allow-insecure` と `--deny-insecure` のために提供した CSV のようなファイルは、Appium config ファイルの `server.allow-insecure` プロパティと `server.deny-insecure` プロパティの値になります(それぞれ文字列の配列)。 - -### :bangbang: 古いドライバーを削除 - - - -古いiOSとAndroid(UiAutomator 1)のドライバーと関連ツール(例えば`authorize-ios`)は削除されました。いずれにせよ、これらは何年も関連していません。 - -### :bangbang: サーバは `--port 0` で起動することはできない - - - -Appium 1.xでは、サーバー起動時に`--port 0`を指定することができました。 -これはランダムな空きポートで Appium を起動するという効果があります。Appium 2.0 では、ポートの値は `1` 以上でなければなりません。 -ランダムなポートのランダムな割り当ては、Appium 1.x の意図的な機能ではありませんでした。HTTP サーバーがどのように動作するか、そして Appium 1.xにはポート入力の検証がなかった結果です。 -Appium を起動するためにランダムな空きポートを見つけたい場合は、Appium を起動する前に自分でこの処理を行う必要があります。 -明示的な既知のポートでAppiumを起動するのが、今後の正しいやり方です。 - -### :warning: 内部パッケージの名称変更 - - - -一部の Appium 内部のnpmパッケージの名前が変更されました(例えば、`appium-base-driver` は `@appium/base-driver` になりました)。これはAppiumのユーザーにとって大きな変更ではなく、Appiumのコードを直接組み込んだソフトウェアをビルドしている人にとっての変更です。 - -### :warning: "WD "JavaScriptクライアント・ライブラリがサポート終了 - - - -何年もの間、Appiumの作者の一部は[WD](https://github.com/admc/wd)クライアントライブラリを保守していました。このライブラリは非推奨であり、W3C WebDriverプロトコルで使用するためには更新されていません。そのため、このライブラリを使用している場合は、より最新のものに移行する必要があります。[WebdriverIO](https://webdriver.io)をお勧めします。 - -### :warning: Appium InspectorがAppium Desktopから分離 - - - -Appium Desktopのインスペクション部分は、専用のアプリAppium Inspector [github.com/appium/appium-inspector](https://github.com/appium/appium-inspector) に移動しました。Appium 2.0サーバーと完全に互換性があります。ダウンロードして実行するだけです。アプリを検査するためにGUIのAppium Desktopサーバーはもう必要ありません。Appium Desktopサーバーは、[github.com/appium/appium-desktop](https://github.com/appium/appium-desktop)で引き続きサポートされます。単にInspectorがバンドルされなくなるだけです。Appium Desktop 1.21以下のバージョンは、非推奨の[WD](https://github.com/admc/wd)クライアントに依存しており、Appium 2.0と互換性がないことに注意してください。現在、Appium DesktopのAppium 2.0サポートは予定されていません。 - - - -また、[Web 版 Appium Inspector](https://inspector.appiumpro.com) にアクセスすることで、何もダウンロードせずに Appium Inspector を使用できるようになりました。なお、ローカルサーバーに対してテストを行う場合は、ブラウザベースのAppium InspectorがAppiumサーバーにアクセスしてセッションを開始できるように、サーバーを `--allow-cors` で起動する必要があります。 +``` +If you do not directly import Appium packages into your code - none! However, if you do, make +sure to update the names of your Appium package imports! +``` ## 主な新機能 - +Apart from the breaking changes mentioned above, here are some of the major new features you may +wish to take advantage of with Appium 2: -上記の変更点とは別に、このセクションではAppium 2.0の主な新機能を紹介します。 +### Third-Party Drivers and Plugins -### プラグイン +You are no longer limited to official drivers or plugins, or ones that the Appium team even knows +about! Developers can now create their own custom drivers or plugins, which can be installed via +Appium's [Extension CLI](../cli/extensions.md) from `npm`, `git`, GitHub, or even the local +filesystem. Interested in building a driver or plugin? Check out the +[Building Drivers](../developing/build-drivers.md) and +[Building Plugins](../developing/build-plugins.md) guides. -#### :tada: _Server Plugins_ +### Configuration Files - - -Appium extensionの作者は、独自のサーバー・プラグインを開発できるようになりました。 -Appium HTTPサーバー自体の動作方法を調整することもできます。 -プラグインの詳細については、新しい[Appium Introduction](../intro/index.md)をお読みください。 -プラグインを作ることに興味がありますか? [プラグインの構築](https://appium.io/docs/en/latest/developing/build-plugins/) ガイドをチェックしてください。 - -### :tada: どこからでもドライバーとプラグインをインストール - - - -もはやAppium付属のドライバーや、Appiumチームが知っているドライバーに限定されることはありません!Appiumエクステンションの作者は、カスタムドライバを開発できるようになりました。 -Appiumの[Extension CLI](https://appium.io/docs/en/latest/cli/extensions/)経由で、`npm`、`git`、GitHub、またはローカルのファイルシステムからダウンロードまたはインストールできます。 -ドライバのビルドに興味がありますか? [ドライバのビルド](https://appium.io/docs/en/latest/developing/build-drivers/) ガイドを参照してください。 - -### :tada: Configuration Files - - - -Appiumは、コマンドライン引数に加え、_設定ファイル_ もサポートするようになりました。つまりAppium 1がCLIで提供することを要求していたほぼすべての引数が、設定ファイルを介して表現できるようになりました。設定ファイルは JSON, JS, YAML 形式があります。設定ファイルは [Config Guide](https://appium.io/docs/en/latest/guides/config/) を参照してください。 +Appiumは、コマンドライン引数に加え、_設定ファイル_ もサポートするようになりました。 Nearly all options +or flags that had to be specified on the CLI in Appium 1, can now also be provided in a +configuration file. The file can be in JSON, JS, or YAML format. For more information, refer to +the [Config File Guide](./config.md). ## クラウド・プロバイダーに関する特記事項 - +Most of this guide has applied to Appium end users or developers, but some of the architectural +changes in Appium 2 will constitute breaking changes for different Appium service providers. At the +end of the day, the maintainer of the Appium server is responsible for installing and exposing the +various Appium drivers and plugins that end users may wish to use. -このドキュメントの残りの部分はAppium全般に適用されていますが、Appium 2のアーキテクチャ上の変更の一部はクラウドベースのAppiumホストであれ、内部サービスであれ、Appium関連のサービスプロバイダーにとって破壊的な変更となります。結局のところ、Appiumサーバーを保守する人は、エンドユーザーが使用したいと思うであろう様々なAppiumドライバーやプラグインをインストールし、利用できるようにする責任を持ちます。 - - - -クラウドプロバイダーには、業界と互換性のある方法でユーザーのニーズをサポートするために、私たちの[クラウドプロバイダーの能力に関する推奨事項](https://appium.io/docs/en/latest/guides/caps/#special-notes-for-cloud-providers) を十分に読み、理解することをお勧めします! - - +クラウドプロバイダーには、業界と互換性のある方法でユーザーのニーズをサポートするために、私たちの[クラウドプロバイダーの能力に関する推奨事項](./caps.md#special-notes-for-cloud-providers) を十分に読み、理解することをお勧めします! diff --git a/packages/appium/docs/ja/guides/security.md b/packages/appium/docs/ja/guides/security.md new file mode 100644 index 000000000..e9efe3cd4 --- /dev/null +++ b/packages/appium/docs/ja/guides/security.md @@ -0,0 +1,100 @@ +--- +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 +all the following are true: + +- You're running your own Appium server locally or within a protected internal network +- You're not sharing it with any untrusted parties +- You don't expose Appium's port(s) to the wider internet + +But because many Appium users might not be able to guarantee such a safe environment, the Appium +team puts many features behind a security protection mechanism which forces system admins (the +people that are in charge of starting the Appium server) to _explicitly opt-in_ to these features. +(Third-party driver and plugin authors can also hide behaviour behind security +flags.) + +For security reasons, Appium client sessions can _not_ request feature enablement via capabilities; +this is the responsibility of the server admin who configures and launches the Appium server. + +## Security Server Args + +The [Server CLI Args](../cli/args.md) doc outlines three relevant arguments which may be passed to +Appium when starting it from the command line: + +|
Parameter
| Description | +| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--relaxed-security` | Turns on _all_ insecure features (unless blocked by `--deny-insecure`; see below) | +| `--allow-insecure` | Turns on _only_ specified features. Features can be provided as a comma-separated list of feature names, or in the [Appium Configuration file](./config.md). For example, `--allow-insecure=adb_shell` will cause _only_ the ADB shell execution feature to be enabled. Has no effect when used in combination with `--relaxed-security`. | +| `--deny-insecure` | Explicitly turns _off_ specified features, overriding `--relaxed-security` and any features specified using `--allow-insecure`. Like `--allow-insecure`, features can be provided as a comma-separated list of feature names, or in the [Appium Configuration file](./config.md). | + +## Insecure Features + +Each Appium driver is responsible for its own security, and can create its own feature names. Thus +you should read through the documentation for a particular driver to know which feature names it +might use. Here is an incomplete list of examples from some of Appium's official drivers: + +|
Feature Name
| Description | Supported Extension(s) | +| ------------------------------------------ | --------------------------------------------------------------------------------------- | ---------------------------------------------- | +| `get_server_logs` | Allows retrieving of Appium server logs via the Webdriver log interface | IOS, XCUITest, Android, UiAutomator2, Espresso | +| `adb_shell` | Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command | Android, UiAutomator2, Espresso | +| `record_audio` | Allow recording of host machine audio inputs | XCUITest | +| `execute_driver_script` | Allows to send a request which has multiple Appium commands. | Execute Driver Plugin | + +Some insecure features operate on the server level, and do not require a driver session: + +|
Feature Name
| Description | +| ------------------------------------------ | ------------------------------------------------------------------------------- | +| `session_discovery` | Allows retrieving the list of active server sessions via `GET /appium/sessions` | + +## Examples + +To turn on the `get_server_logs` feature, the Appium server could be started like this: + +```bash +appium --allow-insecure=get_server_logs +``` + +To turn on multiple features: + +```bash +appium --allow-insecure=get_server_logs,record_audio +``` + +To allow all features except one: + +```bash +appium --relaxed-security --deny-insecure=adb_shell +``` + +## Driver-scope security + +Since Appium server version `2.13`, it is possible to apply features on a per-driver basis. This +can be achieved by prefixing each feature name with the `automationName` of the driver for which +the feature should be applied. To apply a feature for all drivers, or to apply a server-level +feature, the wildcard (`*`) prefix should be used. + +For example, the server could be started as follows: + +```bash +appium --allow-insecure=uiautomator2:adb_shell,xcuitest:get_server_logs,*:record_audio +``` + +This would result in the following: + +- The `adb_shell` feature would be enabled only for the UiAutomator2 driver +- The `get_server_logs` feature would be enabled only for the XCUITest driver +- The `record_audio` feature would be enabled for all drivers + +Feature provided without an explicit prefix are equivalent to having the wildcard prefix. +These prefix rules apply to both the `--allow-insecure` and `--deny-insecure` server arguments. + +!!! warning + +``` +Starting from Appium 3, the scope prefix is required, and features provided without a scope will +raise an error. Note that the behavior of the `--relaxed-security` flag remains unchanged. +``` diff --git a/packages/appium/docs/ja/guides/settings.md b/packages/appium/docs/ja/guides/settings.md new file mode 100644 index 000000000..99c7a59e6 --- /dev/null +++ b/packages/appium/docs/ja/guides/settings.md @@ -0,0 +1,69 @@ +--- +hide: + - toc +title: Session Settings +--- + +Appium has a set of extension APIs that allow you to adjust parameters for a given session during +the session itself. Called "Settings", these parameters are similar to [Capabilities](./caps.md), +but while Capabilities _cannot be adjusted_ once a session has started, Settings _can be adjusted any +number of times_ during the course of a session. + +There are 3 important points to the concept of Settings: + +- Settings are mutable; they can be changed during a session using the Settings API +- Settings are only relevant during the session in which they are set. They are typically reset for + each new session, though depending on the driver, some settings may persist between sessions +- Settings only adjust the way the Appium server behaves during test automation. They do not affect + the device or app under test + +An example of a setting would be the `ignoreUnimportantViews` setting recognized by the UiAutomator2 +driver. The driver can be instructed to ignore elements in the view hierarchy which it deems +irrelevant. Changing this setting to `true` can cause tests to run faster. But if later in the same +session you _want_ to access elements which would be ignored under this setting, you can always +change it back to `false`. + +Settings are implemented via the following API endpoints: + +| Command |
Method/Route
| Params | Description | Returns | +| ----------------- | ------------------------------------------ | ----------------------------------------------------- | ---------------------------------- | ----------------------------------------------------- | +| `Update Settings` | `POST /session/:id/appium/settings` | `settings` (`Record`) | Update the provided setting values | `null` | +| `Get Settings` | `GET /session/:id/appium/settings` | | Return the current settings | `settings` (`Record`) | + +The `settings` object must be a set of keys and values, where the key is the setting name, and the +value is any documented valid value for that setting. + +!!! info + +``` +Settings are driver-specific, so refer to your driver's documentation for a list of supported settings +``` + +## Initializing Settings via Capabilities + +If you want to start an Appium session with a setting in a non-default state, you can do so by +including a capability of the form `appium:settings[]` with the appropriate value. So to turn +on the `ignoreUnimportantViews` setting mentioned above from the very beginning of a session, you +would construct a set of capabilities that includes the following in its JSON representation: + +```json +{ + "appium:settings[ignoreUnimportantViews]": true +} +``` + +Also, since Appium 2.1, there is a possibility to provide multiple settings in a single +`appium:settings` capability value: + +```json +{ + "appium:settings": { + "ignoreUnimportantViews": true, + "allowInvisibleElements": true + } +} +``` + +Of course, initializing a setting via capabilities doesn't prevent you from changing it later on +via the Settings API. To learn more about how to use the Settings API in the context of your +specific client library, visit the documentation for that client. diff --git a/packages/appium/docs/ja/guides/tls.md b/packages/appium/docs/ja/guides/tls.md new file mode 100644 index 000000000..92ff14f54 --- /dev/null +++ b/packages/appium/docs/ja/guides/tls.md @@ -0,0 +1,42 @@ +--- +hide: + - toc +title: SSL/TLS/SPDY Support +--- + +Appium 2.2 introduces the option to start the Appium server with SSL/TLS support. + +## Command Line Arguments + +In order to enable secure connections to the server, you need to provide the following command +line arguments: + +```bash +appium server --ssl-cert-path=/path/to/cert.pem --ssl-key-path=/path/to/key.pem +``` + +Both arguments must be provided and should contain paths to a valid +[X509 PEM](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/) +certificate and its corresponding private key. + +After the server is started use the `https` protocol and a client supporting SSL/TLS or +[SPDY](https://en.wikipedia.org/wiki/SPDY) to communicate to it. + +### Supported Features + +Once a secure server socket is established it supports the following protocols: +`['h2', 'spdy/3.1', 'spdy/3', 'spdy/2', 'http/1.1', 'http/1.0']`. See +[the SPDY node module documentation](https://www.npmjs.com/package/spdy) to get more details about +its features. All insecure client connections will be rejected by the server. + +### Self-Signed Certificates + +Use the following command in order to generate a self-signed certificate/key pair: + +```bash +openssl req -nodes -new -x509 -keyout key.pem -out cert.pem -subj "/C=US/ST=State/L=City/O=company/OU=Com/CN=www.testserver.local" +``` + +Feel free to change the value of `-subj` in the command above with your matching details. The server +should work just fine with a self-signed certificate, although you need to take care about a proper +client setup, e.g. make sure it does not reject unauthorized certificates. diff --git a/packages/appium/docs/ja/index.md b/packages/appium/docs/ja/index.md index 212f085d9..623a7b5b4 100644 --- a/packages/appium/docs/ja/index.md +++ b/packages/appium/docs/ja/index.md @@ -1,112 +1,48 @@ --- -title: Appiumのドキュメント +hide: + - navigation + - toc +title: ようこそ --- - -# Appiumのドキュメント +
- -Appiumのドキュメントにようこそ。Appiumはオープンソースプロジェクトであり、そのエコシステムは多様なプラットフォーム、例えばモバイル(iOS・Android・Tizen)やブラウザ(Chrome・Firefox・Safari)、デスクトップ(macOS・Windows)、TV(Roku・tvOS・Android TV・Samsung)に対するUI自動化を支援するために設計されています。 +Appiumのドキュメントにようこそ! Appiumはオープンソースプロジェクトであり、そのエコシステムは多様なプラットフォーム、例えばモバイル(iOS・Android・Tizen)やブラウザ(Chrome・Firefox・Safari)、デスクトップ(macOS・Windows)、TV(Roku・tvOS・Android TV・Samsung)に対するUI自動化を支援するために設計されています。 - -もしあなたがAppiumを初めて学ぶのであれば、[はじめに](intro/)からとりかかり、[クイックスタート](quickstart/)へと進むとよいでしょう。GitHub上の[appium/appium](https://github.com/appium/appium)においてコードを確認することができます。 +
+ Appiumはパートナーのサポートに非常に感謝しています! (私たちのスポンサーシップと貢献者への報酬の枠組みはこちらから) +
+ +
+
- -## Appiumは何のためにあるか? +## ドキュメントを検索する +
- +- [**Introduction**](./intro/index.md) を読んでして、主要なコンセプトを理解してください +- [**Quickstart**](./quickstart/index.md) を通して、基本的なAndroidテストを用意、実行します。 +- 使用するドライバ、クライアント、プラグインの一覧については、 [**Ecosystem**](./ecosystem/index.md) ページを参照してください。 +- コマンドラインからAppiumを使用する場合、[**CLI リファレンス**](./cli/index.md)を参照してください。 +- Appiumとプラグインで公開されているコマンドの一覧は[**Command Reference**](./commands/index.md)を参照してください。 +- [**Guides**](./guides/migrating-1-to-2.md) にあるさまざまな使い方、ヒント、コツを読んでください。 +- 様々なサードパーティーの [**Resources**](./resources.md) をチェックして、ウェブ上のAppiumを探してみてください。 +- 独自の Appium 拡張を作成するには、 [**Developer**](./developing/index.md) ドキュメントを参考にしてください。 +- Appium自体への貢献については、 [**Contributing**](./contributing.md) を参照してください。 -Appiumは主にソフトウェアの自動テスト領域において、テスト対象となるアプリが機能的に期待通りに動作するかを確認するために使用されます。他のソフトウェアテストとは対照的に、UI自動化では、テストエンジニアが実アプリケーションのUI上から現実世界で実際に起こることになるべく近くなるようなユーザシナリオを構築しながらも、実行速度、拡張性、一貫性といった自動化の利点を実現します。 - - - - -Appiumはいくつものプラットフォームを跨いで標準化された方法で自動化を実現するためのツール群を提供します。たいていのプラットフォームはUI自動化を大なり小なり実現可能ですが、通常はそれらはプラットフォーム固有であり、専用の知識やプログラミング言語経験、ツール群が要求されます。Appiumはそれらの自動化技術を1つの標準化されたインターフェースのもとで、広く使われるプログラミング言語(Java、Python、Ruby、JavaScriptなど)を通して利用できるように試みています。Appiumがどのようにこの目標を達成しているか、どのような要素が関係しているかを学ぶためには[導入](intro/)に進んでください。 - - -## Appiumを学ぶ - - - -Appiumをより知るために: - -- まずはAppiumの考え方、構成を理解するために[導入](intro/)を確認します -- [クイックスタート](quickstart/)でAppiumの準備と基本的なAndroidのテスト実行を体験します -- いくつもの手引き、リファレンスを確認します -- 実プロジェクトでAppiumを使うということは特定のプラットフォームに向けたAppiumドライバー(Appium driver)を使うことを意味します。必要となるドライバー(drivers)やプラグイン(plugins)への各種リンクを持つ[エコシステム](ecosystem/)ページを確認します。そこでは対象とするプラットフォーム固有の情報を確認できます。 - - - -[その他](resources.md)にはWeb上にあるサードパーティ製のリストもあります。これらもAppiumを使う上で役立つでしょう。 - - - -## Appiumに貢献する - - - - -AppiumはApache 2.0 ライセンスのもと利用可能なオープンソースプロジェクトです。Appiumのコピーライト(copyright)は[OpenJS Foundation](https://openjsf.org)にあり、競合状態に関わらず、様々なソフトウェア業界を跨いで多くの企業から助けを得ます。(サードパーティ製のドライバー(drivers)やプラグイン(plugins)は各々のライセンスを持ちます。) - - -そのため、私たちは皆様からの貢献を歓迎しています!企業やボランティアによるコード、ドキュメント、メンテナンス、サポートといった貢献により、Appiumプロジェクトは発展していきます。貢献方法に関してより知るためには、AppiumのGitHubリポジトリ([appium/appium](https://github.com/appium/appium))と[貢献する](contributing/)を確認してください。 - -## 日本語訳によせて - -- 体裁は「です・ます」、コマンド名といった固有の文字はカタカナ表記、英語併記、もしくは英語をそのまま残していく予定です。 - ---- - -- Written by 松尾和昭 (Kazuaki Matsuo, @KazuCocoa) +
diff --git a/packages/appium/docs/ja/intro/appium.md b/packages/appium/docs/ja/intro/appium.md new file mode 100644 index 000000000..1202eb2c3 --- /dev/null +++ b/packages/appium/docs/ja/intro/appium.md @@ -0,0 +1,191 @@ +--- +title: How Does Appium Work? +--- + +「はじめに」でも言及したとおり、Appiumはオープンソースプロジェクトであり、多くのアプリケーションプラットフォームのUI自動化を助けるために設計された関係するソフトウェアのエコシステムです。 Appium 2.0のリリースにより、Appiumは以下の主要な目標を達成します:[^1] + +- 標準化されたAPIにより、クロスプラットフォームながらもプラットフォーム固有の自動化を可能とする +- 様々なプログラミング言語からこのAPIを呼び出すことができる +- コミュニティ間で開発された便利なAppium拡張(Appium extension)を利用できるようになる + +[^1]: これらの主要な目的達成のため、私たちは二次的な目標や原則に沿っています。Appium拡張(Appium extension)の開発者にも同様に推奨するものです。 + + - 可能な限り、オープンソースを活用し、オープンソースに貢献もする + - 可能な限り、開発元から提供されるプラットフォーム固有のツールを使用する + - 可能な限り、テスト対象に変更を必要としない自動化ツールを使用する(専用ビルドを必要とするような追加のSDKやテスト対象版と製品版とで差異があることは好ましくない) + - 可能な限り、新しい独自のものを作るより既にある標準のものを使う + +したがって、iOSやAndroidといったいかなるアプリプラットフォームに対しても、 Appiumは開発者やテスターにそのプラットフォームにおけるUI自動化コードを一つの統一されたAPIで記述できるようにします。 Appiumの目標を実現するために私たちは多くの疑問に答える必要があります。 + +- "一つの統一された" APIとは何か? +- どのように私たちはそのAPIを特定のプラットフォームにおける自動化としての振る舞いに対応させているか? +- どのように私たちは複数のよく知られるプログラミング言語から利用可能にしているか? + +iOSとAndroidだけでなくより多くのアプリプラットフォームが存在していることを考えると、その背景には別の、より大きな疑問が潜んでいます。 + +- どのようにして_全ての_プラットフォームに対して自動化を実現するか? + +これらの疑問へのAppiumの答えを知ることは、Appiumが何かを学ぶ最短の方法ではないかもしれませんが、確かな道になります。 では、見ていきましょう。 + +## Appium's choice of API + +Appium is very fortunate to have been preceded by a technology which has been a long-standing +pioneer in the field of UI automation, namely [Selenium](https://selenium.dev). The goal of the +Selenium project has been to support UI automation of web browsers, and in this way we can think of +it as occupying a subset of Appium's goals. Along the way, Selenium (and, after they merged, +another project called WebDriver) developed a relatively stable API for browser automation. + +Over the years, Selenium worked with various web browser vendors and the [W3C](https://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! + +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. + +[^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. + +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: + +- 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. + +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. + +## 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. + +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. + +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. + +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. + +[^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. + +## 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. + +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. + +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. + +There are a couple important takeaways here for you, the Appium user: + +- 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. + +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's huge scope + +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". + +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: + +- 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!). + +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! + +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](../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. + +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. diff --git a/packages/appium/docs/ja/intro/clients.md b/packages/appium/docs/ja/intro/clients.md new file mode 100644 index 000000000..95bb9b952 --- /dev/null +++ b/packages/appium/docs/ja/intro/clients.md @@ -0,0 +1,138 @@ +--- +hide: + - toc +title: Intro to Appium Clients +--- + +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. + +!!! 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). +``` + +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). + +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`). + +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. + +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): + +\=== "JavaScript (Webdriver.io)" + +```` +```js +const element = await driver.$('//*[@text="Foo"]'); +await element.click(); +console.log(await element.getText()) +console.log(await driver.getPageSource()) +``` +```` + +\=== "Java" + +```` +```java +WebElement element = driver.findElement(By.Xpath("//*[@text='Foo']")) +element.click() +System.out.println(element.getText()) +System.out.println(driver.getPageSource()) +``` +```` + +\=== "Python" + +```` +```py +element = driver.find_element(by=By.XPATH, value='//*[@text="Foo"]') +element.click() +print(element.text) +print(driver.page_source) +``` +```` + +\=== "Ruby" + +```` +```rb +element = driver.find_element :xpath, '//*[@text="Foo"]' +element.click +puts element.text +puts driver.page_source +``` +```` + +\=== "C#" + +```` +```dotnet +AppiumElement element = driver.FindElement(MobileBy.AccessibilityId("Views")); +element.click(); +System.Console.WriteLine(element.Text); +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. + +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! + +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. + +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. + +[^1]: These libraries are alternately called "clients", "client libraries", or "client bindings". + They all mean the same thing! diff --git a/packages/appium/docs/ja/intro/drivers.md b/packages/appium/docs/ja/intro/drivers.md new file mode 100644 index 000000000..3d0085965 --- /dev/null +++ b/packages/appium/docs/ja/intro/drivers.md @@ -0,0 +1,188 @@ +--- +title: Intro to Appium Drivers +--- + +As the [main Overview](./appium.md) makes clear, "drivers" are basically Appium's answer to the +question, "how do we support automation of multiple, unrelated platforms?" In this doc we'll get +into a little more detail about how drivers work. The specific details of how drivers work probably +don't matter too much for you, unless you're planning on writing your own driver or contributing to +an existing driver (things we hope you do!). + +The main benefit in understanding a bit more of how drivers work is that being aware of the typical +complexity or the typical driver architecture will inform your debugging process when you +inevitably run into an issue in one of your tests. + +## Interface Implementations + +At the most basic level, drivers are simply Node.js classes that extend a special class included in +Appium, called `BaseDriver`. You could have something very close to a "working" driver, with these +very simple lines of code: + +```js +import BaseDriver from '@appium/base-driver' + +class MyNewDriver extends BaseDriver { +} +``` + +This empty driver doesn't _do_ anything, but you could wrap it up in a Node.js module, add a few +Appium-related fields to the module's manifest (`package.json`), and then install it using `appium +driver install`. + +So, from a technical perspective, an Appium driver is just a bit of code that inherits from some +other Appium code. That's it! Now, inheriting from `BaseDriver` actually gives us a lot, because +`BaseDriver` is essentially an encapsulation of the entire WebDriver protocol. So all a driver +needs to do something useful is to _implement_ Node.js methods with names corresponding to +their WebDriver protocol equivalents. + +So let's say I wanted to do something with this empty driver; first I have to decide which +WebDriver command I want to implement. For our example, let's take the Navigate +To WebDriver command. Leave aside for the moment +what I want to have the driver _do_ when this command is executed. To tell Appium the driver can +handle the command, all we have to do is define a method like this in our driver class:[^1] + +```js +async setUrl(url) { + // do whatever we want here +} +``` + +[^1]: You might notice that `setUrl` doesn't look anything like `Navigate To`, so how did we know + to use it rather than some other random string? Well, Appium's WebDriver-protocol-to-method-name + mapping is defined in a special file within the `@appium/base-driver` package called + [routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js). + So if you're writing a driver, this is where you would go to figure out what method names to use + and what parameters to expect. Or you could look at the source for any of the main Appium + drivers! + +That's it! How we actually implement the command is totally up to us, and depends on the +platform(s) we want to support. Here are some different example implementations of this command for +different platforms: + +- Browsers: execute some JavaScript to set `window.location.href` +- iOS apps: launch an app using a deep link +- Android apps: launch an app using a deep link +- React apps: load a specific route +- Unity: go to a named scene + +So you can see there can be a lot of differences between how drivers implement the same WebDriver +command across platforms.[^2] What is the _same_, though, is how they express that they can handle +a protocol command. + +[^2]: Of course, we want to keep the semantics as similar as possible, but in the world of iOS, for + example, launching an app via a deep link (a URL with a special app-specific scheme) is about as + close as we are going to get to navigating to a web URL. + +We're going into this great amount of detail (which you don't need to remember, by the way), +because it's important to stress the point that an Appium driver is not inherently anything in +particular, other than a bit of JS code that can handle WebDriver protocol commands. Where you go +from there is up to you, the driver author! + +## Automation mapping + +But _typically_ what driver authors want to do is to provide automation behaviours for a given +platform(s) that are semantically very similar to the the WebDriver spec implementations for +browsers. When you want to find an element, you should get a reference to a UI element. When you +want to click or tap that element, the resulting behaviour should be the same as if a person were +to click or tap on the element. And so on. + +So the real challenge for driver authors is not how to work with the WebDriver protocol (because +`BaseDriver` encapsulates all that for you), but how to make the actual automation happen on the +target platform. Every driver relies on its own set of underlying technologies here. As mentioned +in the [Overview](index.md), the iOS driver uses an Apple technology called +[XCUITest](https://developer.apple.com/documentation/xctest/xcuielement). These underlying +automation technologies usually have proprietary or idiosyncratic APIs of their own. Writing +a driver becomes the task of mapping the WebDriver protocol to this underlying API (or sometimes +a set of different underlying APIs--for example, the UiAutomator2 driver relies not only on the +[UiAutomator2](https://developer.android.com/training/testing/other-components/ui-automator) +technology from Google, but also functions only available through +[ADB](https://developer.android.com/tools/adb), as well as functions only available +via the Android SDK inside a helper app). Tying it all together into a single, usable, WebDriver +interface is the incredibly useful (but incredibly challenging) art of driver development! + +## Multi-level architecture + +In practice, this often results in a pretty complex architecture. Let's take iOS for example again. +The XCUITest framework (the one used by the Appium driver) expects code that calls it to be written +in Objective-C or Swift. Furthermore, XCUITest code can only be run in a special mode triggered by +Xcode (and directly or indirectly, the Xcode command line tools). In other words, there's no +straightforward way to go from a Node.js function implementation (like `setUrl()` above) to +XCUITest API calls. + +What the XCUITest driver authors have done is instead to split the driver into two parts: one part +written in Node.js (the part which is incorporated into Appium and which initially handles the +WebDriver commands), and the other part written in Objective-C (the part which actually gets run on +an iOS device and makes XCUITest API calls). This makes interfacing with XCUITest possible, but +introduces the new problem of coordination between the two parts. + +The driver authors could have chosen any of a number of very different strategies to model the +communication between the Node.js side and the Objective-C side, but at the end of the day decided +to use ... the WebDriver protocol! That's right, the Objective-C side of the XCUITest driver is +itself a WebDriver implementation, called +[WebDriverAgent](https://github.com/appium/webdriveragent).[^3] + +[^3]: You could in theory, therefore, point your WebDriver client straight to WebDriverAgent and + bypass Appium entirely. This is usually not convenient, however, for a few reasons: + +- The Appium XCUITest driver builds and manages WebDriverAgent for you, which can be a pain and + involves the use of Xcode. +- The XCUITest driver does lots more than what can be done by WebDriverAgent, for example working + with simulators or devices, installing apps, and the like. + +The moral of the story is that driver architectures can become quite complicated and multilayered, +due to the nature of the problem we're trying to solve. It also means it can be difficult sometimes +to tell where in this chain of technologies something has gone wrong, if you run into a problem +with a particular test. With the XCUITest world again, we have something like the following set of +technologies all in play at the same time: + +- Your test code (in its programming language) - owned by you +- The Appium client library - owned by Appium +- The Selenium client library - owned by Selenium +- The network (local or Internet) +- The Appium server - owned by Appium +- The Appium XCUITest driver - owned by Appium +- WebDriverAgent - owned by Appium +- Xcode - owned by Apple +- XCUITest - owned by Apple +- iOS itself - owned by Apple +- macOS (where Xcode and iOS simulators run) - owned by Apple + +It's a pretty deep stack! + +## Proxy mode + +There's one other important architectural aspect of drivers to understand. It can be exemplified +again by the XCUITest driver. Recall that we just discussed how the two "halves" of the XCUITest +driver both speak the WebDriver protocol---the Node.js half clicks right into Appium's WebDriver +server, and the Objective-c half (WebDriverAgent) is its own WebDriver implementation. + +This opens up the possibility of Appium taking a shortcut in certain cases. Let's imagine that the +XCUITest driver needs to implement the `Click Element` command. The internal code of this +implementation would look something like taking the appropriate parameters and constructing an HTTP +request to the WebDriverAgent server. In this case, we're basically just reconstructing the +client's original call to the Appium server\![^4] So there's really no need to even write a function +implementing the `Click Element` command. Instead, the XCUITest driver can just let Appium know +that this command should be proxied directly to some other WebDriver server. + +[^4]: It's not _exactly_ the same call, because the Appium server and the WebDriverAgent server + will generate different session IDs, but these differences will be handled transparently. + +If you're not familiar with the concept of "proxying," in this case it just means that the XCUITest +driver will not be involved at all in handling the command. Instead it will merely be repackaged +and forwarded to WebDriverAgent at the protocol level, and WebDriverAgent's response will likewise +be passed back directly to the client, without any XCUITest driver code seeing it or modifying it. + +This architectural pattern provides a nice bonus for driver authors who choose to deal with the +WebDriver protocol everywhere, rather than constructing bespoke protocols. It also means that +Appium can create wrapper drivers for any other existing WebDriver implementation very easily. If +you look at the [Appium Safari driver](https://github.com/appium/appium-safari-driver) code, for +example, you'll see that it implements basically no standard commands, because all of these are +proxied directly to an underlying SafariDriver process. + +It's important to understand that this proxying business is sometimes happening under the hood, +because if you're ever diving into some open source driver code trying to figure out where +a command is implemented, you might be surprised to find no implementation at all in the Node.js +driver code itself! In that case, you'll need to figure out where commands are being proxied to so +you can look there for the appropriate implementation. + +OK, that's enough for this very detailed introduction to drivers! diff --git a/packages/appium/docs/ja/intro/history.md b/packages/appium/docs/ja/intro/history.md new file mode 100644 index 000000000..24c6ab9eb --- /dev/null +++ b/packages/appium/docs/ja/intro/history.md @@ -0,0 +1,182 @@ +--- +title: Appium Project History +--- + +Appium has been around in one form or another since 2012. It's been under the +direction of various individuals and organizations, and it's even been +implemented in 3 different programming languages! Welcome to more than you ever +wanted to know about how Appium got to be what is it today... + +## Early Inspiration + +[Dan Cuellar](https://twitter.com/thedancuellar) was the Test Manager at Zoosk +in 2011, when he encountered a problem. The length of the test passes on the +iOS product was getting out of hand. Less testing was an option, but would come +with additional risk, especially with it taking several days to get patches +through the iOS App Store Review process. He thought back to his days working +on websites and realized automation was the answer. + +Dan surveyed the existing landscape of tools, only to find that all of them +hand major drawbacks. The tool supplied by Apple, UIAutomation, required tests +to be written in JavaScript, and did not allow for real-time debugging or +interpretation. It also had to be executed inside the Xcode profiling tool, +Instruments. Other 3rd-party tools used private APIs and required SDKs and HTTP +Servers to be embedded into the application. This seemed highly undesirable. + +Unsatisfied with the existing options, Dan asked his manager for some +additional time to see if he could find a better way. He spent 2 weeks poking +and prodding around to see if there was a way to use approved Apple +technologies to automate an iOS application. The first implementation he tried +used AppleScript to send messages to Mac UI elements using the OS +X accessibility APIs. This worked to some degree, but would never work on real +devices, not to mention other drawbacks. + +So he thought, what if I could get the UIAutomation framework to run in real +time like an interpreter? He looked into it and he determined that all he would +need to do is find a way to receive, execute, and reply to commands from within +a UIAutomation javascript program. Using the utility Apple provided for +executing shell commands he was able to `cat` sequentially ordered text files +to receive commands, `eval()` the output to execute them, and write them back +to disk with `python`. He then prepared code in C# that implemented the +Selenium-style syntax to write the sequentially ordered javascript commands. +iOSAuto is born. + +## Selenium Conference 2012 + +Dan was selected to speak at Selenium Conference 2012 in London about an +entirely different topic. As part of his presentation, he showed off iOS +Automation using Selenium syntax to demonstrate writing platform-agnostic tests +that use separate platform-specific page objects with a common interface. To +his surprise, the cool test architecture would take a backseat to the spectacle +of iOS tests running like WebDriver tests. Several people suggested that he +give a lightning talk later in the conference to explain exactly how it worked. + +On the second day of the conference, Dan stepped up on stage to give the +lightning talk. Jason Huggins, co-creator of Selenium, moderated the lightning +talks. Dan experienced technical difficulties getting his presentation to +load, and Jason nearly had to move on to the next lightning talk. At the last +moment, the screen turned on and Dan jumped into his presentation. He explained +the details of his implementation and how it worked, begged for contributors, +and in five minutes it was over. The crowd applauded politely, and he left the +stage. + +## The Phone Rings + +Four months after the Selenium Conference, Jason called Dan. Jason had been +working on iOS testing support for a client at Sauce Labs. Jason remembered +Dan's lightning talk and thought the project might be useful to Jason's work, +but Dan's source code was not public. Jason asked Dan to meet up. Later that +week, Dan met Jason in a bar in San Francisco and showed him the source code +for iOS Auto. + +A long-time open source advocate, Jason encouraged Dan to release his code +under an open source license. In August, Dan released the source +code +on GitHub in C#. Jason encouraged Dan to change the language to make the +project more appealing to potential contributors. Dan uploaded a new version +in +Python. +In September, Jason added a web server and began to implement the WebDriver +wire +protocol +over HTTP, making iOS Auto scriptable from any Selenium WebDriver client +library in any language. + +## The Mobile Testing Summit + +Jason decided that the project should be presented at the Mobile Testing +Summit in November, but suggested that the +project get a new name first. Many ideas were thrown out and they settled on +AppleCart. A day later, while he was perusing some of Apple's guidance on +copyright and trademarks, Jason noticed that under the section of examples for +names Apple would defend its trademarks against, the first example was +"AppleCart". He called Dan and informed him of the situation, and they +brainstormed for a bit before Jason hit the jackpot. Appium... Selenium for +Apps. + +## Sauce Labs and Node.js + +In January 2013, not long after the Mobile Testing Summit, Sauce Labs decided +to fully back Appium and provide more developer power. A task force was created +to evaluate the current state and how best to move forward with the project. +The team, which included Jonathan Lipps (the current project lead), decided +that Appium needed a rebirth, and ultimately settled on Node.js as the +framework to use. Node is well-known as a fast and efficient web server +backend, and at the end of the day, Appium is just a highly-specialized web +server. It was also decided that JavaScript as a language was accessible enough +that Appium would be able to grow into a larger community of open-source +developers with JavaScript than the other options on the table. + +In just a few days, the team leveraged the existing work on Appium and had +a new version of Appium with as much functionality as the previous Python +version. The foundation had been laid for Appium's basic architecture, and we +have been successfully building on it since. A few weeks into this sprint, +Jonathan Lipps was formally designated project lead and he began to strategize +how to get more people from the community involved with Appium's development. + +## Appium Around the World + +Ultimately, Jonathan decided that getting Appium in front of as many developers +at conferences and meetups was the best way to attract users and contributions. +Appium in its new incarnation was debuted at the Google Test Automation +Conference 2013. Later in 2013, +Appium was presented at conferences and meetups all around the US, as well as +in England, Poland, Portugal, and Australia. Notably, Jonathan had Appium +[perform as instruments in a band](https://www.youtube.com/watch?v=zsbNVkayYRQ) +and Dan Cuellar put together a fun Appium video +montage for Selenium Conference. + +But during all these presentations and conferences, the project continued to +develop. Early in 2013 we released Android and Selendroid support, making +Appium the first truly cross-platform automation framework. The project also +continued to attract users and contributors, and by the end of 2013, we'd +already had well over 1,000 commits. + +## The Road to Appium 1.0 + +Appium began to grow and mature significantly. In May 2014, +we released Appium 1.0, which stood as a milestone in Appium's development. +Appium was given +[various](https://www.prnewswire.com/news-releases/black-duck-announces-black-duck-open-source-rookies-of-the-year-winners-242383341.html) +[awards](https://www.infoworld.com/article/2241247/164642-bossie-awards-2014-the-best-open-source-application-development-tools.html) +and became the most popular open-source cross-platform mobile automation +framework. Stability improved, bugs were prioritized and fixed, and features +added. Sauce Labs increased the number of developers it donated to working +on Appium, but the entire community stayed involved in guiding the project and +contributing to it, and project governance continued to happen in the open, on +public mailing lists and GitHub's issue tracker. + +## The Appium Umbrella Broadens + +Eventually, it became clear that the Appium codebase was not optimized for +a large team of distributed, sometime contributors. We took the opportunity as +a committer team to rewrite Appium from the ground up, using a more modern +version of the JavaScript language, and redoing Appium's architecture so that +it was easy for users or third-party developers to build their own Appium +"drivers". We wanted for it to be easier for new contributors to get ramped up +on the Appium codebase, and to see support for new platforms added to Appium by +groups other than the core team. That vision has begun to be fulfilled, with +groups like Microsoft and Youi.tv adding drivers to Appium for Windows desktop +app automation and Youi.tv app automation, respectively. Who knows what +platforms will be added next? + +## Appium To The People + +In late 2016, Sauce Labs donated Appium as a project to the JS +Foundation, in order to cement for the world Sauce's +commitment that Appium remains open source. The JS Foundation is a non-profit +open source stewardship organization which takes responsibility for holding the +copyright for open source projects, as well as ensuring they have a long and +successful tenure in the community. As a result of our move to a non-profit +foundation, we hope that the door will open even more widely for new +contributors, either as individuals or representing one of the many companies +which now have an interest in seeing Appium move forward. + +Eventually, the JS Foundation merged into the [OpenJS Foundation](https://openjsf.org), and Appium +is currently an Impact Project in the foundation. + +## Appium 2.0 + +Appium 2 was released in 2023, with a new focus on Appium as an ecosystem rather than a singular +project. Drivers and plugins can be developed and shared by anyone, opening up a world of +possibilities for automation-related development for platforms far beyond iOS and Android. diff --git a/packages/appium/docs/ja/intro/index.md b/packages/appium/docs/ja/intro/index.md index 8262d52a7..6d30ad113 100644 --- a/packages/appium/docs/ja/intro/index.md +++ b/packages/appium/docs/ja/intro/index.md @@ -1,241 +1,38 @@ --- -title: Appiumについて +hide: + - toc +title: Appium in a Nutshell --- - +As mentioned on the main page, Appium aims to support UI automation of many _different platforms_ +(mobile, web, desktop, etc.). Not only that, but it also aims to support automation code written in +_different languages_ (JS, Java, Python, etc.). Combining all of this functionality in a single +program is a very daunting, if not impossible task! -「はじめに」でも言及したとおり、Appiumはオープンソースプロジェクトであり、多くのアプリケーションプラットフォームのUI自動化を助けるために設計された関係するソフトウェアのエコシステムです。Appium 2.0のリリースにより、Appiumは以下の主要な目標を達成します:[^1] +In order to achieve this, Appium is effectively split into four parts: -- 標準化されたAPIにより、クロスプラットフォームながらもプラットフォーム固有の自動化を可能とする -- 様々なプログラミング言語からこのAPIを呼び出すことができる -- コミュニティ間で開発された便利なAppium拡張(Appium extensions)を利用できるようになる +
- +
-[^1]: - これらの主要な目的達成のため、私たちは二次的な目標や原則に沿っています。Appium拡張(Appium extension)の開発者にも同様に推奨するものです。 +Therefore, in order to start automating something with Appium, you need to: - - 可能な限り、オープンソースを活用し、オープンソースに貢献もする - - 可能な限り、開発元から提供されるプラットフォーム固有のツールを使用する - - 可能な限り、テスト対象に変更を必要としない自動化ツールを使用する(専用ビルドを必要とするような追加のSDKやテスト対象版と製品版とで差異があることは好ましくない) - - 可能な限り、新しい独自のものを作るより既にある標準のものを使う +- Install Appium itself +- Install a driver for your target platform +- Install a client library for your target programming language +- (Optional) install one or more plugins - +These are the basics! If you are ready to jump in, proceed with the [Quickstart](../quickstart/index.md)! -したがって、iOSやAndroidといったいかなるアプリプラットフォームに対しても、Appiumは開発者やテスターにそのプラットフォームにおけるUI自動化コードを一つの統一されたAPIで記述できるようにします。 +If you wish to learn more details about how it all works, see these pages for background material: - - -Appiumの目標を実現するために私たちは多くの疑問に答える必要があります。 - -- "一つの統一された" APIとは何か? -- どのように私たちはそのAPIを特定のプラットフォームにおける自動化としての振る舞いに対応させているか? -- どのように私たちは複数のよく知られるプログラミング言語から利用可能にしているか? - - - -iOSとAndroidだけでなくより多くのアプリプラットフォームが存在していることを考えると、その背景には別の、より大きな疑問が潜んでいます。 - -- どのようにして*全ての*プラットフォームに対して自動化を実現するか? - -これらの疑問へのAppiumの答えを知ることは、Appiumが何かを学ぶ最短の方法ではないかもしれませんが、確かな道になります。では、見ていきましょう。 - -## Appium's choice of API - -Appium is very fortunate to have been preceded by a technology which has been a long-standing -pioneer in the field of UI automation, namely [Selenium](https://seleniumhq.org). The goal of the -Selenium project has been to support UI automation of web browsers, and in this way we can think of -it as occupying a subset of Appium's goals. Along the way, Selenium (and, after they merged, -another project called WebDriver) developed a relatively stable API for browser automation. - -Over the years, Selenium worked with various web browser vendors and the [W3C](https://w3c.org) -standards group to turn its API into an official web browser standard, called the [WebDriver -specification](https://w3c.github.io/webdriver/webdriver-spec.html). 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! - -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. - -[^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. - -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: - -- 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. - -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. - -## 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](./drivers.md) which you can read next, so we won't go into huge detail on how they -work for now. - -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](https://github.com/appium/appium-xcuitest-driver) because ultimately what it does is -convert the WebDriver protocol to XCUITest library calls. - -One of the reasons that drivers are independent, pluggable modules is that they work completely -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](../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. - -[^3]: You can build and share your own drivers! Check out [Building - Drivers](../ecosystem/build-drivers.md) to learn more about how to develop drivers in Node.js - that can be used with 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. - -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. - -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. - -There are a couple important takeaways here for you, the Appium user: - -- 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. - -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's huge scope - -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". - -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.0, is to provide tools to empower the community to join in our vision: - -- 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!). - -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.0, Appium has released a plugin system that -enables anyone to build and share modules that change how Appium works! - -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](../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` -plugin](https://github.com/appium/appium/tree/2.0/packages/images-plugin)). There are very few -limitations on what you can do with plugins, so you might also be interested in learning how to -[Build Plugins](../ecosystem/build-plugins.md) in Node.js that can be used with 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. +Finally, to learn about the origins of Appium, check out the [Appium Project History](./history.md). diff --git a/packages/appium/docs/ja/quickstart/index.md b/packages/appium/docs/ja/quickstart/index.md new file mode 100644 index 000000000..75a91217c --- /dev/null +++ b/packages/appium/docs/ja/quickstart/index.md @@ -0,0 +1,22 @@ +--- +hide: + - toc +title: "クイックスタート: はじめに" +--- + +さっそくAppiumを使ってみましょう! このクイックスタートをうまく使うために、[はじめに](../intro/index.md)を読み、Appiumの実行やスクリプトの記述に関わる概念を理解することをお勧めします。 + +このクイックスタートは以下の通り進めます: + +1. Appiumをインストールする +2. Appiumドライバーとその依存関係をインストールする + - このガイドでは、[UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver) について説明します +3. お好みの言語でAppiumクライアント・ライブラリをインストールする + - このガイドでは、JavaScript、Python、Java、Ruby、.NETの例で説明します +4. サンプルアプリケーションを使用した簡単なAppiumでの自動化スクリプトの作成と実行 + +### 必要条件 + +始める前に、お使いのシステムが[要件](../quickstart/requirements.md) を満たしていることを確認してください。 追加要件については、UiAutomator2 ドライバーのインストールと合わせて説明します。 また、このガイドでは基本的なコマンド実行や環境変数の設定と保持などができることを前提としています。 + +さあ、これで準備は整いました! [Appiumのインストール](./install.md)に進んでください。 diff --git a/packages/appium/docs/ja/quickstart/install.md b/packages/appium/docs/ja/quickstart/install.md new file mode 100644 index 000000000..f5bc3d713 --- /dev/null +++ b/packages/appium/docs/ja/quickstart/install.md @@ -0,0 +1,46 @@ +--- +hide: + - toc +title: Appiumをインストールする +--- + +!!! info + +``` +インストールする前に[システム要件](./requirements.md)を満たしているか確認してください。 +``` + +Appium は `npm` を使用してグローバルにインストールできます: + +```bash +npm install -g appium +``` + +!!! note + +``` +他のパッケージマネージャーは現在サポートされていません。 +``` + +## Appiumを実行する + +Appiumは [コマンドラインを使用して](../cli/index.md)始めることができます: + +``` +appium +``` + +このコマンドはインストールされているAppiumドライバーをすべて読み込むAppiumサーバープロセスを起動し、クライアント接続(テスト自動化スクリプトなど)から新規セッションの開始要求を待ちます。 +サーバープロセスはクライアントから独立しているため、新しいセッションを開始する前に明示的に起動する必要があります。 + +サーバーが起動すると、コンソールログに、クライアントがこのサーバーに接続するために使用できる有効なURLがすべてリストされます: + +``` +[Appium] You can provide the following URLs in your client code to connect to this server: +[Appium] http://127.0.0.1:4723/ (only accessible from the same host) +(... any other URLs ...) +``` + +クライアントが新規セッションを要求すると、Appium サーバープロセスは、このセッションが終了するまで、このセッションに関するすべての詳細のログ記録を開始します。 覚えておいてください。Appium テストで問題が発生した場合は、いつでもサーバー ログで詳細を確認できます。 + +次は何でしょうか? Appium はインストールされて実行されていますが、ドライバーがバンドルされていないため、まだ何も自動化できません。 そこで、Android向けに自動化を設定します。[Installing the UiAutomator2 Driver](./uiauto2-driver.md)へ続く。 diff --git a/packages/appium/docs/ja/quickstart/next-steps.md b/packages/appium/docs/ja/quickstart/next-steps.md new file mode 100644 index 000000000..48304c15b --- /dev/null +++ b/packages/appium/docs/ja/quickstart/next-steps.md @@ -0,0 +1,22 @@ +--- +hide: + - toc +title: Next Steps +--- + +Now that you've successfully set up your system for Android automation and run a simple test, +you'll want to continue exploring this documentation. In particular, these are good guides and +reference materials especially for beginners: + +- The [Ecosystem](../ecosystem/index.md) page: browse the available drivers, clients, plugins, and tools +- [Managing Appium Drivers and Plugins](../guides/managing-exts.md) +- [Capabilities](../guides/caps.md) +- [Settings](../guides/settings.md) + +You'll also find that the [Appium Inspector](https://github.com/appium/appium-inspector) is an +indispensable tool for writing Appium tests, as it enables visual inspection of apps and +helps you to discover element locators for use in your test scripts. + +You might also take advantage of one of the many online Appium courses available to you. + +Good luck and have fun! diff --git a/packages/appium/docs/ja/quickstart/requirements.md b/packages/appium/docs/ja/quickstart/requirements.md new file mode 100644 index 000000000..9f983719e --- /dev/null +++ b/packages/appium/docs/ja/quickstart/requirements.md @@ -0,0 +1,28 @@ +--- +hide: + - toc +title: System Requirements +--- + +The basic requirements for the Appium server are: + +- A macOS, Linux, or Windows operating system +- [Node.js](https://nodejs.org) version in the [SemVer](https://semver.org) range `^14.17.0 || ^16.13.0 || >=18.0.0` + - LTS is recommended +- [`npm`](https://npmjs.com) version `>=8` (`npm` is usually bundled with Node.js, but can be upgraded + independently) + +By itself, Appium is relatively lightweight and doesn't have significant disk space or RAM +requirements. It can even be run in resource-constrained environments like Raspberry Pi, so long as +Node.js is available. + +### Driver Requirements + +Drivers for automating specific platforms will likely have other requirements. Refer to the +documentation of the [Appium driver(s)](../ecosystem/drivers.md) for that platform for additional +dependencies. It is almost universally the case that Appium drivers for a given platform will +require the developer toolchain and SDKs for that platform to be installed. + +In order to assist with driver requirements, each (official) driver comes with the Appium Doctor tool, +which allows to verify if all requirements have been set up. Learn more about how to use this tool in +the [Command-Line Usage documentation](../cli/extensions.md#doctor). diff --git a/packages/appium/docs/ja/quickstart/test-dotnet.md b/packages/appium/docs/ja/quickstart/test-dotnet.md new file mode 100644 index 000000000..b198cbf45 --- /dev/null +++ b/packages/appium/docs/ja/quickstart/test-dotnet.md @@ -0,0 +1,106 @@ +--- +hide: + - toc +title: Write a Test (.NET) +--- + +The [Appium .NET Client](https://github.com/appium/dotnet-client/) is +an official Appium client in C#. This driver is an extension of the Selenium C# client. It has all the functionalities of the regular driver, but add Appium-specific methods on top of this. The driver is available on the public NuGet Gallery as [Appium.WebDriver](https://www.nuget.org/packages/Appium.WebDriver/). + +Now, we get inside the directory and create a new [NUnit](https://nunit.org/) project. We will also add the references to the Appium.Net driver, and other dependencies. + +```bash +cd dotnet-client +dotnet new nunit --name appiumtest + +cd appiumtest + +# This will install the latest 5.x version +dotnet add package Appium.WebDriver --prerelease +dotnet add package Newtonsoft.Json --version 13.0.3 +``` + +Once this is done, your project should have a placeholder file `UnitTest1.cs`. We will replace the code to include the OpenQA namespaces, an initialization of the driver, and the actual test. + +```C# title="UnitTest1.cs" +using OpenQA.Selenium; +using OpenQA.Selenium.Appium; +using OpenQA.Selenium.Appium.Android; +using OpenQA.Selenium.Appium.Enums; + +namespace appiumtest; + +public class Tests +{ + private AndroidDriver _driver; + + [OneTimeSetUp] + public void SetUp() + { + var serverUri = new Uri(Environment.GetEnvironmentVariable("APPIUM_HOST") ?? "http://127.0.0.1:4723/"); + var driverOptions = new AppiumOptions() { + AutomationName = AutomationName.AndroidUIAutomator2, + PlatformName = "Android", + DeviceName = "Android Emulator", + }; + + driverOptions.AddAdditionalAppiumOption("appPackage", "com.android.settings"); + driverOptions.AddAdditionalAppiumOption("appActivity", ".Settings"); + // NoReset assumes the app com.google.android is preinstalled on the emulator + driverOptions.AddAdditionalAppiumOption("noReset", true); + + _driver = new AndroidDriver(serverUri, driverOptions, TimeSpan.FromSeconds(180)); + _driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10); + } + + [OneTimeTearDown] + public void TearDown() + { + _driver.Dispose(); + } + + [Test] + public void TestBattery() + { + _driver.StartActivity("com.android.settings", ".Settings"); + _driver.FindElement(By.XPath("//*[@text='Battery']")).Click(); + } +} +``` + +!!! note + +``` +It's not within the scope of this guide to give a complete run-down on the dotnet client +library or everything that's happening here, so we'll leave the code itself unexplained in +detail for now. You may want to read up particularly on Appium +[Capabilities](../guides/caps.md) in addition to familiarizing yourself with the +[dotnet client driver documentation](https://github.com/appium/dotnet-client/) for a fuller explanation +of the various API commands you see and what their purpose is. +``` + +Basically, this code is doing the following: + +1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what + kind of thing you want to automate. Some of these parameters can be overriden using environment variables. +2. Starting an Appium session on the built-in Android settings app. +3. Finding the "Battery" list item and clicking it. +4. Ending the Appium session. + +That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server +running in another terminal session, otherwise you'll get an error about not being able to connect +to one. Then, you can execute the script: + +```bash +dotnet test + +# Example output: +# Starting test execution, please wait... +# A total of 1 test files matched the specified pattern. + +# Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: 323 ms - appiumtest.dll (net7.0) +``` + +If all goes well, you'll see the Settings app open up and navigate to the "Battery" view in the emulator before the app closes again. + +Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore. diff --git a/packages/appium/docs/ja/quickstart/test-java.md b/packages/appium/docs/ja/quickstart/test-java.md new file mode 100644 index 000000000..4fe57ed3a --- /dev/null +++ b/packages/appium/docs/ja/quickstart/test-java.md @@ -0,0 +1,22 @@ +--- +hide: + - toc +title: Write a Test (Java) +--- + +The Appium team maintains an official [client](https://github.com/appium/java-client) for the Java programming language. +It is built on top of [Selenium](https://github.com/SeleniumHQ/selenium). +You can also use this client in your Kotlin projects. + +Follow the [Add Appium java client to your test framework](https://github.com/appium/java-client#add-appium-java-client-to-your-test-framework) +tutorial in order to connect the library to your test framework sources. + +The Appium Java client has dedicated classes to support most of the official Appium drivers. For other drivers +you could simply use the [AppiumDriver](https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/AppiumDriver.java) class +or build your custom derivatives from it. Check the [Drivers Support](https://github.com/appium/java-client#drivers-support) +article to learn more about the current driver class implementations. + +Follow the [Usage Examples](https://github.com/appium/java-client#usage-examples) article in order understand +how to invoke Java client features from your test framework. + +Once you've managed to successfully run a test, you can read on for some [next steps](./next-steps.md) to explore. \ No newline at end of file diff --git a/packages/appium/docs/ja/quickstart/test-js.md b/packages/appium/docs/ja/quickstart/test-js.md new file mode 100644 index 000000000..f297d76ab --- /dev/null +++ b/packages/appium/docs/ja/quickstart/test-js.md @@ -0,0 +1,76 @@ +--- +hide: + - toc +title: Write a Test (JS) +--- + +To write an Appium test in JavaScript (Node.js), we need to choose an Appium-compatible client +library. The best-maintained library and the one the Appium team recommends using is +[WebdriverIO](https://webdriver.io), so let's use that. Since we already have Appium installed we +know our Node and NPM requirements are already satisfied. So just create a new project directory +somewhere on your computer and then initialize a new Node.js project in it: + +```bash +npm init +``` + +It doesn't really matter what you put in the prompts, just so long as you end up with a valid +`package.json`. + +Now, install the `webdriverio` package via NPM: + +```bash +npm i --save-dev webdriverio +``` + +Once this is done, your `package.json` file should include a section like the following: + +```json title="package.json" +--8<-- "./sample-code/quickstarts/js/package.json" +``` + +Now it's time to type up the test itself. Create a new file called `test.js` with the following +contents: + +```js title="test.js" +--8<-- "./sample-code/quickstarts/js/test.js" +``` + +!!! note + +``` +It's not within the scope of this guide to give a complete run-down on the WebdriverIO client +library or everything that's happening here, so we'll leave the code itself unexplained in +detail for now. You may want to read up particularly on Appium +[Capabilities](../guides/caps.md) in addition to familiarizing yourself with the excellent +[WebdriverIO documentation](https://webdriver.io/docs/gettingstarted) for a fuller explanation +of the various API commands you see and what their purpose is. +``` + +!!! note + +``` +The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/js). +``` + +Basically, this code is doing the following: + +1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what + kind of thing you want to automate. +2. Starting an Appium session on the built-in Android settings app. +3. Finding the "Battery" list item and clicking it. +4. Pausing for a moment purely for visual effect. +5. Ending the Appium session. + +That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server +running in another terminal session, otherwise you'll get an error about not being able to connect +to one. Then, you can execute the script: + +```bash +node test.js +``` + +If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the +app closes again. + +Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore. diff --git a/packages/appium/docs/ja/quickstart/test-py.md b/packages/appium/docs/ja/quickstart/test-py.md new file mode 100644 index 000000000..accf08cbf --- /dev/null +++ b/packages/appium/docs/ja/quickstart/test-py.md @@ -0,0 +1,62 @@ +--- +hide: + - toc +title: Write a Test (Python) +--- + +The [Appium Python Client](https://github.com/appium/python-client) is +an official Appium client in Python, which is available via pypi under the [Appium-Python-Client](https://pypi.org/project/Appium-Python-Client/) package name. +It inherits from the [Selenium Python Binding](https://pypi.org/project/selenium/), +so installing the Appium Python Client includes the selenium binding. + +```bash +pip install Appium-Python-Client +``` + +This example uses Python's built-in `unittest` module, though you can use any Python test framework you want. +The Appium Python client adds the `appium:` vendor prefix automatically. +You usually do not need to worry about the prefix. + +```python title="test.py" +--8<-- "./sample-code/quickstarts/py/test.py" +``` + +!!! note + +``` +It's not within the scope of this guide to give a complete run-down on the Python client +library or everything that's happening here, so we'll leave the code itself unexplained in detail for now. + +- You may want to read up particularly on Appium [Capabilities](../guides/caps.md). +- [functional test code](https://github.com/appium/python-client/tree/master/test/functional) in Python Client GitHub repository should help to find more working example. +- [Documentation](https://appium.github.io/python-client-sphinx/) also helps to find methods +defined in the Appium Python Client. +``` + +!!! note + +``` +The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/py). +``` + +Basically, this code is doing the following: + +1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what + kind of thing you want to automate. +2. Starting an Appium session on the built-in Android settings app. +3. Finding the "Battery" list item and clicking it. +4. Pausing for a moment purely for visual effect. +5. Ending the Appium session. + +That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server +running in another terminal session, otherwise you'll get an error about not being able to connect +to one. Then, you can execute the script: + +```bash +python test.py +``` + +If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the +app closes again. + +Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore. diff --git a/packages/appium/docs/ja/quickstart/test-rb.md b/packages/appium/docs/ja/quickstart/test-rb.md new file mode 100644 index 000000000..2c4bd2fe3 --- /dev/null +++ b/packages/appium/docs/ja/quickstart/test-rb.md @@ -0,0 +1,84 @@ +--- +hide: + - toc +title: Write a Test (Ruby) +--- + +The [AppiumLib](https://github.com/appium/ruby_lib) and the [AppiumLibCore](https://github.com/appium/ruby_lib_core) (**recommended**) are official Appium client libraries in Ruby, which are available via gem under the [appium_lib](https://rubygems.org/gems/appium_lib) and the [appium_lib_core](https://rubygems.org/gems/appium_lib_core) package names. The appium_lib_core inherits from the Selenium Ruby Binding, and the appium_lib inherits from the appium_lib_core, so installing these libraries include the selenium binding. We recommend `appium_lib_core` if you need a less complex client-side solution. The `appium_lib` has some useful methods the core does not have, but for the cost of greater complexity and historical methods which may not work in the latest environment. + +As the first step, let's initialize a Gemfile to manage the dependency: + +```bash +bundle init +``` + +Then, you could add Appium Ruby Client dependency as below: + +```bash +bundle add appium_lib_core +# or +# bundle add appium_lib +``` + +Test code example below uses `test-unit` module, thus please run: + +```bash +bundle add test-unit +``` + +Once these steps has done, your `Gemfile` file should include: + +```ruby title="Gemfile" +--8<-- "./sample-code/quickstarts/rb/Gemfile" +``` + +The `appium_lib_core` is the main part as an Appium client. +`appium_lib` has various helper methods, but the driver instance was ordinary designed to be used as a global variable. It could causes an issue to handle the instance. +`appium_lib_core` does not have such a global variable. + +This example is by the `appium_lib_core` with `test-unit` gem module. +Tes code in `appium_lib` should be similar. + +```ruby title="test.rb" +--8<-- "./sample-code/quickstarts/rb/test.rb" +``` + +!!! note + +``` +It's not within the scope of this guide to give a complete run-down on the Ruby client +library or everything that's happening here, so we'll leave the code itself unexplained in detail for now. + +- You may want to read up particularly on Appium [Capabilities](../guides/caps.md). +- [functional test code](https://github.com/appium/ruby_lib_core/tree/master/test/functional) in the appium_lib_core GitHub repository should help to find more working example. +- Documentation [appium_lib_core](https://www.rubydoc.info/github/appium/ruby_lib_core) and [appium_lib](https://www.rubydoc.info/github/appium/ruby_lib) also helps to find available methods. +``` + +!!! note + +``` +The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/rb). +``` + +Basically, this code is doing the following: + +1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what + kind of thing you want to automate. +2. Starting an Appium session on the built-in Android settings app. +3. Finding the "Battery" list item and clicking it. +4. Pausing for a moment purely for visual effect. +5. Ending the Appium session. + +That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server +running in another terminal session, otherwise you'll get an error about not being able to connect +to one. Then, you can execute the script: + +```bash +# Please run "bundle install" first if your environment has not run the installation command yet. +bundle exec ruby test.rb +``` + +If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the +app closes again. + +Congratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore. diff --git a/packages/appium/docs/ja/quickstart/uiauto2-driver.md b/packages/appium/docs/ja/quickstart/uiauto2-driver.md new file mode 100644 index 000000000..92c36b9d2 --- /dev/null +++ b/packages/appium/docs/ja/quickstart/uiauto2-driver.md @@ -0,0 +1,148 @@ +--- +title: Install the UiAutomator2 Driver +--- + +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. + +!!! 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). +``` + +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. + +## Set up Android automation requirements + +According to the driver, in addition to a working Appium server, we also need to set up the following: + +### 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. + +### 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. + +### 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. + +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. + +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! + +## Install the driver itself + +### Standard Install + +Like all Appium drivers, the UiAutomator2 driver is installed via the [Appium Extension CLI](../cli/extensions.md). +Since UiAutomator2 is maintained by the core Appium team, it has an 'official' driver name +(`uiautomator2`), which makes the installation simpler. + +Before installing, make sure your Appium server is _not_ running (if it is, quit it with _Ctrl-C_). +Then run the following command: + +```bash +appium driver install uiautomator2 +``` + +It should produce output that looks something like: + +``` +Attempting to find and install driver 'uiautomator2' +✔ Installing 'uiautomator2' using NPM install spec 'appium-uiautomator2-driver' +Driver uiautomator2@2.0.5 successfully installed +- automationName: UiAutomator2 +- 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`). + +!!! note + +``` +In this quickstart we have used the [Extension CLI](../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). +``` + +### Batch Install + +You may want to use Appium with more than one driver. One way to accomplish this is to run +`appium driver install ` for each individual driver, but you can also install multiple +drivers in one go: + +``` +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). + +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](../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: + +``` +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! + +Now, start the Appium server again (run `appium`), and you should see that the newly-installed +driver is listed as available: + +``` +[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: + +
+ +- :material-language-javascript: [**JavaScript**](./test-js.md) +- :material-language-java: [**Java**](./test-java.md) +- :material-language-python: [**Python**](./test-py.md) +- :material-language-ruby: [**Ruby**](./test-rb.md) +- :material-dot-net: [**.NET C#**](./test-dotnet.md) + +
diff --git a/packages/appium/docs/ja/resources.md b/packages/appium/docs/ja/resources.md new file mode 100644 index 000000000..d333212a5 --- /dev/null +++ b/packages/appium/docs/ja/resources.md @@ -0,0 +1,19 @@ +--- +hide: + - navigation + - toc +title: Additional Resources +--- + +Here you can find links to additional Appium resources around the web: + +## Websites + +- [Appium Pro](https://appiumpro.com) - a blog and newsletter written by one of Appium's + maintainers, Jonathan Lipps, with lots of useful guides + +## Online Courses + +- [Appium and Selenium Fundamentals](https://ui.headspin.io/university/learn/appium-selenium-fundamentals-2020) - a comprehensive video course on learning Python, Selenium, and Appium by Jonathan Lipps +- [Mobile Test Automation with Appium](https://testautomationu.applitools.com/appium-java-tutorial/) - a video course by Moataz Nabil +- [Advanced Appium](https://www.linkedin.com/learning/advanced-appium) - a video course by Jonathan Lipps diff --git a/packages/appium/docs/ja/sponsors.md b/packages/appium/docs/ja/sponsors.md new file mode 100644 index 000000000..b059fe9b5 --- /dev/null +++ b/packages/appium/docs/ja/sponsors.md @@ -0,0 +1,59 @@ +--- +hide: + - navigation + - toc +title: Sponsors & Backers +--- + + + +Appium is an Apache-2 licensed open source project whose development is made possible entirely by +donations of time and money by individuals and companies who benefit from our software and our +mission. If you'd like to join this amazing group and help ensure Appium's continued development +and maintenance, you can contribute via Appium's OpenCollective +Hub. + +## Development Partners + +We are very grateful for the support of our Development Partners, who donate Appium development and +maintenance as part of their employees' core job duties! + +## Strategic Partners + +We are very grateful for the financial and marketing support of our exclusive Strategic Partners, +who contribute a significant ongoing investment of funds to help the project attract and reward +contributors! + + + + + + Browserstack + + + +## Gold Sponsors + + + +[Become a Gold Sponsor](https://opencollective.com/appium/contribute/gold-sponsor-72877/checkout?interval=month&amount=500&contributeAs=me) + +## Silver Sponsors + + + +[Become a Silver Sponsor](https://opencollective.com/appium/contribute/silver-sponsor-72876/checkout?interval=month&amount=250&contributeAs=me) + +## Bronze Sponsors + + + +[Become a Bronze Sponsor](https://opencollective.com/appium/contribute/sponsors-70690/checkout?interval=month&amount=100&contributeAs=me) diff --git a/packages/appium/docs/mkdocs-ja.yml b/packages/appium/docs/mkdocs-ja.yml index ed8ece0c3..a0f2e4299 100644 --- a/packages/appium/docs/mkdocs-ja.yml +++ b/packages/appium/docs/mkdocs-ja.yml @@ -1,21 +1,81 @@ INHERIT: ./base-mkdocs.yml site_url: https://appium.io/docs/ja edit_uri: edit/master/packages/appium/docs/ja -site_description: The Appium automation project documentation +site_description: Appium 自動化プロジェクトのドキュメント docs_dir: ja site_dir: site/docs/ja theme: language: ja nav: - - はじめに: index.md - - 導入: - - Appiumについて: - - Appiumの全体像: intro/index.md - - Command Reference: - - ../en/commands/base-driver.md - - ../en/commands/execute-driver-plugin.md - - ../en/commands/images-plugin.md - - ../en/commands/relaxed-caps-plugin.md - - ../en/commands/universal-xml-plugin.md - - 手引き: - - guides/migrating-1-to-2.md + - ようこそ: index.md + - ブログ: blog/index.md + - はじめに: + - intro/index.md + - 背景: + - intro/appium.md + - intro/drivers.md + - intro/clients.md + - intro/history.md + - クイックスタート: + - quickstart/index.md + - quickstart/requirements.md + - quickstart/install.md + - quickstart/uiauto2-driver.md + - テストを書く: + - quickstart/test-js.md + - quickstart/test-py.md + - quickstart/test-java.md + - quickstart/test-rb.md + - quickstart/test-dotnet.md + - quickstart/next-steps.md + - エコシステム: + - ecosystem/index.md + - ecosystem/drivers.md + - ecosystem/clients.md + - ecosystem/plugins.md + - ecosystem/tools.md + - CLI リファレンス: + - cli/index.md + - cli/args.md + - cli/env-vars.md + - cli/extensions.md + - cli/setup.md + - コマンドリファレンス: + - commands/index.md + - commands/base-driver.md + - commands/execute-driver-plugin.md + - commands/images-plugin.md + - commands/relaxed-caps-plugin.md + - commands/storage-plugin.md + - commands/universal-xml-plugin.md + - ガイド: + - 移行: + - guides/migrating-1-to-2.md + - サーバ/ドライバの設定: + - guides/managing-exts.md + - guides/branch-testing.md + - guides/config.md + - guides/security.md + - guides/log-filters.md + - guides/headers.md + - guides/grid.md + - guides/caching.md + - guides/tls.md + - セッションに関わる設定: + - guides/caps.md + - guides/settings.md + - guides/execute-methods.md + - guides/context.md + - guides/event-timing.md + - 他のリソース: resources.md + - 開発: + - developing/index.md + - developing/build-drivers.md + - developing/build-plugins.md + - developing/build-docs.md + - developing/build-doctor-checks.md + - developing/sensitive.md + - 開発者リファレンス: + - developing/config-system.md + - 貢献: contributing.md + - スポンサー: sponsors.md diff --git a/packages/appium/docs/overrides/assets/images/sponsor-logo-route4me.png b/packages/appium/docs/overrides/assets/images/sponsor-logo-route4me.png deleted file mode 100644 index 46df6d2f8..000000000 Binary files a/packages/appium/docs/overrides/assets/images/sponsor-logo-route4me.png and /dev/null differ diff --git a/packages/appium/lib/cli/driver-command.js b/packages/appium/lib/cli/driver-command.js index 23ec75212..006aa9d63 100644 --- a/packages/appium/lib/cli/driver-command.js +++ b/packages/appium/lib/cli/driver-command.js @@ -109,7 +109,7 @@ export default class DriverCliCommand extends ExtensionCliCommand { if (!_.isEmpty(missingFields)) { throw new Error( - `Driver "${installSpec}" did not expose correct fields for compability ` + + `Driver "${installSpec}" did not expose correct fields for compatibility ` + `with Appium. Missing fields: ${JSON.stringify(missingFields)}` ); } diff --git a/packages/appium/lib/cli/extension-command.js b/packages/appium/lib/cli/extension-command.js index 51f28edda..d28e9972a 100644 --- a/packages/appium/lib/cli/extension-command.js +++ b/packages/appium/lib/cli/extension-command.js @@ -333,7 +333,7 @@ class ExtensionCliCommand { // contain the '@' symbol, as in `npm install @appium/fake-driver@1.2.0` let name; const splits = installSpec.split('@'); - if (installSpec[0] === '@') { + if (installSpec.startsWith('@')) { // this is the case where we have an npm org included in the package name [name, pkgVer] = [`@${splits[1]}`, splits[2]]; } else { diff --git a/packages/appium/lib/cli/parser.js b/packages/appium/lib/cli/parser.js index e6f712879..2a607c26a 100644 --- a/packages/appium/lib/cli/parser.js +++ b/packages/appium/lib/cli/parser.js @@ -31,7 +31,7 @@ export const EXTRA_ARGS = 'extraArgs'; /** * If the parsed args do not contain any of these values, then we - * will automatially inject the `server` subcommand. + * will automatically inject the `server` subcommand. */ const NON_SERVER_ARGS = Object.freeze( new Set([SETUP_SUBCOMMAND, DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND, '-h', '--help', '-v', '--version']) diff --git a/packages/appium/lib/cli/plugin-command.js b/packages/appium/lib/cli/plugin-command.js index 031c69d25..efa0e2aaa 100644 --- a/packages/appium/lib/cli/plugin-command.js +++ b/packages/appium/lib/cli/plugin-command.js @@ -105,7 +105,7 @@ export default class PluginCliCommand extends ExtensionCliCommand { if (!_.isEmpty(missingFields)) { throw new Error( - `Installed plugin "${installSpec}" did not expose correct fields for compability ` + + `Installed plugin "${installSpec}" did not expose correct fields for compatibility ` + `with Appium. Missing fields: ${JSON.stringify(missingFields)}` ); } diff --git a/packages/appium/lib/extension/extension-config.js b/packages/appium/lib/extension/extension-config.js index 098f7b266..874dfc2b6 100644 --- a/packages/appium/lib/extension/extension-config.js +++ b/packages/appium/lib/extension/extension-config.js @@ -464,7 +464,7 @@ export class ExtensionConfig { */ // eslint-disable-next-line @typescript-eslint/no-unused-vars getConfigProblems(extManifest, extName) { - // shoud override this method if special validation is necessary for this extension type + // should override this method if special validation is necessary for this extension type return []; } diff --git a/packages/appium/lib/main.js b/packages/appium/lib/main.js index b646d32d7..8584b3326 100755 --- a/packages/appium/lib/main.js +++ b/packages/appium/lib/main.js @@ -177,7 +177,7 @@ function determineAppiumHomeSource(appiumHomeFromArgs) { * * @template {CliCommand} [Cmd=ServerCommand] * @template {CliExtensionSubcommand|void} [SubCmd=void] - * @param {Args} [args] - Partial args (progammatic usage only) + * @param {Args} [args] - Partial args (programmatic usage only) * @returns {Promise>} * @example * import {init, getSchema} from 'appium'; diff --git a/packages/appium/lib/schema/cli-args.js b/packages/appium/lib/schema/cli-args.js index a6808012a..53f39a86d 100644 --- a/packages/appium/lib/schema/cli-args.js +++ b/packages/appium/lib/schema/cli-args.js @@ -1,6 +1,6 @@ import {ArgumentTypeError} from 'argparse'; import _ from 'lodash'; -import {formatErrors as formatErrors} from '../config-file'; +import {formatErrors} from '../config-file'; import {flattenSchema, validate} from './schema'; import {transformers, parseCsvLine} from './cli-transformers'; @@ -225,7 +225,7 @@ function subSchemaToArgDef(subSchema, argSpec) { * ArgumentDefinitions for handoff to `argparse`. * * @throws If schema has not been added to ajv (via `finalizeSchema()`) - * @returns {import('../cli/args').ArgumentDefinitions} A map of arryas of + * @returns {import('../cli/args').ArgumentDefinitions} A map of arrays of * aliases to `argparse` arguments; empty if no schema found */ export function toParserArgs() { diff --git a/packages/appium/lib/schema/schema.js b/packages/appium/lib/schema/schema.js index 17042b15f..563fd40f6 100644 --- a/packages/appium/lib/schema/schema.js +++ b/packages/appium/lib/schema/schema.js @@ -421,7 +421,7 @@ class AppiumSchema { * name. Used when translating to `argparse` options or getting the list of * default values (see {@link AppiumSchema.getDefaults}) for CLI or otherwise. * - * The return value is an intermediate reprsentation used by `cli-args` + * The return value is an intermediate representation used by `cli-args` * module's `toParserArgs`, which converts the finalized schema to parameters * used by `argparse`. * @throws If {@link AppiumSchema.finalize} has not been called yet. diff --git a/packages/appium/lib/utils.js b/packages/appium/lib/utils.js index 93f86f043..85291aa4a 100644 --- a/packages/appium/lib/utils.js +++ b/packages/appium/lib/utils.js @@ -344,7 +344,7 @@ export function isPluginCommandArgs(args) { * * @param {4|6|null} family Either 4 to include ipv4 addresses only, * 6 to include ipv6 addresses only, or null to include all of them - * @returns {os.NetworkInterfaceInfo[]} The list of matched interfcaes + * @returns {os.NetworkInterfaceInfo[]} The list of matched interfaces */ export function fetchInterfaces (family = null) { let familyValue = null; diff --git a/packages/appium/package.json b/packages/appium/package.json index 0b2efaf69..fdd1b58a2 100644 --- a/packages/appium/package.json +++ b/packages/appium/package.json @@ -81,14 +81,14 @@ "ora": "5.4.1", "package-changed": "3.0.0", "resolve-from": "5.0.0", - "semver": "7.7.1", + "semver": "7.7.2", "source-map-support": "0.5.21", - "teen_process": "2.3.1", - "type-fest": "4.40.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", "winston": "3.17.0", "wrap-ansi": "7.0.0", - "ws": "8.18.1", - "yaml": "2.7.1" + "ws": "8.18.2", + "yaml": "2.8.0" }, "engines": { "node": "^20.9.0 || >=22.11.0", diff --git a/packages/appium/sample-code/quickstarts/js/package.json b/packages/appium/sample-code/quickstarts/js/package.json index 73c6b1ff2..e28f9e4ee 100644 --- a/packages/appium/sample-code/quickstarts/js/package.json +++ b/packages/appium/sample-code/quickstarts/js/package.json @@ -1,5 +1,5 @@ { "devDependencies": { - "webdriverio": "9.12.7" + "webdriverio": "9.14.0" } } diff --git a/packages/base-driver/lib/basedriver/capabilities.ts b/packages/base-driver/lib/basedriver/capabilities.ts index 05cb8d9ba..ab5a2d578 100644 --- a/packages/base-driver/lib/basedriver/capabilities.ts +++ b/packages/base-driver/lib/basedriver/capabilities.ts @@ -27,7 +27,7 @@ export type ParsedCaps = { }; export type ValidateCapsOpts = { /** if true, skip the presence constraint */ - skipPresenceConstraint?: boolean | undefined; + skipPresenceConstraint?: boolean; } /** @@ -375,7 +375,7 @@ export function promoteAppiumOptionsForObject(obj: NSCapa } if (isStandardCap(capName)) { throw new errors.SessionNotCreatedError( - `${PREFIXED_APPIUM_OPTS_CAP} must only contain vendor-specific capabilties. '${capName}' is unexpected` + `${PREFIXED_APPIUM_OPTS_CAP} must only contain vendor-specific capabilities. '${capName}' is unexpected` ); } return capName; diff --git a/packages/base-driver/lib/basedriver/commands/timeout.ts b/packages/base-driver/lib/basedriver/commands/timeout.ts index 2c4822681..293145881 100644 --- a/packages/base-driver/lib/basedriver/commands/timeout.ts +++ b/packages/base-driver/lib/basedriver/commands/timeout.ts @@ -79,7 +79,7 @@ const TimeoutCommands: ITimeoutCommands = { setImplicitWait(this: BaseDriver, ms: number) { this.implicitWaitMs = ms; this.log.debug(`Set implicit wait to ${ms}ms`); - if (this.managedDrivers && this.managedDrivers.length) { + if (this.managedDrivers?.length) { this.log.debug('Setting implicit wait on managed drivers'); for (const driver of this.managedDrivers) { if (_.isFunction(driver.setImplicitWait)) { @@ -92,7 +92,7 @@ const TimeoutCommands: ITimeoutCommands = { setNewCommandTimeout(this: BaseDriver, ms: number) { this.newCommandTimeoutMs = ms; this.log.debug(`Set new command timeout to ${ms}ms`); - if (this.managedDrivers && this.managedDrivers.length) { + if (this.managedDrivers?.length) { this.log.debug('Setting new command timeout on managed drivers'); for (const driver of this.managedDrivers) { if (_.isFunction(driver.setNewCommandTimeout)) { diff --git a/packages/base-driver/lib/basedriver/core.ts b/packages/base-driver/lib/basedriver/core.ts index f9d68baf9..53170a358 100644 --- a/packages/base-driver/lib/basedriver/core.ts +++ b/packages/base-driver/lib/basedriver/core.ts @@ -139,7 +139,7 @@ export class DriverCore { log.info( - `Appium HTTP server has been succesfully closed after ` + + `Appium HTTP server has been successfully closed after ` + `${timer.getDuration().asMilliSeconds.toFixed(0)}ms` ); clearTimeout(onTimeout); @@ -309,7 +309,7 @@ export function normalizeBasePath(basePath) { // likewise, ensure the path prefix does always START with /, unless the path // is empty meaning no base path at all - if (basePath !== '' && basePath[0] !== '/') { + if (basePath !== '' && !basePath.startsWith('/')) { basePath = `/${basePath}`; } diff --git a/packages/base-driver/lib/jsonwp-proxy/protocol-converter.js b/packages/base-driver/lib/jsonwp-proxy/protocol-converter.js index 3e9a565b3..2dae05abb 100644 --- a/packages/base-driver/lib/jsonwp-proxy/protocol-converter.js +++ b/packages/base-driver/lib/jsonwp-proxy/protocol-converter.js @@ -19,12 +19,12 @@ export const COMMAND_URLS_CONFLICTS = [ { commandNames: ['getWindowHandles', 'getWindowHandle'], jsonwpConverter(url) { - return /\/window$/.test(url) + return url.endsWith('/window') ? url.replace(/\/window$/, '/window_handle') : url.replace(/\/window\/handle(s?)$/, '/window_handle$1'); }, w3cConverter(url) { - return /\/window_handle$/.test(url) + return url.endsWith('/window_handle') ? url.replace(/\/window_handle$/, '/window') : url.replace(/\/window_handles$/, '/window/handles'); }, diff --git a/packages/base-driver/lib/jsonwp-proxy/proxy.js b/packages/base-driver/lib/jsonwp-proxy/proxy.js index c60e00ff3..b478ac15c 100644 --- a/packages/base-driver/lib/jsonwp-proxy/proxy.js +++ b/packages/base-driver/lib/jsonwp-proxy/proxy.js @@ -236,7 +236,7 @@ export class JWProxy { } this.log.debug(`Got response with status ${status}: ${truncateBody(data)}`); isResponseLogged = true; - const isSessionCreationRequest = /\/session$/.test(url) && method === 'POST'; + const isSessionCreationRequest = url.endsWith('/session') && method === 'POST'; if (isSessionCreationRequest) { if (status === 200) { this.sessionId = data.sessionId || (data.value || {}).sessionId; diff --git a/packages/base-driver/lib/protocol/routes.js b/packages/base-driver/lib/protocol/routes.js index bd86a903c..5104e8f02 100644 --- a/packages/base-driver/lib/protocol/routes.js +++ b/packages/base-driver/lib/protocol/routes.js @@ -406,7 +406,7 @@ export const METHOD_MAP = /** @type {const} */ ({ // #endregion // - // 3rd party vendor/protcol support + // 3rd party vendor/protocol support // // #region Selenium/Chromium browsers '/session/:sessionId/se/log': { diff --git a/packages/base-driver/package.json b/packages/base-driver/package.json index a38a542bc..14f22a70b 100644 --- a/packages/base-driver/package.json +++ b/packages/base-driver/package.json @@ -62,7 +62,7 @@ "path-to-regexp": "8.2.0", "serve-favicon": "2.5.0", "source-map-support": "0.5.21", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "optionalDependencies": { "spdy": "4.0.2" diff --git a/packages/base-driver/test/unit/basedriver/device-settings.spec.js b/packages/base-driver/test/unit/basedriver/device-settings.spec.js index cb2957f57..191c62ce0 100644 --- a/packages/base-driver/test/unit/basedriver/device-settings.spec.js +++ b/packages/base-driver/test/unit/basedriver/device-settings.spec.js @@ -24,7 +24,7 @@ describe('DeviceSettings', function () { }); describe('constructor', function () { - describe('when no parameteres are provided to the constructor', function () { + describe('when no parameters are provided to the constructor', function () { it('should not throw', function () { expect(() => new DeviceSettings()).not.to.throw(); }); diff --git a/packages/docutils/lib/validate.ts b/packages/docutils/lib/validate.ts index 08155b855..5467d911e 100644 --- a/packages/docutils/lib/validate.ts +++ b/packages/docutils/lib/validate.ts @@ -59,7 +59,7 @@ export type ValidationKind = typeof NAME_PYTHON | typeof NAME_MKDOCS; export class DocutilsValidator extends EventEmitter { /** * Current working directory. Defaults to `process.cwd()` - * @todo This cannot yet be overriden by user + * @todo This cannot yet be overridden by user */ protected readonly cwd: string; diff --git a/packages/docutils/package.json b/packages/docutils/package.json index d00c883c0..d71c075ca 100644 --- a/packages/docutils/package.json +++ b/packages/docutils/package.json @@ -51,15 +51,15 @@ "@appium/support": "^6.1.0", "chalk": "4.1.2", "consola": "3.4.2", - "diff": "7.0.0", + "diff": "8.0.02", "lilconfig": "3.1.3", "lodash": "4.17.21", "pkg-dir": "5.0.0", "read-pkg": "5.2.0", "source-map-support": "0.5.21", - "teen_process": "2.3.1", - "type-fest": "4.40.1", - "yaml": "2.7.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", + "yaml": "2.8.0", "yargs": "17.7.2", "yargs-parser": "21.1.1" }, diff --git a/packages/docutils/requirements.txt b/packages/docutils/requirements.txt index 9cea8f126..e1e4f4851 100644 --- a/packages/docutils/requirements.txt +++ b/packages/docutils/requirements.txt @@ -1,5 +1,5 @@ mkdocs==1.6.1 -mkdocs-git-revision-date-localized-plugin==1.4.5 -mkdocs-material==9.6.12 +mkdocs-git-revision-date-localized-plugin==1.4.6 +mkdocs-material==9.6.14 mkdocs-redirects==1.2.2 mike==2.1.3 diff --git a/packages/driver-test-support/package.json b/packages/driver-test-support/package.json index c8ba78c97..305724582 100644 --- a/packages/driver-test-support/package.json +++ b/packages/driver-test-support/package.json @@ -50,7 +50,7 @@ "lodash": "4.17.21", "sinon": "20.0.0", "source-map-support": "0.5.21", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "peerDependencies": { "appium": "^2.0.0-beta.43 || ^3.0.0-beta.0", diff --git a/packages/execute-driver-plugin/package.json b/packages/execute-driver-plugin/package.json index 8b172f6ff..61f5864fd 100644 --- a/packages/execute-driver-plugin/package.json +++ b/packages/execute-driver-plugin/package.json @@ -41,7 +41,7 @@ "bluebird": "3.7.2", "lodash": "4.17.21", "source-map-support": "0.5.21", - "webdriverio": "9.12.7" + "webdriverio": "9.14.0" }, "peerDependencies": { "appium": "^2.0.0-beta.35 || ^3.0.0-beta.0" diff --git a/packages/fake-driver/lib/driver.js b/packages/fake-driver/lib/driver.js index 72fd3e9b0..5da61d08e 100644 --- a/packages/fake-driver/lib/driver.js +++ b/packages/fake-driver/lib/driver.js @@ -16,7 +16,7 @@ const FAKE_DRIVER_CONSTRAINTS = /** @type {const} */ ({ }); /** - * Constraints for {@linkcode FakeDriver}'s capabilites + * Constraints for {@linkcode FakeDriver}'s capabilities * @typedef {typeof FAKE_DRIVER_CONSTRAINTS} FakeDriverConstraints */ diff --git a/packages/images-plugin/lib/image-element.js b/packages/images-plugin/lib/image-element.js index eae0e5f91..199b89043 100644 --- a/packages/images-plugin/lib/image-element.js +++ b/packages/images-plugin/lib/image-element.js @@ -279,7 +279,7 @@ export default class ImageElement { return imgEl.originalImage; case 'getAttribute': // /session/:sessionId/element/:elementId/attribute/:name - // /session/:sessionId/element/:elementId/attribute/visual should retun the visual data + // /session/:sessionId/element/:elementId/attribute/visual should return the visual data // e.g. ["content-desc","appium-image-element-xxxxx","xxxxx"], ["visual","appium-image-element-xxxxx","xxxxx"] switch (args[0]) { case 'visual': diff --git a/packages/images-plugin/package.json b/packages/images-plugin/package.json index 164e7f5b3..c923fcac2 100644 --- a/packages/images-plugin/package.json +++ b/packages/images-plugin/package.json @@ -43,7 +43,7 @@ "@appium/support": "^6.1.0", "lodash": "4.17.21", "lru-cache": "10.4.3", - "sharp": "0.34.1", + "sharp": "0.34.2", "source-map-support": "0.5.21" }, "peerDependencies": { diff --git a/packages/logger/lib/types.ts b/packages/logger/lib/types.ts index 0c66a04f5..ef93f284e 100644 --- a/packages/logger/lib/types.ts +++ b/packages/logger/lib/types.ts @@ -77,12 +77,12 @@ export type LogLevel = | 'silent'; export interface StyleObject { - fg?: string | undefined; - bg?: string | undefined; - bold?: boolean | undefined; - inverse?: boolean | undefined; - underline?: boolean | undefined; - bell?: boolean | undefined; + fg?: string; + bg?: string; + bold?: boolean; + inverse?: boolean; + underline?: boolean; + bell?: boolean; } export interface MessageObject { diff --git a/packages/logger/test/unit/basic-specs.js b/packages/logger/test/unit/basic-specs.js index 057c3232b..5d7e27945 100644 --- a/packages/logger/test/unit/basic-specs.js +++ b/packages/logger/test/unit/basic-specs.js @@ -362,7 +362,7 @@ describe('basic', function () { }); }); - it('replaces senstive messages', async function() { + it('replaces sensitive messages', async function() { log.updateAsyncStorage({isSensitive: true}, true); log.log('verbose', 'test', markSensitive('log 1')); _.last(log.record).message.should.eql('**SECURE**'); diff --git a/packages/opencv/lib/index.js b/packages/opencv/lib/index.js index 79a770ae7..7c2e5b528 100644 --- a/packages/opencv/lib/index.js +++ b/packages/opencv/lib/index.js @@ -164,7 +164,7 @@ function calculateMatchedRect(matchedPoints) { } /** - * Draws a rectanngle on the given image matrix + * Draws a rectangle on the given image matrix * * @param {OpenCVBindings['Mat']} mat The source image * @param {Rect} region The region to highlight @@ -202,7 +202,7 @@ function highlightRegion(mat, region) { * @property {number|Function?} [goodMatchesFactor] The maximum count of "good" matches * (e. g. with minimal distances) or a function, which accepts 3 arguments: the current distance, * minimal distance, maximum distance and returns true or false to include or exclude the match. - * @property {boolean} [visualize=false] Whether to return the resulting visalization + * @property {boolean} [visualize=false] Whether to return the resulting visualization * as an image (useful for debugging purposes) */ @@ -233,7 +233,7 @@ function highlightRegion(mat, region) { * @param {Buffer} img2Data The data of the second image packed into a NodeJS buffer * @param {MatchingOptions} [options={}] Set of matching options * - * @returns {Promise} Maching result + * @returns {Promise} Matching result * @throws {Error} If `detectorName` value is unknown. */ async function getImagesMatches(img1Data, img2Data, options = {}) { @@ -325,8 +325,8 @@ async function getImagesMatches(img1Data, img2Data, options = {}) { }; if (visualize) { const goodMatchesVec = pool.add(new cv.DMatchVector()); - for (let i = 0; i < matches.length; i++) { - goodMatchesVec.push_back(matches[i]); + for (const match of matches) { + goodMatchesVec.push_back(match); } const visualization = pool.add(new cv.Mat()); const color = pool.add(new cv.Scalar(0, 255, 0, 255)); @@ -464,7 +464,7 @@ async function getImagesSimilarity(img1Data, img2Data, options = {}) { /** * @typedef OccurrenceResult - * @property {import('@appium/types').Rect} rect The region of the partial image occurence + * @property {import('@appium/types').Rect} rect The region of the partial image occurrence * on the full image * @property {Buffer?} [visualization] The visualization of the matching result * represented as PNG image buffer. On this image the matching @@ -472,7 +472,7 @@ async function getImagesSimilarity(img1Data, img2Data, options = {}) { * all results are highlighted here. * @property {number} score The similarity score as a float number in range [0.0, 1.0]. * 1.0 is the highest score (means both images are totally equal). - * @property {OccurrenceResult[]} [multiple] The array of matching OccurenceResults + * @property {OccurrenceResult[]} [multiple] The array of matching OccurrenceResults * - only when multiple option is passed * @property {TemplateMatchingMethod} [method='TM_CCOEFF_NORMED'] The name of the template matching method. * Acceptable values are: @@ -574,17 +574,17 @@ async function getImageOccurrence(fullImgData, partialImgData, options = {}) { if (visualize) { const fullHighlightedImage = pool.add(fullImg.clone()); - const visualisePromises = []; + const visualizePromises = []; for (const result of results) { const singleHighlightedImage = pool.add(fullImg.clone()); highlightRegion(singleHighlightedImage, result.rect); highlightRegion(fullHighlightedImage, result.rect); - visualisePromises.push(cvMatToPng(singleHighlightedImage)); + visualizePromises.push(cvMatToPng(singleHighlightedImage)); } let restPngBuffers = []; [visualization, ...restPngBuffers] = await B.all( - [cvMatToPng(fullHighlightedImage), ...visualisePromises] + [cvMatToPng(fullHighlightedImage), ...visualizePromises] ); for (const [result, pngBuffer] of _.zip(results, restPngBuffers)) { // @ts-ignore This is fine @@ -623,7 +623,7 @@ async function cvMatToPng(mat) { /** * Take an image buffer and return a cv.Mat * - * @param {Buffer} img image data buffer. All image formats avilable for + * @param {Buffer} img image data buffer. All image formats available for * https://www.npmjs.com/package/sharp node library are supported. * @return {Promise} OpenCV image matrix */ @@ -654,7 +654,7 @@ async function cvMatFromImage(img) { function filterNearMatches(nonZeroMatchResults, matchNeighbourThreshold) { return nonZeroMatchResults.reduce((acc, element) => { if (!acc.some((match) => distance(match, element) <= matchNeighbourThreshold)) { - // @ts-ignore TS cannot properly undertstand types here + // @ts-ignore TS cannot properly understand types here acc.push(element); } return acc; diff --git a/packages/opencv/package.json b/packages/opencv/package.json index 905e5780c..103d0dbc5 100644 --- a/packages/opencv/package.json +++ b/packages/opencv/package.json @@ -19,7 +19,7 @@ "repository": { "type": "git", "url": "https://github.com/appium/appium.git", - "directory": "pacakges/opencv" + "directory": "packages/opencv" }, "license": "Apache-2.0", "author": "https://github.com/appium", @@ -44,7 +44,7 @@ "bluebird": "3.7.2", "lodash": "4.17.21", "opencv-bindings": "4.5.5", - "sharp": "0.34.1", + "sharp": "0.34.2", "source-map-support": "0.5.21" }, "engines": { diff --git a/packages/plugin-test-support/package.json b/packages/plugin-test-support/package.json index 3a4053a26..26a497bb0 100644 --- a/packages/plugin-test-support/package.json +++ b/packages/plugin-test-support/package.json @@ -45,7 +45,7 @@ "get-port": "5.1.1", "log-symbols": "4.1.0", "source-map-support": "0.5.21", - "teen_process": "2.3.1" + "teen_process": "2.3.2" }, "peerDependencies": { "appium": "^2.0.0-beta.43 || ^3.0.0-beta.0", diff --git a/packages/storage-plugin/package.json b/packages/storage-plugin/package.json index b2235a0b7..39cc5d186 100644 --- a/packages/storage-plugin/package.json +++ b/packages/storage-plugin/package.json @@ -48,7 +48,7 @@ "lru-cache": "10.4.3", "rimraf": "5.0.10", "source-map-support": "0.5.21", - "ws": "8.18.1" + "ws": "8.18.2" }, "peerDependencies": { "appium": "^2.0.0 || ^3.0.0-beta.0" diff --git a/packages/strongbox/lib/base-item.ts b/packages/strongbox/lib/base-item.ts index 31782129b..37ff9cdd9 100644 --- a/packages/strongbox/lib/base-item.ts +++ b/packages/strongbox/lib/base-item.ts @@ -13,7 +13,7 @@ export class BaseItem implemen /** * {@inheritdoc Item.value} */ - protected _value?: T | undefined; + protected _value?: T; /** * Parent Strongbox instance diff --git a/packages/strongbox/lib/index.ts b/packages/strongbox/lib/index.ts index 453b249c9..149b85ac3 100644 --- a/packages/strongbox/lib/index.ts +++ b/packages/strongbox/lib/index.ts @@ -40,7 +40,7 @@ export interface Item { * * @remarks A custom {@linkcode Item} meant to handle very large files should probably not implement this. */ - value?: T | undefined; + value?: T; /** * Deletes the item. diff --git a/packages/support/lib/console.js b/packages/support/lib/console.js index ece8fe70b..a1e77772b 100644 --- a/packages/support/lib/console.js +++ b/packages/support/lib/console.js @@ -163,7 +163,7 @@ export class CliConsole { * Options for {@linkcode CliConsole}. * * @typedef ConsoleOpts - * @property {boolean} [jsonMode] - If _truthy_, supress all output except JSON (use {@linkcode CliConsole#json}), which writes to `STDOUT`. + * @property {boolean} [jsonMode] - If _truthy_, suppress all output except JSON (use {@linkcode CliConsole#json}), which writes to `STDOUT`. * @property {boolean} [useSymbols] - If _falsy_, do not use fancy symbols. * @property {boolean} [useColor] - If _falsy_, do not use color output. If _truthy_, forces color output. By default, checks terminal/TTY for support via pkg `supports-color`. Ignored if `useSymbols` is `false`. * @see https://npm.im/supports-color diff --git a/packages/support/lib/plist.js b/packages/support/lib/plist.js index 71b0f6f8c..eb8f68b6c 100644 --- a/packages/support/lib/plist.js +++ b/packages/support/lib/plist.js @@ -105,7 +105,7 @@ function createBinaryPlist(data) { /** * Parses a Buffer into an Object - * @param {Buffer} data The beffer of a binary plist + * @param {Buffer} data The buffer of a binary plist */ function parseBinaryPlist(data) { return parseBuffer(data); diff --git a/packages/support/lib/tempdir.js b/packages/support/lib/tempdir.js index b0231af4d..01f1da2bf 100644 --- a/packages/support/lib/tempdir.js +++ b/packages/support/lib/tempdir.js @@ -119,9 +119,9 @@ const _static = tempDir(); const openDir = tempDir; /** - * Returns a path to a temporary directory whcih is defined as static in the same process + * Returns a path to a temporary directory which is defined as static in the same process * - * @returns {Promise} A temp directory path whcih is defined as static in the same process + * @returns {Promise} A temp directory path which is defined as static in the same process */ async function staticDir() { diff --git a/packages/support/lib/zip.js b/packages/support/lib/zip.js index c5f76279a..e5797a821 100644 --- a/packages/support/lib/zip.js +++ b/packages/support/lib/zip.js @@ -264,7 +264,7 @@ async function _extractEntryTo(zipFile, entry, destDir) { const dstPath = path.resolve(destDir, entry.fileName); // Create dest directory if doesn't exist already - if (/\/$/.test(entry.fileName)) { + if (entry.fileName.endsWith('/')) { if (!(await fs.exists(dstPath))) { await fs.mkdirp(dstPath); } diff --git a/packages/support/package.json b/packages/support/package.json index 6778215dc..5fbe763f2 100644 --- a/packages/support/package.json +++ b/packages/support/package.json @@ -68,18 +68,18 @@ "read-pkg": "5.2.0", "resolve-from": "5.0.0", "sanitize-filename": "1.6.3", - "semver": "7.7.1", + "semver": "7.7.2", "shell-quote": "1.8.2", "source-map-support": "0.5.21", "supports-color": "8.1.1", - "teen_process": "2.3.1", - "type-fest": "4.40.1", + "teen_process": "2.3.2", + "type-fest": "4.41.0", "uuid": "11.1.0", "which": "4.0.0", "yauzl": "3.2.0" }, "optionalDependencies": { - "sharp": "0.34.1" + "sharp": "0.34.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", diff --git a/packages/support/test/unit/tempdir.spec.js b/packages/support/test/unit/tempdir.spec.js index 047c94b64..078304689 100644 --- a/packages/support/test/unit/tempdir.spec.js +++ b/packages/support/test/unit/tempdir.spec.js @@ -9,7 +9,7 @@ describe('tempdir', function () { }); afterEach(function () { - // set the process env as undefiend + // set the process env as undefined delete process.env.APPIUM_TMP_DIR; }); diff --git a/packages/types/lib/command.ts b/packages/types/lib/command.ts index 0f2cfc9b3..aaea748e1 100644 --- a/packages/types/lib/command.ts +++ b/packages/types/lib/command.ts @@ -193,11 +193,11 @@ export interface ErrorBiDiCommandResponse extends GenericBiDiCommandResponse { export interface RestCommandItemParam { /** - * Command paremeter name + * Command parameter name */ name: string; /** - * True if the paramter is required for the given command + * True if the parameter is required for the given command */ required: boolean; } @@ -212,7 +212,7 @@ export interface RestCommandItem { */ deprecated?: boolean; /** - * Optinal infostring about the command's purpose or a comment + * Optional infostring about the command's purpose or a comment */ info?: string; /** @@ -245,11 +245,11 @@ export interface RestCommandsMap { export interface BiDiCommandItemParam { /** - * Command paremeter name + * Command parameter name */ name: string; /** - * True if the paramter is required for the given command + * True if the parameter is required for the given command */ required: boolean; } @@ -264,7 +264,7 @@ export interface BiDiCommandItem { */ deprecated?: boolean; /** - * Optinal infostring about the command's purpose or a comment + * Optional infostring about the command's purpose or a comment */ info?: string; /** diff --git a/packages/types/package.json b/packages/types/package.json index 97e1694e6..68406b1f1 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -41,7 +41,7 @@ "@appium/logger": "^1.7.0", "@appium/schema": "^0.8.1", "@appium/tsconfig": "^0.3.5", - "type-fest": "4.40.1" + "type-fest": "4.41.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", diff --git a/packages/universal-xml-plugin/lib/xpath.js b/packages/universal-xml-plugin/lib/xpath.js index cd26c9c37..f23908753 100644 --- a/packages/universal-xml-plugin/lib/xpath.js +++ b/packages/universal-xml-plugin/lib/xpath.js @@ -4,7 +4,7 @@ import _ from 'lodash'; export function runQuery(query, xmlStr) { const dom = new DOMParser().parseFromString(xmlStr, MIME_TYPE.XML_TEXT); - // @ts-expect-error Misssing Node properties are not needed. + // @ts-expect-error Missing Node properties are not needed. // https://github.com/xmldom/xmldom/issues/724 const nodes = xpathQuery(query, dom); return nodes; diff --git a/packages/universal-xml-plugin/package.json b/packages/universal-xml-plugin/package.json index 616b2e65a..0f52a13c5 100644 --- a/packages/universal-xml-plugin/package.json +++ b/packages/universal-xml-plugin/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "@xmldom/xmldom": "0.9.8", - "fast-xml-parser": "5.2.1", + "fast-xml-parser": "5.2.3", "lodash": "4.17.21", "source-map-support": "0.5.21", "xpath": "0.0.34" diff --git a/scripts/crowdin-update-docs-resources.mjs b/scripts/crowdin-update-docs-resources.mjs index e78ea2cac..f9f401912 100644 --- a/scripts/crowdin-update-docs-resources.mjs +++ b/scripts/crowdin-update-docs-resources.mjs @@ -151,7 +151,7 @@ async function uploadDocumentsToStorage(matchedFiles) { let count = 0; for (const matchedFilePath of matchedFiles) { const crowdinPath = toCrowdinPath(matchedFilePath); - // Hashing is used to make sure we aways create the same storage for the same file path in Crowdin + // Hashing is used to make sure we always create the same storage for the same file path in Crowdin const storageName = toHash(crowdinPath); log.info(`Uploading '${crowdinPath}' to Crowdin storage (${++count} of ${matchedFiles.length})`); const storageData = await addStorage(storageName, matchedFilePath, DOCUMENT_CONTENT_TYPE);