mirror of
https://github.com/appium/appium.git
synced 2026-11-04 00:06:31 +08:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7ce83e169 | ||
|
|
8df1c217a1 | ||
|
|
aad5709913 | ||
|
|
17ecc21747 | ||
|
|
3467f32c8e | ||
|
|
6f27d36cf5 | ||
|
|
488e5dea82 | ||
|
|
13d8b03cc1 | ||
|
|
fe209ed660 | ||
|
|
93e4288253 | ||
|
|
fb839be6ea |
@@ -12,6 +12,7 @@ export default [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Ignores',
|
||||
ignores: [
|
||||
'**/build-fixtures/**',
|
||||
'packages/appium/docs/**/assets/**',
|
||||
|
||||
Generated
+140
-111
@@ -19,7 +19,7 @@
|
||||
"@types/chai-as-promised": "8.0.1",
|
||||
"@types/diff": "6.0.0",
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/node": "22.10.3",
|
||||
"@types/node": "22.10.5",
|
||||
"@types/semver": "7.5.8",
|
||||
"@types/sinon": "17.0.3",
|
||||
"@types/sinon-chai": "4.0.0",
|
||||
@@ -27,8 +27,6 @@
|
||||
"@types/teen_process": "2.0.4",
|
||||
"@types/ws": "8.5.13",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@typescript-eslint/eslint-plugin": "8.19.0",
|
||||
"@typescript-eslint/parser": "8.19.0",
|
||||
"asyncbox": "3.0.0",
|
||||
"chai": "5.1.2",
|
||||
"chai-as-promised": "8.0.1",
|
||||
@@ -59,8 +57,9 @@
|
||||
"ts-node": "10.9.2",
|
||||
"tsd": "0.31.2",
|
||||
"typescript": "5.7.2",
|
||||
"typescript-eslint": "8.19.0",
|
||||
"validate.js": "0.13.1",
|
||||
"webdriverio": "9.5.0",
|
||||
"webdriverio": "9.5.1",
|
||||
"ws": "8.18.0",
|
||||
"yaml-js": "0.3.1"
|
||||
},
|
||||
@@ -2927,9 +2926,9 @@
|
||||
"integrity": "sha512-Q8oFIHJHr+htLrTXN2FuZfg+WXVHQRwU/hC2GpUu+Q8e3FUM9EDkS2pE3R2AO1ZGu56f479ybdMCNF1DAu8cAQ=="
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz",
|
||||
"integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==",
|
||||
"version": "4.17.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz",
|
||||
"integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/method-override": {
|
||||
@@ -2976,9 +2975,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.3.tgz",
|
||||
"integrity": "sha512-DifAyw4BkrufCILvD3ucnuN8eydUfc/C1GlyrnI+LK6543w5/L3VeVgf05o3B4fqSXP1dKYLOZsKfutpxPzZrw==",
|
||||
"version": "22.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
|
||||
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
@@ -16137,9 +16136,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/teen_process": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.2.2.tgz",
|
||||
"integrity": "sha512-Qs9JCzsKcbuBtbZxY9WVoYs3GG+WFfxoIDGpkj8AJ/BpWnh+pdLK+x1+E1bDlQuASs+CTQmykYPGAkzxFjqcaA==",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.2.3.tgz",
|
||||
"integrity": "sha512-8L540OalWH83qc6LHV5VMr0DjdP7KWUHQwTOImtWaG2ElW8BvLTh6M9871oGmmpOMb2BpOJQn2+09ZHWYsdTUA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bluebird": "^3.7.2",
|
||||
@@ -16723,6 +16722,28 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.0.tgz",
|
||||
"integrity": "sha512-Ni8sUkVWYK4KAcTtPjQ/UTiRk6jcsuDhPpxULapUDi8A/l8TSBk+t1GtJA1RsCzIJg0q6+J7bf35AwQigENWRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.19.0",
|
||||
"@typescript-eslint/parser": "8.19.0",
|
||||
"@typescript-eslint/utils": "8.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uglify-js": {
|
||||
"version": "3.17.4",
|
||||
"dev": true,
|
||||
@@ -17059,9 +17080,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriver": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.5.0.tgz",
|
||||
"integrity": "sha512-w57Cb+N9VjSoYEFosytqDrICF3W5GqP0ldxiUMrhwaGSe2CfqE666CyRhy533Y3oYg1gZvVMc7jq6CMbfSBoTg==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.5.1.tgz",
|
||||
"integrity": "sha512-uVQJtk1fLoi8ITmIo5jVpzUb7KMILPptB7uMKBumQJpVxjehz3xi0RGcnscSBuKhi59wkPJ3I5BOvomxQUG8Vw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -17156,9 +17177,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriverio": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.5.0.tgz",
|
||||
"integrity": "sha512-74QK4lDH5zkD/oEO/zHs2GqjrTj/d012+4zuZKAIqAnO46E+um50gw4AMmNp7Bc5xcGdU9CoB5EGDMpt2Fwf9g==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.5.1.tgz",
|
||||
"integrity": "sha512-G/YwalPM/wxRdjY28LoZ0jJzldDUuZ2Do1F90THNw3GwSZae9yARs1kHxdpy1aDxBFwrb4BNTMzzL9hpJ0lASw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -17188,7 +17209,7 @@
|
||||
"rgb2hex": "0.2.5",
|
||||
"serialize-error": "^11.0.3",
|
||||
"urlpattern-polyfill": "^10.0.0",
|
||||
"webdriver": "9.5.0"
|
||||
"webdriver": "9.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.20.0"
|
||||
@@ -17203,9 +17224,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriverio/node_modules/@types/node": {
|
||||
"version": "20.17.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.10.tgz",
|
||||
"integrity": "sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==",
|
||||
"version": "20.17.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.11.tgz",
|
||||
"integrity": "sha512-Ept5glCK35R8yeyIeYlRIZtX6SLRyqMhOFTgj5SOkMpLTdw3SEHI9fHx60xaUZ+V1aJxQJODE+7/j5ocZydYTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -17945,17 +17966,17 @@
|
||||
}
|
||||
},
|
||||
"packages/appium": {
|
||||
"version": "2.14.0",
|
||||
"version": "2.15.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/base-driver": "^9.14.0",
|
||||
"@appium/base-plugin": "^2.2.51",
|
||||
"@appium/docutils": "^1.0.27",
|
||||
"@appium/base-driver": "^9.15.0",
|
||||
"@appium/base-plugin": "^2.3.0",
|
||||
"@appium/docutils": "^1.0.29",
|
||||
"@appium/logger": "^1.6.1",
|
||||
"@appium/schema": "^0.7.1",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@sidvind/better-ajv-errors": "3.0.1",
|
||||
"@types/argparse": "2.0.17",
|
||||
"@types/bluebird": "3.5.42",
|
||||
@@ -17978,7 +17999,7 @@
|
||||
"resolve-from": "5.0.0",
|
||||
"semver": "7.6.3",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"winston": "3.17.0",
|
||||
"wrap-ansi": "7.0.0",
|
||||
@@ -18054,16 +18075,16 @@
|
||||
},
|
||||
"packages/base-driver": {
|
||||
"name": "@appium/base-driver",
|
||||
"version": "9.14.0",
|
||||
"version": "9.15.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/async-lock": "1.4.2",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"@types/express": "5.0.0",
|
||||
"@types/lodash": "4.17.13",
|
||||
"@types/lodash": "4.17.14",
|
||||
"@types/method-override": "3.0.0",
|
||||
"@types/serve-favicon": "2.5.7",
|
||||
"async-lock": "1.4.1",
|
||||
@@ -18120,11 +18141,11 @@
|
||||
},
|
||||
"packages/base-plugin": {
|
||||
"name": "@appium/base-plugin",
|
||||
"version": "2.2.51",
|
||||
"version": "2.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/base-driver": "^9.14.0",
|
||||
"@appium/support": "^6.0.1"
|
||||
"@appium/base-driver": "^9.15.0",
|
||||
"@appium/support": "^6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
||||
@@ -18133,10 +18154,10 @@
|
||||
},
|
||||
"packages/docutils": {
|
||||
"name": "@appium/docutils",
|
||||
"version": "1.0.27",
|
||||
"version": "1.0.29",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/tsconfig": "^0.3.3",
|
||||
"@sliphua/lilconfig-ts-loader": "3.2.2",
|
||||
"@types/which": "3.0.4",
|
||||
@@ -18150,7 +18171,7 @@
|
||||
"read-pkg": "5.2.0",
|
||||
"semver": "7.6.3",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"typescript": "5.7.2",
|
||||
"yaml": "2.7.0",
|
||||
@@ -18277,11 +18298,11 @@
|
||||
},
|
||||
"packages/driver-test-support": {
|
||||
"name": "@appium/driver-test-support",
|
||||
"version": "0.7.2",
|
||||
"version": "0.7.4",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/types": "^0.23.0",
|
||||
"@types/lodash": "4.17.13",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@types/lodash": "4.17.14",
|
||||
"axios": "1.7.9",
|
||||
"bluebird": "3.7.2",
|
||||
"chai": "5.1.2",
|
||||
@@ -18341,7 +18362,7 @@
|
||||
},
|
||||
"packages/eslint-config-appium-ts": {
|
||||
"name": "@appium/eslint-config-appium-ts",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
||||
@@ -18350,26 +18371,25 @@
|
||||
"peerDependencies": {
|
||||
"@eslint/compat": "^1.1.0",
|
||||
"@eslint/js": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.0",
|
||||
"eslint-plugin-import": "^2.30.0",
|
||||
"eslint-plugin-mocha": "^10.4.0",
|
||||
"eslint-plugin-promise": "^7.0.0"
|
||||
"eslint-plugin-promise": "^7.0.0",
|
||||
"typescript-eslint": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"packages/execute-driver-plugin": {
|
||||
"name": "@appium/execute-driver-plugin",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.1",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/bluebird": "3.5.42",
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
"source-map-support": "0.5.21",
|
||||
"webdriverio": "9.5.0"
|
||||
"webdriverio": "9.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
||||
@@ -18927,7 +18947,7 @@
|
||||
},
|
||||
"packages/fake-driver": {
|
||||
"name": "@appium/fake-driver",
|
||||
"version": "5.6.0",
|
||||
"version": "5.7.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/bluebird": "3.5.42",
|
||||
@@ -18948,11 +18968,11 @@
|
||||
},
|
||||
"packages/fake-plugin": {
|
||||
"name": "@appium/fake-plugin",
|
||||
"version": "3.1.55",
|
||||
"version": "3.2.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/base-plugin": "^2.2.51",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/base-plugin": "^2.3.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
@@ -18968,11 +18988,11 @@
|
||||
},
|
||||
"packages/images-plugin": {
|
||||
"name": "@appium/images-plugin",
|
||||
"version": "3.0.25",
|
||||
"version": "3.0.27",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/opencv": "^3.0.7",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"lodash": "4.17.21",
|
||||
"lru-cache": "10.4.3",
|
||||
"sharp": "0.33.5",
|
||||
@@ -19166,14 +19186,14 @@
|
||||
},
|
||||
"packages/plugin-test-support": {
|
||||
"name": "@appium/plugin-test-support",
|
||||
"version": "0.3.47",
|
||||
"version": "0.3.49",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/types": "^0.24.0",
|
||||
"get-port": "5.1.1",
|
||||
"log-symbols": "4.1.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2"
|
||||
"teen_process": "2.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
||||
@@ -19229,12 +19249,12 @@
|
||||
},
|
||||
"packages/support": {
|
||||
"name": "@appium/support",
|
||||
"version": "6.0.1",
|
||||
"version": "6.0.3",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/logger": "^1.6.1",
|
||||
"@appium/tsconfig": "^0.3.3",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/base64-stream": "1.0.5",
|
||||
@@ -19279,9 +19299,9 @@
|
||||
"shell-quote": "1.8.2",
|
||||
"source-map-support": "0.5.21",
|
||||
"supports-color": "8.1.1",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"uuid": "11.0.3",
|
||||
"uuid": "11.0.4",
|
||||
"which": "4.0.0",
|
||||
"yauzl": "3.2.0"
|
||||
},
|
||||
@@ -19512,10 +19532,10 @@
|
||||
},
|
||||
"packages/test-support": {
|
||||
"name": "@appium/test-support",
|
||||
"version": "3.1.1",
|
||||
"version": "3.1.3",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@colors/colors": "1.6.0",
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
@@ -19546,7 +19566,7 @@
|
||||
},
|
||||
"packages/types": {
|
||||
"name": "@appium/types",
|
||||
"version": "0.23.0",
|
||||
"version": "0.24.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@appium/logger": "^1.6.1",
|
||||
@@ -19614,13 +19634,13 @@
|
||||
"@appium/base-driver": {
|
||||
"version": "file:packages/base-driver",
|
||||
"requires": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/async-lock": "1.4.2",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"@types/express": "5.0.0",
|
||||
"@types/lodash": "4.17.13",
|
||||
"@types/lodash": "4.17.14",
|
||||
"@types/method-override": "3.0.0",
|
||||
"@types/serve-favicon": "2.5.7",
|
||||
"async-lock": "1.4.1",
|
||||
@@ -19665,14 +19685,14 @@
|
||||
"@appium/base-plugin": {
|
||||
"version": "file:packages/base-plugin",
|
||||
"requires": {
|
||||
"@appium/base-driver": "^9.14.0",
|
||||
"@appium/support": "^6.0.1"
|
||||
"@appium/base-driver": "^9.15.0",
|
||||
"@appium/support": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"@appium/docutils": {
|
||||
"version": "file:packages/docutils",
|
||||
"requires": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/tsconfig": "^0.3.3",
|
||||
"@sliphua/lilconfig-ts-loader": "3.2.2",
|
||||
"@types/which": "3.0.4",
|
||||
@@ -19686,7 +19706,7 @@
|
||||
"read-pkg": "5.2.0",
|
||||
"semver": "7.6.3",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"typescript": "5.7.2",
|
||||
"yaml": "2.7.0",
|
||||
@@ -19755,8 +19775,8 @@
|
||||
"@appium/driver-test-support": {
|
||||
"version": "file:packages/driver-test-support",
|
||||
"requires": {
|
||||
"@appium/types": "^0.23.0",
|
||||
"@types/lodash": "4.17.13",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@types/lodash": "4.17.14",
|
||||
"axios": "1.7.9",
|
||||
"bluebird": "3.7.2",
|
||||
"chai": "5.1.2",
|
||||
@@ -19794,7 +19814,7 @@
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
"source-map-support": "0.5.21",
|
||||
"webdriverio": "9.5.0"
|
||||
"webdriverio": "9.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@puppeteer/browsers": {
|
||||
@@ -20177,8 +20197,8 @@
|
||||
"@appium/fake-plugin": {
|
||||
"version": "file:packages/fake-plugin",
|
||||
"requires": {
|
||||
"@appium/base-plugin": "^2.2.51",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/base-plugin": "^2.3.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
@@ -20189,7 +20209,7 @@
|
||||
"version": "file:packages/images-plugin",
|
||||
"requires": {
|
||||
"@appium/opencv": "^3.0.7",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"lodash": "4.17.21",
|
||||
"lru-cache": "10.4.3",
|
||||
"sharp": "0.33.5",
|
||||
@@ -20335,11 +20355,11 @@
|
||||
"@appium/plugin-test-support": {
|
||||
"version": "file:packages/plugin-test-support",
|
||||
"requires": {
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/types": "^0.24.0",
|
||||
"get-port": "5.1.1",
|
||||
"log-symbols": "4.1.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2"
|
||||
"teen_process": "2.2.3"
|
||||
}
|
||||
},
|
||||
"@appium/relaxed-caps-plugin": {
|
||||
@@ -20369,7 +20389,7 @@
|
||||
"requires": {
|
||||
"@appium/logger": "^1.6.1",
|
||||
"@appium/tsconfig": "^0.3.3",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/base64-stream": "1.0.5",
|
||||
@@ -20415,9 +20435,9 @@
|
||||
"shell-quote": "1.8.2",
|
||||
"source-map-support": "0.5.21",
|
||||
"supports-color": "8.1.1",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"uuid": "11.0.3",
|
||||
"uuid": "11.0.4",
|
||||
"which": "4.0.0",
|
||||
"yauzl": "3.2.0"
|
||||
},
|
||||
@@ -20543,8 +20563,7 @@
|
||||
"integrity": "sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz",
|
||||
"version": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz",
|
||||
"integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg=="
|
||||
},
|
||||
"which": {
|
||||
@@ -20569,7 +20588,7 @@
|
||||
"@appium/test-support": {
|
||||
"version": "file:packages/test-support",
|
||||
"requires": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@colors/colors": "1.6.0",
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
@@ -22389,9 +22408,9 @@
|
||||
"integrity": "sha512-Q8oFIHJHr+htLrTXN2FuZfg+WXVHQRwU/hC2GpUu+Q8e3FUM9EDkS2pE3R2AO1ZGu56f479ybdMCNF1DAu8cAQ=="
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.17.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz",
|
||||
"integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg=="
|
||||
"version": "4.17.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz",
|
||||
"integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A=="
|
||||
},
|
||||
"@types/method-override": {
|
||||
"version": "3.0.0",
|
||||
@@ -22430,9 +22449,9 @@
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "22.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.3.tgz",
|
||||
"integrity": "sha512-DifAyw4BkrufCILvD3ucnuN8eydUfc/C1GlyrnI+LK6543w5/L3VeVgf05o3B4fqSXP1dKYLOZsKfutpxPzZrw==",
|
||||
"version": "22.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
|
||||
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==",
|
||||
"requires": {
|
||||
"undici-types": "~6.20.0"
|
||||
},
|
||||
@@ -23125,13 +23144,13 @@
|
||||
"appium": {
|
||||
"version": "file:packages/appium",
|
||||
"requires": {
|
||||
"@appium/base-driver": "^9.14.0",
|
||||
"@appium/base-plugin": "^2.2.51",
|
||||
"@appium/docutils": "^1.0.27",
|
||||
"@appium/base-driver": "^9.15.0",
|
||||
"@appium/base-plugin": "^2.3.0",
|
||||
"@appium/docutils": "^1.0.29",
|
||||
"@appium/logger": "^1.6.1",
|
||||
"@appium/schema": "^0.7.1",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@sidvind/better-ajv-errors": "3.0.1",
|
||||
"@types/argparse": "2.0.17",
|
||||
"@types/bluebird": "3.5.42",
|
||||
@@ -23154,7 +23173,7 @@
|
||||
"resolve-from": "5.0.0",
|
||||
"semver": "7.6.3",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"winston": "3.17.0",
|
||||
"wrap-ansi": "7.0.0",
|
||||
@@ -31354,9 +31373,9 @@
|
||||
}
|
||||
},
|
||||
"teen_process": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.2.2.tgz",
|
||||
"integrity": "sha512-Qs9JCzsKcbuBtbZxY9WVoYs3GG+WFfxoIDGpkj8AJ/BpWnh+pdLK+x1+E1bDlQuASs+CTQmykYPGAkzxFjqcaA==",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/teen_process/-/teen_process-2.2.3.tgz",
|
||||
"integrity": "sha512-8L540OalWH83qc6LHV5VMr0DjdP7KWUHQwTOImtWaG2ElW8BvLTh6M9871oGmmpOMb2BpOJQn2+09ZHWYsdTUA==",
|
||||
"requires": {
|
||||
"bluebird": "^3.7.2",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -31728,6 +31747,16 @@
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
|
||||
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg=="
|
||||
},
|
||||
"typescript-eslint": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.0.tgz",
|
||||
"integrity": "sha512-Ni8sUkVWYK4KAcTtPjQ/UTiRk6jcsuDhPpxULapUDi8A/l8TSBk+t1GtJA1RsCzIJg0q6+J7bf35AwQigENWRQ==",
|
||||
"requires": {
|
||||
"@typescript-eslint/eslint-plugin": "8.19.0",
|
||||
"@typescript-eslint/parser": "8.19.0",
|
||||
"@typescript-eslint/utils": "8.19.0"
|
||||
}
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.17.4",
|
||||
"dev": true,
|
||||
@@ -31963,9 +31992,9 @@
|
||||
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
|
||||
},
|
||||
"webdriver": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.5.0.tgz",
|
||||
"integrity": "sha512-w57Cb+N9VjSoYEFosytqDrICF3W5GqP0ldxiUMrhwaGSe2CfqE666CyRhy533Y3oYg1gZvVMc7jq6CMbfSBoTg==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.5.1.tgz",
|
||||
"integrity": "sha512-uVQJtk1fLoi8ITmIo5jVpzUb7KMILPptB7uMKBumQJpVxjehz3xi0RGcnscSBuKhi59wkPJ3I5BOvomxQUG8Vw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "^20.1.0",
|
||||
@@ -32031,9 +32060,9 @@
|
||||
}
|
||||
},
|
||||
"webdriverio": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.5.0.tgz",
|
||||
"integrity": "sha512-74QK4lDH5zkD/oEO/zHs2GqjrTj/d012+4zuZKAIqAnO46E+um50gw4AMmNp7Bc5xcGdU9CoB5EGDMpt2Fwf9g==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.5.1.tgz",
|
||||
"integrity": "sha512-G/YwalPM/wxRdjY28LoZ0jJzldDUuZ2Do1F90THNw3GwSZae9yARs1kHxdpy1aDxBFwrb4BNTMzzL9hpJ0lASw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "^20.11.30",
|
||||
@@ -32062,13 +32091,13 @@
|
||||
"rgb2hex": "0.2.5",
|
||||
"serialize-error": "^11.0.3",
|
||||
"urlpattern-polyfill": "^10.0.0",
|
||||
"webdriver": "9.5.0"
|
||||
"webdriver": "9.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "20.17.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.10.tgz",
|
||||
"integrity": "sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==",
|
||||
"version": "20.17.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.11.tgz",
|
||||
"integrity": "sha512-Ept5glCK35R8yeyIeYlRIZtX6SLRyqMhOFTgj5SOkMpLTdw3SEHI9fHx60xaUZ+V1aJxQJODE+7/j5ocZydYTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"undici-types": "~6.19.2"
|
||||
|
||||
+3
-4
@@ -91,7 +91,7 @@
|
||||
"@types/chai-as-promised": "8.0.1",
|
||||
"@types/diff": "6.0.0",
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/node": "22.10.3",
|
||||
"@types/node": "22.10.5",
|
||||
"@types/semver": "7.5.8",
|
||||
"@types/sinon": "17.0.3",
|
||||
"@types/sinon-chai": "4.0.0",
|
||||
@@ -99,8 +99,6 @@
|
||||
"@types/teen_process": "2.0.4",
|
||||
"@types/ws": "8.5.13",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@typescript-eslint/eslint-plugin": "8.19.0",
|
||||
"@typescript-eslint/parser": "8.19.0",
|
||||
"asyncbox": "3.0.0",
|
||||
"chai": "5.1.2",
|
||||
"chai-as-promised": "8.0.1",
|
||||
@@ -131,8 +129,9 @@
|
||||
"ts-node": "10.9.2",
|
||||
"tsd": "0.31.2",
|
||||
"typescript": "5.7.2",
|
||||
"typescript-eslint": "8.19.0",
|
||||
"validate.js": "0.13.1",
|
||||
"webdriverio": "9.5.0",
|
||||
"webdriverio": "9.5.1",
|
||||
"ws": "8.18.0",
|
||||
"yaml-js": "0.3.1"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.15.0](https://github.com/appium/appium/compare/appium@2.14.1...appium@2.15.0) (2025-01-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,base-plugin:** allow plugins to define custom bidi commands and emit bidi events ([#20876](https://github.com/appium/appium/issues/20876)) ([8df1c21](https://github.com/appium/appium/commit/8df1c217a15d30300c04b9f59cdbdffa70325828))
|
||||
|
||||
|
||||
|
||||
## [2.14.1](https://github.com/appium/appium/compare/appium@2.14.0...appium@2.14.1) (2025-01-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Do not update BiDi commands for drivers which don't support it ([#20879](https://github.com/appium/appium/issues/20879)) ([13d8b03](https://github.com/appium/appium/commit/13d8b03cc185c5f4e0631002614981ee6f86fab4))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v9.5.1 ([#20875](https://github.com/appium/appium/issues/20875)) ([93e4288](https://github.com/appium/appium/commit/93e4288253c07a844e6e10f0dd040b1a40eb92ff))
|
||||
* **support:** update dependency teen_process to v2.2.3 ([#20882](https://github.com/appium/appium/issues/20882)) ([488e5de](https://github.com/appium/appium/commit/488e5dea82d3c525acf483952570e32f319f3722))
|
||||
|
||||
|
||||
|
||||
## [2.14.0](https://github.com/appium/appium/compare/appium@2.13.1...appium@2.14.0) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -320,10 +320,6 @@ your driver of the appropriate name, and it will be called when the BiDi command
|
||||
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)
|
||||
|
||||
Currently, you also need to define a `doesSupportBidi` field on your driver instances, and ensure
|
||||
it is set to `true`. Appium will not turn on its Websocket servers for your driver and set up any
|
||||
handlers unless your driver says that it supports BiDi in this way.
|
||||
|
||||
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.
|
||||
@@ -562,11 +558,9 @@ remote endpoint you're proxying to. Appium will take care of all the proxying fo
|
||||
### 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:
|
||||
|
||||
1. Set the `doesSupportBidi` field on your driver instances to `true`.
|
||||
1. 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.
|
||||
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`
|
||||
@@ -624,7 +618,7 @@ an example of a `newBidiCommands` as implemented on an imaginary driver:
|
||||
|
||||
```js
|
||||
static newBidiCommands = {
|
||||
video: {
|
||||
'appium:video': {
|
||||
startFramerateCapture: {
|
||||
command: 'startFrameCap',
|
||||
params: {
|
||||
@@ -639,9 +633,15 @@ static newBidiCommands = {
|
||||
};
|
||||
```
|
||||
|
||||
In this imaginary example, we have defined two new BiDi commands: `video.startFramerateCapture` and
|
||||
`video.stopFramerateCapture`. 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.
|
||||
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
|
||||
@@ -752,7 +752,7 @@ in `this.currentCpuLoad`):
|
||||
|
||||
```js
|
||||
this.eventEmitter.emit('bidiEvent', {
|
||||
method: 'system.cpu',
|
||||
method: 'appium:system.cpu',
|
||||
params: {load: this.currentCpuLoad},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -325,9 +325,12 @@ If you want to offer functionality that doesn't map to any of the existing comma
|
||||
drivers, you can create new commands in one of two ways, just as is possible for drivers:
|
||||
|
||||
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
|
||||
1. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface
|
||||
1. Overloading the Execute Script command by defining [Execute
|
||||
Methods](../guides/execute-methods.md)
|
||||
|
||||
#### 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.
|
||||
@@ -368,7 +371,60 @@ clients won't have nice client-side functions designed to target these endpoints
|
||||
to create and release client-side plugins for each language you want to support (directions or
|
||||
examples can be found at the relevant client docs).
|
||||
|
||||
An alternative to this way of doing things is to overload a command which all WebDriver clients
|
||||
#### 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<any>, driver: DriverClass, videoSource: string, showOnScreen: boolean): Promise<any>;
|
||||
async stopFrameCap(next: () => Promise<any>, driver: DriverClass): Promise<any>;
|
||||
```
|
||||
|
||||
As with adding or overriding existing HTTP protocol commands, these methods are injected with
|
||||
a `next` parameter and a `driver` parameter. The `driver` object represents the driver currently
|
||||
owning the session, and calling `await next()` will execute/return the behavior that would execute
|
||||
were the plugin not active (i.e., the driver's own handling of that method, or the chain of
|
||||
commands executed with the same name by other active plugins).
|
||||
|
||||
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](./build-drivers.md#extend-the-existing-protocol-with-new-commands) in
|
||||
the Building Drivers guide to understand the way this works in general. The way it works with
|
||||
@@ -405,6 +461,11 @@ Overriding Execute Methods from drivers works as you'd expect: if your plugin de
|
||||
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-drivers.md#emit-bidi-events).
|
||||
|
||||
### Build Appium Doctor checks
|
||||
|
||||
Your users can run `appium plugin doctor <pluginName>` to run installation and health checks. Visit
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
GET_STATUS_COMMAND,
|
||||
promoteAppiumOptions,
|
||||
promoteAppiumOptionsForObject,
|
||||
generateDriverLogPrefix,
|
||||
} from '@appium/base-driver';
|
||||
import AsyncLock from 'async-lock';
|
||||
import {
|
||||
@@ -18,7 +19,7 @@ import {
|
||||
makeNonW3cCapsError,
|
||||
validateFeatures,
|
||||
} from './utils';
|
||||
import {util, node, logger} from '@appium/support';
|
||||
import {util} from '@appium/support';
|
||||
import {getDefaultsForExtension} from './schema';
|
||||
import {DRIVER_TYPE, BIDI_BASE_PATH} from './constants';
|
||||
import * as bidiHelpers from './bidi';
|
||||
@@ -140,17 +141,6 @@ class AppiumDriver extends DriverCore {
|
||||
})();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves logger instance for the current umbrella driver instance
|
||||
*/
|
||||
get log() {
|
||||
if (!this._log) {
|
||||
const instanceName = `${this.constructor.name}@${node.getObjectId(this).substring(0, 4)}`;
|
||||
this._log = logger.getLogger(instanceName);
|
||||
}
|
||||
return this._log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel commands queueing for the umbrella Appium driver
|
||||
*/
|
||||
@@ -343,8 +333,11 @@ class AppiumDriver extends DriverCore {
|
||||
}
|
||||
|
||||
// We also want to assign any new Bidi Commands that the driver has specified, including all
|
||||
// the standard bidi commands
|
||||
driverInstance.updateBidiCommands(InnerDriver.newBidiCommands ?? {});
|
||||
// the standard bidi commands. But add a method existence guard since some old driver class
|
||||
// instances might not have this method
|
||||
if (_.isFunction(driverInstance.updateBidiCommands)) {
|
||||
driverInstance.updateBidiCommands(InnerDriver.newBidiCommands ?? {});
|
||||
}
|
||||
|
||||
if (!_.isEmpty(this.args.denyInsecure)) {
|
||||
this.log.info('Explicitly preventing use of insecure features:');
|
||||
@@ -427,11 +420,10 @@ class AppiumDriver extends DriverCore {
|
||||
await driverInstance.updateSettings(jwpSettings);
|
||||
}
|
||||
|
||||
// if the user has asked for bidi support, and the driver says that it supports bidi,
|
||||
// send our bidi url back to the user. The inner driver will need to have already saved any
|
||||
// internal bidi urls it might want to proxy to, cause we are going to overwrite that
|
||||
// information here!
|
||||
if (dCaps.webSocketUrl && driverInstance.doesSupportBidi) {
|
||||
// if the user has asked for bidi support, send our bidi url back to the user. The inner
|
||||
// driver will need to have already saved any internal bidi urls it might want to proxy to,
|
||||
// cause we are going to overwrite that information here!
|
||||
if (dCaps.webSocketUrl) {
|
||||
const {address, port, basePath} = this.args;
|
||||
const scheme = `ws${this.server.isSecure() ? 's' : ''}`;
|
||||
const host = bidiHelpers.determineBiDiHost(address);
|
||||
@@ -626,12 +618,13 @@ class AppiumDriver extends DriverCore {
|
||||
* Get the appropriate plugins for a session (or sessionless plugins)
|
||||
*
|
||||
* @param {?string} sessionId - the sessionId (or null) to use to find plugins
|
||||
* @returns {Array} - array of plugin instances
|
||||
* @returns {Array<import('@appium/types').Plugin>} - array of plugin instances
|
||||
*/
|
||||
pluginsForSession(sessionId = null) {
|
||||
if (sessionId) {
|
||||
if (!this.sessionPlugins[sessionId]) {
|
||||
this.sessionPlugins[sessionId] = this.createPluginInstances();
|
||||
const driverId = generateDriverLogPrefix(this.sessions[sessionId]);
|
||||
this.sessionPlugins[sessionId] = this.createPluginInstances(driverId || null);
|
||||
}
|
||||
return this.sessionPlugins[sessionId];
|
||||
}
|
||||
@@ -662,14 +655,19 @@ class AppiumDriver extends DriverCore {
|
||||
|
||||
/**
|
||||
* Creates instances of all of the enabled Plugin classes
|
||||
* @param {string|null} driverId - ID to use for linking a driver to a plugin in logs
|
||||
* @returns {Plugin[]}
|
||||
*/
|
||||
createPluginInstances() {
|
||||
createPluginInstances(driverId = null) {
|
||||
/** @type {Plugin[]} */
|
||||
const pluginInstances = [];
|
||||
for (const [PluginClass, name] of this.pluginClasses.entries()) {
|
||||
const cliArgs = this.getCliArgsForPlugin(name);
|
||||
const plugin = new PluginClass(name, cliArgs);
|
||||
const plugin = new PluginClass(name, cliArgs, driverId);
|
||||
if (_.isFunction(/** @type {Plugin & ExtensionCore} */(plugin).updateBidiCommands)) {
|
||||
// some old plugin classes don't have `updateBidiCommands`
|
||||
/** @type {Plugin & ExtensionCore} */(plugin).updateBidiCommands(PluginClass.newBidiCommands ?? {});
|
||||
}
|
||||
pluginInstances.push(plugin);
|
||||
}
|
||||
return pluginInstances;
|
||||
@@ -830,6 +828,12 @@ class AppiumDriver extends DriverCore {
|
||||
`to session ID ${sessionId}`,
|
||||
);
|
||||
this.sessionPlugins[sessionId] = this.sessionlessPlugins;
|
||||
for (const p of /** @type {(Plugin & ExtensionCore)[]} */(this.sessionPlugins[sessionId])) {
|
||||
if (_.isFunction(p.updateLogPrefix)) {
|
||||
// some old plugin classes don't have `updateLogPrefix` yet
|
||||
p.updateLogPrefix(`${generateDriverLogPrefix(p)} <${generateDriverLogPrefix(this.sessions[sessionId])}>`);
|
||||
}
|
||||
}
|
||||
this.sessionlessPlugins = [];
|
||||
}
|
||||
|
||||
@@ -977,6 +981,7 @@ export {AppiumDriver};
|
||||
* @typedef {import('@appium/types').ExternalDriver} ExternalDriver
|
||||
* @typedef {import('@appium/types').PluginClass} PluginClass
|
||||
* @typedef {import('@appium/types').Plugin} Plugin
|
||||
* @typedef {import('@appium/base-driver').ExtensionCore} ExtensionCore
|
||||
* @typedef {import('@appium/types').DriverClass<import('@appium/types').Driver>} DriverClass
|
||||
*/
|
||||
|
||||
|
||||
+84
-50
@@ -2,6 +2,7 @@ import _ from 'lodash';
|
||||
import B from 'bluebird';
|
||||
import {
|
||||
errors,
|
||||
ExtensionCore,
|
||||
} from '@appium/base-driver';
|
||||
import {BIDI_BASE_PATH, BIDI_EVENT_NAME} from './constants';
|
||||
import WebSocket from 'ws';
|
||||
@@ -17,14 +18,18 @@ import type {
|
||||
ErrorBiDiCommandResponse,
|
||||
SuccessBiDiCommandResponse,
|
||||
ExternalDriver,
|
||||
StringRecord
|
||||
StringRecord,
|
||||
Plugin,
|
||||
BiDiResultData
|
||||
} from '@appium/types';
|
||||
|
||||
type ExtensionPlugin = Plugin & ExtensionCore
|
||||
type AnyDriver = ExternalDriver | AppiumDriver;
|
||||
type SendData = (data: string | Buffer) => Promise<void>;
|
||||
type LogSocketError = (err: Error) => void;
|
||||
interface InitBiDiSocketResult {
|
||||
bidiHandlerDriver: AnyDriver;
|
||||
bidiHandlerPlugins: ExtensionPlugin[];
|
||||
proxyClient: WebSocket | null;
|
||||
send: SendData;
|
||||
sendToProxy: SendData | null;
|
||||
@@ -64,7 +69,7 @@ export function determineBiDiHost(address: string): string {
|
||||
export function onBidiConnection(this: AppiumDriver, ws: WebSocket, req: IncomingMessage): void {
|
||||
try {
|
||||
const initBiDiSocketFunc: OmitThisParameter<typeof initBidiSocket> = initBidiSocket.bind(this);
|
||||
const {bidiHandlerDriver, proxyClient, send, sendToProxy, logSocketErr} = initBiDiSocketFunc(
|
||||
const {bidiHandlerDriver, bidiHandlerPlugins, proxyClient, send, sendToProxy, logSocketErr} = initBiDiSocketFunc(
|
||||
ws,
|
||||
req,
|
||||
);
|
||||
@@ -77,6 +82,7 @@ export function onBidiConnection(this: AppiumDriver, ws: WebSocket, req: Incomin
|
||||
send,
|
||||
sendToProxy,
|
||||
bidiHandlerDriver,
|
||||
bidiHandlerPlugins,
|
||||
logSocketErr,
|
||||
);
|
||||
if (proxyClient) {
|
||||
@@ -86,7 +92,7 @@ export function onBidiConnection(this: AppiumDriver, ws: WebSocket, req: Incomin
|
||||
}
|
||||
const initBidiEventListenersFunc: OmitThisParameter<typeof initBidiEventListeners> = initBidiEventListeners
|
||||
.bind(this);
|
||||
initBidiEventListenersFunc(ws, bidiHandlerDriver, send);
|
||||
initBidiEventListenersFunc(ws, bidiHandlerDriver, bidiHandlerPlugins, send);
|
||||
} catch (err) {
|
||||
this.log.error(err);
|
||||
try {
|
||||
@@ -95,14 +101,25 @@ export function onBidiConnection(this: AppiumDriver, ws: WebSocket, req: Incomin
|
||||
}
|
||||
}
|
||||
|
||||
function wrapCommandWithPlugins(driver: ExtensionCore, plugins: ExtensionCore[], method: string, params: StringRecord): () => Promise<BiDiResultData> {
|
||||
const [moduleName, methodName] = method.split('.');
|
||||
let next = async () => await driver.executeBidiCommand(method, params);
|
||||
for (const plugin of plugins.filter((p) => p.doesBidiCommandExist(moduleName, methodName))) {
|
||||
next = ((_next) => async () => await plugin.executeBidiCommand(method, params, _next, driver))(next);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* @param driver
|
||||
* @param plugins
|
||||
*/
|
||||
export async function onBidiMessage(
|
||||
this: AppiumDriver,
|
||||
data: Buffer,
|
||||
driver: AnyDriver
|
||||
driver: AnyDriver,
|
||||
plugins: ExtensionPlugin[]
|
||||
): Promise<SuccessBiDiCommandResponse | ErrorBiDiCommandResponse> {
|
||||
let resMessage: SuccessBiDiCommandResponse | ErrorBiDiCommandResponse;
|
||||
let id: number = 0;
|
||||
@@ -129,7 +146,8 @@ export async function onBidiMessage(
|
||||
`Missing params for BiDi operation in '${dataTruncated}`,
|
||||
);
|
||||
}
|
||||
const result = await driver.executeBidiCommand(method, params);
|
||||
const executeWrappedCommand = wrapCommandWithPlugins(driver as ExtensionCore, plugins, method, params);
|
||||
const result = await executeWrappedCommand();
|
||||
resMessage = {
|
||||
id,
|
||||
type: 'success',
|
||||
@@ -186,6 +204,7 @@ function initBidiSocket(this: AppiumDriver, ws: WebSocket, req: IncomingMessage)
|
||||
|
||||
let bidiHandlerDriver: AnyDriver;
|
||||
let proxyClient: WebSocket | null = null;
|
||||
const bidiHandlerPlugins: ExtensionPlugin[] = [];
|
||||
if (sessionMatch) {
|
||||
// If we found a session id, see if it matches an active session
|
||||
const sessionId = sessionMatch[1];
|
||||
@@ -217,15 +236,19 @@ function initBidiSocket(this: AppiumDriver, ws: WebSocket, req: IncomingMessage)
|
||||
`url ${bidiProxyUrl}, but this was not a valid url`,
|
||||
);
|
||||
}
|
||||
this.log.info(`Bidi connection for ${driverName} will be proxied to ${bidiProxyUrl}`);
|
||||
this.log.info(`Bidi connection for ${driverName} will be proxied to ${bidiProxyUrl}. ` +
|
||||
`Plugins will not handle bidi commands`);
|
||||
proxyClient = new WebSocket(bidiProxyUrl);
|
||||
this.bidiProxyClients[sessionId] = proxyClient;
|
||||
} else {
|
||||
bidiHandlerPlugins.push(...this.pluginsForSession(sessionId) as ExtensionPlugin[]);
|
||||
}
|
||||
} else {
|
||||
this.log.info('Bidi websocket connection made to main server');
|
||||
// no need to store the socket connection if it's to the main server since it will just
|
||||
// stay open as long as the server itself is and will close when the server closes.
|
||||
bidiHandlerDriver = this; // eslint-disable-line @typescript-eslint/no-this-alias
|
||||
bidiHandlerPlugins.push(...this.pluginsForSession() as ExtensionPlugin[]);
|
||||
}
|
||||
|
||||
const driverLog = bidiHandlerDriver.log;
|
||||
@@ -254,7 +277,7 @@ function initBidiSocket(this: AppiumDriver, ws: WebSocket, req: IncomingMessage)
|
||||
// bidi socket server (e.g. on a browser)
|
||||
const sendToProxy: SendData | null = proxyClient ? sendFactory(proxyClient) : null;
|
||||
|
||||
return {bidiHandlerDriver, proxyClient, send, sendToProxy, logSocketErr};
|
||||
return {bidiHandlerDriver, bidiHandlerPlugins, proxyClient, send, sendToProxy, logSocketErr};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,6 +338,7 @@ function initBidiProxyHandlers(
|
||||
* upstream socket
|
||||
* @param bidiHandlerDriver - the driver
|
||||
* handling the bidi commands
|
||||
* @param bidiHandlerPlugins - plugins that might also handle bidi commands
|
||||
* @param logSocketErr - a special prefixed logger
|
||||
*/
|
||||
function initBidiSocketHandlers(
|
||||
@@ -324,6 +348,7 @@ function initBidiSocketHandlers(
|
||||
send: SendData,
|
||||
sendToProxy: SendData | null,
|
||||
bidiHandlerDriver: AnyDriver,
|
||||
bidiHandlerPlugins: ExtensionPlugin[],
|
||||
logSocketErr: LogSocketError,
|
||||
): void {
|
||||
const driverLog = bidiHandlerDriver.log;
|
||||
@@ -340,9 +365,11 @@ function initBidiSocketHandlers(
|
||||
ws.on('message', async (data: Buffer) => {
|
||||
if (proxyClient && sendToProxy) {
|
||||
// if we're meant to proxy to an upstream bidi socket, just do that
|
||||
// TODO trying to determine how this proxying behaviour would interface with plugins is too
|
||||
// complex for now, so just ignore plugins in this case
|
||||
await sendToProxy(data.toString('utf8'));
|
||||
} else {
|
||||
const res = await this.onBidiMessage(data, bidiHandlerDriver);
|
||||
const res = await this.onBidiMessage(data, bidiHandlerDriver, bidiHandlerPlugins);
|
||||
await send(JSON.stringify(res));
|
||||
}
|
||||
});
|
||||
@@ -381,56 +408,63 @@ function initBidiEventListeners(
|
||||
this: AppiumDriver,
|
||||
ws: WebSocket,
|
||||
bidiHandlerDriver: AnyDriver,
|
||||
bidiHandlerPlugins: ExtensionPlugin[],
|
||||
send: SendData,
|
||||
): void {
|
||||
// If the driver emits a bidi event that should maybe get sent to the client, check to make
|
||||
// sure the client is subscribed and then pass it on
|
||||
const driverLog = bidiHandlerDriver.log;
|
||||
const driverEe = bidiHandlerDriver.eventEmitter;
|
||||
const eventLogCounts: Record<string, number> = BIDI_EVENTS_MAP.get(bidiHandlerDriver) ?? {};
|
||||
BIDI_EVENTS_MAP.set(bidiHandlerDriver, eventLogCounts);
|
||||
const eventListener = async ({context, method, params = {}}) => {
|
||||
// if the driver didn't specify a context, use the empty context
|
||||
if (!context) {
|
||||
context = '';
|
||||
}
|
||||
if (!method || !params) {
|
||||
driverLog.warn(
|
||||
`Driver emitted a bidi event that was malformed. Require method and params keys ` +
|
||||
`(with optional context). But instead received: ${_.truncate(JSON.stringify({
|
||||
context,
|
||||
method,
|
||||
params,
|
||||
}), {length: MAX_LOGGED_DATA_LENGTH})}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (ws.readyState !== WebSocket.OPEN) {
|
||||
// if the websocket is not still 'open', then we can ignore sending these events
|
||||
if (ws.readyState > WebSocket.OPEN) {
|
||||
// if the websocket is closed or closing, we can remove this listener as well to avoid
|
||||
// leaks
|
||||
driverEe.removeListener(BIDI_EVENT_NAME, eventListener);
|
||||
const eventListenerFactory = (extType: 'driver'|'plugin', ext: ExtensionCore) => {
|
||||
const eventListener = async ({context, method, params = {}}) => {
|
||||
// if the driver didn't specify a context, use the empty context
|
||||
if (!context) {
|
||||
context = '';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const eventSubs = bidiHandlerDriver.bidiEventSubs[method];
|
||||
if (_.isArray(eventSubs) && eventSubs.includes(context)) {
|
||||
if (method in eventLogCounts) {
|
||||
++eventLogCounts[method];
|
||||
} else {
|
||||
driverLog.info(
|
||||
`<-- BIDI EVENT ${method} (context: '${context}', ` +
|
||||
`params: ${_.truncate(JSON.stringify(params), {length: MAX_LOGGED_DATA_LENGTH})}). ` +
|
||||
`All further similar events won't be logged.`,
|
||||
if (!method || !params) {
|
||||
ext.log?.warn( // some old plugins might not have the `log` property
|
||||
`${_.capitalize(extType)} emitted a bidi event that was malformed. Require method and params keys ` +
|
||||
`(with optional context). But instead received: ${_.truncate(JSON.stringify({
|
||||
context,
|
||||
method,
|
||||
params,
|
||||
}), {length: MAX_LOGGED_DATA_LENGTH})}`,
|
||||
);
|
||||
eventLogCounts[method] = 1;
|
||||
return;
|
||||
}
|
||||
// now we can send the event onto the socket
|
||||
const ev = {type: 'event', context, method, params};
|
||||
await send(JSON.stringify(ev));
|
||||
}
|
||||
if (ws.readyState !== WebSocket.OPEN) {
|
||||
// if the websocket is not still 'open', then we can ignore sending these events
|
||||
if (ws.readyState > WebSocket.OPEN) {
|
||||
// if the websocket is closed or closing, we can remove this listener as well to avoid
|
||||
// leaks. Some old plugin classes might not have the `eventEmitter` property, so use an
|
||||
// existence guard for now.
|
||||
ext.eventEmitter?.removeListener(BIDI_EVENT_NAME, eventListener);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const eventSubs = bidiHandlerDriver.bidiEventSubs[method];
|
||||
if (_.isArray(eventSubs) && eventSubs.includes(context)) {
|
||||
if (method in eventLogCounts) {
|
||||
++eventLogCounts[method];
|
||||
} else {
|
||||
ext.log?.info( // some old plugins might not have the `log` property
|
||||
`<-- BIDI EVENT ${method} (context: '${context}', ` +
|
||||
`params: ${_.truncate(JSON.stringify(params), {length: MAX_LOGGED_DATA_LENGTH})}). ` +
|
||||
`All further similar events won't be logged.`,
|
||||
);
|
||||
eventLogCounts[method] = 1;
|
||||
}
|
||||
// now we can send the event onto the socket
|
||||
const ev = {type: 'event', context, method, params};
|
||||
await send(JSON.stringify(ev));
|
||||
}
|
||||
};
|
||||
return eventListener;
|
||||
};
|
||||
driverEe.on(BIDI_EVENT_NAME, eventListener);
|
||||
bidiHandlerDriver.eventEmitter.on(BIDI_EVENT_NAME, eventListenerFactory('driver', bidiHandlerDriver as ExtensionCore));
|
||||
for (const plugin of bidiHandlerPlugins) {
|
||||
// some old plugins might not have the eventEmitter property
|
||||
plugin.eventEmitter?.on(BIDI_EVENT_NAME, eventListenerFactory('plugin', plugin));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "appium",
|
||||
"version": "2.14.0",
|
||||
"version": "2.15.0",
|
||||
"description": "Automation for Apps.",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -60,13 +60,13 @@
|
||||
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/base-driver": "^9.14.0",
|
||||
"@appium/base-plugin": "^2.2.51",
|
||||
"@appium/docutils": "^1.0.27",
|
||||
"@appium/base-driver": "^9.15.0",
|
||||
"@appium/base-plugin": "^2.3.0",
|
||||
"@appium/docutils": "^1.0.29",
|
||||
"@appium/logger": "^1.6.1",
|
||||
"@appium/schema": "^0.7.1",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@sidvind/better-ajv-errors": "3.0.1",
|
||||
"@types/argparse": "2.0.17",
|
||||
"@types/bluebird": "3.5.42",
|
||||
@@ -89,7 +89,7 @@
|
||||
"resolve-from": "5.0.0",
|
||||
"semver": "7.6.3",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"winston": "3.17.0",
|
||||
"wrap-ansi": "7.0.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"webdriverio": "9.5.0"
|
||||
"webdriverio": "9.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ describe('FakeDriver via HTTP', function () {
|
||||
it('should be able to subscribe and unsubscribe to bidi events', async function () {
|
||||
let collectedEvents = [];
|
||||
// asyncrhonously start our listener
|
||||
driver.on('clock.currentTime', ({time}) => {
|
||||
driver.on('appium:clock.currentTime', ({time}) => {
|
||||
collectedEvents.push(time);
|
||||
});
|
||||
|
||||
@@ -556,22 +556,22 @@ describe('FakeDriver via HTTP', function () {
|
||||
collectedEvents.should.be.empty;
|
||||
|
||||
// now subscribe and wait and assert that some events have been collected
|
||||
await driver.sessionSubscribe({events: ['clock.currentTime']});
|
||||
await driver.sessionSubscribe({events: ['appium:clock.currentTime']});
|
||||
await B.delay(750);
|
||||
collectedEvents.should.not.be.empty;
|
||||
|
||||
// finally unsubscribe and wait and assert that some events have been collected
|
||||
await driver.sessionUnsubscribe({events: ['clock.currentTime']});
|
||||
await driver.sessionUnsubscribe({events: ['appium:clock.currentTime']});
|
||||
collectedEvents = [];
|
||||
await B.delay(750);
|
||||
collectedEvents.should.be.empty;
|
||||
});
|
||||
|
||||
it('should allow custom bidi commands', async function () {
|
||||
let {result} = await driver.send({method: 'fake.getFakeThing', params: {}});
|
||||
let {result} = await driver.send({method: 'appium:fake.getFakeThing', params: {}});
|
||||
should.not.exist(result);
|
||||
await driver.send({method: 'fake.setFakeThing', params: {thing: 'this is from bidi'}});
|
||||
({result} = await driver.send({method: 'fake.getFakeThing', params: {}}));
|
||||
await driver.send({method: 'appium:fake.setFakeThing', params: {thing: 'this is from bidi'}});
|
||||
({result} = await driver.send({method: 'appium:fake.getFakeThing', params: {}}));
|
||||
result.should.eql('this is from bidi');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,11 +28,32 @@ const wdOpts = {
|
||||
capabilities: W3C_PREFIXED_CAPS,
|
||||
};
|
||||
|
||||
/** @type {Partial<import('appium/types').ParsedArgs>} */
|
||||
let baseServerArgs;
|
||||
|
||||
/**
|
||||
* @param {Partial<import('appium/types').ParsedArgs>} args
|
||||
*/
|
||||
function serverSetup(args) {
|
||||
/** @type {AppiumServer|null} */
|
||||
let server = null;
|
||||
|
||||
before(async function () { // eslint-disable-line mocha/no-top-level-hooks
|
||||
// then start server if we need to
|
||||
server = /** @type {AppiumServer} */ (
|
||||
await appiumServer({...baseServerArgs, ...args})
|
||||
);
|
||||
});
|
||||
after(async function () { // eslint-disable-line mocha/no-top-level-hooks
|
||||
if (server) {
|
||||
await server.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('FakePlugin w/ FakeDriver via HTTP', function () {
|
||||
/** @type {string} */
|
||||
let appiumHome;
|
||||
/** @type {Partial<import('appium/types').ParsedArgs>} */
|
||||
let baseServerArgs;
|
||||
/** @type {string} */
|
||||
let testServerBaseUrl;
|
||||
/** @type {number} */
|
||||
@@ -61,7 +82,7 @@ describe('FakePlugin w/ FakeDriver via HTTP', function () {
|
||||
subcommand: DRIVER_TYPE,
|
||||
suppressOutput: true,
|
||||
},
|
||||
driverConfig
|
||||
driverConfig,
|
||||
);
|
||||
if (!('fake' in driverList)) {
|
||||
await runExtensionCommand(
|
||||
@@ -71,7 +92,7 @@ describe('FakePlugin w/ FakeDriver via HTTP', function () {
|
||||
installType: INSTALL_TYPE_LOCAL,
|
||||
subcommand: DRIVER_TYPE,
|
||||
},
|
||||
driverConfig
|
||||
driverConfig,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,7 +104,7 @@ describe('FakePlugin w/ FakeDriver via HTTP', function () {
|
||||
json: true,
|
||||
suppressOutput: true,
|
||||
},
|
||||
pluginConfig
|
||||
pluginConfig,
|
||||
);
|
||||
if (!('fake' in pluginList)) {
|
||||
await runExtensionCommand(
|
||||
@@ -93,7 +114,7 @@ describe('FakePlugin w/ FakeDriver via HTTP', function () {
|
||||
plugin: FAKE_PLUGIN_DIR,
|
||||
installType: INSTALL_TYPE_LOCAL,
|
||||
},
|
||||
pluginConfig
|
||||
pluginConfig,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -133,27 +154,9 @@ describe('FakePlugin w/ FakeDriver via HTTP', function () {
|
||||
|
||||
for (const registrationType of ['explicit', 'all']) {
|
||||
describe(`with plugin registered via type ${registrationType}`, function () {
|
||||
/** @type {AppiumServer} */
|
||||
let server;
|
||||
/** @type {import('type-fest').LiteralUnion<'all', string>[]} */
|
||||
let usePlugins;
|
||||
before(async function () {
|
||||
// then start server if we need to
|
||||
usePlugins = registrationType === 'explicit' ? ['fake'] : ['all'];
|
||||
const args = {
|
||||
appiumHome,
|
||||
port,
|
||||
address: TEST_HOST,
|
||||
usePlugins,
|
||||
useDrivers: ['fake'],
|
||||
};
|
||||
server = /** @type {AppiumServer} */ (await appiumServer(args));
|
||||
});
|
||||
after(async function () {
|
||||
if (server) {
|
||||
await server.close();
|
||||
}
|
||||
});
|
||||
const usePlugins = registrationType === 'explicit' ? ['fake'] : ['all'];
|
||||
serverSetup({usePlugins});
|
||||
it('should update the server', async function () {
|
||||
const res = {fake: 'fakeResponse'};
|
||||
(await axios.post(`http://${TEST_HOST}:${port}/fake`)).data.should.eql(res);
|
||||
@@ -369,6 +372,91 @@ describe('FakePlugin w/ FakeDriver via HTTP', function () {
|
||||
sum.should.eql(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('BiDi support', function () {
|
||||
describe('with a single plugin', function() {
|
||||
/** @type {import('webdriverio').Browser} */
|
||||
let driver;
|
||||
|
||||
// this 'after' block needs to come before 'serverSetup' so that the delete session happens
|
||||
// before the server shutdown
|
||||
after(async function () {
|
||||
if (driver) {
|
||||
await driver.deleteSession();
|
||||
}
|
||||
});
|
||||
|
||||
serverSetup({});
|
||||
|
||||
before(async function () {
|
||||
const caps = {...wdOpts.capabilities, webSocketUrl: true, 'appium:runClock': true};
|
||||
driver = await wdio({...wdOpts, capabilities: caps});
|
||||
});
|
||||
|
||||
it('should handle custom bidi commands if registered', async function () {
|
||||
let {result} = await driver.send({method: 'appium:fake.getPluginThing', params: {}});
|
||||
should.not.exist(result);
|
||||
await driver.send({method: 'appium:fake.setPluginThing', params: {thing: 'plugin bidi'}});
|
||||
({result} = await driver.send({method: 'appium:fake.getPluginThing', params: {}}));
|
||||
result.should.eql('plugin bidi');
|
||||
});
|
||||
|
||||
it('should subscribe and unsubscribe to/from custom bidi events', async function () {
|
||||
let retrievals = 0;
|
||||
// asyncrhonously start our listener
|
||||
driver.on('appium:fake.pluginThingRetrieved', () => {
|
||||
retrievals++;
|
||||
});
|
||||
|
||||
await driver.send({method: 'appium:fake.getPluginThing', params: {}});
|
||||
retrievals.should.eql(0);
|
||||
|
||||
await driver.sessionSubscribe({events: ['appium:fake.pluginThingRetrieved']});
|
||||
await driver.send({method: 'appium:fake.getPluginThing', params: {}});
|
||||
await driver.send({method: 'appium:fake.getPluginThing', params: {}});
|
||||
retrievals.should.eql(2);
|
||||
|
||||
await driver.sessionUnsubscribe({events: ['appium:fake.pluginThingRetrieved']});
|
||||
await driver.send({method: 'appium:fake.getPluginThing', params: {}});
|
||||
await driver.send({method: 'appium:fake.getPluginThing', params: {}});
|
||||
retrievals.should.eql(2);
|
||||
});
|
||||
|
||||
it('should subscribe and unsubscribe to/from custom bidi events and merge with driver', async function () {
|
||||
let collectedEvents = [];
|
||||
// asyncrhonously start our listener
|
||||
driver.on('appium:clock.currentTime', ({time}) => {
|
||||
collectedEvents.push(time);
|
||||
});
|
||||
|
||||
// wait for some time to be sure clock events have happened, and assert we don't receive
|
||||
// any yet
|
||||
await B.delay(750);
|
||||
collectedEvents.should.be.empty;
|
||||
|
||||
// now subscribe and wait and assert that some events have been collected
|
||||
await driver.sessionSubscribe({events: ['appium:clock.currentTime']});
|
||||
await B.delay(800);
|
||||
collectedEvents.length.should.eql(5);
|
||||
|
||||
// finally unsubscribe and wait and assert that some events have been collected
|
||||
await driver.sessionUnsubscribe({events: ['appium:clock.currentTime']});
|
||||
collectedEvents = [];
|
||||
await B.delay(800);
|
||||
collectedEvents.should.be.empty;
|
||||
});
|
||||
|
||||
it('should call underlying driver bidi method if next is called', async function () {
|
||||
const {result} = await driver.send({method: 'appium:fake.doSomeMath', params: {num1: 2, num2: 3}});
|
||||
result.should.eql(11);
|
||||
});
|
||||
|
||||
it('should override and not call underlying driver bidi method if next is not called', async function () {
|
||||
const {result} = await driver.send({method: 'appium:fake.doSomeMath2', params: {num1: 2, num2: 3}});
|
||||
result.should.eql(6);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [9.15.0](https://github.com/appium/appium/compare/@appium/base-driver@9.14.1...@appium/base-driver@9.15.0) (2025-01-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,base-plugin:** allow plugins to define custom bidi commands and emit bidi events ([#20876](https://github.com/appium/appium/issues/20876)) ([8df1c21](https://github.com/appium/appium/commit/8df1c217a15d30300c04b9f59cdbdffa70325828))
|
||||
|
||||
|
||||
|
||||
## [9.14.1](https://github.com/appium/appium/compare/@appium/base-driver@9.14.0...@appium/base-driver@9.14.1) (2025-01-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **driver-test-support:** update dependency @types/lodash to v4.17.14 ([#20877](https://github.com/appium/appium/issues/20877)) ([fe209ed](https://github.com/appium/appium/commit/fe209ed660e0f790c98cd51938d0c75712cfd8e4))
|
||||
|
||||
|
||||
|
||||
## [9.14.0](https://github.com/appium/appium/compare/@appium/base-driver@9.13.1...@appium/base-driver@9.14.0) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {logger} from '@appium/support';
|
||||
import type {
|
||||
AppiumLogger,
|
||||
Constraints,
|
||||
@@ -11,22 +10,18 @@ import type {
|
||||
Protocol,
|
||||
RouteMatcher,
|
||||
StringRecord,
|
||||
BidiModuleMap,
|
||||
BiDiResultData,
|
||||
} from '@appium/types';
|
||||
import AsyncLock from 'async-lock';
|
||||
import _ from 'lodash';
|
||||
import {EventEmitter} from 'node:events';
|
||||
import os from 'node:os';
|
||||
import {
|
||||
DEFAULT_BASE_PATH,
|
||||
PROTOCOLS,
|
||||
MAX_LOG_BODY_LENGTH,
|
||||
} from '../constants';
|
||||
import {errors} from '../protocol';
|
||||
import {DeviceSettings} from './device-settings';
|
||||
import * as helpers from './helpers';
|
||||
import {BIDI_COMMANDS} from '../protocol/bidi-commands';
|
||||
import {ExtensionCore} from './extension-core';
|
||||
|
||||
const NEW_COMMAND_TIMEOUT_MS = 60 * 1000;
|
||||
|
||||
@@ -36,7 +31,7 @@ const ALL_DRIVERS_MATCH = '*';
|
||||
const FEATURE_NAME_SEPARATOR = ':';
|
||||
|
||||
export class DriverCore<const C extends Constraints, Settings extends StringRecord = StringRecord>
|
||||
implements Core<C, Settings>
|
||||
extends ExtensionCore implements Core<C, Settings>
|
||||
{
|
||||
/**
|
||||
* Make the basedriver version available so for any driver which inherits from this package, we
|
||||
@@ -82,11 +77,8 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
||||
|
||||
protected _eventHistory: EventHistory;
|
||||
|
||||
// used to handle driver events
|
||||
eventEmitter: NodeJS.EventEmitter;
|
||||
|
||||
/**
|
||||
* @privateRemarks XXX: unsure why this is wrapped in a getter when nothing else is
|
||||
* TODO: remove this._log and use this.log instead
|
||||
*/
|
||||
protected _log: AppiumLogger;
|
||||
|
||||
@@ -106,14 +98,10 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
||||
|
||||
protocol?: Protocol;
|
||||
|
||||
bidiEventSubs: Record<string, string[]>;
|
||||
|
||||
doesSupportBidi: boolean;
|
||||
|
||||
bidiCommands: BidiModuleMap = BIDI_COMMANDS as BidiModuleMap;
|
||||
|
||||
constructor(opts: InitialOpts = <InitialOpts>{}, shouldValidateCaps = true) {
|
||||
this._log = logger.getLogger(helpers.generateDriverLogPrefix(this as Core<C>));
|
||||
super();
|
||||
this._log = this.log; // TODO: remove references to this._log and use this.log instead
|
||||
|
||||
|
||||
// setup state
|
||||
this.opts = opts as DriverOpts<C>;
|
||||
@@ -141,16 +129,9 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
||||
this.managedDrivers = [];
|
||||
this.noCommandTimer = null;
|
||||
this._eventHistory = {commands: []};
|
||||
this.eventEmitter = new EventEmitter();
|
||||
this.shutdownUnexpectedly = false;
|
||||
this.commandsQueueGuard = new AsyncLock();
|
||||
this.settings = new DeviceSettings();
|
||||
this.bidiEventSubs = {};
|
||||
this.doesSupportBidi = false;
|
||||
}
|
||||
|
||||
get log() {
|
||||
return this._log;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,75 +414,4 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
||||
}
|
||||
}
|
||||
|
||||
updateBidiCommands(cmds: BidiModuleMap): void {
|
||||
const overlappingKeys = _.intersection(Object.keys(cmds), Object.keys(this.bidiCommands));
|
||||
if (overlappingKeys.length) {
|
||||
this.log.warn(`Overwriting existing bidi modules: ${JSON.stringify(overlappingKeys)}. This may not be intended!`);
|
||||
}
|
||||
this.bidiCommands = {
|
||||
...this.bidiCommands,
|
||||
...cmds,
|
||||
};
|
||||
}
|
||||
|
||||
async executeBidiCommand(bidiCmd: string, bidiParams: StringRecord): Promise<BiDiResultData> {
|
||||
const [moduleName, methodName] = bidiCmd.split('.');
|
||||
|
||||
// if we don't get a valid format for bidi command name, reject
|
||||
if (!moduleName || !methodName) {
|
||||
throw new errors.UnknownCommandError(
|
||||
`Did not receive a valid BiDi module and method name ` +
|
||||
`of the form moduleName.methodName. Instead received ` +
|
||||
`'${moduleName}.${methodName}'`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// if the command module or method isn't part of our spec, reject
|
||||
if (!this.bidiCommands[moduleName] || !this.bidiCommands[moduleName][methodName]) {
|
||||
throw new errors.UnknownCommandError();
|
||||
}
|
||||
|
||||
const {command, params} = this.bidiCommands[moduleName][methodName];
|
||||
// if the command method isn't part of our spec, also reject
|
||||
if (!command) {
|
||||
throw new errors.UnknownCommandError();
|
||||
}
|
||||
|
||||
// If the driver doesn't have this command, it must not be implemented
|
||||
if (!this[command]) {
|
||||
throw new errors.NotYetImplementedError();
|
||||
}
|
||||
|
||||
// TODO improve param parsing and error messages along the lines of what we have in the http
|
||||
// handlers
|
||||
const args: any[] = [];
|
||||
if (params?.required?.length) {
|
||||
for (const requiredParam of params.required) {
|
||||
if (_.isUndefined(bidiParams[requiredParam])) {
|
||||
throw new errors.InvalidArgumentError(
|
||||
`The ${requiredParam} parameter was required but you omitted it`,
|
||||
);
|
||||
}
|
||||
args.push(bidiParams[requiredParam]);
|
||||
}
|
||||
}
|
||||
if (params?.optional?.length) {
|
||||
for (const optionalParam of params.optional) {
|
||||
args.push(bidiParams[optionalParam]);
|
||||
}
|
||||
}
|
||||
const logParams = _.truncate(JSON.stringify(bidiParams), {length: MAX_LOG_BODY_LENGTH});
|
||||
this.log.debug(
|
||||
`Executing bidi command '${bidiCmd}' with params ${logParams} by passing to driver ` +
|
||||
`method '${command}'`,
|
||||
);
|
||||
const response = await this[command](...args);
|
||||
const finalResponse = _.isUndefined(response) ? {} : response;
|
||||
this.log.debug(
|
||||
`Responding to bidi command '${bidiCmd}' with ` +
|
||||
`${_.truncate(JSON.stringify(finalResponse), {length: MAX_LOG_BODY_LENGTH})}`
|
||||
);
|
||||
return finalResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
import {logger} from '@appium/support';
|
||||
import {EventEmitter} from 'node:events';
|
||||
import type {
|
||||
AppiumLogger,
|
||||
BidiModuleMap,
|
||||
BiDiResultData,
|
||||
StringRecord,
|
||||
} from '@appium/types';
|
||||
import {
|
||||
MAX_LOG_BODY_LENGTH,
|
||||
} from '../constants';
|
||||
import {errors} from '../protocol';
|
||||
import {BIDI_COMMANDS} from '../protocol/bidi-commands';
|
||||
import _ from 'lodash';
|
||||
import {generateDriverLogPrefix} from './helpers';
|
||||
|
||||
export class ExtensionCore {
|
||||
bidiEventSubs: Record<string, string[]>;
|
||||
bidiCommands: BidiModuleMap = BIDI_COMMANDS as BidiModuleMap;
|
||||
_logPrefix?: string;
|
||||
protected _log: AppiumLogger;
|
||||
// used to handle driver events
|
||||
readonly eventEmitter: NodeJS.EventEmitter;
|
||||
|
||||
|
||||
constructor(logPrefix?: string) {
|
||||
this._logPrefix = logPrefix;
|
||||
this.bidiEventSubs = {};
|
||||
this.eventEmitter = new EventEmitter();
|
||||
}
|
||||
|
||||
get log(): AppiumLogger {
|
||||
if (!this._log) {
|
||||
this.updateLogPrefix(this._logPrefix ?? generateDriverLogPrefix(this));
|
||||
}
|
||||
return this._log;
|
||||
}
|
||||
|
||||
updateLogPrefix(logPrefix: string) {
|
||||
this._log = logger.getLogger(logPrefix);
|
||||
}
|
||||
|
||||
updateBidiCommands(cmds: BidiModuleMap): void {
|
||||
const overlappingKeys = _.intersection(Object.keys(cmds), Object.keys(this.bidiCommands));
|
||||
if (overlappingKeys.length) {
|
||||
this.log.warn(`Overwriting existing bidi modules: ${JSON.stringify(overlappingKeys)}. This may not be intended!`);
|
||||
}
|
||||
this.bidiCommands = {
|
||||
...this.bidiCommands,
|
||||
...cmds,
|
||||
};
|
||||
}
|
||||
|
||||
doesBidiCommandExist(moduleName: string, methodName: string): boolean {
|
||||
try {
|
||||
this.ensureBidiCommandExists(moduleName, methodName);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ensureBidiCommandExists(moduleName: string, methodName: string): void {
|
||||
// if we don't get a valid format for bidi command name, reject
|
||||
if (!moduleName || !methodName) {
|
||||
throw new errors.UnknownCommandError(
|
||||
`Did not receive a valid BiDi module and method name ` +
|
||||
`of the form moduleName.methodName. Instead received ` +
|
||||
`'${moduleName}.${methodName}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// if the command module or method isn't part of our spec, reject
|
||||
if (!this.bidiCommands[moduleName] || !this.bidiCommands[moduleName][methodName]) {
|
||||
throw new errors.UnknownCommandError();
|
||||
}
|
||||
|
||||
const {command} = this.bidiCommands[moduleName][methodName];
|
||||
// if the command method isn't part of our spec, also reject
|
||||
if (!command) {
|
||||
throw new errors.UnknownCommandError();
|
||||
}
|
||||
|
||||
// If the driver doesn't have this command, it must not be implemented
|
||||
if (!this[command]) {
|
||||
throw new errors.NotYetImplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
async executeBidiCommand(bidiCmd: string, bidiParams: StringRecord, next?: () => Promise<any>, driver?: ExtensionCore): Promise<BiDiResultData> {
|
||||
const handlerType = (next && driver) ? 'plugin' : 'driver';
|
||||
const [moduleName, methodName] = bidiCmd.split('.');
|
||||
this.ensureBidiCommandExists(moduleName, methodName);
|
||||
const {command, params} = this.bidiCommands[moduleName][methodName];
|
||||
|
||||
// TODO improve param parsing and error messages along the lines of what we have in the http
|
||||
// handlers
|
||||
const args: any[] = [];
|
||||
if (params?.required?.length) {
|
||||
for (const requiredParam of params.required) {
|
||||
if (_.isUndefined(bidiParams[requiredParam])) {
|
||||
throw new errors.InvalidArgumentError(
|
||||
`The ${requiredParam} parameter was required but you omitted it`,
|
||||
);
|
||||
}
|
||||
args.push(bidiParams[requiredParam]);
|
||||
}
|
||||
}
|
||||
if (params?.optional?.length) {
|
||||
for (const optionalParam of params.optional) {
|
||||
args.push(bidiParams[optionalParam]);
|
||||
}
|
||||
}
|
||||
const logParams = _.truncate(JSON.stringify(bidiParams), {length: MAX_LOG_BODY_LENGTH});
|
||||
this.log.debug(
|
||||
`Executing bidi command '${bidiCmd}' with params ${logParams} by passing to ${handlerType} ` +
|
||||
`method '${command}'`,
|
||||
);
|
||||
// call the handler with the signature appropriate to extension type (plugin or driver)
|
||||
const response = (next && driver) ? await this[command](next, driver, ...args) : await this[command](...args);
|
||||
const finalResponse = _.isUndefined(response) ? {} : response;
|
||||
this.log.debug(
|
||||
`Responding to bidi command '${bidiCmd}' with ` +
|
||||
`${_.truncate(JSON.stringify(finalResponse), {length: MAX_LOG_BODY_LENGTH})}`
|
||||
);
|
||||
return finalResponse;
|
||||
}
|
||||
}
|
||||
@@ -401,7 +401,7 @@ export function parseCapsArray(cap) {
|
||||
/**
|
||||
* Generate a string that uniquely describes driver instance
|
||||
*
|
||||
* @param {import('@appium/types').Core} obj driver instance
|
||||
* @param {object} obj driver instance
|
||||
* @param {string?} [sessionId=null] session identifier (if exists).
|
||||
* This parameter is deprecated and is not used.
|
||||
* @returns {string}
|
||||
|
||||
@@ -10,6 +10,7 @@ try {
|
||||
}
|
||||
|
||||
// BaseDriver exports
|
||||
export {ExtensionCore} from './basedriver/extension-core';
|
||||
import {BaseDriver} from './basedriver/driver';
|
||||
export {DriverCore} from './basedriver/core';
|
||||
export {DeviceSettings} from './basedriver/device-settings';
|
||||
@@ -48,6 +49,8 @@ export {
|
||||
// Web socket helpers
|
||||
export {DEFAULT_WS_PATHNAME_PREFIX} from './express/websocket';
|
||||
|
||||
export {generateDriverLogPrefix} from './basedriver/helpers';
|
||||
|
||||
/**
|
||||
* @typedef {import('./express/server').ServerOpts} ServerOpts
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/base-driver",
|
||||
"version": "9.14.0",
|
||||
"version": "9.15.0",
|
||||
"description": "Base driver class for Appium drivers",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -44,13 +44,13 @@
|
||||
"test:types": "tsd"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/async-lock": "1.4.2",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"@types/express": "5.0.0",
|
||||
"@types/lodash": "4.17.13",
|
||||
"@types/lodash": "4.17.14",
|
||||
"@types/method-override": "3.0.0",
|
||||
"@types/serve-favicon": "2.5.7",
|
||||
"async-lock": "1.4.1",
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.3.0](https://github.com/appium/appium/compare/@appium/base-plugin@2.2.52...@appium/base-plugin@2.3.0) (2025-01-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,base-plugin:** allow plugins to define custom bidi commands and emit bidi events ([#20876](https://github.com/appium/appium/issues/20876)) ([8df1c21](https://github.com/appium/appium/commit/8df1c217a15d30300c04b9f59cdbdffa70325828))
|
||||
|
||||
|
||||
|
||||
## [2.2.52](https://github.com/appium/appium/compare/@appium/base-plugin@2.2.51...@appium/base-plugin@2.2.52) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @appium/base-plugin
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.51](https://github.com/appium/appium/compare/@appium/base-plugin@2.2.50...@appium/base-plugin@2.2.51) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import {logger} from '@appium/support';
|
||||
import {validateExecuteMethodParams} from '@appium/base-driver';
|
||||
import {ExtensionCore, generateDriverLogPrefix, validateExecuteMethodParams} from '@appium/base-driver';
|
||||
|
||||
/**
|
||||
* @implements {Plugin}
|
||||
*/
|
||||
class BasePlugin {
|
||||
class BasePlugin extends ExtensionCore {
|
||||
|
||||
/**
|
||||
* @deprecated Use this.log instead of this.logger
|
||||
* @type {import('@appium/types').AppiumLogger}
|
||||
*/
|
||||
logger;
|
||||
|
||||
/**
|
||||
* Subclasses should use type `import('@appium/types').MethodMap<SubclassName>`.
|
||||
*
|
||||
@@ -43,11 +49,16 @@ class BasePlugin {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Record<string,unknown>} [cliArgs]
|
||||
* @param {string|null} driverId
|
||||
*/
|
||||
constructor(name, cliArgs = {}) {
|
||||
constructor(name, cliArgs = {}, driverId = null) {
|
||||
super();
|
||||
if (driverId) {
|
||||
this.updateLogPrefix(`${generateDriverLogPrefix(this)} <${driverId}>`);
|
||||
}
|
||||
this.name = name;
|
||||
this.cliArgs = cliArgs;
|
||||
this.logger = logger.getLogger(`Plugin [${name}]`);
|
||||
this.logger = this.log;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/base-plugin",
|
||||
"version": "2.2.51",
|
||||
"version": "2.3.0",
|
||||
"description": "The base plugin used to create Appium 2.0 plugins",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -40,8 +40,8 @@
|
||||
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/base-driver": "^9.14.0",
|
||||
"@appium/support": "^6.0.1"
|
||||
"@appium/base-driver": "^9.15.0",
|
||||
"@appium/support": "^6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.0.29](https://github.com/appium/appium/compare/@appium/docutils@1.0.28...@appium/docutils@1.0.29) (2025-01-08)
|
||||
|
||||
**Note:** Version bump only for package @appium/docutils
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.28](https://github.com/appium/appium/compare/@appium/docutils@1.0.27...@appium/docutils@1.0.28) (2025-01-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **support:** update dependency teen_process to v2.2.3 ([#20882](https://github.com/appium/appium/issues/20882)) ([488e5de](https://github.com/appium/appium/commit/488e5dea82d3c525acf483952570e32f319f3722))
|
||||
|
||||
|
||||
|
||||
## [1.0.27](https://github.com/appium/appium/compare/@appium/docutils@1.0.26...@appium/docutils@1.0.27) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/docutils",
|
||||
"version": "1.0.27",
|
||||
"version": "1.0.29",
|
||||
"description": "Documentation generation utilities for Appium and related projects",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -48,7 +48,7 @@
|
||||
"start": "node ./build/lib/cli/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@appium/tsconfig": "^0.3.3",
|
||||
"@sliphua/lilconfig-ts-loader": "3.2.2",
|
||||
"@types/which": "3.0.4",
|
||||
@@ -62,7 +62,7 @@
|
||||
"read-pkg": "5.2.0",
|
||||
"semver": "7.6.3",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"typescript": "5.7.2",
|
||||
"yaml": "2.7.0",
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.7.4](https://github.com/appium/appium/compare/@appium/driver-test-support@0.7.3...@appium/driver-test-support@0.7.4) (2025-01-08)
|
||||
|
||||
**Note:** Version bump only for package @appium/driver-test-support
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.7.3](https://github.com/appium/appium/compare/@appium/driver-test-support@0.7.2...@appium/driver-test-support@0.7.3) (2025-01-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **driver-test-support:** update dependency @types/lodash to v4.17.14 ([#20877](https://github.com/appium/appium/issues/20877)) ([fe209ed](https://github.com/appium/appium/commit/fe209ed660e0f790c98cd51938d0c75712cfd8e4))
|
||||
|
||||
|
||||
|
||||
## [0.7.2](https://github.com/appium/appium/compare/@appium/driver-test-support@0.7.1...@appium/driver-test-support@0.7.2) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/driver-test-support",
|
||||
"version": "0.7.2",
|
||||
"version": "0.7.4",
|
||||
"description": "Test utilities for Appium drivers",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -41,8 +41,8 @@
|
||||
},
|
||||
"types": "./build/lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@appium/types": "^0.23.0",
|
||||
"@types/lodash": "4.17.13",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@types/lodash": "4.17.14",
|
||||
"axios": "1.7.9",
|
||||
"bluebird": "3.7.2",
|
||||
"chai": "5.1.2",
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.0.2](https://github.com/appium/appium/compare/@appium/eslint-config-appium-ts@1.0.1...@appium/eslint-config-appium-ts@1.0.2) (2025-01-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **eslint-config-appium-ts:** add Prettier config, update typescript-eslint imports ([#20887](https://github.com/appium/appium/issues/20887)) ([aad5709](https://github.com/appium/appium/commit/aad57099135a02907b0cd03617c52d7baf248a26))
|
||||
|
||||
|
||||
|
||||
## [1.0.1](https://github.com/appium/appium/compare/@appium/eslint-config-appium-ts@0.3.3...@appium/eslint-config-appium-ts@1.0.1) (2025-01-02)
|
||||
|
||||
**Note:** Version bump only for package @appium/eslint-config-appium-ts
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
import path from 'node:path';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import fs from 'node:fs';
|
||||
|
||||
import {includeIgnoreFile} from '@eslint/compat';
|
||||
import js from '@eslint/js';
|
||||
import tsPlugin from '@typescript-eslint/eslint-plugin';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
import eslintConfigPrettier from 'eslint-config-prettier';
|
||||
import globals from 'globals';
|
||||
import pluginPromise from 'eslint-plugin-promise';
|
||||
import importPlugin from 'eslint-plugin-import';
|
||||
import mochaPlugin from 'eslint-plugin-mocha';
|
||||
import {includeIgnoreFile} from '@eslint/compat';
|
||||
import {configs as tsConfigs, parser as tsParser, plugin as tsPlugin} from 'typescript-eslint';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const gitignorePath = path.resolve(__dirname, '.gitignore');
|
||||
const gitignorePath = path.resolve(process.cwd(), '.gitignore');
|
||||
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
pluginPromise.configs['flat/recommended'],
|
||||
importPlugin.flatConfigs.recommended,
|
||||
...tsConfigs.recommended,
|
||||
|
||||
{
|
||||
name: 'Script Files',
|
||||
@@ -50,7 +49,6 @@ export default [
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
...tsPlugin.configs.recommended.rules,
|
||||
/**
|
||||
* This rule is configured to warn if a `@ts-ignore` or `@ts-expect-error` directive is used
|
||||
* without explanation.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@appium/eslint-config-appium-ts",
|
||||
"type": "module",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"description": "Shared ESLint config for Appium projects (TypeScript version)",
|
||||
"keywords": [
|
||||
"eslint",
|
||||
@@ -31,14 +31,13 @@
|
||||
"peerDependencies": {
|
||||
"@eslint/compat": "^1.1.0",
|
||||
"@eslint/js": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.0",
|
||||
"eslint-plugin-import": "^2.30.0",
|
||||
"eslint-plugin-mocha": "^10.4.0",
|
||||
"eslint-plugin-promise": "^7.0.0"
|
||||
"eslint-plugin-promise": "^7.0.0",
|
||||
"typescript-eslint": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [4.0.1](https://github.com/appium/appium/compare/@appium/execute-driver-plugin@4.0.0...@appium/execute-driver-plugin@4.0.1) (2025-01-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v9.5.1 ([#20875](https://github.com/appium/appium/issues/20875)) ([93e4288](https://github.com/appium/appium/commit/93e4288253c07a844e6e10f0dd040b1a40eb92ff))
|
||||
|
||||
|
||||
|
||||
## [4.0.0](https://github.com/appium/appium/compare/@appium/execute-driver-plugin@3.0.36...@appium/execute-driver-plugin@4.0.0) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/execute-driver-plugin",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.1",
|
||||
"description": "Plugin for batching and executing driver commands with Appiums",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -42,7 +42,7 @@
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
"source-map-support": "0.5.21",
|
||||
"webdriverio": "9.5.0"
|
||||
"webdriverio": "9.5.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"appium": "^2.0.0-beta.35"
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [5.7.0](https://github.com/appium/appium/compare/@appium/fake-driver@5.6.0...@appium/fake-driver@5.7.0) (2025-01-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,base-plugin:** allow plugins to define custom bidi commands and emit bidi events ([#20876](https://github.com/appium/appium/issues/20876)) ([8df1c21](https://github.com/appium/appium/commit/8df1c217a15d30300c04b9f59cdbdffa70325828))
|
||||
|
||||
|
||||
|
||||
## [5.6.0](https://github.com/appium/appium/compare/@appium/fake-driver@5.5.7...@appium/fake-driver@5.6.0) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ export class FakeDriver extends BaseDriver {
|
||||
this.shook = false;
|
||||
this.appModel = new FakeApp();
|
||||
this.desiredCapConstraints = FAKE_DRIVER_CONSTRAINTS;
|
||||
this.doesSupportBidi = true;
|
||||
this._bidiProxyUrl = null;
|
||||
}
|
||||
|
||||
@@ -183,7 +182,7 @@ export class FakeDriver extends BaseDriver {
|
||||
while (this._clockRunning) {
|
||||
await B.delay(500);
|
||||
this.eventEmitter.emit('bidiEvent', {
|
||||
method: 'clock.currentTime',
|
||||
method: 'appium:clock.currentTime',
|
||||
params: {time: Date.now()},
|
||||
});
|
||||
}
|
||||
@@ -235,8 +234,26 @@ export class FakeDriver extends BaseDriver {
|
||||
await B.delay(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} num1
|
||||
* @param {number} num2
|
||||
*/
|
||||
async doSomeMath(num1, num2) {
|
||||
await B.delay(1);
|
||||
return num1 + num2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} num1
|
||||
* @param {number} num2
|
||||
*/
|
||||
async doSomeMath2(num1, num2) {
|
||||
await B.delay(1);
|
||||
return num1 + num2;
|
||||
}
|
||||
|
||||
static newBidiCommands = /** @type {const} */({
|
||||
fake: {
|
||||
'appium:fake': {
|
||||
getFakeThing: {
|
||||
command: 'getFakeThing',
|
||||
},
|
||||
@@ -246,6 +263,18 @@ export class FakeDriver extends BaseDriver {
|
||||
required: ['thing'],
|
||||
},
|
||||
},
|
||||
doSomeMath: {
|
||||
command: 'doSomeMath',
|
||||
params: {
|
||||
required: ['num1', 'num2'],
|
||||
},
|
||||
},
|
||||
doSomeMath2: {
|
||||
command: 'doSomeMath2',
|
||||
params: {
|
||||
required: ['num1', 'num2'],
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/fake-driver",
|
||||
"version": "5.6.0",
|
||||
"version": "5.7.0",
|
||||
"description": "Mock driver used internally by Appium for testing. Ignore",
|
||||
"keywords": [
|
||||
"automation",
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.2.0](https://github.com/appium/appium/compare/@appium/fake-plugin@3.1.56...@appium/fake-plugin@3.2.0) (2025-01-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,base-plugin:** allow plugins to define custom bidi commands and emit bidi events ([#20876](https://github.com/appium/appium/issues/20876)) ([8df1c21](https://github.com/appium/appium/commit/8df1c217a15d30300c04b9f59cdbdffa70325828))
|
||||
|
||||
|
||||
|
||||
## [3.1.56](https://github.com/appium/appium/compare/@appium/fake-plugin@3.1.55...@appium/fake-plugin@3.1.56) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @appium/fake-plugin
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.1.55](https://github.com/appium/appium/compare/@appium/fake-plugin@3.1.54...@appium/fake-plugin@3.1.55) (2025-01-02)
|
||||
|
||||
**Note:** Version bump only for package @appium/fake-plugin
|
||||
|
||||
@@ -11,6 +11,13 @@ class FakePlugin extends BasePlugin {
|
||||
*/
|
||||
fakeThing;
|
||||
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
pluginThing = null;
|
||||
|
||||
_clockRunning = true;
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Record<string,unknown>} cliArgs
|
||||
@@ -18,6 +25,7 @@ class FakePlugin extends BasePlugin {
|
||||
constructor(name, cliArgs) {
|
||||
super(name, cliArgs);
|
||||
this.fakeThing = 'PLUGIN_FAKE_THING';
|
||||
this.startClock();
|
||||
}
|
||||
|
||||
static newMethodMap = /** @type {const} */ ({
|
||||
@@ -34,6 +42,32 @@ class FakePlugin extends BasePlugin {
|
||||
},
|
||||
});
|
||||
|
||||
static newBidiCommands = /** @type {const} */({
|
||||
'appium:fake': {
|
||||
getPluginThing: {
|
||||
command: 'getPluginThing',
|
||||
},
|
||||
setPluginThing: {
|
||||
command: 'setPluginThing',
|
||||
params: {
|
||||
required: ['thing'],
|
||||
},
|
||||
},
|
||||
doSomeMath: {
|
||||
command: 'doSomeMath',
|
||||
params: {
|
||||
required: ['num1', 'num2'],
|
||||
},
|
||||
},
|
||||
doSomeMath2: {
|
||||
command: 'doSomeMath2',
|
||||
params: {
|
||||
required: ['num1', 'num2'],
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
/** @type {string?} */
|
||||
static _unexpectedData = null;
|
||||
|
||||
@@ -68,11 +102,49 @@ class FakePlugin extends BasePlugin {
|
||||
});
|
||||
}
|
||||
|
||||
async startClock() {
|
||||
while (this._clockRunning) {
|
||||
await B.delay(250);
|
||||
this.eventEmitter.emit('bidiEvent', {
|
||||
method: 'appium:clock.currentTime',
|
||||
params: {time: Date.now()},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async doSomeMath(next, driver, num1, num2) {
|
||||
const sum = await next(); // call driver's 'doSomeMath' which sums num1 and num2
|
||||
return (num1 * num2) + sum;
|
||||
}
|
||||
|
||||
async doSomeMath2(next, driver, num1, num2) {
|
||||
// ignore next & driver in this method
|
||||
await B.delay(1);
|
||||
return num1 * num2;
|
||||
}
|
||||
|
||||
async getFakeThing() {
|
||||
await B.delay(1);
|
||||
return this.fakeThing;
|
||||
}
|
||||
|
||||
async getPluginThing() {
|
||||
this.eventEmitter.emit('bidiEvent', {
|
||||
method: 'appium:fake.pluginThingRetrieved',
|
||||
params: {},
|
||||
});
|
||||
return this.pluginThing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {() => Promise<any>} next
|
||||
* @param {import('@appium/types').Driver} driver
|
||||
* @param {any} thing
|
||||
*/
|
||||
async setPluginThing(next, driver, thing) {
|
||||
this.pluginThing = thing;
|
||||
}
|
||||
|
||||
async plugMeIn(next, driver, /** @type {string} */ socket) {
|
||||
await B.delay(1);
|
||||
return `Plugged in to ${socket}`;
|
||||
@@ -114,12 +186,18 @@ class FakePlugin extends BasePlugin {
|
||||
|
||||
|
||||
async onUnexpectedShutdown(driver, cause) {
|
||||
this._clockRunning = false;
|
||||
FakePlugin._unexpectedData = `Session ended because ${cause}`;
|
||||
}
|
||||
|
||||
async execute(next, driver, script, args) {
|
||||
return await this.executeMethod(next, driver, script, args);
|
||||
}
|
||||
|
||||
async deleteSession(next) {
|
||||
this._clockRunning = false;
|
||||
return await next();
|
||||
}
|
||||
}
|
||||
|
||||
export {FakePlugin};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/fake-plugin",
|
||||
"version": "3.1.55",
|
||||
"version": "3.2.0",
|
||||
"description": "A fake Appium 2.0 plugin",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -39,8 +39,8 @@
|
||||
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/base-plugin": "^2.2.51",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/base-plugin": "^2.3.0",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import {FakePlugin} from '../../lib/plugin';
|
||||
import {FakePlugin as _FakePlugin} from '../../lib/plugin';
|
||||
import B from 'bluebird';
|
||||
|
||||
// Let's not use the actual FakePlugin because it runs a timer and we don't want to worry about
|
||||
// needing to clean up timers so that unit test processes can exit!
|
||||
class FakePlugin extends _FakePlugin {
|
||||
_clockRunning = false;
|
||||
}
|
||||
|
||||
class FakeExpress {
|
||||
constructor() {
|
||||
this.routes = {};
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.0.27](https://github.com/appium/appium/compare/@appium/images-plugin@3.0.26...@appium/images-plugin@3.0.27) (2025-01-08)
|
||||
|
||||
**Note:** Version bump only for package @appium/images-plugin
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.0.26](https://github.com/appium/appium/compare/@appium/images-plugin@3.0.25...@appium/images-plugin@3.0.26) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @appium/images-plugin
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.0.25](https://github.com/appium/appium/compare/@appium/images-plugin@3.0.24...@appium/images-plugin@3.0.25) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/images-plugin",
|
||||
"version": "3.0.25",
|
||||
"version": "3.0.27",
|
||||
"description": "Plugin for working with images and image elements in Appium",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/opencv": "^3.0.7",
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"lodash": "4.17.21",
|
||||
"lru-cache": "10.4.3",
|
||||
"sharp": "0.33.5",
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.3.49](https://github.com/appium/appium/compare/@appium/plugin-test-support@0.3.48...@appium/plugin-test-support@0.3.49) (2025-01-08)
|
||||
|
||||
**Note:** Version bump only for package @appium/plugin-test-support
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.3.48](https://github.com/appium/appium/compare/@appium/plugin-test-support@0.3.47...@appium/plugin-test-support@0.3.48) (2025-01-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **support:** update dependency teen_process to v2.2.3 ([#20882](https://github.com/appium/appium/issues/20882)) ([488e5de](https://github.com/appium/appium/commit/488e5dea82d3c525acf483952570e32f319f3722))
|
||||
|
||||
|
||||
|
||||
## [0.3.47](https://github.com/appium/appium/compare/@appium/plugin-test-support@0.3.46...@appium/plugin-test-support@0.3.47) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/plugin-test-support",
|
||||
"version": "0.3.47",
|
||||
"version": "0.3.49",
|
||||
"description": "Testing utilities for Appium plugins",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -41,11 +41,11 @@
|
||||
"test:unit": "exit 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/types": "^0.24.0",
|
||||
"get-port": "5.1.1",
|
||||
"log-symbols": "4.1.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"teen_process": "2.2.2"
|
||||
"teen_process": "2.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"appium": "^2.0.0-beta.43",
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [6.0.3](https://github.com/appium/appium/compare/@appium/support@6.0.2...@appium/support@6.0.3) (2025-01-08)
|
||||
|
||||
**Note:** Version bump only for package @appium/support
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [6.0.2](https://github.com/appium/appium/compare/@appium/support@6.0.1...@appium/support@6.0.2) (2025-01-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **support:** update dependency teen_process to v2.2.3 ([#20882](https://github.com/appium/appium/issues/20882)) ([488e5de](https://github.com/appium/appium/commit/488e5dea82d3c525acf483952570e32f319f3722))
|
||||
* **support:** update dependency uuid to v11.0.4 ([#20883](https://github.com/appium/appium/issues/20883)) ([6f27d36](https://github.com/appium/appium/commit/6f27d36cf526002af1e40965b793141f5ef065b6))
|
||||
|
||||
|
||||
|
||||
## [6.0.1](https://github.com/appium/appium/compare/@appium/support@6.0.0...@appium/support@6.0.1) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/support",
|
||||
"version": "6.0.1",
|
||||
"version": "6.0.3",
|
||||
"description": "Support libs used across appium packages",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -43,7 +43,7 @@
|
||||
"dependencies": {
|
||||
"@appium/logger": "^1.6.1",
|
||||
"@appium/tsconfig": "^0.3.3",
|
||||
"@appium/types": "^0.23.0",
|
||||
"@appium/types": "^0.24.0",
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/base64-stream": "1.0.5",
|
||||
@@ -88,9 +88,9 @@
|
||||
"shell-quote": "1.8.2",
|
||||
"source-map-support": "0.5.21",
|
||||
"supports-color": "8.1.1",
|
||||
"teen_process": "2.2.2",
|
||||
"teen_process": "2.2.3",
|
||||
"type-fest": "4.31.0",
|
||||
"uuid": "11.0.3",
|
||||
"uuid": "11.0.4",
|
||||
"which": "4.0.0",
|
||||
"yauzl": "3.2.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.1.3](https://github.com/appium/appium/compare/@appium/test-support@3.1.2...@appium/test-support@3.1.3) (2025-01-08)
|
||||
|
||||
**Note:** Version bump only for package @appium/test-support
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.1.2](https://github.com/appium/appium/compare/@appium/test-support@3.1.1...@appium/test-support@3.1.2) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @appium/test-support
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.1.1](https://github.com/appium/appium/compare/@appium/test-support@3.1.0...@appium/test-support@3.1.1) (2025-01-02)
|
||||
|
||||
**Note:** Version bump only for package @appium/test-support
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/test-support",
|
||||
"version": "3.1.1",
|
||||
"version": "3.1.3",
|
||||
"description": "A collection of test utilities used across Appium packages",
|
||||
"keywords": [
|
||||
"automation",
|
||||
@@ -45,7 +45,7 @@
|
||||
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/support": "^6.0.1",
|
||||
"@appium/support": "^6.0.3",
|
||||
"@colors/colors": "1.6.0",
|
||||
"bluebird": "3.7.2",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.24.0](https://github.com/appium/appium/compare/@appium/types@0.23.0...@appium/types@0.24.0) (2025-01-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,base-plugin:** allow plugins to define custom bidi commands and emit bidi events ([#20876](https://github.com/appium/appium/issues/20876)) ([8df1c21](https://github.com/appium/appium/commit/8df1c217a15d30300c04b9f59cdbdffa70325828))
|
||||
|
||||
|
||||
|
||||
## [0.23.0](https://github.com/appium/appium/compare/@appium/types@0.22.3...@appium/types@0.23.0) (2025-01-02)
|
||||
|
||||
|
||||
|
||||
@@ -497,7 +497,7 @@ export interface DriverHelpers {
|
||||
isPackageOrBundle: (app: string) => boolean;
|
||||
duplicateKeys: <T>(input: T, firstKey: string, secondKey: string) => T;
|
||||
parseCapsArray: (cap: string | string[]) => string[];
|
||||
generateDriverLogPrefix: <C extends Constraints>(obj: Core<C>, sessionId?: string) => string;
|
||||
generateDriverLogPrefix: (obj: object, sessionId?: string) => string;
|
||||
}
|
||||
|
||||
export type SettingsUpdateListener<T extends Record<string, unknown> = Record<string, unknown>> = (
|
||||
@@ -610,7 +610,10 @@ export interface Core<C extends Constraints, Settings extends StringRecord = Str
|
||||
isCommandsQueueEnabled: boolean;
|
||||
eventHistory: EventHistory;
|
||||
bidiEventSubs: Record<string, string[]>;
|
||||
doesSupportBidi: boolean;
|
||||
/**
|
||||
* @deprecated Drivers no longer need to opt into BiDi support explicitly
|
||||
*/
|
||||
doesSupportBidi?: boolean;
|
||||
updateBidiCommands(cmds: BidiModuleMap): void;
|
||||
onUnexpectedShutdown(handler: () => any): void;
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {AsyncReturnType} from 'type-fest';
|
||||
import {ExecuteMethodMap, MethodMap} from './command';
|
||||
import {BidiModuleMap, ExecuteMethodMap, MethodMap} from './command';
|
||||
import {DriverCommand, ExternalDriver} from './driver';
|
||||
import {AppiumLogger} from './logger';
|
||||
import {UpdateServerCallback} from './server';
|
||||
@@ -26,6 +26,7 @@ export interface PluginStatic<P extends Plugin> {
|
||||
*/
|
||||
newMethodMap?: MethodMap<P>;
|
||||
executeMethodMap?: ExecuteMethodMap<P>;
|
||||
newBidiCommands?: BidiModuleMap;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,5 +123,5 @@ export type PluginCommand<
|
||||
export type PluginClass<P extends Plugin = Plugin> = Class<
|
||||
P,
|
||||
PluginStatic<P>,
|
||||
[pluginName: string, cliArgs: StringRecord<unknown>]
|
||||
[pluginName: string, cliArgs: StringRecord<unknown>, driverId: string|null]
|
||||
>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@appium/types",
|
||||
"version": "0.23.0",
|
||||
"version": "0.24.0",
|
||||
"description": "Various type declarations used across Appium",
|
||||
"keywords": [
|
||||
"automation",
|
||||
|
||||
Reference in New Issue
Block a user