mirror of
https://github.com/appium/appium.git
synced 2026-11-08 19:06:50 +08:00
Compare commits
531
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b67de03966 | ||
|
|
2b39493e98 | ||
|
|
e916673e32 | ||
|
|
76ff5aa69a | ||
|
|
b1b313b989 | ||
|
|
658f88d8c1 | ||
|
|
3999208fc0 | ||
|
|
1f945716a0 | ||
|
|
0a3ad48419 | ||
|
|
17be28c750 | ||
|
|
746073148f | ||
|
|
73ef2f7d43 | ||
|
|
6fb07a5dbc | ||
|
|
5dd80daf63 | ||
|
|
05e36962e6 | ||
|
|
eaa824f601 | ||
|
|
6cb62d21e8 | ||
|
|
8254a7a3b5 | ||
|
|
83e99bc752 | ||
|
|
147c0bcac3 | ||
|
|
ddd4251108 | ||
|
|
b19bd7878b | ||
|
|
91446df648 | ||
|
|
d5b316031e | ||
|
|
737cf77b6e | ||
|
|
c35a12a51d | ||
|
|
5c2aafa208 | ||
|
|
4422d99d45 | ||
|
|
ce50dd7fa7 | ||
|
|
f06226b7bb | ||
|
|
33459705ed | ||
|
|
f4ca259852 | ||
|
|
a49ae68f13 | ||
|
|
50bd67e59d | ||
|
|
549b4d4179 | ||
|
|
26ffad4f24 | ||
|
|
1a81ac88f3 | ||
|
|
c9fca97cae | ||
|
|
7d87b26047 | ||
|
|
87930a2df1 | ||
|
|
29ee04cf03 | ||
|
|
8892b1022d | ||
|
|
b97fe497cf | ||
|
|
a729d86637 | ||
|
|
e5bd73272b | ||
|
|
037b42454a | ||
|
|
5cf259f974 | ||
|
|
1486078c82 | ||
|
|
01a4eaec49 | ||
|
|
10086b543f | ||
|
|
68ce0e2bdd | ||
|
|
ae4ca98826 | ||
|
|
1d1631e64e | ||
|
|
5721d50b3a | ||
|
|
bd3a120587 | ||
|
|
3e2592804a | ||
|
|
93c0842dbb | ||
|
|
13e8834405 | ||
|
|
3ab2320e1b | ||
|
|
258fc2245a | ||
|
|
5dd9baf5ea | ||
|
|
481807f8db | ||
|
|
8a90e74af3 | ||
|
|
ea9595ff53 | ||
|
|
5d796139f6 | ||
|
|
b3f8a5eea6 | ||
|
|
ae549c8613 | ||
|
|
af8efc0882 | ||
|
|
63103cfa0d | ||
|
|
b0938e6334 | ||
|
|
4b0cc9d37f | ||
|
|
909cc3d4c0 | ||
|
|
1a8f88029b | ||
|
|
3a8049887d | ||
|
|
2ed7bb04d8 | ||
|
|
db87f3cdd4 | ||
|
|
2c0f3fd9e3 | ||
|
|
63b167c408 | ||
|
|
406dfad41f | ||
|
|
85574e7e80 | ||
|
|
336395fcfa | ||
|
|
d9e8b3ba73 | ||
|
|
e625408f55 | ||
|
|
d2a981a45f | ||
|
|
76f2dd3b36 | ||
|
|
03dac9d6e8 | ||
|
|
eb93d49802 | ||
|
|
3f21bcf1a7 | ||
|
|
d708029325 | ||
|
|
485b8d7a70 | ||
|
|
c688932525 | ||
|
|
77d159838f | ||
|
|
c733c090f6 | ||
|
|
2a07c2818c | ||
|
|
52cbfd2708 | ||
|
|
a551c38171 | ||
|
|
0f42831afa | ||
|
|
5c870329a3 | ||
|
|
a236fdbc97 | ||
|
|
a2e9cef145 | ||
|
|
7d72502769 | ||
|
|
12a91e5293 | ||
|
|
d093b76bef | ||
|
|
120b9ddfac | ||
|
|
281e61c297 | ||
|
|
8ac6bfcc3b | ||
|
|
cdd448800e | ||
|
|
e977a29b0b | ||
|
|
2d8fa2662e | ||
|
|
b96c8fa718 | ||
|
|
c6a88e7dd7 | ||
|
|
087a83a27e | ||
|
|
6a241d760a | ||
|
|
e648569dfb | ||
|
|
ea6a2e117f | ||
|
|
4fffe28f89 | ||
|
|
a4a9022303 | ||
|
|
8fd47be066 | ||
|
|
0af2a4bfd8 | ||
|
|
e0c9018453 | ||
|
|
f4d14c1969 | ||
|
|
e44e5ea918 | ||
|
|
32f0bdf870 | ||
|
|
bf30246a65 | ||
|
|
764cfbae75 | ||
|
|
5f0534f154 | ||
|
|
0b7e7419ef | ||
|
|
fee213e49d | ||
|
|
2fa12e915a | ||
|
|
f943fab141 | ||
|
|
6609b2be57 | ||
|
|
f17899a0f5 | ||
|
|
350eab89a5 | ||
|
|
57092711c0 | ||
|
|
cac18e30b5 | ||
|
|
77d249226a | ||
|
|
154ea18252 | ||
|
|
0cfafb23c0 | ||
|
|
b56646198c | ||
|
|
13d3b615e6 | ||
|
|
7c0d771408 | ||
|
|
0a40623085 | ||
|
|
b9ad1f1712 | ||
|
|
608668ed47 | ||
|
|
73d4b7760b | ||
|
|
5112541a34 | ||
|
|
cfde82a40e | ||
|
|
0f3fd55c65 | ||
|
|
67cf081098 | ||
|
|
d63f5441c7 | ||
|
|
0bb61073e2 | ||
|
|
52eb9e308e | ||
|
|
868153fee4 | ||
|
|
c25293b23e | ||
|
|
4c380d7604 | ||
|
|
1e93aec531 | ||
|
|
22f8a9b04d | ||
|
|
1a7199fbbc | ||
|
|
fa9c4b2aab | ||
|
|
3836f0e614 | ||
|
|
6e3fd0a8bc | ||
|
|
d5b1393285 | ||
|
|
123b0e1908 | ||
|
|
eabe372b0b | ||
|
|
416c3349b7 | ||
|
|
ad720f5ca0 | ||
|
|
6d31d6acb2 | ||
|
|
4e93a63ac5 | ||
|
|
7233dd315a | ||
|
|
97d53ffa5b | ||
|
|
2cec9fa27f | ||
|
|
a1a7b7e981 | ||
|
|
228103f489 | ||
|
|
9dcb2c4056 | ||
|
|
a9dd7f5e41 | ||
|
|
de2cd50b96 | ||
|
|
ccb3106814 | ||
|
|
f707dfa174 | ||
|
|
53b2db196d | ||
|
|
279ebb5cd6 | ||
|
|
f1fc5a6869 | ||
|
|
24586d4ed9 | ||
|
|
4915433aae | ||
|
|
fd70da7ab4 | ||
|
|
fa769cebd9 | ||
|
|
1eb55e85d7 | ||
|
|
f98eea77d1 | ||
|
|
4cbcf95d77 | ||
|
|
4c947872f1 | ||
|
|
11882be379 | ||
|
|
e3334b4dd7 | ||
|
|
a10f403bb1 | ||
|
|
08d50889c2 | ||
|
|
d3628a9410 | ||
|
|
8d6b5f87c7 | ||
|
|
531b20a3c1 | ||
|
|
6699d1b266 | ||
|
|
37a6006537 | ||
|
|
1b449709d1 | ||
|
|
0e4ecc49d6 | ||
|
|
bf29503054 | ||
|
|
ab0633a70c | ||
|
|
0c44ddeebe | ||
|
|
d9eb36f413 | ||
|
|
b483d82b13 | ||
|
|
93e81777b9 | ||
|
|
623ef38f2a | ||
|
|
5c696c5c91 | ||
|
|
98215066ee | ||
|
|
8026a953aa | ||
|
|
c8556f172e | ||
|
|
e9a41bd9ae | ||
|
|
e810f2f23d | ||
|
|
c04c38d1e6 | ||
|
|
d9c4e4c4ad | ||
|
|
bce22834ba | ||
|
|
ac65be5a1e | ||
|
|
1e570c4d29 | ||
|
|
52ec456d17 | ||
|
|
a89e429a84 | ||
|
|
4b0666d7d5 | ||
|
|
816ca05020 | ||
|
|
31036f65b2 | ||
|
|
4bb987c037 | ||
|
|
0162f3ab4e | ||
|
|
813c6b5b7a | ||
|
|
edc2013073 | ||
|
|
979a6e4c9d | ||
|
|
1cc4f0f2e5 | ||
|
|
0467311286 | ||
|
|
cb9c476fbb | ||
|
|
44278bdfc3 | ||
|
|
a8418f95e9 | ||
|
|
7e67b54726 | ||
|
|
e6b583a209 | ||
|
|
3016201f2a | ||
|
|
e0d5c4dfd6 | ||
|
|
779a3a048f | ||
|
|
07302ab3e9 | ||
|
|
609db021f4 | ||
|
|
213efd0fa4 | ||
|
|
d94a40af9f | ||
|
|
47638650ee | ||
|
|
bf8517a106 | ||
|
|
8d25be469b | ||
|
|
e118e453cc | ||
|
|
cf1dbe5389 | ||
|
|
f475b41785 | ||
|
|
8eb41d6fe8 | ||
|
|
0e6a33bd26 | ||
|
|
982571c894 | ||
|
|
78683d9176 | ||
|
|
f572c42921 | ||
|
|
dec148e997 | ||
|
|
e4faa6919b | ||
|
|
35034552b9 | ||
|
|
e5071fbf02 | ||
|
|
b1872b47b8 | ||
|
|
136903398e | ||
|
|
c704023790 | ||
|
|
27c22b7103 | ||
|
|
2b6bf4fa59 | ||
|
|
a740d9d8dd | ||
|
|
a97a7cde25 | ||
|
|
5fee01752f | ||
|
|
1445da48d8 | ||
|
|
7eb65eff9f | ||
|
|
987187e740 | ||
|
|
fa96e81341 | ||
|
|
c6abe8f102 | ||
|
|
f0de6b8719 | ||
|
|
939339adc1 | ||
|
|
d8d0c12cf9 | ||
|
|
389bff1173 | ||
|
|
367b28d5e3 | ||
|
|
2939478b47 | ||
|
|
d91add8000 | ||
|
|
84f9b4dbe4 | ||
|
|
e2fceea6b4 | ||
|
|
1a46d7d61e | ||
|
|
2ee7d4fe75 | ||
|
|
3b76a4bb63 | ||
|
|
39131c8c27 | ||
|
|
f9fa1d429d | ||
|
|
36caf86a1a | ||
|
|
24fd9a2813 | ||
|
|
27a4161b67 | ||
|
|
f18fc39de3 | ||
|
|
93722c05fa | ||
|
|
c4151a771c | ||
|
|
d9a30c1ace | ||
|
|
a7e19d1fc3 | ||
|
|
9129feb880 | ||
|
|
710738a987 | ||
|
|
41264445a3 | ||
|
|
1c5c48b582 | ||
|
|
fd270f2b09 | ||
|
|
8018f8b70e | ||
|
|
ea38864e95 | ||
|
|
cf79b3283a | ||
|
|
7c60cee787 | ||
|
|
bfac5ab9ec | ||
|
|
d329ecd7f7 | ||
|
|
aa85993c01 | ||
|
|
3c34ec1a04 | ||
|
|
2cd71fc45d | ||
|
|
bab02cc7c1 | ||
|
|
66b38e31ab | ||
|
|
66eeaa2791 | ||
|
|
a1fc1c0e18 | ||
|
|
ccbe297d3a | ||
|
|
101b31f35d | ||
|
|
b01bed2d2e | ||
|
|
6b9ad08246 | ||
|
|
2694d789c4 | ||
|
|
58fad654c3 | ||
|
|
0d1271f812 | ||
|
|
c79225f8cf | ||
|
|
2afd0e651c | ||
|
|
075466243d | ||
|
|
abb83bde62 | ||
|
|
eb139abf97 | ||
|
|
377011bdb3 | ||
|
|
1fc8582327 | ||
|
|
f6a96d6647 | ||
|
|
04b408aace | ||
|
|
f600982578 | ||
|
|
c8b9321667 | ||
|
|
c9b7eac365 | ||
|
|
efbf7115cc | ||
|
|
679ec8864c | ||
|
|
094daa24be | ||
|
|
9c3aaa1056 | ||
|
|
e58253033d | ||
|
|
25d922b7d3 | ||
|
|
0264775ecb | ||
|
|
f5b193ccf0 | ||
|
|
6d88f54918 | ||
|
|
95c4091b8b | ||
|
|
ecf927395d | ||
|
|
e1e228380f | ||
|
|
74170ec575 | ||
|
|
3f9a2ea18f | ||
|
|
2ef20b988b | ||
|
|
1dffc4e833 | ||
|
|
97c879cdd0 | ||
|
|
8300e115b2 | ||
|
|
ea186eae17 | ||
|
|
07466e02f7 | ||
|
|
a91f4a718b | ||
|
|
f53e443d64 | ||
|
|
fc11de2bda | ||
|
|
82343effc4 | ||
|
|
59a460949a | ||
|
|
b4dd22512c | ||
|
|
a18700fed6 | ||
|
|
2f312722d7 | ||
|
|
f5369c65a8 | ||
|
|
8c6c19982e | ||
|
|
e39017feac | ||
|
|
fd6dbe9eff | ||
|
|
c18b535d42 | ||
|
|
9045dfcefa | ||
|
|
98a1735913 | ||
|
|
3229e74d3d | ||
|
|
9c35776756 | ||
|
|
1b31db3be9 | ||
|
|
0a4b4f5a55 | ||
|
|
a085d44616 | ||
|
|
a10f558382 | ||
|
|
f61e7d57fa | ||
|
|
705710adc5 | ||
|
|
6a3d659c5a | ||
|
|
c760f02e14 | ||
|
|
e1ab96fc4e | ||
|
|
e8d31c63c4 | ||
|
|
787571d338 | ||
|
|
4849ad015d | ||
|
|
0878f3c8ce | ||
|
|
3dd0ac715a | ||
|
|
ce09eb2e7d | ||
|
|
9cc0377acf | ||
|
|
9b21b92418 | ||
|
|
c758fcaf13 | ||
|
|
63218cdac6 | ||
|
|
08493df3d1 | ||
|
|
bde5bd57f4 | ||
|
|
b5bdfdd4e4 | ||
|
|
cb4aa687a2 | ||
|
|
180f2611c1 | ||
|
|
1f3119ec1f | ||
|
|
2c0fb7a2e4 | ||
|
|
fa1e87535b | ||
|
|
79370cd307 | ||
|
|
712832ae61 | ||
|
|
6c9f7bbf6a | ||
|
|
0f0f60effd | ||
|
|
be35e0b3d1 | ||
|
|
17f84265d1 | ||
|
|
7da5477e7a | ||
|
|
49f0dc7ab1 | ||
|
|
622f1999d7 | ||
|
|
52b96394d6 | ||
|
|
abba69f23a | ||
|
|
83bfbce9cc | ||
|
|
9670d93a12 | ||
|
|
c986fbe5ac | ||
|
|
1c8735dfbe | ||
|
|
6d76b1ded6 | ||
|
|
9c1c5ba06e | ||
|
|
bbb70d3c1e | ||
|
|
6476197bff | ||
|
|
4c4e8d8911 | ||
|
|
c65e6d26f1 | ||
|
|
97af269d68 | ||
|
|
a31b82cc7b | ||
|
|
efe167f59a | ||
|
|
3efaac1e9a | ||
|
|
3d3abbdc6f | ||
|
|
862fbbb438 | ||
|
|
5484e9a4ff | ||
|
|
943866bcf3 | ||
|
|
62c7132476 | ||
|
|
dbcf4a133c | ||
|
|
4da7da0a14 | ||
|
|
8e68b3e2c9 | ||
|
|
2e465ef433 | ||
|
|
021aed1fdf | ||
|
|
a929cd6024 | ||
|
|
6e0fdfd967 | ||
|
|
18138f939d | ||
|
|
e43b9052d0 | ||
|
|
1a5d266c04 | ||
|
|
97d26a5796 | ||
|
|
20d410e108 | ||
|
|
ad562353d9 | ||
|
|
96152aef42 | ||
|
|
71ca18c565 | ||
|
|
4d45af1ef2 | ||
|
|
73a9891c24 | ||
|
|
dfe8bde687 | ||
|
|
9b0a5a4096 | ||
|
|
73abe981de | ||
|
|
e34c0dd639 | ||
|
|
c8f0ed5deb | ||
|
|
62fb60a8b5 | ||
|
|
4e9bf1944b | ||
|
|
7a8965f5c3 | ||
|
|
daa99525eb | ||
|
|
6234359ff2 | ||
|
|
24d8344927 | ||
|
|
e00cd5e7eb | ||
|
|
27d3c517d7 | ||
|
|
76e060cf75 | ||
|
|
3b8c41e3d4 | ||
|
|
0e5db551b4 | ||
|
|
e79c521fa7 | ||
|
|
1c4ce5d5ec | ||
|
|
a36736862f | ||
|
|
22b60daf75 | ||
|
|
7153d0adf8 | ||
|
|
ad13932e6e | ||
|
|
f044afd932 | ||
|
|
ac46d8ef5c | ||
|
|
dc37b2766d | ||
|
|
fe8b8eb808 | ||
|
|
aca8f72ee5 | ||
|
|
f135acadd4 | ||
|
|
4539f868fc | ||
|
|
5cd7076fd6 | ||
|
|
96254ef3b8 | ||
|
|
ed9d4aed09 | ||
|
|
a03b28a12c | ||
|
|
b649c64df5 | ||
|
|
22eed52c60 | ||
|
|
5e2006ae23 | ||
|
|
c45839f057 | ||
|
|
b31574d0ed | ||
|
|
c2b7070c53 | ||
|
|
e907832667 | ||
|
|
6e104d4ba1 | ||
|
|
41f2304e16 | ||
|
|
4ec08dbbf9 | ||
|
|
a842430634 | ||
|
|
4d3a5dc74a | ||
|
|
e6fc983d9d | ||
|
|
a2be0836da | ||
|
|
46f2160bf1 | ||
|
|
00e3d864f0 | ||
|
|
caee6b733b | ||
|
|
4d94dffa80 | ||
|
|
86c8f23a67 | ||
|
|
73b7820df5 | ||
|
|
26f8429509 | ||
|
|
ff96c9a6e1 | ||
|
|
87704de080 | ||
|
|
e20ee97139 | ||
|
|
52a620818a | ||
|
|
72b9efcb42 | ||
|
|
2f17a1a0ac | ||
|
|
87b8603329 | ||
|
|
7ab1df8e62 | ||
|
|
1412d58452 | ||
|
|
63908458c0 | ||
|
|
2c12f647e5 | ||
|
|
75682fa2e5 | ||
|
|
af16eafbb2 | ||
|
|
6cffa01c8d | ||
|
|
7abbd51c28 | ||
|
|
2b859134a8 | ||
|
|
06b5fe5019 | ||
|
|
d6a195a556 | ||
|
|
69bd198a18 | ||
|
|
3ca551ba2e | ||
|
|
f897dbaacb | ||
|
|
e83e513957 | ||
|
|
d3e8ddc35b | ||
|
|
d5092ffd30 | ||
|
|
91a9eb782a | ||
|
|
3a452888fc | ||
|
|
66ddff0a33 | ||
|
|
d7c30108d6 | ||
|
|
f628d517fe | ||
|
|
190c30b418 | ||
|
|
fa7ba639d4 | ||
|
|
1b1314cd6b | ||
|
|
36179e8795 | ||
|
|
825431b14a | ||
|
|
c745352c65 | ||
|
|
1d89e2a5f8 | ||
|
|
2dfae495ff |
@@ -0,0 +1,10 @@
|
||||
<!-- CODEGRAPH_START -->
|
||||
## CodeGraph
|
||||
|
||||
In repositories indexed by CodeGraph (a `.codegraph/` directory exists at the repo root), reach for it BEFORE grep/find or reading files when you need to understand or locate code:
|
||||
|
||||
- **MCP tool** (when available): `codegraph_explore` answers most code questions in one call — the relevant symbols' verbatim source plus the call paths between them, including dynamic-dispatch hops grep can't follow. Name a file or symbol in the query to read its current line-numbered source. If it's listed but deferred, load it by name via tool search.
|
||||
- **Shell** (always works): `codegraph explore "<symbol names or question>"` prints the same output.
|
||||
|
||||
If there is no `.codegraph/` directory, skip CodeGraph entirely — indexing is the user's decision.
|
||||
<!-- CODEGRAPH_END -->
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": ["mcp__codegraph__*"]
|
||||
},
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "codegraph prompt-hook"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# CodeGraph data files — local to each machine, not for committing.
|
||||
# Ignore everything in .codegraph/ except this file itself, so transient
|
||||
# files (the database, daemon.pid, sockets, logs) never show up in git.
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"codegraph": {
|
||||
"type": "stdio",
|
||||
"command": "codegraph",
|
||||
"args": ["serve", "--mcp", "--path", "."]
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,13 +1,14 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
[*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,json,jsonc}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
@@ -29,8 +29,6 @@ targets:
|
||||
path: ./packages/fake-driver
|
||||
- type: npm
|
||||
path: ./packages/support
|
||||
- type: npm
|
||||
path: ./packages/test-support
|
||||
- type: npm
|
||||
path: ./packages/types
|
||||
- type: npm
|
||||
|
||||
@@ -3,7 +3,6 @@ description: Create a new bug report.
|
||||
title: '🐞 bug: <title>'
|
||||
labels: [Bug, Needs Triage]
|
||||
body:
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: ':stop_sign: _Make sure you are reporting an issue. For general questions, please use [http://discuss.appium.io](http://discuss.appium.io)._'
|
||||
@@ -13,9 +12,9 @@ body:
|
||||
label: Is there an existing issue for this?
|
||||
description: 'Please [search :mag: the issues](https://github.com/appium/appium/issues) to check if this bug has already been reported.'
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Appium Version
|
||||
@@ -49,7 +48,7 @@ body:
|
||||
description: |
|
||||
You can retrieve the latest server/driver/plugin version number by running `npm info <package-name> version`. If you are not up to date, please try to reproduce your issue after updating all affected components.
|
||||
options:
|
||||
- label: I confirm the issue is still reproducible with the latest component versions
|
||||
- label: I confirm the issue is still reproducible with the latest component versions
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
@@ -82,10 +81,10 @@ body:
|
||||
|
||||
:warning: _Remember to redact or remove any sensitive information!_
|
||||
value: |
|
||||
- Debug details (`appium --show-debug-info`):
|
||||
- Last component version(s) which did _not_ exhibit the problem:
|
||||
- Platform and version of device under test:
|
||||
- Real device or emulator/simulator:
|
||||
- Debug details (`appium --show-debug-info`):
|
||||
- Last component version(s) which did _not_ exhibit the problem:
|
||||
- Platform and version of device under test:
|
||||
- Real device or emulator/simulator:
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: ❓ Question
|
||||
- name: ❓ Question
|
||||
url: https://discuss.appium.io/
|
||||
about: Please use the Appium forum for any questions.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
name: 💡 Feature Request
|
||||
description: Suggest an idea for this project.
|
||||
title: "💡 feat: <title>"
|
||||
title: '💡 feat: <title>'
|
||||
labels: [Enhancement]
|
||||
body:
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem?
|
||||
|
||||
@@ -20,12 +20,12 @@ runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Use Node.js ${{ inputs.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v7.0.0
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: npm
|
||||
- name: SocketDev Security Check
|
||||
uses: SocketDev/action@v1
|
||||
uses: SocketDev/action@v1.3.2
|
||||
with:
|
||||
mode: firewall-free
|
||||
- name: Install dependencies
|
||||
@@ -33,8 +33,44 @@ runs:
|
||||
run: |
|
||||
# Replace npm with sfw npm in the install command
|
||||
install_cmd="${{ inputs.install-command }}"
|
||||
install_cmd="${install_cmd//npm /sfw npm }"
|
||||
$install_cmd
|
||||
sfw_install_cmd="${install_cmd//npm /sfw npm }"
|
||||
|
||||
# Socket Firewall can fail to reach its own backend (a transient
|
||||
# network error unrelated to the actual npm install) and, in that
|
||||
# case, either exit non-zero or exit 0 without having actually
|
||||
# completed the install, leaving node_modules incomplete. We only
|
||||
# want to fall back to a plain (non-firewalled) install when we can
|
||||
# positively attribute the failure to *that* Socket Firewall error —
|
||||
# a real npm/package problem (bad version, checksum mismatch, failing
|
||||
# postinstall script, etc.) must fail the job as-is, not be silently
|
||||
# retried and potentially masked.
|
||||
sfw_log="$(mktemp)"
|
||||
set +e
|
||||
$sfw_install_cmd 2>&1 | tee "$sfw_log"
|
||||
sfw_exit="${PIPESTATUS[0]}"
|
||||
set -e
|
||||
|
||||
sfw_infra_failure=0
|
||||
if grep -qi 'Socket Firewall encountered an unexpected error' "$sfw_log"; then
|
||||
sfw_infra_failure=1
|
||||
fi
|
||||
|
||||
install_incomplete=0
|
||||
if [ "$sfw_exit" -eq 0 ]; then
|
||||
npm ls --depth=0 >/dev/null 2>&1 || install_incomplete=1
|
||||
fi
|
||||
rm -f "$sfw_log"
|
||||
|
||||
if [ "$sfw_infra_failure" -eq 1 ] && { [ "$sfw_exit" -ne 0 ] || [ "$install_incomplete" -eq 1 ]; }; then
|
||||
echo "::warning::Socket Firewall failed to reach its backend; retrying with a plain npm install"
|
||||
$install_cmd
|
||||
elif [ "$sfw_exit" -ne 0 ]; then
|
||||
echo "::error::npm install failed"
|
||||
exit "$sfw_exit"
|
||||
elif [ "$install_incomplete" -eq 1 ]; then
|
||||
echo "::error::npm install appears incomplete and is not attributable to a Socket Firewall failure"
|
||||
exit 1
|
||||
fi
|
||||
- name: Build packages
|
||||
if: ${{ inputs.run-build == 'true' }}
|
||||
shell: bash
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copilot Instructions
|
||||
|
||||
## Code Review
|
||||
|
||||
When reviewing JavaScript or TypeScript changes, check new uses of Node.js built-in APIs against the supported Node.js versions declared in package.json#engines.node. The current supported range is ^20.19.0 || ^22.12.0 || >=24.0.0.
|
||||
|
||||
For each new Node.js built-in API or option, verify that it exists and is stable across all supported Node.js versions. If any supported version lacks the API, only supports it experimentally, or has different behavior, leave a review comment and suggest using the existing dependency, adding a fallback, avoiding the API, or raising the engine requirement.
|
||||
|
||||
Example: util.styleText exists in Node.js 20.12+, but only became stable in Node.js 22.13.0 and 23.5.0. Because this repository supports Node.js 20.19.0 and 22.12.0, replacing a color library with util.styleText should be flagged unless the project explicitly accepts relying on a non-stable API for those supported versions.
|
||||
+10
-5
@@ -73,6 +73,11 @@ labels:
|
||||
matcher:
|
||||
files: ['packages/eslint-config-appium-ts/**']
|
||||
|
||||
- label: '@appium/oxc-config'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/oxc-config/**']
|
||||
|
||||
- label: '@appium/execute-driver-plugin'
|
||||
sync: true
|
||||
matcher:
|
||||
@@ -118,6 +123,11 @@ labels:
|
||||
matcher:
|
||||
files: ['packages/schema/**']
|
||||
|
||||
- label: '@appium/semantic-release-config'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/semantic-release-config/**']
|
||||
|
||||
- label: '@appium/support'
|
||||
sync: true
|
||||
matcher:
|
||||
@@ -128,11 +138,6 @@ labels:
|
||||
matcher:
|
||||
files: ['packages/strongbox/**']
|
||||
|
||||
- label: '@appium/test-support'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/test-support/**']
|
||||
|
||||
- label: '@appium/tsconfig'
|
||||
sync: true
|
||||
matcher:
|
||||
|
||||
@@ -13,4 +13,4 @@ jobs:
|
||||
name: Auto-Label PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: fuxingloh/multi-labeler@v4
|
||||
- uses: fuxingloh/multi-labeler@v5.0.0
|
||||
|
||||
+22
-20
@@ -6,7 +6,7 @@ on:
|
||||
# this list of paths could potentially impact the build
|
||||
paths:
|
||||
- '**/tsconfig*.json'
|
||||
- 'packages/base-driver/static/**/*'
|
||||
- 'packages/base-driver/test-fixtures/**/*'
|
||||
- 'packages/*/test/**'
|
||||
- 'packages/*/bin'
|
||||
- 'packages/**/*.ts'
|
||||
@@ -15,10 +15,9 @@ on:
|
||||
- 'package*.json'
|
||||
- 'lerna.json'
|
||||
- '.npmrc'
|
||||
- '.mocharc.js'
|
||||
- '.github/workflows/build.yml' # this file
|
||||
- '.eslintrc'
|
||||
- '.eslintignore'
|
||||
- 'oxlint.config.mjs'
|
||||
- 'oxfmt.config.mjs'
|
||||
- '!**/sample-code/**'
|
||||
- '!packages/*/docs/**'
|
||||
pull_request:
|
||||
@@ -26,7 +25,7 @@ on:
|
||||
- master
|
||||
paths:
|
||||
- '**/tsconfig*.json'
|
||||
- 'packages/base-driver/static/**/*'
|
||||
- 'packages/base-driver/test-fixtures/**/*'
|
||||
- 'packages/*/test/**'
|
||||
- 'packages/*/bin'
|
||||
- 'packages/**/*.ts'
|
||||
@@ -35,10 +34,9 @@ on:
|
||||
- 'package*.json'
|
||||
- 'lerna.json'
|
||||
- '.npmrc'
|
||||
- '.mocharc.js'
|
||||
- '.github/workflows/build.yml' # this file
|
||||
- '.eslintrc'
|
||||
- '.eslintignore'
|
||||
- 'oxlint.config.mjs'
|
||||
- 'oxfmt.config.mjs'
|
||||
- '!**/sample-code/**'
|
||||
- '!packages/*/docs/**'
|
||||
|
||||
@@ -61,7 +59,7 @@ jobs:
|
||||
outputs:
|
||||
packages: ${{ steps.discover-packages.outputs.packages }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Discover packages with e2e tests
|
||||
id: discover-packages
|
||||
run: |
|
||||
@@ -103,14 +101,14 @@ jobs:
|
||||
|
||||
test-smoke:
|
||||
needs:
|
||||
- prepare_matrix
|
||||
- prepare_matrix
|
||||
name: Smoke Tests
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Setup, install and build
|
||||
uses: ./.github/actions/setup-build
|
||||
with:
|
||||
@@ -122,14 +120,14 @@ jobs:
|
||||
|
||||
test-unit:
|
||||
needs:
|
||||
- prepare_matrix
|
||||
- prepare_matrix
|
||||
name: Unit Tests
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Setup, install and build
|
||||
uses: ./.github/actions/setup-build
|
||||
with:
|
||||
@@ -141,14 +139,14 @@ jobs:
|
||||
|
||||
test-types:
|
||||
needs:
|
||||
- prepare_matrix
|
||||
- prepare_matrix
|
||||
name: Type Tests
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ${{ fromJSON(needs.prepare_matrix.outputs.versions) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Setup, install and build
|
||||
uses: ./.github/actions/setup-build
|
||||
with:
|
||||
@@ -160,8 +158,8 @@ jobs:
|
||||
|
||||
test-e2e:
|
||||
needs:
|
||||
- prepare_matrix
|
||||
- prepare_e2e_packages
|
||||
- prepare_matrix
|
||||
- prepare_e2e_packages
|
||||
name: E2E Tests - ${{ matrix.package_dir }} (Node ${{ matrix.node-version }})
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
strategy:
|
||||
@@ -171,7 +169,7 @@ jobs:
|
||||
package_dir: ${{ fromJSON(needs.prepare_e2e_packages.outputs.packages) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Setup, install and build
|
||||
uses: ./.github/actions/setup-build
|
||||
with:
|
||||
@@ -188,12 +186,16 @@ jobs:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Setup and install (no build)
|
||||
uses: ./.github/actions/setup-build
|
||||
with:
|
||||
node-version: lts/*
|
||||
install-command: npm ci
|
||||
run-build: 'false'
|
||||
- name: ESLint
|
||||
- name: Lint
|
||||
run: npm run lint:ci
|
||||
- name: Format check
|
||||
run: npm run format:check
|
||||
- name: Verify changelog generation
|
||||
run: npm run verify:changelog-generation
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7.0.1
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
|
||||
@@ -21,9 +21,9 @@ jobs:
|
||||
project_name: appium-inspector
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Use Node.js LTS
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v7.0.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
CROWDIN_PROJECT_ID: ${{ vars[matrix.project_id_var] }}
|
||||
CROWDIN_TOKEN: ${{ secrets.CROWDIN_DOCS_TOKEN }}
|
||||
- name: Post to Slack for ${{ matrix.project_name }}
|
||||
uses: slackapi/slack-github-action@v2.1.1
|
||||
uses: slackapi/slack-github-action@v4.0.0
|
||||
with:
|
||||
errors: true
|
||||
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
||||
@@ -12,11 +12,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Use Node.js LTS
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v7.0.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_DOCS_PROJECT_ID }}
|
||||
CROWDIN_TOKEN: ${{ secrets.CROWDIN_DOCS_TOKEN }}
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v8.1.0
|
||||
uses: peter-evans/create-pull-request@v8.1.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
commit-message: 'docs(appium): Update documentation translations'
|
||||
|
||||
@@ -15,9 +15,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Use Node.js LTS
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v7.0.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
|
||||
@@ -14,13 +14,13 @@ jobs:
|
||||
outputs:
|
||||
versions: ${{ steps.generate-matrix.outputs.lts }}
|
||||
steps:
|
||||
- name: Select all current LTS versions of Node.js
|
||||
id: generate-matrix
|
||||
uses: msimerson/node-lts-versions@v1
|
||||
- name: Select all current LTS versions of Node.js
|
||||
id: generate-matrix
|
||||
uses: msimerson/node-lts-versions@v2.0.2
|
||||
|
||||
check:
|
||||
needs:
|
||||
- prepare_matrix
|
||||
- prepare_matrix
|
||||
name: Check
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
steps:
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v7.0.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Appium
|
||||
|
||||
@@ -37,9 +37,9 @@ jobs:
|
||||
name: Docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Install dependencies (Node.js)
|
||||
uses: bahmutov/npm-install@v1
|
||||
uses: bahmutov/npm-install@v1.12.1
|
||||
with:
|
||||
useRollingCache: true
|
||||
install-command: npm ci
|
||||
|
||||
@@ -13,11 +13,11 @@ jobs:
|
||||
env:
|
||||
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
ref: master
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@v1
|
||||
uses: bahmutov/npm-install@v1.12.1
|
||||
- name: Install fossa-cli
|
||||
run: |
|
||||
curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash
|
||||
|
||||
@@ -14,9 +14,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Use Node.js LTS
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v7.0.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
# GITHUB_TOKEN is optional - if not provided, uses unauthenticated requests (rate limited)
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Post to Slack
|
||||
uses: slackapi/slack-github-action@v2.1.1
|
||||
uses: slackapi/slack-github-action@v4.0.0
|
||||
with:
|
||||
errors: true
|
||||
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
||||
@@ -8,6 +8,16 @@ on:
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
recover_missing_only:
|
||||
description: 'Recovery mode: skip version bump, publish only packages missing on npm at their current package.json version'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
bootstrap_packages:
|
||||
description: 'One-time beta-branch bootstrap only: comma-separated package names (e.g. @appium/base-driver,@appium/support) to force-bump to their next-major beta (premajor --preid beta), bypassing conventional-commit detection. Leave empty for a normal release.'
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -18,11 +28,15 @@ permissions:
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/master' && contains(fromJSON('["mykola-mokhnach", "jlipps", "eglitise", "KazuCocoa"]'), github.actor)
|
||||
# keep this branch name in sync with env.BETA_BRANCH below - the `env` context isn't available
|
||||
# to jobs.<job_id>.if (GitHub Actions resolves it before job-level env is set up)
|
||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/appium4') && contains(fromJSON('["mykola-mokhnach", "jlipps", "eglitise", "KazuCocoa"]'), github.actor)
|
||||
env:
|
||||
BETA_BRANCH: appium4
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -43,13 +57,186 @@ jobs:
|
||||
# for lerna createRelease
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DRY_RUN: ${{ inputs.dry_run }}
|
||||
RECOVER_MISSING_ONLY: ${{ inputs.recover_missing_only }}
|
||||
BOOTSTRAP_PACKAGES: ${{ inputs.bootstrap_packages }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "Running lerna publish in dry-run mode"
|
||||
printf "n\n" | npx lerna version --no-git-tag-version --no-push
|
||||
else
|
||||
echo "Running lerna publish for real"
|
||||
npm run release -- --yes
|
||||
|
||||
# On the beta branch ($BETA_BRANCH), every release is a beta prerelease anchored at its
|
||||
# target major (see packages/semantic-release-config's "Next-major beta branches" docs
|
||||
# for the equivalent semantic-release behavior this mirrors).
|
||||
BETA_FLAGS=""
|
||||
DIST_TAG_FLAGS=""
|
||||
if [ "${{ github.ref_name }}" = "$BETA_BRANCH" ]; then
|
||||
BETA_FLAGS="--conventional-prerelease --preid beta"
|
||||
DIST_TAG_FLAGS="--dist-tag beta"
|
||||
fi
|
||||
|
||||
# One-time bootstrap for packages just starting their beta train: force them
|
||||
# straight to <next-major>.0.0-beta.0 instead of waiting for/relying on a commit that
|
||||
# happens to be marked as breaking. Not part of the normal release flow below - this
|
||||
# exits early on its own.
|
||||
if [ -n "$BOOTSTRAP_PACKAGES" ]; then
|
||||
if [ "${{ github.ref_name }}" != "$BETA_BRANCH" ]; then
|
||||
echo "bootstrap_packages is only meaningful on the $BETA_BRANCH branch" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$RECOVER_MISSING_ONLY" = "true" ]; then
|
||||
echo "bootstrap_packages cannot be combined with recover_missing_only" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Bootstrapping ${BOOTSTRAP_PACKAGES} to their next-major beta (premajor --preid beta), bypassing conventional-commit detection"
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
printf "n\n" | npx lerna version premajor --preid beta --exact --no-git-tag-version --no-push --force-publish="$BOOTSTRAP_PACKAGES"
|
||||
else
|
||||
npx lerna publish premajor --preid beta --exact --force-publish="$BOOTSTRAP_PACKAGES" --dist-tag beta --yes
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Prints "<pkg_name>@<pkg_version>" to stdout for each non-private workspace package
|
||||
# whose current package.json version is not yet on npm.
|
||||
find_missing_packages() {
|
||||
for pkg_json in packages/*/package.json; do
|
||||
if [ ! -f "$pkg_json" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$(jq -r '.private // false' "$pkg_json")" = "true" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
pkg_name="$(jq -r '.name // empty' "$pkg_json")"
|
||||
pkg_version="$(jq -r '.version // empty' "$pkg_json")"
|
||||
if [ -z "$pkg_name" ] || [ -z "$pkg_version" ]; then
|
||||
echo "Skipping malformed package manifest: $pkg_json" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
pkg_spec="${pkg_name}@${pkg_version}"
|
||||
if ! npm view "$pkg_spec" version >/dev/null 2>&1; then
|
||||
echo "$pkg_spec"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Resolves the workspace directory of a package given its npm name.
|
||||
package_dir_for() {
|
||||
local target="$1"
|
||||
for pkg_json in packages/*/package.json; do
|
||||
if [ ! -f "$pkg_json" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ "$(jq -r '.name // empty' "$pkg_json")" = "$target" ]; then
|
||||
dirname "$pkg_json"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Publishes each "<pkg_name>@<pkg_version>" package spec passed as an argument.
|
||||
# `lerna publish` has no per-package scope filter, so this runs `npm publish`
|
||||
# directly from each package's directory instead. Returns non-zero if any
|
||||
# individual publish failed; npm publish's own exit code is taken as authoritative,
|
||||
# no npm registry re-scan is done to double-check it.
|
||||
publish_missing_packages() {
|
||||
echo "Publishing missing packages one-by-one"
|
||||
local overall_status=0
|
||||
for pkg_spec in "$@"; do
|
||||
pkg_name="${pkg_spec%@*}"
|
||||
pkg_dir="$(package_dir_for "$pkg_name")"
|
||||
if [ -z "$pkg_dir" ]; then
|
||||
echo "Could not resolve workspace directory for ${pkg_name}"
|
||||
overall_status=1
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Publishing ${pkg_spec}"
|
||||
set +e
|
||||
(cd "$pkg_dir" && npm publish $DIST_TAG_FLAGS)
|
||||
publish_exit_code=$?
|
||||
set -e
|
||||
if [ $publish_exit_code -ne 0 ]; then
|
||||
echo "npm publish failed for ${pkg_spec} (exit code ${publish_exit_code})"
|
||||
overall_status=1
|
||||
fi
|
||||
done
|
||||
return $overall_status
|
||||
}
|
||||
|
||||
if [ "$RECOVER_MISSING_ONLY" = "true" ]; then
|
||||
echo "Recovery mode: scanning for packages missing on npm at their current package.json version"
|
||||
mapfile -t missing < <(find_missing_packages)
|
||||
|
||||
if [ ${#missing[@]} -eq 0 ]; then
|
||||
echo "No missing packages found; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Missing package versions on npm:"
|
||||
printf ' - %s\n' "${missing[@]}"
|
||||
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "Dry run: not publishing"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! publish_missing_packages "${missing[@]}"; then
|
||||
echo "Recovery incomplete: one or more packages failed to publish"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All missing packages published successfully"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "Running lerna publish in dry-run mode"
|
||||
printf "n\n" | npx lerna version --exact --no-git-tag-version --no-push $BETA_FLAGS
|
||||
else
|
||||
echo "Running lerna publish for real"
|
||||
set +e
|
||||
release_output="$(npm run release -- --yes $BETA_FLAGS $DIST_TAG_FLAGS 2>&1)"
|
||||
release_exit_code=$?
|
||||
set -e
|
||||
printf '%s\n' "$release_output"
|
||||
|
||||
if [ $release_exit_code -eq 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$release_output" == *"fatal: tag '"*"' already exists"* ]]; then
|
||||
existing_tag="$(printf '%s\n' "$release_output" | sed -n "s/.*fatal: tag '\\([^']*\\)' already exists.*/\\1/p" | head -n 1)"
|
||||
if [ -z "$existing_tag" ]; then
|
||||
echo "Detected existing tag failure, but could not parse tag name"
|
||||
exit $release_exit_code
|
||||
fi
|
||||
|
||||
echo "Detected existing tag failure for ${existing_tag}; attempting scoped publish recovery from tagged commit"
|
||||
git fetch --tags --force origin
|
||||
tagged_commit="$(git rev-list -n 1 "$existing_tag")"
|
||||
if [ -z "$tagged_commit" ]; then
|
||||
echo "Tag ${existing_tag} was not found after fetching tags"
|
||||
exit $release_exit_code
|
||||
fi
|
||||
|
||||
git checkout "$tagged_commit"
|
||||
mapfile -t missing < <(find_missing_packages)
|
||||
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
echo "Missing package versions on npm before scoped recovery:"
|
||||
printf ' - %s\n' "${missing[@]}"
|
||||
if ! publish_missing_packages "${missing[@]}"; then
|
||||
echo "Recovery incomplete: one or more packages failed to publish"
|
||||
exit $release_exit_code
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "All publishable workspace package versions are present on npm; treating recovery as successful."
|
||||
else
|
||||
echo "Release failed and no known recovery condition matched"
|
||||
exit $release_exit_code
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# This job only publishes new releases on GitHub and updates the changelog, without publishing to NPM.
|
||||
# It can be used if the standard release workflow failed and *only* published to NPM.
|
||||
|
||||
name: Appium Server Version (Without NPM Publish)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
# keep this branch name in sync with env.BETA_BRANCH below - the `env` context isn't available
|
||||
# to jobs.<job_id>.if (GitHub Actions resolves it before job-level env is set up)
|
||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/appium4') && contains(fromJSON('["mykola-mokhnach", "jlipps", "eglitise", "KazuCocoa"]'), github.actor)
|
||||
env:
|
||||
BETA_BRANCH: appium4
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure git user
|
||||
run: |
|
||||
git config user.name "github-actions"
|
||||
git config user.email "github-actions@github.com"
|
||||
|
||||
- name: Setup Node and install deps (LTS)
|
||||
uses: ./.github/actions/setup-build
|
||||
with:
|
||||
node-version: lts/*
|
||||
install-command: npm ci
|
||||
run-build: 'true'
|
||||
|
||||
- name: Run Lerna version
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
BETA_FLAGS=""
|
||||
if [ "${{ github.ref_name }}" = "$BETA_BRANCH" ]; then
|
||||
BETA_FLAGS="--conventional-prerelease --preid beta"
|
||||
fi
|
||||
npx lerna version --exact --yes $BETA_FLAGS
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check for "On Hold" label
|
||||
uses: egmacke/action-check-label@v4
|
||||
uses: egmacke/action-check-label@v5
|
||||
with:
|
||||
label: On Hold
|
||||
state: absent
|
||||
|
||||
@@ -1,38 +1,33 @@
|
||||
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
||||
|
||||
name: Publish docs
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
# Runs when any new Appium tag is pushed = there is a new release
|
||||
# Does not trigger for tags with a slash, e.g. 1.0/beta
|
||||
tags:
|
||||
- 'appium@*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install dependencies (Node.js)
|
||||
uses: bahmutov/npm-install@v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
install-command: npm ci
|
||||
- name: Install dependencies (Python)
|
||||
run: PIP_BREAK_SYSTEM_PACKAGES=1 pip install -r packages/docutils/requirements.txt
|
||||
- name: Publish docs
|
||||
run: |
|
||||
cd packages/appium
|
||||
npm run publish:docs
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
- name: Setup Node and install deps (LTS)
|
||||
uses: ./.github/actions/setup-build
|
||||
with:
|
||||
node-version: lts/*
|
||||
install-command: npm ci
|
||||
run-build: 'true'
|
||||
- name: Install dependencies (Python)
|
||||
run: npm run install-docs-deps
|
||||
- name: Fetch gh-pages
|
||||
run: |
|
||||
git fetch origin gh-pages:gh-pages || true
|
||||
- name: Publish docs
|
||||
run: |
|
||||
npm run docs:publish
|
||||
|
||||
@@ -23,8 +23,8 @@ jobs:
|
||||
name: Check Renovate Configs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7.0.1
|
||||
- name: Validate Renovate Config
|
||||
uses: rinchsan/renovate-config-validator@v0.2.0
|
||||
uses: rinchsan/renovate-config-validator@v0.2.1
|
||||
with:
|
||||
pattern: '{.renovaterc.json,renovate/default.json}'
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"codegraph": {
|
||||
"type": "stdio",
|
||||
"command": "codegraph",
|
||||
"args": ["serve", "--mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
require: ['ts-node/register'],
|
||||
// forbids use of .only() in CI
|
||||
forbidOnly: Boolean(process.env.CI),
|
||||
color: true,
|
||||
timeout: '5s',
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
**/node_modules/**
|
||||
**/build/**
|
||||
**/fixtures/**
|
||||
**/*.min.*
|
||||
**/*.md
|
||||
package-lock.json
|
||||
package.json
|
||||
**/.vscode/**
|
||||
**/*.html
|
||||
**/generated/**
|
||||
# generated
|
||||
packages/types/lib/appium-config.ts
|
||||
**/*.hbs
|
||||
|
||||
/.nx/workspace-data
|
||||
+1
-4
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>appium/appium//renovate/default"],
|
||||
"schedule": [
|
||||
"after 10pm",
|
||||
"before 5:00am"
|
||||
],
|
||||
"schedule": ["after 10pm", "before 5:00am"],
|
||||
"timezone": "America/Vancouver"
|
||||
}
|
||||
|
||||
+3
-1
@@ -29,11 +29,12 @@ to driver/client documentation
|
||||
* [fake-plugin](packages/fake-plugin/CHANGELOG.md)
|
||||
* [logger](packages/logger/CHANGELOG.md)
|
||||
* [opencv](packages/opencv/CHANGELOG.md)
|
||||
* [oxc-config](packages/oxc-config/CHANGELOG.md)
|
||||
* [plugin-test-support](packages/plugin-test-support/CHANGELOG.md)
|
||||
* [schema](packages/schema/CHANGELOG.md)
|
||||
* [semantic-release-config](packages/semantic-release-config/CHANGELOG.md)
|
||||
* [strongbox](packages/strongbox/CHANGELOG.md)
|
||||
* [support](packages/support/CHANGELOG.md)
|
||||
* [test-support](packages/test-support/CHANGELOG.md)
|
||||
* [tsconfig](packages/tsconfig/CHANGELOG.md)
|
||||
* [types](packages/types/CHANGELOG.md)
|
||||
|
||||
@@ -42,4 +43,5 @@ The changelog links used for these modules lead to the last version of their cha
|
||||
* [doctor](https://github.com/appium/appium/blob/8daf5e123ac14c8325acf504fb33eb28e1a3dd78/packages/doctor/CHANGELOG.md) ([removal PR](https://github.com/appium/appium/pull/20805))
|
||||
* [eslint-config-appium](https://github.com/appium/appium/blob/4b3a8c2197a587ec5a2606b662e4e7667a7852cb/packages/eslint-config-appium/CHANGELOG.md) ([removal PR](https://github.com/appium/appium/pull/20856))
|
||||
* [gulp-plugins](https://github.com/appium/appium/blob/0823f0b60e40395cd1dc3b72cfa3c0092bc81302/packages/gulp-plugins/CHANGELOG.md) ([removal PR](https://github.com/appium/appium/pull/17943))
|
||||
* [test-support](https://github.com/appium/appium/blob/1a46d7d61ee49c7e82a63687c5647c42ab69513d/packages/test-support/CHANGELOG.md) ([removal PR](https://github.com/appium/appium/pull/22351))
|
||||
* [typedoc-plugin-appium](https://github.com/appium/appium/blob/d6204b6902074210943d7bbbf72d139b9b170a20/packages/typedoc-plugin-appium/CHANGELOG.md) ([removal PR](https://github.com/appium/appium/pull/19465))
|
||||
|
||||
@@ -50,18 +50,22 @@ The current committers are (along with their primary areas(s) of ownership or ma
|
||||
|
||||
* [@dan-maor](https://github.com/Dan-Maor) - XCUITest driver and iOS internals
|
||||
* [@dor-bl](https://github.com/Dor-bl) - DotNet client
|
||||
* [@Delta456](https://github.com/Delta456) - appium-mcp, iOS support libraries
|
||||
* [@eglitise](https://github.com/eglitise) - Appium server, Inspector
|
||||
* [@harsha509](https://github.com/harsha509) - appium-ios-tuntap
|
||||
* [@jlipps](https://github.com/jlipps) - Appium server, Inspector
|
||||
* [@kazucocoa](https://github.com/KazuCocoa) - all Appium projects
|
||||
* [@laolubenson](https://github.com/laolubenson) - DotNet client
|
||||
* [@mwakizaka](https://github.com/mwakizaka) - XCUITest driver
|
||||
* [@mykola-mokhnach](https://github.com/mykola-mokhnach) - all Appium projects
|
||||
* [@navin772](https://github.com/navin772) - appium-mcp, iOS support libraries
|
||||
* [@rerorero](https://github.com/rerorero) - XCUITest/UIA2 driver
|
||||
* [@saikrishna321](https://github.com/saikrishna321) - Java client
|
||||
* [@srinivasantarget](https://github.com/SrinivasanTarget) - Java client
|
||||
* [@tomriddly](https://github.com/tomriddly) - appium-ios-device
|
||||
* [@valfirst](https://github.com/valfirst) - Java client
|
||||
|
||||
|
||||
See [Emeritus Contributors](#emeritus-contributors) below for a list of people who formerly made
|
||||
significant contributions to the project but are no longer actively committing.
|
||||
|
||||
|
||||
+6
-8
@@ -3,13 +3,11 @@ import {defineConfig, globalIgnores} from 'eslint/config';
|
||||
|
||||
// Create a modified config subset for test support files:
|
||||
// Extract the test file related configs (Mocha plugin and custom rules),
|
||||
// then override their 'files' property
|
||||
const testFileConfigItems = [appiumConfig[8], appiumConfig[9]];
|
||||
const testSupportFiles = [
|
||||
'packages/test-support/lib/**',
|
||||
'packages/driver-test-support/lib/**',
|
||||
'packages/plugin-test-support/lib/**',
|
||||
];
|
||||
// then override their 'files' property (match by name — resilient to new config entries).
|
||||
const testFileConfigItems = appiumConfig.filter(
|
||||
(item) => typeof item?.name === 'string' && item.name.startsWith('Test Files'),
|
||||
);
|
||||
const testSupportFiles = ['packages/driver-test-support/lib/**', 'packages/plugin-test-support/lib/**'];
|
||||
const testSupportConfig = testFileConfigItems.map((item) => ({...item, files: testSupportFiles}));
|
||||
|
||||
export default defineConfig([
|
||||
@@ -27,7 +25,7 @@ export default defineConfig([
|
||||
rules: {
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'error',
|
||||
{ fixStyle: 'separate-type-imports', prefer: 'type-imports' },
|
||||
{fixStyle: 'separate-type-imports', prefer: 'type-imports'},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@
|
||||
"version": {
|
||||
"conventionalCommits": true,
|
||||
"createRelease": "github",
|
||||
"allowBranch": ["master", "appium3"]
|
||||
"allowBranch": ["master", "appium4"],
|
||||
"exact": true
|
||||
}
|
||||
},
|
||||
"ignoreChanges": ["**/test/**", "**/*.md"],
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import appiumConfig, {defineConfig, ignorePatterns as appiumIgnorePatterns} from '@appium/oxc-config/oxfmt';
|
||||
|
||||
export default defineConfig({
|
||||
...appiumConfig,
|
||||
ignorePatterns: [
|
||||
...appiumIgnorePatterns,
|
||||
'packages/appium/docs/**',
|
||||
'packages/schema/lib/appium-config.schema.json',
|
||||
'packages/types/lib/appium-config.ts',
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import appiumConfig, {defineConfig, ignorePatterns as appiumIgnorePatterns} from '@appium/oxc-config/oxlint';
|
||||
|
||||
export default defineConfig({
|
||||
extends: [appiumConfig],
|
||||
ignorePatterns: [
|
||||
...appiumIgnorePatterns,
|
||||
'packages/appium/docs/**/assets/**',
|
||||
'packages/appium/docs/**/js/**',
|
||||
'packages/appium/sample-code/**',
|
||||
],
|
||||
});
|
||||
Generated
+8611
-5508
File diff suppressed because it is too large
Load Diff
+46
-80
@@ -4,28 +4,31 @@
|
||||
"private": true,
|
||||
"description": "Automation for Apps.",
|
||||
"keywords": [
|
||||
"android",
|
||||
"automation",
|
||||
"firefoxos",
|
||||
"ios",
|
||||
"javascript",
|
||||
"selenium",
|
||||
"webdriver",
|
||||
"ios",
|
||||
"android",
|
||||
"firefoxos",
|
||||
"testing"
|
||||
"testing",
|
||||
"webdriver"
|
||||
],
|
||||
"homepage": "https://appium.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/appium/appium/issues"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": "https://github.com/appium",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appium/appium.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": "https://github.com/appium",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "run-s build:*",
|
||||
"build:compile": "tsc -b",
|
||||
@@ -47,9 +50,11 @@
|
||||
"docs:publish": "npm run -w packages/appium publish:docs",
|
||||
"doctor": "node ./scripts/doctor-stub.mjs",
|
||||
"install-docs-deps": "npm run -w packages/appium install-docs-deps",
|
||||
"lint": "eslint .",
|
||||
"lint:ci": "eslint --quiet .",
|
||||
"lint:fix": "run-s \"lint -- --fix\"",
|
||||
"format": "oxfmt -c oxfmt.config.mjs .",
|
||||
"format:check": "oxfmt -c oxfmt.config.mjs --check .",
|
||||
"lint": "oxlint -c oxlint.config.mjs .",
|
||||
"lint:ci": "oxlint -c oxlint.config.mjs --quiet .",
|
||||
"lint:fix": "oxlint -c oxlint.config.mjs --fix .",
|
||||
"prepare": "run-p rebuild",
|
||||
"prepublishOnly": "run-s rebuild",
|
||||
"preversion": "run-s rebuild",
|
||||
@@ -57,117 +62,78 @@
|
||||
"rebuild": "run-s clean build",
|
||||
"reinstall": "run-s clean clean:deps ci",
|
||||
"reinstall:angry": "npm run clean:dangerously && npm ci",
|
||||
"release": "lerna publish",
|
||||
"release": "lerna publish --exact",
|
||||
"stage-synced-pkgs": "git add -A packages/appium/README.md \"packages/*/package.json\"",
|
||||
"start": "appium",
|
||||
"sync-pkgs": "run-p sync-pkgs:*",
|
||||
"sync-pkgs:appium-readme": "sync-monorepo-packages --force --no-package-json --packages=packages/appium README.md",
|
||||
"sync-pkgs:common-fields:default": "sync-monorepo-packages --packages=\"!packages/logger\" --fields=author,license,bugs,homepage",
|
||||
"sync-pkgs:common-fields:logger": "sync-monorepo-packages --packages=\"packages/logger\" --fields=author,bugs,homepage",
|
||||
"sync-pkgs:keywords": "sync-monorepo-packages --field=keywords --packages=\"packages/*\" --packages=\"!packages/types\" --packages=\"!packages/eslint-config-appium-ts\" ",
|
||||
"sync-pkgs:license": "sync-monorepo-packages --force --no-package-json --packages=\"!packages/logger\" LICENSE",
|
||||
"sync-pkgs": "node ./scripts/sync-monorepo-packages.mjs",
|
||||
"test": "run-s test:quick",
|
||||
"test:ci": "run-s test:smoke test:unit test:types test:e2e",
|
||||
"test:e2e": "lerna run test:e2e",
|
||||
"test:quick": "run-s lint test:unit test:types",
|
||||
"test:slow": "run-s test:quick test:smoke test:e2e",
|
||||
"test:smoke": "smoker --all test:smoke",
|
||||
"test:smoke": "lerna run test:smoke",
|
||||
"test:types": "lerna run test:types",
|
||||
"test:unit": "lerna run test",
|
||||
"upload": "gulp github-upload",
|
||||
"verify:changelog-generation": "node ./scripts/verify-changelog-generation.mjs",
|
||||
"zip": "zip -qr ./appium.zip ./packages/appium",
|
||||
"zip-and-upload": "run-s zip upload"
|
||||
},
|
||||
"prettier": {
|
||||
"bracketSpacing": false,
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
},
|
||||
"devDependencies": {
|
||||
"@colors/colors": "1.6.0",
|
||||
"@eslint/js": "9.39.4",
|
||||
"@stylistic/eslint-plugin": "5.10.0",
|
||||
"@tsconfig/node20": "20.1.9",
|
||||
"@types/archiver": "7.0.0",
|
||||
"@types/argparse": "2.0.17",
|
||||
"@appium/oxc-config": "1.0.0",
|
||||
"@tsconfig/node20": "20.1.10",
|
||||
"@types/async-lock": "1.4.2",
|
||||
"@types/base64-stream": "1.0.5",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"@types/chai": "5.2.3",
|
||||
"@types/chai-as-promised": "8.0.2",
|
||||
"@types/content-disposition": "0.5.9",
|
||||
"@types/express": "5.0.6",
|
||||
"@types/finalhandler": "1.2.4",
|
||||
"@types/jsftp": "2.1.5",
|
||||
"@types/json-schema": "7.0.15",
|
||||
"@types/klaw": "3.0.7",
|
||||
"@types/lockfile": "1.0.4",
|
||||
"@types/lodash": "4.17.24",
|
||||
"@types/method-override": "3.0.0",
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/mv": "2.1.4",
|
||||
"@types/ncp": "2.0.8",
|
||||
"@types/node": "24.12.0",
|
||||
"@types/morgan": "1.9.10",
|
||||
"@types/node": "24.13.3",
|
||||
"@types/plist": "3.0.5",
|
||||
"@types/pluralize": "0.0.33",
|
||||
"@types/semver": "7.7.1",
|
||||
"@types/semver": "7.8.0",
|
||||
"@types/serve-favicon": "2.5.7",
|
||||
"@types/shell-quote": "1.7.5",
|
||||
"@types/sinon": "21.0.0",
|
||||
"@types/sinon-chai": "4.0.0",
|
||||
"@types/sinon": "22.0.0",
|
||||
"@types/which": "3.0.4",
|
||||
"@types/ws": "8.18.1",
|
||||
"@types/xmldom": "0.1.34",
|
||||
"@types/yargs": "17.0.35",
|
||||
"asyncbox": "6.1.0",
|
||||
"chai": "6.2.2",
|
||||
"chai-as-promised": "8.0.2",
|
||||
"conventional-changelog-conventionalcommits": "7.0.2",
|
||||
"asyncbox": "6.4.2",
|
||||
"conventional-changelog-conventionalcommits": "9.3.1",
|
||||
"cpy-cli": "7.0.0",
|
||||
"cross-env": "10.1.0",
|
||||
"eslint": "9.39.4",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-import-resolver-typescript": "4.4.4",
|
||||
"eslint-plugin-import-x": "4.16.1",
|
||||
"eslint-plugin-mocha": "11.2.0",
|
||||
"eslint-plugin-n": "17.24.0",
|
||||
"eslint-plugin-promise": "7.2.1",
|
||||
"finalhandler": "2.1.1",
|
||||
"get-port": "7.1.0",
|
||||
"json-schema-to-typescript": "15.0.4",
|
||||
"lerna": "9.0.5",
|
||||
"log-symbols": "7.0.1",
|
||||
"midnight-smoker": "8.0.0",
|
||||
"lerna": "10.0.1",
|
||||
"mjpeg-consumer": "2.0.0",
|
||||
"mjpeg-server": "0.3.1",
|
||||
"mocha": "11.7.5",
|
||||
"npm-run-all2": "8.0.4",
|
||||
"prettier": "3.8.1",
|
||||
"npm-run-all2": "9.0.3",
|
||||
"rewiremock": "3.14.6",
|
||||
"rimraf": "6.1.3",
|
||||
"serve-static": "2.2.1",
|
||||
"sinon": "21.0.2",
|
||||
"sinon-chai": "4.0.1",
|
||||
"sync-monorepo-packages": "1.0.2",
|
||||
"teen_process": "4.0.10",
|
||||
"ts-node": "10.9.2",
|
||||
"sinon": "22.1.0",
|
||||
"teen_process": "4.2.1",
|
||||
"tsd": "0.33.0",
|
||||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.56.1",
|
||||
"webdriverio": "9.24.0",
|
||||
"ws": "8.19.0"
|
||||
"typescript": "6.0.3",
|
||||
"webdriverio": "9.31.1",
|
||||
"ws": "8.21.3"
|
||||
},
|
||||
"overrides": {
|
||||
"@sidvind/better-ajv-errors": {
|
||||
"ajv": "8.20.0"
|
||||
},
|
||||
"ajv-formats": {
|
||||
"ajv": "8.20.0"
|
||||
},
|
||||
"http-cache-semantics": "4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
||||
"npm": ">=10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"overrides": {
|
||||
"@sidvind/better-ajv-errors": {
|
||||
"ajv": "8.18.0"
|
||||
},
|
||||
"ajv-formats": {
|
||||
"ajv": "8.18.0"
|
||||
},
|
||||
"http-cache-semantics": "4.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,118 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.7.0](https://github.com/appium/appium/compare/appium@3.6.0...appium@3.7.0) (2026-08-24)
|
||||
|
||||
### Features
|
||||
|
||||
* **base-driver:** add httpServer.frontRouter for global extension middleware ([#22632](https://github.com/appium/appium/issues/22632)) ([f06226b](https://github.com/appium/appium/commit/f06226b7bb2fb7ee2f3a61833f4a1d7777d4ef21))
|
||||
* **storage-plugin:** Add route aliases ([#22558](https://github.com/appium/appium/issues/22558)) ([a551c38](https://github.com/appium/appium/commit/a551c3817156bbc7e06793227643a2d11c0c0259))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** load @appium/docutils dynamically in docs build script ([#22584](https://github.com/appium/appium/issues/22584)) ([2c0f3fd](https://github.com/appium/appium/commit/2c0f3fd9e319c3bc774bdd2a65148da11094c87c))
|
||||
* **appium:** parse --webhook as a URI instead of host:port ([#22635](https://github.com/appium/appium/issues/22635)) ([c35a12a](https://github.com/appium/appium/commit/c35a12a51d30fe311ef96ebe386cd9c5540e3927))
|
||||
* **support:** do not treat a sibling folder as a subpath of the root ([#22586](https://github.com/appium/appium/issues/22586)) ([3a80498](https://github.com/appium/appium/commit/3a8049887dc673a6658c3821a2882e0145c3aa86))
|
||||
|
||||
|
||||
## [3.6.0](https://github.com/appium/appium/compare/appium@3.5.2...appium@3.6.0) (2026-07-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** add --allow-unknown-args to tolerate unrecognized server CLI arguments ([#22477](https://github.com/appium/appium/issues/22477)) ([f943fab](https://github.com/appium/appium/commit/f943fab1411826212cfb174e3847e610c25f37b7))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Duplicated module import ([#22519](https://github.com/appium/appium/issues/22519)) ([154ea18](https://github.com/appium/appium/commit/154ea1825281335569f0d6952db527135c75e153))
|
||||
* typescript config ([#22540](https://github.com/appium/appium/issues/22540)) ([ea6a2e1](https://github.com/appium/appium/commit/ea6a2e117f56c1d7ff459378700494407c51608e))
|
||||
* Typescript references ([#22458](https://github.com/appium/appium/issues/22458)) ([fd70da7](https://github.com/appium/appium/commit/fd70da7ab407bf1f6fec8a3576b9a33f0aef9b69))
|
||||
|
||||
|
||||
|
||||
## [3.5.2](https://github.com/appium/appium/compare/appium@3.5.1...appium@3.5.2) (2026-06-18)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.5.1](https://github.com/appium/appium/compare/appium@3.5.0...appium@3.5.1) (2026-06-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **storage-plugin:** add fs.sanitizeName for the delete request as well ([#22362](https://github.com/appium/appium/issues/22362)) ([5fee017](https://github.com/appium/appium/commit/5fee01752f2782e96fbe64fd13520b433d4a7535))
|
||||
|
||||
|
||||
|
||||
## [3.5.0](https://github.com/appium/appium/compare/appium@3.4.2...appium@3.5.0) (2026-05-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add IPC channels per session for drivers and plugins to communicate ([#22211](https://github.com/appium/appium/issues/22211)) ([97c879c](https://github.com/appium/appium/commit/97c879cdd02e6fcccaaea45a8d1a7088bed4ae66)), closes [#22206](https://github.com/appium/appium/issues/22206)
|
||||
* **appium:** Ditch bluebird ([#22301](https://github.com/appium/appium/issues/22301)) ([abb83bd](https://github.com/appium/appium/commit/abb83bde62e8beefdd9483a276ef2aa888722245))
|
||||
* Limit the maximum count of topics per session and make it configurable ([#22279](https://github.com/appium/appium/issues/22279)) ([0264775](https://github.com/appium/appium/commit/0264775ecb8ecaca9dac2eae47784da02a653255))
|
||||
* make assignIpc internal ([#22278](https://github.com/appium/appium/issues/22278)) ([25d922b](https://github.com/appium/appium/commit/25d922b7d3062c306c1631d6f5c227600ddd226a))
|
||||
|
||||
|
||||
|
||||
## [3.4.2](https://github.com/appium/appium/compare/appium@3.4.1...appium@3.4.2) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.4.1](https://github.com/appium/appium/compare/appium@3.4.0...appium@3.4.1) (2026-05-06)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [3.4.0](https://github.com/appium/appium/compare/appium@3.3.1...appium@3.4.0) (2026-05-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add 3 WebDriver extension endpoints ([#22237](https://github.com/appium/appium/issues/22237)) ([787571d](https://github.com/appium/appium/commit/787571d33836c06bb1332d7bc6cc2f9800bbdd82))
|
||||
|
||||
|
||||
|
||||
## [3.3.1](https://github.com/appium/appium/compare/appium@3.3.0...appium@3.3.1) (2026-04-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** lint warnings ([#22171](https://github.com/appium/appium/issues/22171)) ([8e68b3e](https://github.com/appium/appium/commit/8e68b3e2c9c7b6238e0ffc241adbd4d9991ead7a))
|
||||
* **appium:** plugins caching per session ([#22203](https://github.com/appium/appium/issues/22203)) ([622f199](https://github.com/appium/appium/commit/622f1999d72d2f7ebc7cc279879ea0fcefe29a54))
|
||||
|
||||
|
||||
|
||||
## [3.3.0](https://github.com/appium/appium/compare/appium@3.2.2...appium@3.3.0) (2026-04-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* use exact version for dependencies in monorepo packages instead of ^ ([#22090](https://github.com/appium/appium/issues/22090)) ([86c8f23](https://github.com/appium/appium/commit/86c8f23a670d0bbc2d359a8235828606bd36e6aa))
|
||||
|
||||
|
||||
|
||||
## [3.2.2](https://github.com/appium/appium/compare/appium@3.2.1...appium@3.2.2) (2026-03-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Exclude package.json from tsconfig ([#22052](https://github.com/appium/appium/issues/22052)) ([1d89e2a](https://github.com/appium/appium/commit/1d89e2a5f8e478f3331666d3c308427ab834471a))
|
||||
|
||||
|
||||
|
||||
## [3.2.1](https://github.com/appium/appium/compare/appium@3.2.0...appium@3.2.1) (2026-03-08)
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ plugins:
|
||||
blog:
|
||||
enabled: true
|
||||
post_excerpt: required
|
||||
mike:
|
||||
canonical_version: 'latest'
|
||||
redirects:
|
||||
redirect_maps:
|
||||
'intro/requirements.md': 'quickstart/requirements.md'
|
||||
|
||||
@@ -8,11 +8,13 @@ date: 2025-11-25
|
||||
# Announcing LambdaTest as Appium's Newest Development Partner
|
||||
|
||||
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
|
||||
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
|
||||
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
|
||||
|
||||
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
|
||||
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
|
||||
@@ -22,15 +24,19 @@ This kind of hands-on contribution is crucial for ensuring Appium continues to e
|
||||
|
||||
|
||||
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
|
||||
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
|
||||
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
|
||||
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
|
||||
|
||||
* [`appium-mcp`](https://github.com/appium/appium-mcp) – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
|
||||
* [`appium-ios-remotexpc`](https://github.com/appium/appium-ios-remotexpc) – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
|
||||
* [`appium-ios-tuntap`](https://github.com/appium/appium-ios-tuntap) – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
|
||||
|
||||
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
|
||||
About LambdaTest
|
||||
|
||||
**About LambdaTest**
|
||||
|
||||
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
|
||||
|
||||
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
|
||||
|
||||
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
|
||||
|
||||
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
|
||||
|
||||
@@ -222,17 +222,22 @@ So you'll probably end up overriding `createSession`. You can do so by defining
|
||||
driver:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) {
|
||||
const [sessionId, caps] = super.createSession(w3cCaps);
|
||||
async createSession(w3cCaps) {
|
||||
const [sessionId, caps] = await super.createSession(w3cCaps);
|
||||
// do your own stuff here
|
||||
return [sessionId, caps];
|
||||
}
|
||||
```
|
||||
|
||||
For legacy reasons, your function will receive old-style JSON Wire Protocol desired and required
|
||||
caps as the first two arguments. Given that the old protocol isn't supported anymore and clients
|
||||
have all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion
|
||||
about what `otherDriverData` is about, see the section below on concurrent drivers).
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Older drivers may still define `createSession` with up to four parameters, e.g.
|
||||
`createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData)`. This shape is a holdover from the
|
||||
retired JSON Wire Protocol, which required desired and required caps as the first two
|
||||
arguments; only the first W3C-shaped argument was ever used. The `otherDriverData` parameter is
|
||||
likewise deprecated in favor of [IPC](#send-messages-to-plugins-running-on-the-same-session) for
|
||||
coordinating with other concurrently-running sessions. New drivers should use the single-argument
|
||||
form shown above.
|
||||
|
||||
You'll want to make sure to call `super.createSession` in order to get the session ID as well as
|
||||
the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`
|
||||
@@ -520,14 +525,13 @@ route, then the route will not be proxied and instead will be handled by your dr
|
||||
example, we are avoiding proxying all `POST` routes that have the `appium` prefix.
|
||||
|
||||
Next, we have to set up the proxying itself. The way to do this is to use a special class from
|
||||
Appium called `JWProxy`. (The name means "JSON Wire Proxy" and is related to a legacy
|
||||
implementation of the protocol). You'll want to create a `JWProxy` object using the details required to
|
||||
connect to the remote server:
|
||||
Appium called `WebDriverProxy`. You'll want to create a `WebDriverProxy` object using the details
|
||||
required to connect to the remote server:
|
||||
|
||||
```js
|
||||
// import {JWProxy} from 'appium/driver';
|
||||
// import {WebDriverProxy} from 'appium/driver';
|
||||
|
||||
const proxy = new JWProxy({
|
||||
const proxy = new WebDriverProxy({
|
||||
server: 'remote.server',
|
||||
port: 1234,
|
||||
base: '/',
|
||||
@@ -539,8 +543,8 @@ this.proxyCommand = proxy.command.bind(proxy);
|
||||
|
||||
Here we are creating a proxy object and assigning some of its methods to `this` under the names
|
||||
`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget
|
||||
this step! The `JWProxy` has a variety of other options which you can check out in the source code,
|
||||
as well. (TODO: publish options as API docs and link here).
|
||||
this step! The `WebDriverProxy` has a variety of other options [which you can check out in the
|
||||
source code as well.](https://github.com/appium/appium/blob/master/packages/base-driver/lib/jsonwp-proxy/proxy.ts)
|
||||
|
||||
Finally, we need a way to tell Appium when the proxy is active. For your driver it might always
|
||||
be active, or it might only be active when in a certain context. You can define the logic as an
|
||||
@@ -568,6 +572,33 @@ capability), and then to set an internal field to that value, so that it can be
|
||||
bidiProxyUrl`. Once all this is in place, Appium will proxy BiDi commands from the client straight
|
||||
to the upstream connection.
|
||||
|
||||
### Understand server-assigned driver properties and security flags
|
||||
|
||||
When your driver is running under the main Appium server, Appium assigns a small set of
|
||||
server-related properties on your driver instance when a session is created:
|
||||
|
||||
- `cliArgs`: Driver-specific configuration derived from the Appium server’s CLI flags and/or
|
||||
configuration files (for example via the `server.driver.<your-driver-name>` section). These
|
||||
options are **not** user capabilities and cannot be influenced directly by test code.
|
||||
- `server`, `serverHost`, `serverPort`, `serverPath`: Information about the HTTP server that is
|
||||
hosting your driver. These values reflect how the Appium server was started (for example the
|
||||
`--address`, `--port`, and `--base-path` flags) and are useful when your driver needs to construct
|
||||
URLs that point back to the Appium server itself (for example when setting up proxies, webhooks,
|
||||
or other callbacks).
|
||||
|
||||
`BaseDriver` and `AppiumDriver` also cooperate to expose security-related flags on your driver
|
||||
instance:
|
||||
|
||||
- `relaxedSecurityEnabled`: Indicates whether the server is running with relaxed security enabled
|
||||
(for example via `--relaxed-security`).
|
||||
- `allowInsecure`: A list of insecure features which are explicitly allowed for this driver (derived
|
||||
from server-level options like `--allow-insecure`).
|
||||
- `denyInsecure`: A list of insecure features which are explicitly disabled for this driver (derived
|
||||
from server-level options like `--deny-insecure`).
|
||||
|
||||
See [Hide behaviour behind security flags](#hide-behaviour-behind-security-flags) for how to use
|
||||
these flags in your driver (e.g. via `isFeatureEnabled` and `assertFeatureEnabled`).
|
||||
|
||||
### Extend the existing protocol with new commands
|
||||
|
||||
You may find that the existing commands don't cut it for your driver. If you want to expose
|
||||
@@ -770,6 +801,12 @@ that multiple simultaneous sessions don't use the same resources:
|
||||
1. Have each driver express what resources it is using, then examine currently-used resources from
|
||||
other drivers when a new session begins.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
The `driverData`-based mechanism described below is deprecated. Prefer
|
||||
[IPC](#send-messages-to-plugins-running-on-the-same-session) for coordinating resources across
|
||||
concurrently-running sessions instead.
|
||||
|
||||
To support this third strategy, you can implement `get driverData` in your driver to return what
|
||||
sorts of resources your driver is currently using, for example:
|
||||
|
||||
@@ -781,7 +818,7 @@ get driverData() {
|
||||
|
||||
Now, when a new session is started on your driver, the `driverData` response from any other
|
||||
simultaneously running drivers (of the same type) will also be included, as the last parameter of
|
||||
the `createSession` method:
|
||||
the deprecated, multi-argument form of the `createSession` method:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, driverData)
|
||||
@@ -858,3 +895,118 @@ this.onUnexpectedShutdown(handler)
|
||||
|
||||
`handler` should be a function which receives an error object (representing the reason for the
|
||||
unexpected shutdown).
|
||||
|
||||
### Send messages to plugins running on the same session
|
||||
|
||||
Appium's driver and plugin architecture means that a single driver and any number of plugins can be
|
||||
running together for a current session. The driver and plugins don't really know anything about
|
||||
each other though, which can make coordination potentially difficult. Without creating any kind of
|
||||
tight coupling between drivers or plugins, it's possible for drivers and plugins to communicate
|
||||
along a pub/sub style message bus. With Appium's IPC feature, "message" means a combination of
|
||||
"data" (the data intended to be published or received), and metadata (timestamp, the name of the
|
||||
publisher, etc...).
|
||||
|
||||
Drivers and plugins can implement an instance method called `async onIpcInit`, in which they will
|
||||
know that the IPC channel for the session is now active. At this point, they have access to the
|
||||
following methods:
|
||||
|
||||
#### `ipcSubscribe<T>(topic: string): IIpcSubscription`
|
||||
|
||||
This method allows a driver or plugin to subscribe to a topic on the IPC channel for the session.
|
||||
Topics are simply strings. To coordinate effectively, drivers or plugins would use the same topic
|
||||
string (so this would be something advertised in the driver/plugin documentation).
|
||||
|
||||
The result of this call is an `IpcSubscription` object that allows:
|
||||
- Looping through messages on the topic via an async generator
|
||||
- Hooking up an event handler for new messages
|
||||
- Getting the last message sent on the topic
|
||||
- Publishing a message to the topic
|
||||
- Unsubscribing from the topic
|
||||
|
||||
#### `IpcSubscription` object
|
||||
|
||||
Here is an example of how subscribing and use of these subscription methods might work:
|
||||
|
||||
```ts
|
||||
async onIpcInit() {
|
||||
// we know at this point in our driver/plugin lifecycle that we can use IPC methods
|
||||
type MyMessageData = {myData: string}; // let's say the message data for this channel has this shape
|
||||
|
||||
const subscription = this.ipcSubscribe<MyMessageData>('coolTopic');
|
||||
|
||||
// listen for new messages on topic
|
||||
subscription.on('message', (message) => {
|
||||
console.log(message.data); // {myData: 'something'}
|
||||
});
|
||||
|
||||
// publish data to the topic; might throw if the data is larger than configured max size, or we
|
||||
// are no longer subscribed
|
||||
await subscription.publish({myData: 'hi'});
|
||||
|
||||
// get last message sent to topic
|
||||
const {data} = subscription.getMessage() ?? {data: null};
|
||||
// data = {myData: 'hi'}
|
||||
|
||||
// unsubscribe
|
||||
subscription.unsubscribe(); // returns true if we unsubscribed and false if no subscription existed
|
||||
}
|
||||
```
|
||||
|
||||
With a subscription object, we can also iterate async over it to receive new messages:
|
||||
|
||||
```ts
|
||||
for await (const message of subscription) {
|
||||
// here we have a message and can unwrap its data
|
||||
}
|
||||
```
|
||||
|
||||
Note that the iteration will stop when the subscription ends (i.e., when `unsubscribe` is called).
|
||||
|
||||
You can also check whether the subscription is still active (if your subscribe and unsubscribe
|
||||
logic is not locally connected):
|
||||
|
||||
```ts
|
||||
if (subscription.isActive) {
|
||||
// we know we have not yet unsubscribed
|
||||
}
|
||||
```
|
||||
|
||||
If the subscription is not active, attempts to call `subscription.publish` will throw an error.
|
||||
|
||||
#### `IpcMessage` object
|
||||
|
||||
When you get a message on a topic, it has the following shape:
|
||||
|
||||
```ts
|
||||
export type IpcMessage<T> = {
|
||||
publisher: string, // the id of the publishing object (typically of the form <ClassName>@<uniqueObjectId>)
|
||||
timestampMs: number, // when the message was published, in ms since epoch
|
||||
topic: string, // the topic the message was published on
|
||||
data: T, // the arbitrary message data. Must be serializable and a valid argument to 'structuredClone()'
|
||||
};
|
||||
```
|
||||
|
||||
#### IPC Notes
|
||||
|
||||
There are some important things to keep in mind when using Appium's IPC feature:
|
||||
- IPC is only available once `onIpcInit` has been called, at the end of the `createSession` flow.
|
||||
It cannot be used statically or in `createSession` hooks
|
||||
- In sum, IPC is only for use during a session (this is also to prevent drivers/plugins from
|
||||
accessing or reading data sent on IPC channels in other sessions.)
|
||||
- The default max size of an IPC message is 1MB. This can be configured by the server-admin by
|
||||
using the `--max-ipc-data-size` arg (value is a number in bytes).
|
||||
- If a message exceeds the configured size, any call to `publish` methods will throw, so be
|
||||
sure to cover this case in your error handling.
|
||||
- The default max number of IPC topics per session is 1000. This can be configured by the
|
||||
server-admin using the `--max-ipc-topics` arg.
|
||||
- If the topic limit is reached, calls to `subscribe` or `publish` on a new topic will throw, so
|
||||
be sure to cover this case in your error handling.
|
||||
- Topic names exist within a global namespace per session. So if you don't want to clash with other
|
||||
drivers or plugins, make sure you prefix your topic names with something unique, akin to vendor
|
||||
prefixes in the WebDriver standard (for example: `fake-driver:some-topic`). We recommend the
|
||||
format `<namespace>:<topic>`.
|
||||
|
||||
To see examples of IPC in action, check out Appium's own
|
||||
[FakeDriver](https://github.com/appium/appium/blob/master/packages/fake-driver/lib/driver.ts) and
|
||||
[FakePlugin](https://github.com/appium/appium/blob/master/packages/fake-plugin/lib/plugin.ts)
|
||||
extensions, which showcase several ways of using IPC messages.
|
||||
|
||||
@@ -477,9 +477,9 @@ capability.
|
||||
You probably don't normally need to update the Appium server object (which is an
|
||||
[Express](https://expressjs.com/) server having already been
|
||||
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)
|
||||
in a variety of ways). But, for example, you could add new Express middleware to the server to
|
||||
support your plugin's requirements. To update the server you must implement the `static async
|
||||
updateServer` method in your class. This method takes three parameters:
|
||||
in a variety of ways). But, for example, you could add new routes to the server to support your
|
||||
plugin's requirements. To update the server you must implement the `static async updateServer`
|
||||
method in your class. This method takes three parameters:
|
||||
|
||||
* `expressApp`: the Express app object
|
||||
* `httpServer`: the Node HTTP server object
|
||||
@@ -492,6 +492,25 @@ results you'll need to test! Warning: this should be considered an advanced feat
|
||||
knowledge of Express, as well as the care not to do anything that could affect the operation of
|
||||
other parts of the Appium server!
|
||||
|
||||
`updateServer` runs *after* Appium's own routes are registered, so `expressApp.use(...)` here
|
||||
won't see requests to paths Appium already owns — Express matches middleware and routes in
|
||||
registration order. For middleware that must see requests to those routes too (e.g. logging or
|
||||
auth), use `httpServer.frontRouter` instead: Appium mounts this
|
||||
[Router](https://expressjs.com/en/5x/api/router/) before any route is registered, so anything
|
||||
attached to it — even from inside `updateServer` — still runs ahead of route matching. Note this
|
||||
is still *after* Appium's own baseline middleware (CORS, WebSocket upgrade handling, body
|
||||
parsing, etc.), so it won't see requests Appium itself has already rejected, e.g. a CORS
|
||||
preflight failure or a body that failed to parse:
|
||||
|
||||
```js
|
||||
static async updateServer(expressApp, httpServer, cliArgs) {
|
||||
httpServer.frontRouter.use((req, res, next) => {
|
||||
console.log(`Incoming request: ${req.method} ${req.url}`);
|
||||
next();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Handle unexpected session shutdown
|
||||
|
||||
When developing a plugin you may want to add some cleanup logic for when a session ends. You would
|
||||
@@ -512,3 +531,12 @@ async onUnexpectedShutdown(driver, cause) {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Send messages to the driver or other plugins running on the same session
|
||||
|
||||
Even though drivers and plugins don't know anything about each other, it's possible for them to
|
||||
send messages that other drivers or plugins can listen for, within the context of the same session,
|
||||
using an IPC channel. Given that the developer instructions for this feature are the same for
|
||||
drivers and plugins, please head over to the [IPC development docs for
|
||||
drivers](./build-drivers.md#send-messages-to-plugins-running-on-the-same-session) at the driver
|
||||
development guide.
|
||||
|
||||
@@ -30,7 +30,7 @@ In lieu of a separate file, configuration can be embedded in a project's `packag
|
||||
```
|
||||
|
||||
When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`
|
||||
will call into `lib/config-file.js` to load and/or search for a configuration file and in
|
||||
will call into `lib/bootstrap/config-file.js` to load and/or search for a configuration file and in
|
||||
`package.json`.
|
||||
|
||||
!!! note
|
||||
@@ -69,7 +69,7 @@ It is more straightforward to explain how config files are validated, so we'll s
|
||||
|
||||
### Validating Config Files
|
||||
|
||||
When a config file is found (`lib/config-file.js`), it will call the `validate` function exported
|
||||
When a config file is found (`lib/bootstrap/config-file.js`), it will call the `validate` function exported
|
||||
from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to
|
||||
validate the data against the schema that Appium has provided it.
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ appium driver install --source=npm appium-flutter-integration-driver
|
||||
appium driver install --source=npm appium-lg-webos-driver
|
||||
```
|
||||
|
||||
### [Linux](https://github.com/fantonglang/appium-linux-driver)
|
||||
### [Linux (@fantonglang)](https://github.com/fantonglang/appium-linux-driver)
|
||||
|
||||
!!! warning
|
||||
|
||||
@@ -143,6 +143,16 @@ yarn install
|
||||
node ./
|
||||
```
|
||||
|
||||
### [Linux (@Itsmeaj)](https://github.com/Itsmeaj/appium)
|
||||
|
||||
* Target: Linux desktop applications on X11 and Wayland
|
||||
* Mode: Native
|
||||
* Supported by: `@Itsmeaj`
|
||||
|
||||
```sh title="Install This Driver"
|
||||
appium driver install --source=npm @itsmeaj/appium-linux-driver
|
||||
```
|
||||
|
||||
### [NovaWindows](https://github.com/AutomateThePlanet/appium-novawindows-driver)
|
||||
|
||||
!!! info
|
||||
|
||||
@@ -49,6 +49,13 @@ automation capabilities using Appium.
|
||||
}
|
||||
```
|
||||
|
||||
### [Skills](https://github.com/appium/skills)
|
||||
|
||||
A set of AI Agent skills to support Appium automation, for example:
|
||||
|
||||
- Help preparing Appium test environment from scratch, including common driver setup
|
||||
- Help preparing XCUITest driver and WebDriverAgent for real device automation
|
||||
|
||||
## Extension Tools
|
||||
|
||||
Appium driver or plugin developers can choose to include these tools in their driver/plugin:
|
||||
@@ -74,6 +81,18 @@ It shows no results if the driver/plugin does not have such validation checks.
|
||||
|
||||
These tools are not maintained by the Appium team:
|
||||
|
||||
### [AppClaw](https://github.com/AppiumTestDistribution/AppClaw)
|
||||
|
||||
AppClaw is a CLI-based agentic AI layer for mobile automation, powered by [Appium MCP](#appium-mcp).
|
||||
Agent instructions can be passed directly via CLI, or defined as YAML flows in either structured
|
||||
or natural language syntax.
|
||||
|
||||
Supported by: `@AppiumTestDistribution`
|
||||
|
||||
```sh title="Install This Tool"
|
||||
npm install -g appclaw
|
||||
```
|
||||
|
||||
### [Appium Installer](https://github.com/AppiumTestDistribution/appium-installer)
|
||||
|
||||
Appium Installer is a command-line tool for simplifying setups of new Appium test environments.
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
title: Session Capabilities
|
||||
---
|
||||
|
||||
"Capabilities" is the name given to the set of parameters used to start an Appium session. The
|
||||
information in the set describes what sort of "capabilities" you want your session to have, for
|
||||
example, a certain mobile operating system or a certain version of a device. Capabilities are
|
||||
represented as key-value pairs, with values allowed to be any valid JSON type, including
|
||||
other objects.
|
||||
Capabilities are the core parameters used to start an Appium session. They describe various
|
||||
features that you want your session to have, for example, a certain mobile operating system or a
|
||||
certain version of a device. Capabilities are represented as key-value pairs, with values allowed
|
||||
to be any valid JSON type, including other objects. Most importantly, they cannot be changed
|
||||
during the lifecycle of the session.
|
||||
|
||||
The W3C WebDriver spec's [section on Capabilities](https://w3c.github.io/webdriver/#capabilities)
|
||||
identifies a small set of 10 standard capabilities, including the following:
|
||||
The capabilities used in Appium follow [the W3C WebDriver specification of the same name](https://w3c.github.io/webdriver/#capabilities).
|
||||
The WebDriver spec defines a small set of standard capabilities, including the following:
|
||||
|
||||
| Capability Name | Type | Description |
|
||||
|------------------|----------|------------------------------------------------|
|
||||
@@ -17,65 +17,62 @@ identifies a small set of 10 standard capabilities, including the following:
|
||||
| `browserVersion` | `string` | The specific version of the browser |
|
||||
| `platformName` | `string` | The type of platform hosting the browser |
|
||||
|
||||
While the above capabilities are commonly used by Appium drivers, they are not sufficient for
|
||||
describing Appium-specific features, such as the name of the driver to use, or the name of the app
|
||||
to launch. In order to achieve this, Appium defines its own [extension capabilities](https://w3c.github.io/webdriver/#dfn-extension-capability).
|
||||
|
||||
## Common Appium Capabilities
|
||||
|
||||
Appium understands these browser-focused capabilities, but introduces a number of additional
|
||||
capabilities. According to the WebDriver spec, any
|
||||
non-standard "extension capabilities" must include a namespace prefix (signifying the vendor
|
||||
introducing the capability), ending in a `:`. Appium's vendor prefix is
|
||||
`appium:`, and so any Appium-specific capabilities must include this prefix. Depending on which
|
||||
client you are using, the prefix may be added automatically or in conjunction with certain
|
||||
interfaces, but it is always a good practice to explicitly include it for clarity.
|
||||
According to the WebDriver spec, extension capabilities must include a namespace prefix (signifying
|
||||
the vendor introducing the capability), and the namespace must end a colon (`:`). Appium's vendor
|
||||
prefix is `appium:`, and so any Appium-specific capabilities must include this prefix. Depending on
|
||||
your Appium client, the prefix may be added automatically or in conjunction with certain interfaces,
|
||||
but it is always a good practice to explicitly include it for clarity.
|
||||
|
||||
Here is a list of all the globally-recognized Appium capabilities:
|
||||
Here are a few commonly (but not universally!) used Appium-specific capabilities:
|
||||
|
||||
!!! info
|
||||
| Capability Name | Type | Description |
|
||||
|-------------------------|----------|-----------------------------------------------------------------|
|
||||
| `appium:automationName` | `string` | The name of the Appium driver to use |
|
||||
| `appium:udid` | `string` | The unique device identifier of a particular device to automate |
|
||||
| `appium:app` | `string` | The path to an installable application |
|
||||
|
||||
Individual drivers and plugins can support other capabilities, so refer to their documentation
|
||||
for lists of specific capability names. Some drivers may also not support all of these capabilities
|
||||
All capabilities recognized by the Appium base driver (inherited by all drivers) can be found in the
|
||||
[Capabilities Reference document](../reference/session/caps.md). While this common capability set
|
||||
is fairly small, it can be greatly extended by Appium drivers and plugins, who can (and should)
|
||||
define their own capabilities. Make sure to reference their documentation to learn more about the
|
||||
capabilities they support. You can find a list of known drivers in the [Ecosystem Drivers](../ecosystem/drivers.md) document.
|
||||
|
||||
| <div style="width:12em">Capability</div> | Type | Required? | Description |
|
||||
|--------------------------------------------|-----------|-----------|----------------------------|
|
||||
| `platformName` | `string` | yes | The type of platform hosting the app or browser |
|
||||
| `appium:automationName` | `string` | yes | The name of the Appium driver to use |
|
||||
| `browserName` | `string` | no | The name of the browser to launch and automate, if the driver supports web browsers as a special case |
|
||||
| `appium:app` | `string` | no | The path to an installable application |
|
||||
| `appium:deviceName` | `string` | no | The name of a particular device to automate, e.g., `iPhone 14` (currently only actually useful for specifying iOS simulators, since in other situations it's typically recommended to use a specific device id via the `appium:udid` capability). |
|
||||
| `appium:platformVersion` | `string` | no | The version of a platform, e.g., for iOS, `16.0` |
|
||||
| `appium:newCommandTimeout` | `number` | no | The number of seconds the Appium server should wait for clients to send commands before deciding that the client has gone away and the session should shut down. `60` seconds by default. Setting it to zero disables the timer. |
|
||||
| `appium:noReset` | `boolean` | no | If true, instruct an Appium driver to avoid its usual reset logic during session start and cleanup (default `false`) |
|
||||
| `appium:fullReset` | `boolean` | no | If true, instruct an Appium driver to augment its usual reset logic with additional steps to ensure maximum environmental reproducibility (default `false`) |
|
||||
| `appium:eventTimings` | `boolean` | no | If true, instruct an Appium driver to collect [Event Timings](./event-timing.md) (default `false`) |
|
||||
| `appium:printPageSourceOnFindFailure` | `boolean` | no | If true, collect the page source and print it to the Appium log whenever a request to find an element fails (default `false`) |
|
||||
Drivers are also able to place more complex constraints on capabilities as a group. For example,
|
||||
the XCUITest driver recommends that at least one of `browserName`, `appium:app`, or `appium:bundleId`
|
||||
is included in the capabilities, otherwise it will not be able to auto-install or auto-launch any
|
||||
application. Each driver will document how it interprets these capabilities and any other
|
||||
platform-specific requirements.
|
||||
|
||||
|
||||
Some drivers place more complex constraints on capabilities as a group. For example, while the
|
||||
`appium:app` and `browserName` capabilities are listed above as optional, if you want to launch
|
||||
a session with a specific app, the XCUITest driver requires that at least one of `appium:app`,
|
||||
`browserName`, or `appium:bundleId` are included in the capabilities (otherwise it will not know
|
||||
what app to install and/or launch and will simply open a session on the home screen). Each driver
|
||||
will document how it interprets these capabilities and any other platform-specific requirements.
|
||||
The way to construct capabilities and start a session will likely differ depending on your Appium
|
||||
client. For examples of doing this in each client library, head to the [Ecosystem Clients](../ecosystem/clients.md)
|
||||
page and click through to the appropriate client documentation.
|
||||
|
||||
!!! note
|
||||
|
||||
Capabilities are like parameters used when starting a session. After the capabilities are sent
|
||||
and the session is started, they cannot be changed. If a driver supports updating aspects of
|
||||
its behaviour in the course of a session, it will provide a [Setting](./settings.md) for this
|
||||
purpose instead of, or in addition to, a capability.
|
||||
|
||||
Each Appium client has its own way of constructing capabilities and starting a session. For
|
||||
examples of doing this in each client library, head to the [Ecosystem](../ecosystem/index.md) page
|
||||
and click through to the appropriate client documentation.
|
||||
Once your capabilities are sent to the server and the session is started, they cannot be
|
||||
changed. If a driver supports updating its behaviour during a session, it will use the
|
||||
[Settings API](./settings.md) for this purpose.
|
||||
|
||||
## BiDi Protocol Support
|
||||
|
||||
Appium supports [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol since base–driver 9.5.0.
|
||||
The actual behavior depends on individual drivers while the Appium and the baseーdriver support the protocol.
|
||||
Please make sure if a driver supports the protocol and what kind of commands/events it supports in the documentation.
|
||||
In addition to the standard WebDriver protocol (now known as WebDriver Classic), Appium supports the
|
||||
[WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol. Support for this protocol is
|
||||
opt-in, and requires the use of the standard `webSocketUrl` capability.
|
||||
|
||||
| Capability Name | Type | Description |
|
||||
|-----------------|-----------|-----------------------------------------|
|
||||
| `webSocketUrl` | `boolean` | To enable BiDi protocol in the session. |
|
||||
| Capability Name | Type | Description |
|
||||
|-----------------|-----------|--------------------------------------------------|
|
||||
| `webSocketUrl` | `boolean` | Whether BiDi protocol is enabled in the session |
|
||||
|
||||
All BiDi commands supported by the Appium base driver (inherited by all drivers) can be found in the
|
||||
[BiDi Protocol API Reference document](../reference/api/bidi.md). Similarly to WebDriver Classic
|
||||
commands, individual Appium drivers and plugins can define their own supported standard and custom
|
||||
BiDi commands, so make sure to reference their documentation.
|
||||
|
||||
## Using `appium:options` to Group Capabilities
|
||||
|
||||
@@ -118,8 +115,7 @@ creates in response to a new session request. This is through the concept of "al
|
||||
|
||||
!!! note
|
||||
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or
|
||||
a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) for
|
||||
a more in-depth description of how capabilities are processed.
|
||||
|
||||
In practice, use of first-match capabilities is not necessary or recommended for use with Appium.
|
||||
|
||||
@@ -3,27 +3,27 @@ title: Appium Server Security
|
||||
---
|
||||
|
||||
The Appium team makes every effort to ensure the security of the Appium server. This is especially
|
||||
important when Appium is run in a multitenant environment, or when multiple users are running
|
||||
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
|
||||
all the following are true:
|
||||
important when Appium is run in a multi-tenant environment, or when multiple users are running
|
||||
sessions on the same Appium server. To ensure a safe environment for Appium's purposes, all of the
|
||||
following should be true:
|
||||
|
||||
- You're running your own Appium server locally or within a protected internal network
|
||||
- You're not sharing it with any untrusted parties
|
||||
- You don't expose Appium's port(s) to the wider internet
|
||||
|
||||
But because many Appium users might not be able to guarantee such a safe environment, the Appium
|
||||
team puts many features behind a security protection mechanism, which forces system admins (the
|
||||
people who are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
|
||||
(Third-party driver and plugin authors can also [hide behaviour behind security
|
||||
flags](../developing/build-drivers.md).)
|
||||
But because not all Appium hosts can guarantee such a safe environment, certain insecure Appium
|
||||
features are disabled by default, and require explicit opt-in in order to enable them. Most
|
||||
importantly, this can _only_ be done by the Appium server _host_, and Appium _client_ sessions are
|
||||
not allowed to change this.
|
||||
|
||||
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities.
|
||||
This is the responsibility of the server admin who configures and launches the Appium server.
|
||||
While it is possible for an Appium host to simply enable all insecure features at once, each
|
||||
feature also has a unique name, which can be used for granular control over the server state.
|
||||
|
||||
## Security Server Args
|
||||
|
||||
The [Server CLI](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
|
||||
Appium, when starting it from the command line:
|
||||
Enabling or disabling insecure features is done via [Appium server launch arguments](../reference/cli/server.md)
|
||||
or [configuration file](./config.md). The former document outlines three relevant arguments for
|
||||
achieving this:
|
||||
|
||||
|<div style="width:10em">Parameter</div>|Description|
|
||||
|---------------------------------------|-----------|
|
||||
@@ -31,36 +31,28 @@ Appium, when starting it from the command line:
|
||||
|`--allow-insecure`|Turns on _only_ specified features, except those blocked by `--deny-insecure`. Has no effect when used in combination with `--relaxed-security`|
|
||||
|`--deny-insecure`|Explicitly turns _off_ specified features, overriding `--relaxed-security` and `--allow-insecure`|
|
||||
|
||||
All of the above arguments can also be specified in the [Appium Configuration file](./config.md).
|
||||
|
||||
Features passed to `--allow-insecure`/`--deny-insecure` must be specified as a comma-separated list,
|
||||
and each feature in the list must additionally include a prefix, indicating the driver to which the
|
||||
feature should apply. The prefix can be either the driver's `automationName`, or the wildcard (`*`)
|
||||
symbol, if the feature should be applied to all drivers. The prefix and feature name are separated
|
||||
using the colon character (`:`).
|
||||
and each feature in the list must additionally include a prefix, indicating the driver to whose
|
||||
sessions the feature should apply. The prefix can be either the driver's `automationName`, or the
|
||||
wildcard (`*`) symbol, if the feature should be applied to all drivers. The prefix and feature name
|
||||
are separated using the colon character (`:`).
|
||||
|
||||
For example, `first:foo` refers to the `foo` feature for the `first` driver, whereas `*:bar` refers
|
||||
to the `bar` feature for all drivers.
|
||||
|
||||
## Insecure Features
|
||||
|
||||
Each Appium driver is responsible for its own security, and can create its own feature names. Thus,
|
||||
you should read through the documentation for a particular driver to know which feature names it
|
||||
might use. Here is an incomplete list of examples from some of Appium's official drivers:
|
||||
Almost all insecure features are defined on a per-driver or plugin basis, so make sure to read the
|
||||
documentation for a particular driver/plugin to know which feature names it might use.
|
||||
|
||||
|<div style="width:12em">Feature Name</div>|Description|Supported Extension(s)|
|
||||
|------------|-----------|-------|
|
||||
|`get_server_logs`|Allows retrieving of Appium server logs via the Webdriver log interface|IOS, XCUITest, Android, UiAutomator2, Espresso|
|
||||
|`adb_shell`|Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command|Android, UiAutomator2, Espresso|
|
||||
|`record_audio`|Allow recording of host machine audio inputs|XCUITest|
|
||||
|`execute_driver_script`| Allows sending a request that has multiple Appium commands.|Execute Driver Plugin|
|
||||
Certain insecure features are also defined on the Appium server itself. For a list of these
|
||||
features, as well as the features defined in official plugins, see
|
||||
[the Insecure Features CLI Reference](../reference/cli/insecure-features.md) doc.
|
||||
|
||||
Some insecure features operate on the server level and do not require a driver session. Enabling
|
||||
these features require using the wildcard prefix:
|
||||
!!! note
|
||||
|
||||
|<div style="width:12em">Feature Name</div>|Description|
|
||||
|------------|-----------|
|
||||
|`session_discovery`|Allows retrieving the list of active server sessions via `GET /appium/sessions`|
|
||||
If you are a driver or plugin author and want to implement insecure features of your own, check
|
||||
out the [Building Drivers documentation](../developing/build-drivers.md#understand-server-assigned-driver-properties-and-security-flags).
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -106,6 +106,48 @@ Retrieves the [execute methods](../../guides/execute-methods.md) supported in th
|
||||
origin (driver-specific or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)
|
||||
for a detailed structure of this object.
|
||||
|
||||
### getCurrentAppiumContext
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/context
|
||||
```
|
||||
|
||||
Retrieves the active application context.
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - the name of the active context
|
||||
|
||||
### setAppiumContext
|
||||
|
||||
```
|
||||
POST /session/:sessionId/appium/context
|
||||
```
|
||||
|
||||
Sets an application context as the active context.
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
|--|--|--|
|
||||
|`name`|Name of the context to set as the active one|string|
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
### getAppiumContexts
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/contexts
|
||||
```
|
||||
|
||||
Retrieves all available application contexts.
|
||||
|
||||
#### Response
|
||||
|
||||
`string[]` - the names of available contexts
|
||||
|
||||
### getLogEvents
|
||||
|
||||
```
|
||||
@@ -392,3 +434,71 @@ Retrieves data from a directory on the device under test.
|
||||
#### Response
|
||||
|
||||
`string` - the Base64-encoded zip file of the directory contents
|
||||
|
||||
### getAppiumRotation
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/device/rotation
|
||||
```
|
||||
|
||||
Retrieves the current spatial orientation of the device under test.
|
||||
|
||||
#### Response
|
||||
|
||||
`Rotation` - an object with the following properties:
|
||||
|
||||
|Name|Description|Type|
|
||||
|--|--|--|
|
||||
|`x`|Degrees by which the device is rotated on its X axis|number|
|
||||
|`y`|Degrees by which the device is rotated on its Y axis|number|
|
||||
|`z`|Degrees by which the device is rotated on its Z axis|number|
|
||||
|
||||
### setAppiumRotation
|
||||
|
||||
```
|
||||
POST /session/:sessionId/appium/device/rotation
|
||||
```
|
||||
|
||||
Sets the spatial orientation of the device under test.
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
|--|--|--|
|
||||
|`x`|Degrees by which the device is rotated on its X axis|number|
|
||||
|`y`|Degrees by which the device is rotated on its Y axis|number|
|
||||
|`z`|Degrees by which the device is rotated on its Z axis|number|
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
### getAppiumOrientation
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/device/orientation
|
||||
```
|
||||
|
||||
Retrieves the current orientation of the device under test.
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - either `PORTRAIT` or `LANDSCAPE`
|
||||
|
||||
### setAppiumOrientation
|
||||
|
||||
```
|
||||
POST /session/:sessionId/appium/device/orientation
|
||||
```
|
||||
|
||||
Sets the orientation of the device under test.
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
|--|--|--|
|
||||
|`orientation`|New device orientation. Supported values are `PORTRAIT` or `LANDSCAPE`.|string|
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
@@ -139,6 +139,10 @@ GET /session/:sessionId/orientation
|
||||
|
||||
Retrieves the current orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getAppiumOrientation`](./appium.md#getappiumorientation) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - either `PORTRAIT` or `LANDSCAPE`
|
||||
@@ -153,6 +157,10 @@ POST /session/:sessionId/orientation
|
||||
|
||||
Sets the orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`setAppiumOrientation`](./appium.md#setappiumorientation) instead
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
|
||||
@@ -20,6 +20,10 @@ GET /session/:sessionId/rotation
|
||||
|
||||
Retrieves the current spatial orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getAppiumRotation`](./appium.md#getappiumrotation) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`Rotation` - an object with the following properties:
|
||||
@@ -40,6 +44,10 @@ POST /session/:sessionId/rotation
|
||||
|
||||
Sets the spatial orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`setAppiumRotation`](./appium.md#setappiumrotation) instead
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
@@ -62,6 +70,10 @@ GET /session/:sessionId/context
|
||||
|
||||
Retrieves the active application context.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getCurrentAppiumContext`](./appium.md#getcurrentappiumcontext) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - the name of the active context
|
||||
@@ -76,6 +88,10 @@ POST /session/:sessionId/context
|
||||
|
||||
Sets an application context as the active context.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`setAppiumContext`](./appium.md#setappiumcontext) instead
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
@@ -96,6 +112,10 @@ GET /session/:sessionId/contexts
|
||||
|
||||
Retrieves all available application contexts.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getAppiumContexts`](./appium.md#getappiumcontexts) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`string[]` - the names of available contexts
|
||||
|
||||
@@ -396,6 +396,45 @@ Deletes the virtual sensor with the type identified by `:sensorType`.
|
||||
|
||||
`null`
|
||||
|
||||
## Global Privacy Control Protocol
|
||||
|
||||
The [Global Privacy Control protocol](https://www.w3.org/TR/gpc) (GPC) is an extension of the W3C
|
||||
WebDriver protocol.
|
||||
|
||||
### setGlobalPrivacyControl
|
||||
|
||||
```
|
||||
POST /session/:sessionId/privacy
|
||||
```
|
||||
|
||||
> GPC documentation: [Set Global Privacy Control](https://www.w3.org/TR/gpc/#set-global-privacy-control)
|
||||
|
||||
Sets the value of the do-not-sell-or-share preference for the current session.
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
|--|--|--|
|
||||
|`gpc`|Whether the browser should perform do-not-sell-or-share interactions|boolean|
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
### getGlobalPrivacyControl
|
||||
|
||||
```
|
||||
GET /session/:sessionId/privacy
|
||||
```
|
||||
|
||||
> GPC documentation: [Get Global Privacy Control](https://www.w3.org/TR/gpc/#get-global-privacy-control)
|
||||
|
||||
Retrieves the value of the do-not-sell-or-share preference for the current session.
|
||||
|
||||
#### Response
|
||||
|
||||
`boolean` - the preference value
|
||||
|
||||
## Permissions Protocol
|
||||
|
||||
The [Permissions protocol](https://www.w3.org/TR/permissions/) is an extension of the W3C WebDriver
|
||||
@@ -523,6 +562,32 @@ Retrieves the available log types that can be used to call the [`getLog`](#getlo
|
||||
|
||||
`string[]` - an array of log types
|
||||
|
||||
## Storage Access Protocol
|
||||
|
||||
The [Storage Access protocol](https://privacycg.github.io/storage-access/) is an extension of the
|
||||
W3C WebDriver protocol.
|
||||
|
||||
### setStorageAccess
|
||||
|
||||
```
|
||||
POST /session/:sessionId/storageaccess
|
||||
```
|
||||
|
||||
> Storage Access documentation: [Set Storage Access](https://privacycg.github.io/storage-access/#set-storage-access-command)
|
||||
|
||||
Sets the storage access policy of the current browsing context.
|
||||
|
||||
#### Parameters
|
||||
|
||||
|Name|Description|Type|
|
||||
|--|--|--|
|
||||
|`blocked`|Whether storage access should be blocked (`true`) or allowed (`false`)|boolean|
|
||||
|`origin`|The origin to which the policy should be applied. Must be either a valid URL, or an asterisk (`*`) if the policy should apply to all origins.|string|
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
## Web Authentication Protocol
|
||||
|
||||
The [Web Authentication protocol](https://w3c.github.io/webauthn/) (WebAuthn) is an extension of
|
||||
|
||||
@@ -169,10 +169,17 @@ Modifies the [`createSession`](./webdriver.md#createsession) endpoint:
|
||||
All endpoints for this plugin can be invoked without creating a session, allowing you to prepare
|
||||
your test environment in advance.
|
||||
|
||||
!!! info
|
||||
|
||||
Prior to plugin version 1.2.0, all endpoints below were mounted under the `/storage` prefix
|
||||
(e.g. `/storage/add`) instead of `/appium/storage`. The `/storage`-prefixed routes are still
|
||||
available for backward compatibility, but are deprecated and will be removed in a future
|
||||
version of the plugin.
|
||||
|
||||
### addStorageItem
|
||||
|
||||
```
|
||||
POST /storage/add
|
||||
POST /appium/storage/add
|
||||
```
|
||||
|
||||
Adds a new file to the storage.
|
||||
@@ -198,8 +205,8 @@ Example:
|
||||
```json
|
||||
{
|
||||
"ws": {
|
||||
"stream": "/storage/add/ccc963411b2621335657963322890305ebe96186/stream",
|
||||
"events": "/storage/add/ccc963411b2621335657963322890305ebe96186/events"
|
||||
"stream": "/appium/storage/add/ccc963411b2621335657963322890305ebe96186/stream",
|
||||
"events": "/appium/storage/add/ccc963411b2621335657963322890305ebe96186/events"
|
||||
},
|
||||
"ttlMs": 300000
|
||||
}
|
||||
@@ -208,7 +215,7 @@ Example:
|
||||
### deleteStorageItem
|
||||
|
||||
```
|
||||
POST /storage/delete
|
||||
POST /appium/storage/delete
|
||||
```
|
||||
|
||||
Deletes a file in the storage.
|
||||
@@ -222,12 +229,12 @@ Deletes a file in the storage.
|
||||
#### Response
|
||||
|
||||
`boolean` - `true` upon successful file deletion, or `false` if the file does not exist in
|
||||
the storage
|
||||
the storage, or if the delete request is invalid.
|
||||
|
||||
### listStorageItems
|
||||
|
||||
```
|
||||
GET /storage/list
|
||||
GET /appium/storage/list
|
||||
```
|
||||
|
||||
List all files present in the storage.
|
||||
@@ -245,7 +252,7 @@ List all files present in the storage.
|
||||
### resetStorage
|
||||
|
||||
```
|
||||
POST /storage/reset
|
||||
POST /appium/storage/reset
|
||||
```
|
||||
|
||||
Deletes all uploaded files and stops any incomplete uploads.
|
||||
|
||||
@@ -158,13 +158,13 @@ extensions include scripts.
|
||||
#### Usage
|
||||
|
||||
```
|
||||
appium {driver|plugin} run <extension-name> <script-name> [script-args]
|
||||
appium {driver|plugin} run <extension-name> [<script-name> [<script-args>]]
|
||||
```
|
||||
|
||||
|Argument|Description|
|
||||
|--|--|
|
||||
|`extension-name`|The short name of the installed extension|
|
||||
|`script-name`|The name of the script to be run|
|
||||
|`script-name`|The name of the script to run. If not provided, a list of available scripts is returned.|
|
||||
|`script-args`|Any additional arguments passed to the script|
|
||||
|
||||
#### Options
|
||||
@@ -181,6 +181,12 @@ appium {driver|plugin} run <extension-name> <script-name> [script-args]
|
||||
appium driver run uiautomator2 reset
|
||||
```
|
||||
|
||||
- List all available scripts included in the XCUITest driver:
|
||||
|
||||
```
|
||||
appium driver run xcuitest
|
||||
```
|
||||
|
||||
## `update`
|
||||
|
||||
Updates one or more extensions. Only supported for extensions installed via `npm`. By default,
|
||||
|
||||
@@ -31,5 +31,6 @@ The executable has four main subcommands: `server`, `driver`, `plugin`, and `set
|
||||
|
||||
</div>
|
||||
|
||||
Appium also recognizes several [environment variables](./env-vars.md), which may be used for
|
||||
advanced configuration.
|
||||
The Appium server also recognizes several [environment variables](./env-vars.md) and
|
||||
[insecure feature names](./insecure-features.md), though drivers and plugins can also define
|
||||
variables and features of their own.
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Insecure Features
|
||||
---
|
||||
|
||||
The Appium server implements [a security protection mechanism](../../guides/security.md) that
|
||||
allows the management of various insecure features.
|
||||
|
||||
The following features are defined on the server level and can be used even without drivers, but
|
||||
they can only be enabled using the wildcard (`*`) prefix:
|
||||
|
||||
| Feature Name | Description |
|
||||
|-------------------|-------------------------------------------------------------------------------|
|
||||
|`session_discovery`|Allows retrieving the list of active server sessions via `GET /appium/sessions`|
|
||||
|
||||
|
||||
Of course, Appium drivers and plugins are free to define additional insecure features of their own.
|
||||
The following features are defined by official plugins:
|
||||
|
||||
| Feature Name | Plugin | Description |
|
||||
|-----------------------|----------------|----------------------------------------------------------|
|
||||
|`execute_driver_script`|`execute_driver`|Allows sending a request that has multiple Appium commands|
|
||||
@@ -29,6 +29,7 @@ appium
|
||||
|`--address`, `-a`|IPv4/IPv6 address to listen on|string|`0.0.0.0`|
|
||||
|`--allow-cors`|Allow web browser connections from any host|boolean|`false`|
|
||||
|`--allow-insecure`|List of [insecure features](../../guides/security.md) that should be allowed in this server's sessions. Individual features can be overridden by `--deny-insecure`. Has no effect in combination with `--relaxed-security`.|array<string>|`[]`|
|
||||
|`--allow-unknown-args`|Do not exit if unrecognized command-line arguments are passed to the server; ignore them instead. Useful when the Appium CLI is wrapped by external tooling that appends extra flags.|boolean|`false`|
|
||||
|`--base-path`, `-pa`|Base path to use as the prefix for all webdriver routes running on the server|string|`""`|
|
||||
|`--callback-address`, `-ca`|Callback IP address|string|`0.0.0.0`|
|
||||
|`--callback-port`, `-cp`|Callback port|integer|`4723`|
|
||||
@@ -48,6 +49,8 @@ appium
|
||||
|`--log-no-colors`|Disable colors in the server log|boolean|`false`|
|
||||
|`--log-timestamp`|Show timestamps in the server log|boolean|`false`|
|
||||
|`--long-stacktrace`|Add long stack traces to log entries. Recommended for debugging only.|boolean|`false`|
|
||||
|`--max-ipc-data-size`|Maximum byte size of IPC message objects.|integer|`1048576` (1MB)|
|
||||
|`--max-ipc-topics`|Maximum number of IPC topics per session.|integer|`1000`|
|
||||
|`--no-perms-check`|Skip various permission checks on the server startup|boolean|`false`|
|
||||
|`--nodeconfig`|JSON configuration for registering Appium as a node with Selenium Grid 3|object||
|
||||
|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object||
|
||||
@@ -62,7 +65,7 @@ appium
|
||||
|`--tmp`|Absolute path to the directory used for temporary files|string|[`os.tmpdir()`](https://nodejs.org/api/os.html#ostmpdir)|
|
||||
|`--use-drivers`|List of drivers to activate. By default, all installed drivers are activated.|array<string>|`[]`|
|
||||
|`--use-plugins`|List of plugins to activate. By default, no plugins are activated. Set to `["all"]` to activate all installed plugins.|array<string>|`[]`|
|
||||
|`--webhook`, `-G`|URL for an HTTP listener where the server logs should be output. This does not affect output on the console.|string||
|
||||
|`--webhook`, `-G`|URL for an HTTP listener where the server logs should be output. This does not affect output on the console. A bare `host:port` is also accepted, which posts the logs to the root path over plain http; a value having neither a scheme nor a port falls back to `127.0.0.1:9003`.|string||
|
||||
|
||||
### Info Options
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ hide:
|
||||
title: Reference
|
||||
---
|
||||
|
||||
This section of the Appium documentation provides a reference to the two main interfaces within the
|
||||
Appium server: the command-line executable, and the supported API endpoints.
|
||||
This section of the Appium documentation provides a reference to the core interfaces supported within the
|
||||
Appium server:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
@@ -16,10 +16,16 @@ Appium server: the command-line executable, and the supported API endpoints.
|
||||
|
||||
Learn how to use the Appium command-line executable
|
||||
|
||||
- :material-lan-connect: [__Session Properties__](./session/index.md)
|
||||
|
||||
---
|
||||
|
||||
See the values of global Appium session properties
|
||||
|
||||
- :material-cloud-braces: [__API Endpoints__](./api/index.md)
|
||||
|
||||
---
|
||||
|
||||
View endpoints supported by the Appium server
|
||||
View endpoints supported by the core Appium server
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Capabilities
|
||||
---
|
||||
|
||||
The following [capabilities](../../guides/caps.md) are recognized by the Appium server/base driver,
|
||||
and are therefore supported by all drivers as well. Some capabilities are directly handled by the
|
||||
server/base driver, while others are only validated before being passed to the actual driver.
|
||||
|
||||
!!! note
|
||||
|
||||
Capabilities not listed here will _not_ be rejected by Appium: they will simply be forwarded
|
||||
directly to the active driver/plugin.
|
||||
|
||||
### Required Capabilities
|
||||
|
||||
These capabilities are used in the Appium server/base driver, and are explicitly required in all
|
||||
Appium sessions.
|
||||
|
||||
| Capability | Description | Type |
|
||||
|-------------------------|---------------------------------------------|-----------|
|
||||
| `platformName` | Type of platform hosting the app or browser | `string` |
|
||||
| `appium:automationName` | Name of the Appium driver to use | `string` |
|
||||
|
||||
### Optional Capabilities
|
||||
|
||||
These capabilities are used in the Appium server/base driver, but are optional, and may have a
|
||||
default value.
|
||||
|
||||
| <div style="width:19em">Capability</div> | Description | Type | Default |
|
||||
|--|--|--|--|
|
||||
| `webSocketUrl` | Toggle support of the WebDriver BiDi protocol | `boolean` ||
|
||||
| `appium:eventTimings` (deprecated) | Toggle collection of [Event Timings](../../guides/event-timing.md). This capability is deprecated - please use the [`getLogEvents`](../api/appium.md#getlogevents) endpoint instead. | `boolean` ||
|
||||
| `appium:newCommandTimeout` | Number of seconds the Appium server should wait for clients to send commands before stopping the session. A value of `0` disables the timeout. | `number` | `60` |
|
||||
| `appium:printPageSourceOnFindFailure` | Toggle retrieval of the the page source and its printing to the Appium log, whenever a request to find an element fails | `boolean` ||
|
||||
|
||||
### Validated Capabilities
|
||||
|
||||
These capabilities are not directly used in the Appium server/base driver, but are still subject to
|
||||
validation checks due to their relevance in other drivers. The actual handling of these
|
||||
capabilities is optional and entirely driver-dependent.
|
||||
|
||||
| Capability | Validation |
|
||||
|-----------------------------------|---------------------------------------------------------------|
|
||||
| `platformVersion` | Must be `string` |
|
||||
| `appium:app` | Must be `string`; empty values are ignored |
|
||||
| `appium:autoLaunch` (deprecated) | Must be `boolean` |
|
||||
| `appium:autoWebview` | Must be `boolean` |
|
||||
| `appium:fullReset` | Must be `boolean`; mutually exclusive with `appium:noReset` |
|
||||
| `appium:language` | Must be `string` |
|
||||
| `appium:locale` | Must be `string` |
|
||||
| `appium:orientation` | Must be either `LANDSCAPE` or `PORTRAIT` |
|
||||
| `appium:noReset` | Must be `boolean`; mutually exclusive with `appium:fullReset` |
|
||||
| `appium:udid` | Must be `string` |
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Session Properties
|
||||
---
|
||||
|
||||
An Appium session has several key properties, each with its own set of supported values:
|
||||
capabilities, execute methods, settings, locator strategies, and others. The supported values for
|
||||
each property are primarily defined by the active driver and plugins, but some properties also have
|
||||
common values provided by the Appium server and its base driver:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [__Capabilities__](./caps.md)
|
||||
|
||||
A small set of basic capabilities
|
||||
|
||||
- [__Command Endpoints__](../api/index.md)
|
||||
|
||||
The core set of API endpoints
|
||||
|
||||
</div>
|
||||
@@ -8,11 +8,6 @@ title: Additional Resources
|
||||
|
||||
Here you can find links to additional Appium resources around the web:
|
||||
|
||||
## Websites
|
||||
|
||||
- [Appium Pro](https://appiumpro.com) - a blog and newsletter written by one of Appium's
|
||||
maintainers, Jonathan Lipps, with lots of useful guides
|
||||
|
||||
## Online Courses
|
||||
|
||||
- [Appium and Selenium Fundamentals](https://ui.headspin.io/university/learn/appium-selenium-fundamentals-2020) - a comprehensive video course on learning Python, Selenium, and Appium by Jonathan Lipps
|
||||
@@ -26,3 +21,4 @@ maintainers, Jonathan Lipps, with lots of useful guides
|
||||
- [AppiumConf 2021](https://www.youtube.com/playlist?list=PL9Z-JgiTsOYRCcJhDfmKAah9XmAp2b903)
|
||||
- [AppiumConf 2024](https://www.youtube.com/playlist?list=PL9Z-JgiTsOYQaU5i5LJtAWlh5WVZPi3If)
|
||||
- [SeleniumConf & AppiumConf 2025](https://www.youtube.com/playlist?list=PLRdSclUtJDYV2R92TLbmwxws6clruuTjH)
|
||||
- [SeleniumConf & AppiumConf 2026](https://www.youtube.com/playlist?list=PLRdSclUtJDYVgVqdKnSyBLBmFdA0KE_Dk)
|
||||
|
||||
@@ -8,11 +8,13 @@ date: 2025-11-25
|
||||
# Announcing LambdaTest as Appium's Newest Development Partner
|
||||
|
||||
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
|
||||
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
|
||||
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
|
||||
|
||||
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
|
||||
|
||||
<div style="text-align:center;width:100%"><a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
|
||||
@@ -20,15 +22,19 @@ This kind of hands-on contribution is crucial for ensuring Appium continues to e
|
||||
</div>
|
||||
|
||||
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
|
||||
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
|
||||
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
|
||||
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
|
||||
|
||||
- [`appium-mcp`](https://github.com/appium/appium-mcp) – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
|
||||
- [`appium-ios-remotexpc`](https://github.com/appium/appium-ios-remotexpc) – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
|
||||
- [`appium-ios-tuntap`](https://github.com/appium/appium-ios-tuntap) – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
|
||||
|
||||
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
|
||||
About LambdaTest
|
||||
|
||||
**About LambdaTest**
|
||||
|
||||
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
|
||||
|
||||
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
|
||||
|
||||
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
|
||||
|
||||
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
|
||||
|
||||
@@ -222,17 +222,24 @@ So you'll probably end up overriding `createSession`. You can do so by defining
|
||||
driver:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) {
|
||||
const [sessionId, caps] = super.createSession(w3cCaps);
|
||||
async createSession(w3cCaps) {
|
||||
const [sessionId, caps] = await super.createSession(w3cCaps);
|
||||
// do your own stuff here
|
||||
return [sessionId, caps];
|
||||
}
|
||||
```
|
||||
|
||||
For legacy reasons, your function will receive old-style JSON Wire Protocol desired and required
|
||||
caps as the first two arguments. Given that the old protocol isn't supported anymore and clients
|
||||
have all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion
|
||||
about what `otherDriverData` is about, see the section below on concurrent drivers).
|
||||
!!! warning "Deprecated"
|
||||
|
||||
```
|
||||
Older drivers may still define `createSession` with up to four parameters, e.g.
|
||||
`createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData)`. This shape is a holdover from the
|
||||
retired JSON Wire Protocol, which required desired and required caps as the first two
|
||||
arguments; only the first W3C-shaped argument was ever used. The `otherDriverData` parameter is
|
||||
likewise deprecated in favor of [IPC](#send-messages-to-plugins-running-on-the-same-session) for
|
||||
coordinating with other concurrently-running sessions. New drivers should use the single-argument
|
||||
form shown above.
|
||||
```
|
||||
|
||||
You'll want to make sure to call `super.createSession` in order to get the session ID as well as
|
||||
the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`
|
||||
@@ -522,14 +529,13 @@ route, then the route will not be proxied and instead will be handled by your dr
|
||||
example, we are avoiding proxying all `POST` routes that have the `appium` prefix.
|
||||
|
||||
Next, we have to set up the proxying itself. The way to do this is to use a special class from
|
||||
Appium called `JWProxy`. (The name means "JSON Wire Proxy" and is related to a legacy
|
||||
implementation of the protocol). You'll want to create a `JWProxy` object using the details required to
|
||||
connect to the remote server:
|
||||
Appium called `WebDriverProxy`. You'll want to create a `WebDriverProxy` object using the details
|
||||
required to connect to the remote server:
|
||||
|
||||
```js
|
||||
// import {JWProxy} from 'appium/driver';
|
||||
// import {WebDriverProxy} from 'appium/driver';
|
||||
|
||||
const proxy = new JWProxy({
|
||||
const proxy = new WebDriverProxy({
|
||||
server: 'remote.server',
|
||||
port: 1234,
|
||||
base: '/',
|
||||
@@ -541,8 +547,8 @@ this.proxyCommand = proxy.command.bind(proxy);
|
||||
|
||||
Here we are creating a proxy object and assigning some of its methods to `this` under the names
|
||||
`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget
|
||||
this step! The `JWProxy` has a variety of other options which you can check out in the source code,
|
||||
as well. (TODO: publish options as API docs and link here).
|
||||
this step! The `WebDriverProxy` has a variety of other options which you can check out in the
|
||||
source code as well.
|
||||
|
||||
Finally, we need a way to tell Appium when the proxy is active. For your driver it might always
|
||||
be active, or it might only be active when in a certain context. You can define the logic as an
|
||||
@@ -570,6 +576,33 @@ capability), and then to set an internal field to that value, so that it can be
|
||||
bidiProxyUrl`. Once all this is in place, Appium will proxy BiDi commands from the client straight
|
||||
to the upstream connection.
|
||||
|
||||
### Understand server-assigned driver properties and security flags
|
||||
|
||||
When your driver is running under the main Appium server, Appium assigns a small set of
|
||||
server-related properties on your driver instance when a session is created:
|
||||
|
||||
- `cliArgs`: Driver-specific configuration derived from the Appium server’s CLI flags and/or
|
||||
configuration files (for example via the `server.driver.<your-driver-name>` section). These
|
||||
options are **not** user capabilities and cannot be influenced directly by test code.
|
||||
- `server`, `serverHost`, `serverPort`, `serverPath`: Information about the HTTP server that is
|
||||
hosting your driver. These values reflect how the Appium server was started (for example the
|
||||
`--address`, `--port`, and `--base-path` flags) and are useful when your driver needs to construct
|
||||
URLs that point back to the Appium server itself (for example when setting up proxies, webhooks,
|
||||
or other callbacks).
|
||||
|
||||
`BaseDriver` and `AppiumDriver` also cooperate to expose security-related flags on your driver
|
||||
instance:
|
||||
|
||||
- `relaxedSecurityEnabled`: Indicates whether the server is running with relaxed security enabled
|
||||
(for example via `--relaxed-security`).
|
||||
- `allowInsecure`: A list of insecure features which are explicitly allowed for this driver (derived
|
||||
from server-level options like `--allow-insecure`).
|
||||
- `denyInsecure`: A list of insecure features which are explicitly disabled for this driver (derived
|
||||
from server-level options like `--deny-insecure`).
|
||||
|
||||
See [Hide behaviour behind security flags](#hide-behaviour-behind-security-flags) for how to use
|
||||
these flags in your driver (e.g. via `isFeatureEnabled` and `assertFeatureEnabled`).
|
||||
|
||||
### Extend the existing protocol with new commands
|
||||
|
||||
You may find that the existing commands don't cut it for your driver. If you want to expose
|
||||
@@ -579,7 +612,7 @@ three ways:
|
||||
1. Extending the classic WebDriver protocol and creating client-side plugins to access the extensions via the classic HTTP interface
|
||||
2. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface
|
||||
3. Overloading the Execute Script command by defining Execute
|
||||
Methods
|
||||
Methods
|
||||
|
||||
If you want to follow the first path, you can direct Appium to recognize new methods and add them
|
||||
to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`
|
||||
@@ -685,17 +718,17 @@ async execute(script, args) {
|
||||
A couple notes about this system:
|
||||
|
||||
1. The arguments array sent via the call to Execute Script must contain only zero or one element(s). The
|
||||
first item in the list is considered to be the parameters object for your method. These parameters
|
||||
will be parsed, validated, and then applied to your overload method in the order specified in
|
||||
`executeMethodMap` (the order specified in the `required` parameters list, followed by the
|
||||
`optional` parameters list). I.e., this framework assumes only a single actual argument sent in via
|
||||
Execute Script (and this argument should be an object with keys/values representing the
|
||||
parameters your execute method expects).
|
||||
first item in the list is considered to be the parameters object for your method. These parameters
|
||||
will be parsed, validated, and then applied to your overload method in the order specified in
|
||||
`executeMethodMap` (the order specified in the `required` parameters list, followed by the
|
||||
`optional` parameters list). I.e., this framework assumes only a single actual argument sent in via
|
||||
Execute Script (and this argument should be an object with keys/values representing the
|
||||
parameters your execute method expects).
|
||||
2. Appium does not automatically implement `execute` (the Execute Script handler) for you. You may
|
||||
wish, for example, to only call the `executeMethod` helper function when you're not in proxy
|
||||
mode!
|
||||
wish, for example, to only call the `executeMethod` helper function when you're not in proxy
|
||||
mode!
|
||||
3. The `executeMethod` helper will reject with an error if a script name doesn't match one of the
|
||||
script names defined as a command in `executeMethodMap`, or if there are missing parameters.
|
||||
script names defined as a command in `executeMethodMap`, or if there are missing parameters.
|
||||
|
||||
One of the nice things about the Execute Method strategy is that methods implemented in this way
|
||||
will be available via the classic or BiDi interfaces (since they will result in the same Appium
|
||||
@@ -770,7 +803,15 @@ that multiple simultaneous sessions don't use the same resources:
|
||||
1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc)
|
||||
2. Just always use free resources (find a new random port for each session)
|
||||
3. Have each driver express what resources it is using, then examine currently-used resources from
|
||||
other drivers when a new session begins.
|
||||
other drivers when a new session begins.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
```
|
||||
The `driverData`-based mechanism described below is deprecated. Prefer
|
||||
[IPC](#send-messages-to-plugins-running-on-the-same-session) for coordinating resources across
|
||||
concurrently-running sessions instead.
|
||||
```
|
||||
|
||||
To support this third strategy, you can implement `get driverData` in your driver to return what
|
||||
sorts of resources your driver is currently using, for example:
|
||||
@@ -783,7 +824,7 @@ get driverData() {
|
||||
|
||||
Now, when a new session is started on your driver, the `driverData` response from any other
|
||||
simultaneously running drivers (of the same type) will also be included, as the last parameter of
|
||||
the `createSession` method:
|
||||
the deprecated, multi-argument form of the `createSession` method:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, driverData)
|
||||
@@ -864,3 +905,120 @@ this.onUnexpectedShutdown(handler)
|
||||
|
||||
`handler` should be a function which receives an error object (representing the reason for the
|
||||
unexpected shutdown).
|
||||
|
||||
### Send messages to plugins running on the same session
|
||||
|
||||
Appium's driver and plugin architecture means that a single driver and any number of plugins can be
|
||||
running together for a current session. The driver and plugins don't really know anything about
|
||||
each other though, which can make coordination potentially difficult. Without creating any kind of
|
||||
tight coupling between drivers or plugins, it's possible for drivers and plugins to communicate
|
||||
along a pub/sub style message bus. With Appium's IPC feature, "message" means a combination of
|
||||
"data" (the data intended to be published or received), and metadata (timestamp, the name of the
|
||||
publisher, etc...).
|
||||
|
||||
Drivers and plugins can implement an instance method called `async onIpcInit`, in which they will
|
||||
know that the IPC channel for the session is now active. At this point, they have access to the
|
||||
following methods:
|
||||
|
||||
#### `ipcSubscribe<T>(topic: string): IIpcSubscription`
|
||||
|
||||
This method allows a driver or plugin to subscribe to a topic on the IPC channel for the session.
|
||||
Topics are simply strings. To coordinate effectively, drivers or plugins would use the same topic
|
||||
string (so this would be something advertised in the driver/plugin documentation).
|
||||
|
||||
The result of this call is an `IpcSubscription` object that allows:
|
||||
|
||||
- Looping through messages on the topic via an async generator
|
||||
- Hooking up an event handler for new messages
|
||||
- Getting the last message sent on the topic
|
||||
- Publishing a message to the topic
|
||||
- Unsubscribing from the topic
|
||||
|
||||
#### `IpcSubscription` object
|
||||
|
||||
Here is an example of how subscribing and use of these subscription methods might work:
|
||||
|
||||
```ts
|
||||
async onIpcInit() {
|
||||
// we know at this point in our driver/plugin lifecycle that we can use IPC methods
|
||||
type MyMessageData = {myData: string}; // let's say the message data for this channel has this shape
|
||||
|
||||
const subscription = this.ipcSubscribe<MyMessageData>('coolTopic');
|
||||
|
||||
// listen for new messages on topic
|
||||
subscription.on('message', (message) => {
|
||||
console.log(message.data); // {myData: 'something'}
|
||||
});
|
||||
|
||||
// publish data to the topic; might throw if the data is larger than configured max size, or we
|
||||
// are no longer subscribed
|
||||
await subscription.publish({myData: 'hi'});
|
||||
|
||||
// get last message sent to topic
|
||||
const {data} = subscription.getMessage() ?? {data: null};
|
||||
// data = {myData: 'hi'}
|
||||
|
||||
// unsubscribe
|
||||
subscription.unsubscribe(); // returns true if we unsubscribed and false if no subscription existed
|
||||
}
|
||||
```
|
||||
|
||||
With a subscription object, we can also iterate async over it to receive new messages:
|
||||
|
||||
```ts
|
||||
for await (const message of subscription) {
|
||||
// here we have a message and can unwrap its data
|
||||
}
|
||||
```
|
||||
|
||||
Note that the iteration will stop when the subscription ends (i.e., when `unsubscribe` is called).
|
||||
|
||||
You can also check whether the subscription is still active (if your subscribe and unsubscribe
|
||||
logic is not locally connected):
|
||||
|
||||
```ts
|
||||
if (subscription.isActive) {
|
||||
// we know we have not yet unsubscribed
|
||||
}
|
||||
```
|
||||
|
||||
If the subscription is not active, attempts to call `subscription.publish` will throw an error.
|
||||
|
||||
#### `IpcMessage` object
|
||||
|
||||
When you get a message on a topic, it has the following shape:
|
||||
|
||||
```ts
|
||||
export type IpcMessage<T> = {
|
||||
publisher: string, // the id of the publishing object (typically of the form <ClassName>@<uniqueObjectId>)
|
||||
timestampMs: number, // when the message was published, in ms since epoch
|
||||
topic: string, // the topic the message was published on
|
||||
data: T, // the arbitrary message data. Must be serializable and a valid argument to 'structuredClone()'
|
||||
};
|
||||
```
|
||||
|
||||
#### IPC Notes
|
||||
|
||||
There are some important things to keep in mind when using Appium's IPC feature:
|
||||
|
||||
- IPC is only available once `onIpcInit` has been called, at the end of the `createSession` flow.
|
||||
It cannot be used statically or in `createSession` hooks
|
||||
- In sum, IPC is only for use during a session (this is also to prevent drivers/plugins from
|
||||
accessing or reading data sent on IPC channels in other sessions.)
|
||||
- The default max size of an IPC message is 1MB. This can be configured by the server-admin by
|
||||
using the `--max-ipc-data-size` arg (value is a number in bytes).
|
||||
- If a message exceeds the configured size, any call to `publish` methods will throw, so be
|
||||
sure to cover this case in your error handling.
|
||||
- The default max number of IPC topics per session is 1000. This can be configured by the
|
||||
server-admin using the `--max-ipc-topics` arg.
|
||||
- If the topic limit is reached, calls to `subscribe` or `publish` on a new topic will throw, so
|
||||
be sure to cover this case in your error handling.
|
||||
- Topic names exist within a global namespace per session. So if you don't want to clash with other
|
||||
drivers or plugins, make sure you prefix your topic names with something unique, akin to vendor
|
||||
prefixes in the WebDriver standard (for example: `fake-driver:some-topic`). We recommend the
|
||||
format `<namespace>:<topic>`.
|
||||
|
||||
To see examples of IPC in action, check out Appium's own
|
||||
[FakeDriver](https://github.com/appium/appium/blob/master/packages/fake-driver/lib/driver.ts) and
|
||||
[FakePlugin](https://github.com/appium/appium/blob/master/packages/fake-plugin/lib/plugin.ts)
|
||||
extensions, which showcase several ways of using IPC messages.
|
||||
|
||||
@@ -236,13 +236,13 @@ upstream server. In this case, we might run into a problem, because the plugin n
|
||||
handle that command! The way Appium handles this is as follows:
|
||||
|
||||
1. When a command comes in, before deciding whether to proxy the command, the main protocol handler
|
||||
checks to see whether a plugin would handle the command.
|
||||
checks to see whether a plugin would handle the command.
|
||||
2. If a plugin would _not_ handle the command--all proceeds as normal, and the request is either
|
||||
proxied or not, based on the driver's proxy mode.
|
||||
proxied or not, based on the driver's proxy mode.
|
||||
3. If a plugin _would_ handle the command, then the proxy behavior is skipped for the time being,
|
||||
and wrapped up as the `next` function sent to the plugin. So if you have a command handler in
|
||||
your plugin, and you want to be sure that the default driver proxying _does_ take place, then
|
||||
simply `await next()` instead of (or in addition to) whatever your plugin handler is doing.
|
||||
and wrapped up as the `next` function sent to the plugin. So if you have a command handler in
|
||||
your plugin, and you want to be sure that the default driver proxying _does_ take place, then
|
||||
simply `await next()` instead of (or in addition to) whatever your plugin handler is doing.
|
||||
|
||||
### Throw WebDriver-specific errors
|
||||
|
||||
@@ -331,7 +331,7 @@ drivers, you can create new commands in one of two ways, just as is possible for
|
||||
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
|
||||
2. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface
|
||||
3. Overloading the Execute Script command by defining Execute
|
||||
Methods
|
||||
Methods
|
||||
|
||||
#### Extending the HTTP Protocol
|
||||
|
||||
@@ -458,10 +458,10 @@ inside the plugin class:
|
||||
|
||||
1. The `executeMethodMap`, defined in just the same way as for drivers
|
||||
2. The implementation of the command method as defined in `executeMethodMap` (in this case,
|
||||
`plugMeIn`)
|
||||
`plugMeIn`)
|
||||
3. The overriding/handling of the `execute` command. Just like any plugin command handlers, the
|
||||
first two arguments are `next` and `driver`, followed by the script name and args. `BasePlugin`
|
||||
implements a helper method which we can simply call with all of these arguments.
|
||||
first two arguments are `next` and `driver`, followed by the script name and args. `BasePlugin`
|
||||
implements a helper method which we can simply call with all of these arguments.
|
||||
|
||||
Overriding Execute Methods from drivers works as you'd expect: if your plugin defines an Execute
|
||||
Method with the same name as that of a driver, your command (in this case `plugMeIn`) will be
|
||||
@@ -483,9 +483,9 @@ capability.
|
||||
You probably don't normally need to update the Appium server object (which is an
|
||||
[Express](https://expressjs.com/) server having already been
|
||||
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)
|
||||
in a variety of ways). But, for example, you could add new Express middleware to the server to
|
||||
support your plugin's requirements. To update the server you must implement the `static async
|
||||
updateServer` method in your class. This method takes three parameters:
|
||||
in a variety of ways). But, for example, you could add new routes to the server to support your
|
||||
plugin's requirements. To update the server you must implement the `static async updateServer`
|
||||
method in your class. This method takes three parameters:
|
||||
|
||||
- `expressApp`: the Express app object
|
||||
- `httpServer`: the Node HTTP server object
|
||||
@@ -498,6 +498,25 @@ results you'll need to test! Warning: this should be considered an advanced feat
|
||||
knowledge of Express, as well as the care not to do anything that could affect the operation of
|
||||
other parts of the Appium server!
|
||||
|
||||
`updateServer` runs _after_ Appium's own routes are registered, so `expressApp.use(...)` here
|
||||
won't see requests to paths Appium already owns — Express matches middleware and routes in
|
||||
registration order. For middleware that must see requests to those routes too (e.g. logging or
|
||||
auth), use `httpServer.frontRouter` instead: Appium mounts this
|
||||
[Router](https://expressjs.com/en/5x/api/router/) before any route is registered, so anything
|
||||
attached to it — even from inside `updateServer` — still runs ahead of route matching. Note this
|
||||
is still _after_ Appium's own baseline middleware (CORS, WebSocket upgrade handling, body
|
||||
parsing, etc.), so it won't see requests Appium itself has already rejected, e.g. a CORS
|
||||
preflight failure or a body that failed to parse:
|
||||
|
||||
```js
|
||||
static async updateServer(expressApp, httpServer, cliArgs) {
|
||||
httpServer.frontRouter.use((req, res, next) => {
|
||||
console.log(`Incoming request: ${req.method} ${req.url}`);
|
||||
next();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Handle unexpected session shutdown
|
||||
|
||||
When developing a plugin you may want to add some cleanup logic for when a session ends. You would
|
||||
@@ -518,3 +537,12 @@ async onUnexpectedShutdown(driver, cause) {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Send messages to the driver or other plugins running on the same session
|
||||
|
||||
Even though drivers and plugins don't know anything about each other, it's possible for them to
|
||||
send messages that other drivers or plugins can listen for, within the context of the same session,
|
||||
using an IPC channel. Given that the developer instructions for this feature are the same for
|
||||
drivers and plugins, please head over to the IPC development docs for
|
||||
drivers at the driver
|
||||
development guide.
|
||||
|
||||
@@ -29,7 +29,7 @@ In lieu of a separate file, configuration can be embedded in a project's `packag
|
||||
```
|
||||
|
||||
When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`
|
||||
will call into `lib/config-file.js` to load and/or search for a configuration file and in
|
||||
will call into `lib/bootstrap/config-file.js` to load and/or search for a configuration file and in
|
||||
`package.json`.
|
||||
|
||||
!!! note
|
||||
@@ -72,7 +72,7 @@ It is more straightforward to explain how config files are validated, so we'll s
|
||||
|
||||
### Validating Config Files
|
||||
|
||||
When a config file is found (`lib/config-file.js`), it will call the `validate` function exported
|
||||
When a config file is found (`lib/bootstrap/config-file.js`), it will call the `validate` function exported
|
||||
from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to
|
||||
validate the data against the schema that Appium has provided it.
|
||||
|
||||
|
||||
@@ -56,6 +56,13 @@ automation capabilities using Appium.
|
||||
}
|
||||
```
|
||||
|
||||
### [Skills](https://github.com/appium/skills)
|
||||
|
||||
A set of AI Agent skills to support Appium automation, for example:
|
||||
|
||||
- Help preparing Appium test environment from scratch, including common driver setup
|
||||
- Help preparing XCUITest driver and WebDriverAgent for real device automation
|
||||
|
||||
## Extension Tools
|
||||
|
||||
Appium driver or plugin developers can choose to include these tools in their driver/plugin:
|
||||
@@ -83,6 +90,18 @@ out the documentation on [Building Doctor Checks](../developing/build-doctor-che
|
||||
|
||||
These tools are not maintained by the Appium team:
|
||||
|
||||
### [AppClaw](https://github.com/AppiumTestDistribution/AppClaw)
|
||||
|
||||
AppClaw is a CLI-based agentic AI layer for mobile automation, powered by [Appium MCP](#appium-mcp).
|
||||
Agent instructions can be passed directly via CLI, or defined as YAML flows in either structured
|
||||
or natural language syntax.
|
||||
|
||||
Supported by: `@AppiumTestDistribution`
|
||||
|
||||
```sh title="Install This Tool"
|
||||
npm install -g appclaw
|
||||
```
|
||||
|
||||
### [Appium Installer](https://github.com/AppiumTestDistribution/appium-installer)
|
||||
|
||||
Appium Installer is a command-line tool for simplifying setups of new Appium test environments.
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
title: Session Capabilities
|
||||
---
|
||||
|
||||
「Capabilities」は、Appiumセッションを開始するために使用されるパラメータセットに付けられた名前です。 セット内の情報は、セッションにどのような「Capabilities」を持たせたいかを表します。たとえば、特定のモバイルオペレーティングシステムや特定のデバイスバージョンなどです。 Capabilities はキーと値のペアとして表され、値には他のオブジェクトを含む任意の有効な JSON 型を使用できます。
|
||||
Capabilities are the core parameters used to start an Appium session. They describe various
|
||||
features that you want your session to have, for example, a certain mobile operating system or a
|
||||
certain version of a device. Capabilities are represented as key-value pairs, with values allowed
|
||||
to be any valid JSON type, including other objects. Most importantly, they cannot be changed
|
||||
during the lifecycle of the session.
|
||||
|
||||
W3C WebDriver 仕様の [Capabilities に関するセクション](https://w3c.github.io/webdriver/#capabilities) では、以下の機能を含む 10 個の標準機能のセットが定義されています:
|
||||
The capabilities used in Appium follow [the W3C WebDriver specification of the same name](https://w3c.github.io/webdriver/#capabilities).
|
||||
The WebDriver spec defines a small set of standard capabilities, including the following:
|
||||
|
||||
| Capability 名 | 型 | 説明 |
|
||||
| ---------------- | -------- | --------------------- |
|
||||
@@ -12,51 +17,64 @@ W3C WebDriver 仕様の [Capabilities に関するセクション](https://w3c.g
|
||||
| `browserVersion` | `string` | ブラウザのバージョン |
|
||||
| `platformName` | `string` | ブラウザをホストするプラットフォームの種類 |
|
||||
|
||||
While the above capabilities are commonly used by Appium drivers, they are not sufficient for
|
||||
describing Appium-specific features, such as the name of the driver to use, or the name of the app
|
||||
to launch. In order to achieve this, Appium defines its own [extension capabilities](https://w3c.github.io/webdriver/#dfn-extension-capability).
|
||||
|
||||
## 一般的なAppiumのCapabilities
|
||||
|
||||
Appium はこれらのブラウザに焦点を当てた capabilities を理解しますが、いくつかの capabilities も追加導入しています。 WebDriver 仕様によれば、非標準の「拡張 capabilities」には、capabilities を導入したベンダーを示す名前空間となる接頭辞(末尾に「:」)を含める必要があります。 Appium の接頭辞は「appium:」であるため、Appium 固有の capabilities には必ずこの接頭辞を含める必要があります。 使用しているクライアントによっては接頭辞が自動的に追加される場合もあれば、特定のインターフェースと組み合わせて追加される場合もありますが、明確にするために明示的に追加することをお勧めします。
|
||||
According to the WebDriver spec, extension capabilities must include a namespace prefix (signifying
|
||||
the vendor introducing the capability), and the namespace must end a colon (`:`). Appium's vendor
|
||||
prefix is `appium:`, and so any Appium-specific capabilities must include this prefix. Depending on
|
||||
your Appium client, the prefix may be added automatically or in conjunction with certain interfaces,
|
||||
but it is always a good practice to explicitly include it for clarity.
|
||||
|
||||
以下は様々なドライバーで認識される Appium の capabilities の一覧です:
|
||||
Here are a few commonly (but not universally!) used Appium-specific capabilities:
|
||||
|
||||
!!! info
|
||||
| Capability 名 | 型 | Description |
|
||||
| ----------------------- | -------- | --------------------------------------------------------------- |
|
||||
| `appium:automationName` | `string` | 使用するAppiumドライバの名前 |
|
||||
| `appium:udid` | `string` | The unique device identifier of a particular device to automate |
|
||||
| `appium:app` | `string` | インストール可能なアプリケーションへのパス |
|
||||
|
||||
```
|
||||
個々のドライバやプラグインは独自の capabilities をサポートしている場合があるため、具体的な capability 名のリストについては、それぞれのドキュメントを参照してください。また、一部のドライバはこれらの capabilities をすべてサポートしていない場合があります
|
||||
```
|
||||
All capabilities recognized by the Appium base driver (inherited by all drivers) can be found in the
|
||||
[Capabilities Reference document](../reference/session/caps.md). While this common capability set
|
||||
is fairly small, it can be greatly extended by Appium drivers and plugins, who can (and should)
|
||||
define their own capabilities. Make sure to reference their documentation to learn more about the
|
||||
capabilities they support. You can find a list of known drivers in the [Ecosystem Drivers](../ecosystem/drivers.md) document.
|
||||
|
||||
| <div style="width:12em">Capability 名</div> | 型 | 必須か | 説明 |
|
||||
| ------------------------------------------ | --------- | --- | ------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `platformName` | `string` | はい | アプリまたはブラウザをホストするプラットフォームの種類 |
|
||||
| `appium:automationName` | `string` | はい | 使用するAppiumドライバの名前 |
|
||||
| `browserName` | `string` | いいえ | ドライバーが特別なケースとしてWebブラウザーをサポートしている場合、起動して自動化するブラウザーの名前 |
|
||||
| `appium:app` | `string` | いいえ | インストール可能なアプリケーションへのパス |
|
||||
| `appium:deviceName` | `string` | いいえ | 自動化する特定のデバイスの名前、例:`iPhone 14`(現在のところ、iOS シミュレーターを指定する場合にのみ役立ちます。他の状況では通常、`appium:udid` 機能を使用して特定のデバイス Id を使用することをお勧めします)。 |
|
||||
| `appium:platformVersion` | `string` | いいえ | プラットフォームのバージョン(例:iOS の場合は `16.0`) |
|
||||
| `appium:newCommandTimeout` | `number` | いいえ | クライアントがこれ以上コマンドを送信してこないと判断しセッションを終了する前に、Appium サーバーがクライアントからのコマンド送信を待機する秒数。 デフォルトは `60` 秒。 ゼロに設定するとタイマーが無効になります。 |
|
||||
| `appium:noReset` | `boolean` | いいえ | true の場合、セッションの開始とクリーンアップ中に通常のリセット処理を回避するように Appium ドライバーに指示します (デフォルトは `false`) |
|
||||
| `appium:fullReset` | `boolean` | いいえ | true の場合、Appium ドライバーに通常のリセット処理に追加の手順を追加して、環境の再現性を最大限に高めるように指示します (デフォルトは `false`) |
|
||||
| `appium:eventTimings` | `boolean` | いいえ | true の場合、Appium ドライバーに [Event Timings](./event-timing.md) を収集するように指示します (デフォルトは `false`) |
|
||||
| `appium:printPageSourceOnFindFailure` | `boolean` | いいえ | true の場合、要素の検索リクエストが失敗するたびにページソースを収集し、Appium ログに出力します (デフォルトは `false`) |
|
||||
Drivers are also able to place more complex constraints on capabilities as a group. For example,
|
||||
the XCUITest driver recommends that at least one of `browserName`, `appium:app`, or `appium:bundleId`
|
||||
is included in the capabilities, otherwise it will not be able to auto-install or auto-launch any
|
||||
application. Each driver will document how it interprets these capabilities and any other
|
||||
platform-specific requirements.
|
||||
|
||||
ドライバーの中には、capabilitiesのより複雑な制約をグループとして設定しているものもあります。 たとえば、`appium:app` および `browserName` capabilities は上記では必須ではないと記載していますが、特定のアプリでセッションを開始する場合、XCUITest ドライバーは、`appium:app`、`browserName`、または `appium:bundleId` の少なくとも1 つが capabilities に含まれていることが必要です (含まれていない場合、どのアプリをインストールまたは起動すればよいか判断できないため、ホーム画面からセッションが開かれます)。 各ドライバーは、これらの capabilities やその他のプラットフォーム固有の要件をどのように解釈するかを記述しています。
|
||||
The way to construct capabilities and start a session will likely differ depending on your Appium
|
||||
client. For examples of doing this in each client library, head to the [Ecosystem Clients](../ecosystem/clients.md)
|
||||
page and click through to the appropriate client documentation.
|
||||
|
||||
!!! note
|
||||
|
||||
```
|
||||
Capabilitiesは、セッション開始時に使用されるパラメータのようなものです。Capabilitiesが送信され、セッションが開始された後変更できません。ドライバーがセッション中に動作の一部を更新する場合、capabilitiesの代わりに、またはcapabilitiesに加えて、[Settings](./settings.md)も利用可能です。
|
||||
Once your capabilities are sent to the server and the session is started, they cannot be
|
||||
changed. If a driver supports updating its behaviour during a session, it will use the
|
||||
[Settings API](./settings.md) for this purpose.
|
||||
```
|
||||
|
||||
各 Appium クライアントには、capabilities を構築し、セッションを開始する独自の方法があります。 各クライアントライブラリでこれを行う例については、[エコシステム](../ecosystem/index.md) ページにアクセスし、適切なクライアントドキュメントをクリックしてください。
|
||||
|
||||
## BiDi プロトコルのサポート
|
||||
|
||||
Appiumは、base-driver 9.5.0以降で[WebDriver BiDi](https://w3c.github.io/webdriver-bidi/)プロトコルをサポートしています。
|
||||
実際の動作は個々のドライバーによって異なりますが、Appium と base-driver はプロトコルをサポートしています。
|
||||
ドライバーが BiDi プロトコルをサポートしているかどうか、また、どのようなコマンド/イベントをサポートしているかはドキュメントで確認してください。
|
||||
In addition to the standard WebDriver protocol (now known as WebDriver Classic), Appium supports the
|
||||
[WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol. Support for this protocol is
|
||||
opt-in, and requires the use of the standard `webSocketUrl` capability.
|
||||
|
||||
| Capability 名 | 型 | 説明 |
|
||||
| -------------- | --------- | ------------------------- |
|
||||
| `webSocketUrl` | `boolean` | セッションで BiDi プロトコルを有効にします。 |
|
||||
| Capability Name | 型 | 説明 |
|
||||
| --------------- | --------- | ----------------------------------------------- |
|
||||
| `webSocketUrl` | `boolean` | Whether BiDi protocol is enabled in the session |
|
||||
|
||||
All BiDi commands supported by the Appium base driver (inherited by all drivers) can be found in the
|
||||
[BiDi Protocol API Reference document](../reference/api/bidi.md). Similarly to WebDriver Classic
|
||||
commands, individual Appium drivers and plugins can define their own supported standard and custom
|
||||
BiDi commands, so make sure to reference their documentation.
|
||||
|
||||
## `appium:options` を使用して機能をグループ化する
|
||||
|
||||
@@ -99,8 +117,7 @@ creates in response to a new session request. This is through the concept of "al
|
||||
!!! note
|
||||
|
||||
```
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or
|
||||
a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) for
|
||||
a more in-depth description of how capabilities are processed.
|
||||
```
|
||||
|
||||
|
||||
@@ -3,27 +3,27 @@ title: Appium Server Security
|
||||
---
|
||||
|
||||
The Appium team makes every effort to ensure the security of the Appium server. This is especially
|
||||
important when Appium is run in a multitenant environment, or when multiple users are running
|
||||
sessions on the same Appium server. In general, you can only safely enable all of Appium's features if
|
||||
all the following are true:
|
||||
important when Appium is run in a multi-tenant environment, or when multiple users are running
|
||||
sessions on the same Appium server. To ensure a safe environment for Appium's purposes, all of the
|
||||
following should be true:
|
||||
|
||||
- You're running your own Appium server locally or within a protected internal network
|
||||
- You're not sharing it with any untrusted parties
|
||||
- You don't expose Appium's port(s) to the wider internet
|
||||
|
||||
But because many Appium users might not be able to guarantee such a safe environment, the Appium
|
||||
team puts many features behind a security protection mechanism, which forces system admins (the
|
||||
people who are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
|
||||
(Third-party driver and plugin authors can also hide behaviour behind security
|
||||
flags.)
|
||||
But because not all Appium hosts can guarantee such a safe environment, certain insecure Appium
|
||||
features are disabled by default, and require explicit opt-in in order to enable them. Most
|
||||
importantly, this can _only_ be done by the Appium server _host_, and Appium _client_ sessions are
|
||||
not allowed to change this.
|
||||
|
||||
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities.
|
||||
This is the responsibility of the server admin who configures and launches the Appium server.
|
||||
While it is possible for an Appium host to simply enable all insecure features at once, each
|
||||
feature also has a unique name, which can be used for granular control over the server state.
|
||||
|
||||
## Security Server Args
|
||||
|
||||
The [Server CLI](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to
|
||||
Appium, when starting it from the command line:
|
||||
Enabling or disabling insecure features is done via [Appium server launch arguments](../reference/cli/server.md)
|
||||
or [configuration file](./config.md). The former document outlines three relevant arguments for
|
||||
achieving this:
|
||||
|
||||
| <div style="width:10em">Parameter</div> | Description |
|
||||
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -31,36 +31,30 @@ Appium, when starting it from the command line:
|
||||
| `--allow-insecure` | Turns on _only_ specified features, except those blocked by `--deny-insecure`. Has no effect when used in combination with `--relaxed-security` |
|
||||
| `--deny-insecure` | Explicitly turns _off_ specified features, overriding `--relaxed-security` and `--allow-insecure` |
|
||||
|
||||
All of the above arguments can also be specified in the [Appium Configuration file](./config.md).
|
||||
|
||||
Features passed to `--allow-insecure`/`--deny-insecure` must be specified as a comma-separated list,
|
||||
and each feature in the list must additionally include a prefix, indicating the driver to which the
|
||||
feature should apply. The prefix can be either the driver's `automationName`, or the wildcard (`*`)
|
||||
symbol, if the feature should be applied to all drivers. The prefix and feature name are separated
|
||||
using the colon character (`:`).
|
||||
and each feature in the list must additionally include a prefix, indicating the driver to whose
|
||||
sessions the feature should apply. The prefix can be either the driver's `automationName`, or the
|
||||
wildcard (`*`) symbol, if the feature should be applied to all drivers. The prefix and feature name
|
||||
are separated using the colon character (`:`).
|
||||
|
||||
For example, `first:foo` refers to the `foo` feature for the `first` driver, whereas `*:bar` refers
|
||||
to the `bar` feature for all drivers.
|
||||
|
||||
## Insecure Features
|
||||
|
||||
Each Appium driver is responsible for its own security, and can create its own feature names. Thus,
|
||||
you should read through the documentation for a particular driver to know which feature names it
|
||||
might use. Here is an incomplete list of examples from some of Appium's official drivers:
|
||||
Almost all insecure features are defined on a per-driver or plugin basis, so make sure to read the
|
||||
documentation for a particular driver/plugin to know which feature names it might use.
|
||||
|
||||
| <div style="width:12em">Feature Name</div> | Description | Supported Extension(s) |
|
||||
| ------------------------------------------ | --------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
||||
| `get_server_logs` | Allows retrieving of Appium server logs via the Webdriver log interface | IOS, XCUITest, Android, UiAutomator2, Espresso |
|
||||
| `adb_shell` | Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command | Android, UiAutomator2, Espresso |
|
||||
| `record_audio` | Allow recording of host machine audio inputs | XCUITest |
|
||||
| `execute_driver_script` | Allows sending a request that has multiple Appium commands. | Execute Driver Plugin |
|
||||
Certain insecure features are also defined on the Appium server itself. For a list of these
|
||||
features, as well as the features defined in official plugins, see
|
||||
[the Insecure Features CLI Reference](../reference/cli/insecure-features.md) doc.
|
||||
|
||||
Some insecure features operate on the server level and do not require a driver session. Enabling
|
||||
these features require using the wildcard prefix:
|
||||
!!! note
|
||||
|
||||
| <div style="width:12em">Feature Name</div> | Description |
|
||||
| ------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| `session_discovery` | Allows retrieving the list of active server sessions via `GET /appium/sessions` |
|
||||
```
|
||||
If you are a driver or plugin author and want to implement insecure features of your own, check
|
||||
out the [Building Drivers documentation](../developing/build-drivers.md#understand-server-assigned-driver-properties-and-security-flags).
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -107,6 +107,48 @@ Retrieves the [execute methods](../../guides/execute-methods.md) supported in th
|
||||
origin (driver-specific or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)
|
||||
for a detailed structure of this object.
|
||||
|
||||
### getCurrentAppiumContext
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/context
|
||||
```
|
||||
|
||||
Retrieves the active application context.
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - the name of the active context
|
||||
|
||||
### setAppiumContext
|
||||
|
||||
```
|
||||
POST /session/:sessionId/appium/context
|
||||
```
|
||||
|
||||
Sets an application context as the active context.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
| ------ | -------------------------------------------- | ------ |
|
||||
| `name` | Name of the context to set as the active one | string |
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
### getAppiumContexts
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/contexts
|
||||
```
|
||||
|
||||
Retrieves all available application contexts.
|
||||
|
||||
#### Response
|
||||
|
||||
`string[]` - the names of available contexts
|
||||
|
||||
### getLogEvents
|
||||
|
||||
```
|
||||
@@ -393,3 +435,71 @@ Retrieves data from a directory on the device under test.
|
||||
#### Response
|
||||
|
||||
`string` - the Base64-encoded zip file of the directory contents
|
||||
|
||||
### getAppiumRotation
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/device/rotation
|
||||
```
|
||||
|
||||
Retrieves the current spatial orientation of the device under test.
|
||||
|
||||
#### Response
|
||||
|
||||
`Rotation` - an object with the following properties:
|
||||
|
||||
| Name | Description | Type |
|
||||
| ---- | ---------------------------------------------------- | ------ |
|
||||
| `x` | Degrees by which the device is rotated on its X axis | number |
|
||||
| `y` | Degrees by which the device is rotated on its Y axis | number |
|
||||
| `z` | Degrees by which the device is rotated on its Z axis | number |
|
||||
|
||||
### setAppiumRotation
|
||||
|
||||
```
|
||||
POST /session/:sessionId/appium/device/rotation
|
||||
```
|
||||
|
||||
Sets the spatial orientation of the device under test.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
| ---- | ---------------------------------------------------- | ------ |
|
||||
| `x` | Degrees by which the device is rotated on its X axis | number |
|
||||
| `y` | Degrees by which the device is rotated on its Y axis | number |
|
||||
| `z` | Degrees by which the device is rotated on its Z axis | number |
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
### getAppiumOrientation
|
||||
|
||||
```
|
||||
GET /session/:sessionId/appium/device/orientation
|
||||
```
|
||||
|
||||
Retrieves the current orientation of the device under test.
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - either `PORTRAIT` or `LANDSCAPE`
|
||||
|
||||
### setAppiumOrientation
|
||||
|
||||
```
|
||||
POST /session/:sessionId/appium/device/orientation
|
||||
```
|
||||
|
||||
Sets the orientation of the device under test.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------- | ------ |
|
||||
| `orientation` | New device orientation. Supported values are `PORTRAIT` or `LANDSCAPE`. | string |
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
@@ -140,6 +140,10 @@ GET /session/:sessionId/orientation
|
||||
|
||||
Retrieves the current orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getAppiumOrientation`](./appium.md#getappiumorientation) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - either `PORTRAIT` or `LANDSCAPE`
|
||||
@@ -154,6 +158,10 @@ POST /session/:sessionId/orientation
|
||||
|
||||
Sets the orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`setAppiumOrientation`](./appium.md#setappiumorientation) instead
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
|
||||
@@ -21,6 +21,10 @@ GET /session/:sessionId/rotation
|
||||
|
||||
Retrieves the current spatial orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getAppiumRotation`](./appium.md#getappiumrotation) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`Rotation` - an object with the following properties:
|
||||
@@ -41,6 +45,10 @@ POST /session/:sessionId/rotation
|
||||
|
||||
Sets the spatial orientation of the device under test.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`setAppiumRotation`](./appium.md#setappiumrotation) instead
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
@@ -63,6 +71,10 @@ GET /session/:sessionId/context
|
||||
|
||||
Retrieves the active application context.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getCurrentAppiumContext`](./appium.md#getcurrentappiumcontext) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`string` - the name of the active context
|
||||
@@ -77,6 +89,10 @@ POST /session/:sessionId/context
|
||||
|
||||
Sets an application context as the active context.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`setAppiumContext`](./appium.md#setappiumcontext) instead
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
@@ -97,6 +113,10 @@ GET /session/:sessionId/contexts
|
||||
|
||||
Retrieves all available application contexts.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use [`getAppiumContexts`](./appium.md#getappiumcontexts) instead
|
||||
|
||||
#### Response
|
||||
|
||||
`string[]` - the names of available contexts
|
||||
|
||||
@@ -397,6 +397,45 @@ Deletes the virtual sensor with the type identified by `:sensorType`.
|
||||
|
||||
`null`
|
||||
|
||||
## Global Privacy Control Protocol
|
||||
|
||||
The [Global Privacy Control protocol](https://www.w3.org/TR/gpc) (GPC) is an extension of the W3C
|
||||
WebDriver protocol.
|
||||
|
||||
### setGlobalPrivacyControl
|
||||
|
||||
```
|
||||
POST /session/:sessionId/privacy
|
||||
```
|
||||
|
||||
> GPC documentation: [Set Global Privacy Control](https://www.w3.org/TR/gpc/#set-global-privacy-control)
|
||||
|
||||
Sets the value of the do-not-sell-or-share preference for the current session.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
| ----- | -------------------------------------------------------------------- | ------- |
|
||||
| `gpc` | Whether the browser should perform do-not-sell-or-share interactions | boolean |
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
### getGlobalPrivacyControl
|
||||
|
||||
```
|
||||
GET /session/:sessionId/privacy
|
||||
```
|
||||
|
||||
> GPC documentation: [Get Global Privacy Control](https://www.w3.org/TR/gpc/#get-global-privacy-control)
|
||||
|
||||
Retrieves the value of the do-not-sell-or-share preference for the current session.
|
||||
|
||||
#### Response
|
||||
|
||||
`boolean` - the preference value
|
||||
|
||||
## Permissions Protocol
|
||||
|
||||
The [Permissions protocol](https://www.w3.org/TR/permissions/) is an extension of the W3C WebDriver
|
||||
@@ -524,6 +563,32 @@ Retrieves the available log types that can be used to call the [`getLog`](#getlo
|
||||
|
||||
`string[]` - an array of log types
|
||||
|
||||
## Storage Access Protocol
|
||||
|
||||
The [Storage Access protocol](https://privacycg.github.io/storage-access/) is an extension of the
|
||||
W3C WebDriver protocol.
|
||||
|
||||
### setStorageAccess
|
||||
|
||||
```
|
||||
POST /session/:sessionId/storageaccess
|
||||
```
|
||||
|
||||
> Storage Access documentation: [Set Storage Access](https://privacycg.github.io/storage-access/#set-storage-access-command)
|
||||
|
||||
Sets the storage access policy of the current browsing context.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Description | Type |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
|
||||
| `blocked` | Whether storage access should be blocked (`true`) or allowed (`false`) | boolean |
|
||||
| `origin` | The origin to which the policy should be applied. Must be either a valid URL, or an asterisk (`*`) if the policy should apply to all origins. | string |
|
||||
|
||||
#### Response
|
||||
|
||||
`null`
|
||||
|
||||
## Web Authentication Protocol
|
||||
|
||||
The [Web Authentication protocol](https://w3c.github.io/webauthn/) (WebAuthn) is an extension of
|
||||
|
||||
@@ -170,10 +170,17 @@ Modifies the [`createSession`](./webdriver.md#createsession) endpoint:
|
||||
All endpoints for this plugin can be invoked without creating a session, allowing you to prepare
|
||||
your test environment in advance.
|
||||
|
||||
!!! info
|
||||
|
||||
Prior to plugin version 1.2.0, all endpoints below were mounted under the `/storage` prefix
|
||||
(e.g. `/storage/add`) instead of `/appium/storage`. The `/storage`-prefixed routes are still
|
||||
available for backward compatibility, but are deprecated and will be removed in a future
|
||||
version of the plugin.
|
||||
|
||||
### addStorageItem
|
||||
|
||||
```
|
||||
POST /storage/add
|
||||
POST /appium/storage/add
|
||||
```
|
||||
|
||||
Adds a new file to the storage.
|
||||
@@ -200,8 +207,8 @@ Example:
|
||||
```json
|
||||
{
|
||||
"ws": {
|
||||
"stream": "/storage/add/ccc963411b2621335657963322890305ebe96186/stream",
|
||||
"events": "/storage/add/ccc963411b2621335657963322890305ebe96186/events"
|
||||
"stream": "/appium/storage/add/ccc963411b2621335657963322890305ebe96186/stream",
|
||||
"events": "/appium/storage/add/ccc963411b2621335657963322890305ebe96186/events"
|
||||
},
|
||||
"ttlMs": 300000
|
||||
}
|
||||
@@ -210,7 +217,7 @@ Example:
|
||||
### deleteStorageItem
|
||||
|
||||
```
|
||||
POST /storage/delete
|
||||
POST /appium/storage/delete
|
||||
```
|
||||
|
||||
Deletes a file in the storage.
|
||||
@@ -224,12 +231,12 @@ Deletes a file in the storage.
|
||||
#### Response
|
||||
|
||||
`boolean` - `true` upon successful file deletion, or `false` if the file does not exist in
|
||||
the storage
|
||||
the storage, or if the delete request is invalid.
|
||||
|
||||
### listStorageItems
|
||||
|
||||
```
|
||||
GET /storage/list
|
||||
GET /appium/storage/list
|
||||
```
|
||||
|
||||
List all files present in the storage.
|
||||
@@ -247,7 +254,7 @@ List all files present in the storage.
|
||||
### resetStorage
|
||||
|
||||
```
|
||||
POST /storage/reset
|
||||
POST /appium/storage/reset
|
||||
```
|
||||
|
||||
Deletes all uploaded files and stops any incomplete uploads.
|
||||
|
||||
@@ -159,14 +159,14 @@ extensions include scripts.
|
||||
#### Usage
|
||||
|
||||
```
|
||||
appium {driver|plugin} run <extension-name> <script-name> [script-args]
|
||||
appium {driver|plugin} run <extension-name> [<script-name> [<script-args>]]
|
||||
```
|
||||
|
||||
| Argument | Description |
|
||||
| ---------------- | --------------------------------------------- |
|
||||
| `extension-name` | The short name of the installed extension |
|
||||
| `script-name` | The name of the script to be run |
|
||||
| `script-args` | Any additional arguments passed to the script |
|
||||
| Argument | Description |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `extension-name` | The short name of the installed extension |
|
||||
| `script-name` | The name of the script to run. If not provided, a list of available scripts is returned. |
|
||||
| `script-args` | Any additional arguments passed to the script |
|
||||
|
||||
#### Options
|
||||
|
||||
@@ -182,6 +182,12 @@ appium {driver|plugin} run <extension-name> <script-name> [script-args]
|
||||
appium driver run uiautomator2 reset
|
||||
```
|
||||
|
||||
- List all available scripts included in the XCUITest driver:
|
||||
|
||||
```
|
||||
appium driver run xcuitest
|
||||
```
|
||||
|
||||
## `update`
|
||||
|
||||
Updates one or more extensions. Only supported for extensions installed via `npm`. By default,
|
||||
|
||||
@@ -31,5 +31,6 @@ The executable has four main subcommands: `server`, `driver`, `plugin`, and `set
|
||||
|
||||
</div>
|
||||
|
||||
Appium also recognizes several [environment variables](./env-vars.md), which may be used for
|
||||
advanced configuration.
|
||||
The Appium server also recognizes several [environment variables](./env-vars.md) and
|
||||
[insecure feature names](./insecure-features.md), though drivers and plugins can also define
|
||||
variables and features of their own.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Insecure Features
|
||||
---
|
||||
|
||||
The Appium server implements [a security protection mechanism](../../guides/security.md) that
|
||||
allows the management of various insecure features.
|
||||
|
||||
The following features are defined on the server level and can be used even without drivers, but
|
||||
they can only be enabled using the wildcard (`*`) prefix:
|
||||
|
||||
| Feature Name | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------- |
|
||||
| `session_discovery` | Allows retrieving the list of active server sessions via `GET /appium/sessions` |
|
||||
|
||||
Of course, Appium drivers and plugins are free to define additional insecure features of their own.
|
||||
The following features are defined by official plugins:
|
||||
|
||||
| Feature Name | Plugin | Description |
|
||||
| ----------------------- | ---------------- | ---------------------------------------------------------- |
|
||||
| `execute_driver_script` | `execute_driver` | Allows sending a request that has multiple Appium commands |
|
||||
@@ -29,6 +29,7 @@ appium
|
||||
| `--address`, `-a` | IPv4/IPv6 address to listen on | string | `0.0.0.0` |
|
||||
| `--allow-cors` | Allow web browser connections from any host | boolean | `false` |
|
||||
| `--allow-insecure` | List of [insecure features](../../guides/security.md) that should be allowed in this server's sessions. Individual features can be overridden by `--deny-insecure`. Has no effect in combination with `--relaxed-security`. | array<string> | `[]` |
|
||||
| `--allow-unknown-args` | Do not exit if unrecognized command-line arguments are passed to the server; ignore them instead. Useful when the Appium CLI is wrapped by external tooling that appends extra flags. | boolean | `false` |
|
||||
| `--base-path`, `-pa` | Base path to use as the prefix for all webdriver routes running on the server | string | `""` |
|
||||
| `--callback-address`, `-ca` | Callback IP address | string | `0.0.0.0` |
|
||||
| `--callback-port`, `-cp` | Callback port | integer | `4723` |
|
||||
@@ -48,6 +49,8 @@ appium
|
||||
| `--log-no-colors` | Disable colors in the server log | boolean | `false` |
|
||||
| `--log-timestamp` | Show timestamps in the server log | boolean | `false` |
|
||||
| `--long-stacktrace` | Add long stack traces to log entries. Recommended for debugging only. | boolean | `false` |
|
||||
| `--max-ipc-data-size` | Maximum byte size of IPC message objects. | integer | `1048576` (1MB) |
|
||||
| `--max-ipc-topics` | Maximum number of IPC topics per session. | integer | `1000` |
|
||||
| `--no-perms-check` | Skip various permission checks on the server startup | boolean | `false` |
|
||||
| `--nodeconfig` | JSON configuration for registering Appium as a node with Selenium Grid 3 | object | |
|
||||
| `--plugin` | Plugin-specific configuration. Keys should correspond to plugin package names | object | |
|
||||
@@ -62,7 +65,7 @@ appium
|
||||
| `--tmp` | Absolute path to the directory used for temporary files | string | [`os.tmpdir()`](https://nodejs.org/api/os.html#ostmpdir) |
|
||||
| `--use-drivers` | List of drivers to activate. By default, all installed drivers are activated. | array<string> | `[]` |
|
||||
| `--use-plugins` | List of plugins to activate. By default, no plugins are activated. Set to `["all"]` to activate all installed plugins. | array<string> | `[]` |
|
||||
| `--webhook`, `-G` | URL for an HTTP listener where the server logs should be output. This does not affect output on the console. | string | |
|
||||
| `--webhook`, `-G` | URL for an HTTP listener where the server logs should be output. This does not affect output on the console. A bare `host:port` is also accepted, which posts the logs to the root path over plain http; a value having neither a scheme nor a port falls back to `127.0.0.1:9003`. | string | |
|
||||
|
||||
### Info Options
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ hide:
|
||||
title: Reference
|
||||
---
|
||||
|
||||
This section of the Appium documentation provides a reference to the two main interfaces within the
|
||||
Appium server: the command-line executable, and the supported API endpoints.
|
||||
This section of the Appium documentation provides a reference to the core interfaces supported within the
|
||||
Appium server:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
@@ -16,10 +16,16 @@ Appium server: the command-line executable, and the supported API endpoints.
|
||||
|
||||
Learn how to use the Appium command-line executable
|
||||
|
||||
- :material-lan-connect: [**Session Properties**](./session/index.md)
|
||||
|
||||
---
|
||||
|
||||
See the values of global Appium session properties
|
||||
|
||||
- :material-cloud-braces: [**API Endpoints**](./api/index.md)
|
||||
|
||||
---
|
||||
|
||||
View endpoints supported by the Appium server
|
||||
View endpoints supported by the core Appium server
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Capabilities
|
||||
---
|
||||
|
||||
The following [capabilities](../../guides/caps.md) are recognized by the Appium server/base driver,
|
||||
and are therefore supported by all drivers as well. Some capabilities are directly handled by the
|
||||
server/base driver, while others are only validated before being passed to the actual driver.
|
||||
|
||||
!!! note
|
||||
|
||||
Capabilities not listed here will _not_ be rejected by Appium: they will simply be forwarded
|
||||
directly to the active driver/plugin.
|
||||
|
||||
### Required Capabilities
|
||||
|
||||
These capabilities are used in the Appium server/base driver, and are explicitly required in all
|
||||
Appium sessions.
|
||||
|
||||
| Capability | Description | Type |
|
||||
| ----------------------- | ------------------------------------------- | -------- |
|
||||
| `platformName` | Type of platform hosting the app or browser | `string` |
|
||||
| `appium:automationName` | Name of the Appium driver to use | `string` |
|
||||
|
||||
### Optional Capabilities
|
||||
|
||||
These capabilities are used in the Appium server/base driver, but are optional, and may have a
|
||||
default value.
|
||||
|
||||
| <div style="width:19em">Capability</div> | Description | Type | Default |
|
||||
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
|
||||
| `webSocketUrl` | Toggle support of the WebDriver BiDi protocol | `boolean` | |
|
||||
| `appium:eventTimings` (deprecated) | Toggle collection of [Event Timings](../../guides/event-timing.md). This capability is deprecated - please use the [`getLogEvents`](../api/appium.md#getlogevents) endpoint instead. | `boolean` | |
|
||||
| `appium:newCommandTimeout` | Number of seconds the Appium server should wait for clients to send commands before stopping the session. A value of `0` disables the timeout. | `number` | `60` |
|
||||
| `appium:printPageSourceOnFindFailure` | Toggle retrieval of the the page source and its printing to the Appium log, whenever a request to find an element fails | `boolean` | |
|
||||
|
||||
### Validated Capabilities
|
||||
|
||||
These capabilities are not directly used in the Appium server/base driver, but are still subject to
|
||||
validation checks due to their relevance in other drivers. The actual handling of these
|
||||
capabilities is optional and entirely driver-dependent.
|
||||
|
||||
| Capability | Validation |
|
||||
| --------------------------------------------------- | ------------------------------------------------------------- |
|
||||
| `platformVersion` | Must be `string` |
|
||||
| `appium:app` | Must be `string`; empty values are ignored |
|
||||
| `appium:autoLaunch` (deprecated) | Must be `boolean` |
|
||||
| `appium:autoWebview` | Must be `boolean` |
|
||||
| `appium:fullReset` | Must be `boolean`; mutually exclusive with `appium:noReset` |
|
||||
| `appium:language` | Must be `string` |
|
||||
| `appium:locale` | Must be `string` |
|
||||
| `appium:orientation` | Must be either `LANDSCAPE` or `PORTRAIT` |
|
||||
| `appium:noReset` | Must be `boolean`; mutually exclusive with `appium:fullReset` |
|
||||
| `appium:udid` | Must be `string` |
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Session Properties
|
||||
---
|
||||
|
||||
An Appium session has several key properties, each with its own set of supported values:
|
||||
capabilities, execute methods, settings, locator strategies, and others. The supported values for
|
||||
each property are primarily defined by the active driver and plugins, but some properties also have
|
||||
common values provided by the Appium server and its base driver:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**Capabilities**](./caps.md)
|
||||
|
||||
A small set of basic capabilities
|
||||
|
||||
- [**Command Endpoints**](../api/index.md)
|
||||
|
||||
The core set of API endpoints
|
||||
|
||||
</div>
|
||||
@@ -8,11 +8,6 @@ title: Additional Resources
|
||||
|
||||
Here you can find links to additional Appium resources around the web:
|
||||
|
||||
## Websites
|
||||
|
||||
- [Appium Pro](https://appiumpro.com) - a blog and newsletter written by one of Appium's
|
||||
maintainers, Jonathan Lipps, with lots of useful guides
|
||||
|
||||
## Online Courses
|
||||
|
||||
- [Appium and Selenium Fundamentals](https://ui.headspin.io/university/learn/appium-selenium-fundamentals-2020) - a comprehensive video course on learning Python, Selenium, and Appium by Jonathan Lipps
|
||||
@@ -26,3 +21,4 @@ Here you can find links to additional Appium resources around the web:
|
||||
- [AppiumConf 2021](https://www.youtube.com/playlist?list=PL9Z-JgiTsOYRCcJhDfmKAah9XmAp2b903)
|
||||
- [AppiumConf 2024](https://www.youtube.com/playlist?list=PL9Z-JgiTsOYQaU5i5LJtAWlh5WVZPi3If)
|
||||
- [SeleniumConf & AppiumConf 2025](https://www.youtube.com/playlist?list=PLRdSclUtJDYV2R92TLbmwxws6clruuTjH)
|
||||
- [SeleniumConf & AppiumConf 2026](https://www.youtube.com/playlist?list=PLRdSclUtJDYVgVqdKnSyBLBmFdA0KE_Dk)
|
||||
|
||||
@@ -42,6 +42,10 @@ nav:
|
||||
- reference/cli/extensions.md
|
||||
- reference/cli/setup.md
|
||||
- reference/cli/env-vars.md
|
||||
- reference/cli/insecure-features.md
|
||||
- Session Properties:
|
||||
- reference/session/index.md
|
||||
- reference/session/caps.md
|
||||
- API Endpoints:
|
||||
- reference/api/index.md
|
||||
- reference/api/webdriver.md
|
||||
|
||||
@@ -42,6 +42,10 @@ nav:
|
||||
- reference/cli/extensions.md
|
||||
- reference/cli/setup.md
|
||||
- reference/cli/env-vars.md
|
||||
- reference/cli/insecure-features.md
|
||||
- Session Properties:
|
||||
- reference/session/index.md
|
||||
- reference/session/caps.md
|
||||
- API Endpoints:
|
||||
- reference/api/index.md
|
||||
- reference/api/webdriver.md
|
||||
|
||||
@@ -42,6 +42,10 @@ nav:
|
||||
- reference/cli/extensions.md
|
||||
- reference/cli/setup.md
|
||||
- reference/cli/env-vars.md
|
||||
- reference/cli/insecure-features.md
|
||||
- Session Properties:
|
||||
- reference/session/index.md
|
||||
- reference/session/caps.md
|
||||
- API 端点:
|
||||
- reference/api/index.md
|
||||
- reference/api/webdriver.md
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block announce %}
|
||||
<center>
|
||||
SeleniumConf & AppiumConf returns on May 6-8, 2026! Join us to learn and connect with the community!
|
||||
<a href="https://seleniumconf.com/">Register Now</a>
|
||||
</center>
|
||||
{% endblock %}
|
||||
@@ -10,7 +10,6 @@
|
||||
/* eslint-disable promise/prefer-await-to-callbacks */
|
||||
/* eslint-disable promise/prefer-await-to-then */
|
||||
|
||||
const {deploy, buildSite} = require('@appium/docutils');
|
||||
const {
|
||||
log,
|
||||
LANGS,
|
||||
@@ -31,7 +30,13 @@ const preview = Boolean(process.env.APPIUM_DOCS_PREVIEW);
|
||||
|
||||
const push = Boolean(process.env.APPIUM_DOCS_PUBLISH);
|
||||
|
||||
/**
|
||||
* Builds and optionally deploys docs for each supported language.
|
||||
*/
|
||||
async function main() {
|
||||
// @appium/docutils is ESM-only; this file is CommonJS, so it must be loaded dynamically
|
||||
const {deploy, buildSite} = await import('@appium/docutils');
|
||||
|
||||
log.info(`Building Appium docs and committing to ${DOCS_BRANCH}`);
|
||||
|
||||
const semVersion = semver.parse(version);
|
||||
|
||||
@@ -12,6 +12,9 @@ const DOC_PATH = path.resolve(__dirname, '..', 'en', 'cli', 'args.md');
|
||||
const START_TAG = `<!-- AUTOGEN-START -->`;
|
||||
const STOP_TAG = `<!-- AUTOGEN-STOP -->`;
|
||||
|
||||
/**
|
||||
* Regenerates the CLI arguments table in docs.
|
||||
*/
|
||||
async function main() {
|
||||
console.log(`Gathering current cli doc file contents...`);
|
||||
const [preStart, postEnd] = await getDocParts();
|
||||
|
||||
@@ -5,9 +5,9 @@ authors:
|
||||
date: 2024-07-13
|
||||
---
|
||||
|
||||
# Appium Conf 2024: Call for Proposals Now Open!
|
||||
# Appium Conf 2024: 现在开始征集提案
|
||||
|
||||
We're thrilled to announce that Appium Conf is back and going online for 2024! This is the official Appium conference where you can learn all about what's new in Appium 2.0 and explore the latest in automating tests for devices, mobile apps, and desktop applications.
|
||||
我们很兴奋地宣布,Appium Conf 已回归并在2024年上线! 这是官方的Appium会议,您可以在会上了解Appium 2中的所有新内容。 并探索设备自动化测试、移动应用程序和桌面应用程序的最新版本。
|
||||
|
||||
<!-- more -->
|
||||
|
||||
@@ -17,29 +17,29 @@ We're thrilled to announce that Appium Conf is back and going online for 2024! T
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## Mark Your Calendars: September 13, 2024
|
||||
## 标记您的日历:2024年9月13日
|
||||
|
||||
Join us on September 13, 2024, for a full day of inspiring and practical talks from the Appium team and the world's top mobile testing and automation experts. With Appium 2.0 now well-established, this is your opportunity to dive deep and learn how to maximize its potential.
|
||||
2024年9月13日,请加入我们,参加Appium团队和世界顶级移动测试和自动化专家为期一天的鼓舞人心且实用的演讲。 随着Appium 2.0的成熟,这是您深入了解并学习如何最大限度地发挥其潜力的机会。
|
||||
|
||||
## Why Attend Appium Conf 2024?
|
||||
## 为什么参加了2024年的Appium Conf ?
|
||||
|
||||
1. **Gain Insights**: Hear interesting insights and inspiring case studies from global experts and the core Appium team.
|
||||
2. **Improve Your Strategy**: Gain valuable knowledge to enhance your own automation strategy.
|
||||
3. **Network**: Make connections with Appium users from around the globe.
|
||||
4. **Learn from Specialists**: Benefit from Appium specialists' expertise on a variety of topics.
|
||||
1. **获得见解**:听取全球专家和核心Appium团队的有趣见解和鼓舞人心的案例研究。
|
||||
2. **改进您的战略**:获得有价值的知识,以增强您自己的自动化战略。
|
||||
3. **网络**:与来自全球的Appium用户建立联系。
|
||||
4. **向专家学习**:从Appium专家在各种主题上的专业知识中受益。
|
||||
|
||||
## Call for Proposals: Share Your Knowledge!
|
||||
## 征集提案:分享您的知识!
|
||||
|
||||
We're looking for a diverse range of speakers from around the globe who are eager to share innovative ideas and use-cases of mobile test automation. If you have experience with Appium and insights that could benefit the community of test practitioners, we want to hear from you!
|
||||
我们正在寻找来自全球各地的各种演讲者,他们渴望分享移动测试自动化的创新想法和用例。 如果您有使用Appium的经验和见解,可以使测试从业者社区受益,我们想听听您的意见!
|
||||
|
||||
Don't miss this chance to contribute to the Appium community and showcase your expertise on a global stage.
|
||||
不要错过这个机会,为Appium社区做出贡献,并在全球舞台上展示你的专业知识。
|
||||
|
||||
## How to Submit Your Proposal
|
||||
## 如何提交您的提案
|
||||
|
||||
Visit our website at [https://appiumconf.com/](https://appiumconf.com/) and [Submit a Proposal](https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch). We're excited to see your innovative ideas and experiences with Appium!
|
||||
访问我们的网站 [https://appiumconf.com/](https://appiumconf.com/) 并[提交提案](https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch)。 我们很高兴看到您在 Appium 中的创新想法和经验!
|
||||
|
||||
## Stay Tuned
|
||||
## 敬请期待
|
||||
|
||||
Keep an eye on our website and social media channels for updates on the conference schedule, keynote speakers, and more exciting details about Appium Conf 2024.
|
||||
关注我们的网站和社交媒体频道以了解会议日程安排的更新, 主旨演讲人和2024年Appium Conf 的更令人兴奋的细节。
|
||||
|
||||
Join us in shaping the future of mobile and device test automation. Submit your proposal today and be part of this exciting event!
|
||||
加入我们来塑造移动设备测试自动化的未来。 立即提交您的提案,成为这一激动人心的活动的一部分!
|
||||
@@ -8,11 +8,13 @@ date: 2025-11-25
|
||||
# Announcing LambdaTest as Appium's Newest Development Partner
|
||||
|
||||
As part of our ongoing effort to recognize organizations that meaningfully support the Appium project through dedicated maintainer time, we are excited to welcome our newest Development Partner: LambdaTest!
|
||||
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
|
||||
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
LambdaTest has long been an active participant in the automated testing ecosystem. Today, they are officially formalizing their commitment by investing people—dedicated engineers who will directly support Appium's development, maintenance, and ecosystem growth.
|
||||
|
||||
This kind of hands-on contribution is crucial for ensuring Appium continues to evolve. We deeply value partners who empower their engineering teams to contribute code directly to open source rather than just sponsorship.
|
||||
|
||||
<div style="text-align:center;width:100%"><a href="https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage">
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark" width="300" />
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light" width="300" />
|
||||
@@ -20,15 +22,19 @@ This kind of hands-on contribution is crucial for ensuring Appium continues to e
|
||||
</div>
|
||||
|
||||
LambdaTest engineers are already contributing actively across several key Appium repositories. Their current focus includes:
|
||||
**appium-mcp** – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
|
||||
**appium-remote-xpc** – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
|
||||
**appium-tun-tap** – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
|
||||
|
||||
- [`appium-mcp`](https://github.com/appium/appium-mcp) – Supporting Appium's implementation of the Model Context Protocol (MCP) to drive forward modern AI-assisted capabilities.
|
||||
- [`appium-ios-remotexpc`](https://github.com/appium/appium-ios-remotexpc) – Contributing to the native macOS/XPC-based remote execution layer, essential for iOS automation.
|
||||
- [`appium-ios-tuntap`](https://github.com/appium/appium-ios-tuntap) – Assisting in the development and maintenance of network virtualization and tunneling components for advanced testing scenarios.
|
||||
|
||||
These contributions strengthen critical infrastructure within the Appium ecosystem and demonstrate LambdaTest's commitment to deep technical involvement in the project's evolution.
|
||||
About LambdaTest
|
||||
|
||||
**About LambdaTest**
|
||||
|
||||
LambdaTest’s platform already serves a massive community of Appium users. As a GenAI-powered Quality Engineering Platform, they provide a full-stack testing cloud with 10,000+ real mobile devices and 3,000+ browsers.
|
||||
|
||||
Beyond standard infrastructure, they are pushing the boundaries of test execution with AI-native test management and next-generation agents like KaneAI. By supporting Appium alongside Selenium, Playwright, and other major frameworks, LambdaTest helps teams orchestrate intelligent automation at cloud scale.
|
||||
|
||||
LambdaTest will continue contributing people, code, and development expertise to strengthen Appium's core functionality. Their commitment represents a significant investment into the future of the framework, and we're thrilled to have them collaborating with us at this deeper level.
|
||||
|
||||
The Appium project is proud to recognize LambdaTest as our newest official Development Partner. We can't wait to see what we'll build together!
|
||||
|
||||
@@ -7,8 +7,7 @@ title: 对Appium 的贡献
|
||||
|
||||
Appium项目离不开来自公司和志愿者的代码、文档、维护和支持的众多贡献。 因此,我们欢迎贡献!
|
||||
|
||||
有许多不同的方式可以帮助项目——请参阅下方了解您可以做的一切以及每个贡献方法的流程。 Note that no matter how you contribute, your
|
||||
participation is governed by our [Code of Conduct](https://github.com/appium/.github/blob/master/CODE_OF_CONDUCT.md).
|
||||
有许多不同的方式可以帮助项目——请参阅下方了解您可以做的一切以及每个贡献方法的流程。 请注意,无论您如何贡献,您的参与都受我们的[行为准则](https://github.com/appium/.github/blob/master/CODE_OF_CONDUCT.md)管辖。
|
||||
|
||||
## 加入讨论论坛
|
||||
|
||||
|
||||
@@ -1,84 +1,66 @@
|
||||
---
|
||||
title: Building Documentation
|
||||
title: 构建文档
|
||||
---
|
||||
|
||||
Once you've [built a driver](./build-drivers.md) or [built a plugin](./build-plugins.md) for Appium,
|
||||
you will hopefully want to document how that extension works for your users. The most basic way of
|
||||
doing this is to write up a quick `README.md` and keep it in the root of your project's repository.
|
||||
However, this can involve a lot of effort.
|
||||
一旦你为 Appium 构建了 [驱动](./build-drivers.md) 或 [插件](./build-plugins.md),通常也会希望为用户说明这个扩展是如何工作的。 最基础的方式就是编写一个简短的 `README.md`,并将它放在项目仓库的根目录中。
|
||||
不过,这样做可能会耗费不少精力。
|
||||
|
||||
The Appium project has built tools to help with this, and we've packaged up these tools so our
|
||||
ecosystem developers building drivers and plugins can _also_ use them. The best way to get going
|
||||
with these tools is probably to look at an existing Appium driver repo to see how it's done, for
|
||||
example the [XCUITest driver repo](https://github.com/appium/appium-xcuitest-driver). But this guide
|
||||
will outline the basic approach.
|
||||
Appium 项目已经提供了辅助工具,并且我们把这些工具打包好了,以便生态系统中的驱动和插件开发者也能使用。 这些工具最好的入门方式是查看一个现有的 Appium 驱动仓库,看看它是如何组织文档的,例如 [XCUITest 驱动仓库](https://github.com/appium/appium-xcuitest-driver)。 不过,本指南会先介绍基本的实现思路。
|
||||
|
||||
### Conceptual architecture
|
||||
### 概念架构
|
||||
|
||||
Appium settled on [MkDocs](https://www.mkdocs.org/) as a Markdown-based documentation site
|
||||
generator. It uses a Python toolchain (and not Node.js), but it turned out to be the best option
|
||||
for our purposes. You can adjust this, but by default Appium's utilities also assume that you'll be
|
||||
using the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) theme/extension for
|
||||
MkDocs.
|
||||
Appium 采用 [MkDocs](https://www.mkdocs.org/) 作为基于 Markdown 的文档站点的生成工具。 它使用 Python 工具链(而不是 Node.js),但这恰好是我们当前需求下最合适的选择。 你可以自行调整,不过默认情况下,Appium 的工具链也会假设你使用 [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) 主题与扩展来搭建 MkDocs。
|
||||
|
||||
In order to make different versions of your docs available (one for each minor release of your
|
||||
extension, typically), we also bundle [Mike](https://github.com/jimporter/mike).
|
||||
为了让你的文档能够支持不同版本(通常是每个小版本一个),我们还会捆绑 [Mike](https://github.com/jimporter/mike)。
|
||||
|
||||
From here, building a basic docs site is as easy as collecting your Markdown files together and
|
||||
defining how you want them to be organized.
|
||||
从这里开始,构建一个基础文档站点其实很简单:把 Markdown 文件收集起来,再定义你希望它们如何组织即可。
|
||||
|
||||
### Prerequisites
|
||||
### 前置条件
|
||||
|
||||
To take advantage of Appium's documentation utilities, you'll need to install:
|
||||
要使用 Appium 的文档工具,你需要安装以下内容:
|
||||
|
||||
- [Python v3+](https://www.python.org/downloads/)
|
||||
- [pip](https://pip.pypa.io/en/stable/installation/) (this may be installed automatically with Python)
|
||||
- The `@appium/docutils` package:
|
||||
- [pip](https://pip.pypa.io/en/stable/installation/)(通常 Python 会自动附带安装)
|
||||
- `@appium/docutils` 包:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @appium/docutils
|
||||
```
|
||||
|
||||
### Initializing an Extension for Building Docs
|
||||
### 初始化用于构建文档的扩展
|
||||
|
||||
To prepare your extension for generating documentation, run the following command:
|
||||
要为你的扩展准备文档生成环境,请运行下面的命令:
|
||||
|
||||
```bash
|
||||
npx appium-docs init
|
||||
```
|
||||
|
||||
This will:
|
||||
这一步会:
|
||||
|
||||
1. Create a `tsconfig.json` if one does not already exist. This is necessary even if your extension
|
||||
is not written in TypeScript.
|
||||
2. Create a `mkdocs.yml` with the necessary configuration for MkDocs.
|
||||
1. 创建一个 `tsconfig.json`(如果当前还没有的话)。 即使你的扩展并不是 TypeScript 编写的,这也是必需的。
|
||||
2. 创建一个 `mkdocs.yml`,其中包含 MkDocs 所需的配置。
|
||||
|
||||
### Documenting Your Extension
|
||||
### 为你的扩展编写文档
|
||||
|
||||
At this point, you can begin documenting your extension. By default, MkDocs will look for Markdown
|
||||
files in the `docs` directory. You can therefore create your Markdown documentation files, place
|
||||
them in `docs`, and add links to these files in `mkdocs.yml`.
|
||||
此时你就可以开始为扩展编写文档了。 默认情况下,MkDocs 会在 `docs` 目录中查找 Markdown 文件。 因此,你可以创建文档文件并放入 `docs`,然后在 `mkdocs.yml` 里添加相应链接。
|
||||
|
||||
Refer to the [MkDocs documentation](https://www.mkdocs.org/user-guide/writing-your-docs/) for
|
||||
information on how to organize and structure your documentation.
|
||||
请参考 [MkDocs 文档](https://www.mkdocs.org/user-guide/writing-your-docs/) 来了解如何组织与构建你的文档结构。
|
||||
|
||||
### Building the Docs
|
||||
### 构建文档
|
||||
|
||||
At this point, you can use the `appium-docs` CLI tool. Run this tool with no arguments to get the
|
||||
full help output and see all the available subcommands and parameters. Here are a few usage
|
||||
examples:
|
||||
在这个阶段,你可以使用 `appium-docs` CLI 工具。 运行这个工具时不传任何参数,可以看到完整的帮助信息,以及所有可用的子命令与参数。 下面是几个常见用法示例:
|
||||
|
||||
```bash
|
||||
# Generate reference and build the mkdocs site into the site dir
|
||||
# 生成参考文档并将 mkdocs 站点构建到 site 目录
|
||||
npx appium-docs build
|
||||
|
||||
# Same as build, but host the docs on a local dev server
|
||||
# and watch for changes and rebuild when files change
|
||||
# 与 build 相同,但会在本地启动开发服务器
|
||||
# 并监听文件变化,在内容变更时自动重建
|
||||
npx appium-docs build --serve
|
||||
|
||||
# Build the docs and deploy them with mike versioning to the docs-site branch
|
||||
# using the included commit message.
|
||||
# This is particularly useful for pushing content to a GitHub pages branch!
|
||||
# 构建文档并使用 mike 进行版本化部署到 docs-site 分支
|
||||
# 其中包含内置提交信息。
|
||||
# 这对于把内容推送到 GitHub Pages 分支特别有用!
|
||||
npx appium-docs build \
|
||||
--deploy \
|
||||
-b docs-site \
|
||||
|
||||
@@ -1,45 +1,33 @@
|
||||
---
|
||||
title: Building Doctor Checks
|
||||
title: 构建 Doctor Checks
|
||||
---
|
||||
|
||||
The idea of Appium Doctor is to assist users with driver or plugin preconditions setup. Sometimes such
|
||||
preconditions might be quite complicated and require non-trivial technical knowledge. Doctor checks,
|
||||
which are vanilla Node.js class instances written by extension authors, simplify
|
||||
the setup process by automating diagnostics and possible fixes for the found issues. These checks
|
||||
might also be interactive to ensure better usage experience.
|
||||
Appium Doctor 的目标,是帮助用户完成驱动或插件的前置条件配置。 有时这些前置条件可能相当复杂,需要一定的技术知识。 Doctor checks是由扩展作者编写的普通 Node.js 类实例,它可以自动完成诊断并尝试修复发现的问题。 为了提供更好的使用体验,这些检查项有时也会是交互式的。
|
||||
|
||||
This tutorial is supposed to be used by plugin or driver authors that would like to help their users
|
||||
to deal with complicated setup or configuration steps.
|
||||
本教程适用于希望帮助用户处理复杂配置或设置步骤的插件或驱动作者。
|
||||
|
||||
## Adding Doctor Checks
|
||||
## 添加 Doctor Checks
|
||||
|
||||
### Typing Requirements
|
||||
### 类型要求
|
||||
|
||||
The term `Doctor Check` literally describes a single javascript class instance that implements the
|
||||
[IDoctorCheck interface](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts).
|
||||
The interface defines the following methods and properties:
|
||||
术语 `Doctor Check` 的字面含义,是指一个实现了 [IDoctorCheck 接口](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts) 的 JavaScript 类实例。
|
||||
这个接口定义了以下方法和属性:
|
||||
|
||||
- `diagnose(): Promise<DoctorCheckResult>`: Contains the code to diagnose a possible issue
|
||||
- `fix(): Promise<string|null>`: Either fixes the actual problem if `hasAutofix()` returns true or
|
||||
returns a string description for possible manual fixes. If this method throws an exception named
|
||||
`FixSkippedError` and `hasAutofix()` returns true then the result of the method invocation
|
||||
is going to be ignored.
|
||||
- `hasAutofix(): boolean`: Whether calling `fix()` would resolve the found issue
|
||||
- `isOptional(): boolean`: Whether the found issue can be ignored and is not a showstopper
|
||||
- `log: AppiumLogger`: May be used for logging. This property may be assigned
|
||||
by the instance itself or by the Appium server if it is left unassigned.
|
||||
- `diagnose(): Promise<DoctorCheckResult>`:包含诊断某个问题的代码
|
||||
- `fix(): Promise<string|null>`:如果 `hasAutofix()` 返回 true,则修复实际问题;否则返回一段手动修复的说明。 如果此方法抛出名为 `FixSkippedError` 的异常,并且 `hasAutofix()` 返回 true,那么该调用结果将被忽略。
|
||||
- `hasAutofix(): boolean`:表示调用 `fix()` 是否能解决发现的问题
|
||||
- `isOptional(): boolean`:表示发现的问题是否可以被忽略且不是阻塞性问题
|
||||
- `log: AppiumLogger`:可用于日志输出。 这个属性可以由实例自行赋值,也可以由 Appium 服务在未赋值时自动提供。
|
||||
|
||||
The `DoctorCheckResult` object returned by the `diagnose()` method must contain the following properties:
|
||||
`diagnose()` 方法返回的 `DoctorCheckResult` 对象必须包含以下属性:
|
||||
|
||||
- `ok: boolean`: Whether the diagnosis found no issues
|
||||
- `optional: boolean`: Whether the diagnosed issue is safe to ignore
|
||||
- `message: string`: The text message describing the diagnostic result
|
||||
- `ok: boolean`:诊断是否未发现任何问题。
|
||||
- `optional: boolean`:诊断出的问题是否可以安全忽略。
|
||||
- `message: string`:描述诊断结果的文本信息。
|
||||
|
||||
### Manifest Requirements
|
||||
### 清单要求
|
||||
|
||||
A single extension may export multiple Doctor checks to Appium. In order for these checks to be properly
|
||||
picked up by the server CLI after the corresponding extension is installed they might be listed in the
|
||||
package .json manifest under the `appium.doctor.checks` section similar to the definition below:
|
||||
一个扩展可以向 Appium 导出多个 Doctor checks。 为了让这些检查项在对应扩展安装后能够被服务端 CLI 正确识别,它们需要在package .json 清单文件中列在 `appium.doctor.checks` 部分,格式类似下面这样:
|
||||
|
||||
```json
|
||||
// ...
|
||||
@@ -67,12 +55,11 @@ package .json manifest under the `appium.doctor.checks` section similar to the d
|
||||
// ...
|
||||
```
|
||||
|
||||
Also, it makes sense to include the [@appium/types](https://www.npmjs.com/package/@appium/types) import
|
||||
to the package dev dependencies.
|
||||
此外,建议将 [@appium/types](https://www.npmjs.com/package/@appium/types) 加入包的开发依赖中。
|
||||
|
||||
### Implementation Example
|
||||
### 实现示例
|
||||
|
||||
The below example is a "raw" Node.JS implementation that does not use any transpilation:
|
||||
下面是一个“原生”的 Node.js 实现示例,没有使用任何转译工具:
|
||||
|
||||
```js
|
||||
const {fs, doctor} = require('@appium/support');
|
||||
@@ -123,8 +110,7 @@ module.exports = {androidHomeCheck};
|
||||
*/
|
||||
```
|
||||
|
||||
This file could be saved as `doctor/android-home-check.js` and then added to the package.json manifest
|
||||
as
|
||||
这个文件可以保存为 `doctor/android-home-check.js`,然后再将其加入到 package.json 清单中,例如:
|
||||
|
||||
```json
|
||||
// ...
|
||||
|
||||
@@ -222,17 +222,24 @@ So you'll probably end up overriding `createSession`. You can do so by defining
|
||||
driver:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) {
|
||||
const [sessionId, caps] = super.createSession(w3cCaps);
|
||||
async createSession(w3cCaps) {
|
||||
const [sessionId, caps] = await super.createSession(w3cCaps);
|
||||
// do your own stuff here
|
||||
return [sessionId, caps];
|
||||
}
|
||||
```
|
||||
|
||||
For legacy reasons, your function will receive old-style JSON Wire Protocol desired and required
|
||||
caps as the first two arguments. Given that the old protocol isn't supported anymore and clients
|
||||
have all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion
|
||||
about what `otherDriverData` is about, see the section below on concurrent drivers).
|
||||
!!! warning "Deprecated"
|
||||
|
||||
```
|
||||
Older drivers may still define `createSession` with up to four parameters, e.g.
|
||||
`createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData)`. This shape is a holdover from the
|
||||
retired JSON Wire Protocol, which required desired and required caps as the first two
|
||||
arguments; only the first W3C-shaped argument was ever used. The `otherDriverData` parameter is
|
||||
likewise deprecated in favor of [IPC](#send-messages-to-plugins-running-on-the-same-session) for
|
||||
coordinating with other concurrently-running sessions. New drivers should use the single-argument
|
||||
form shown above.
|
||||
```
|
||||
|
||||
You'll want to make sure to call `super.createSession` in order to get the session ID as well as
|
||||
the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`
|
||||
@@ -522,14 +529,13 @@ route, then the route will not be proxied and instead will be handled by your dr
|
||||
example, we are avoiding proxying all `POST` routes that have the `appium` prefix.
|
||||
|
||||
Next, we have to set up the proxying itself. The way to do this is to use a special class from
|
||||
Appium called `JWProxy`. (The name means "JSON Wire Proxy" and is related to a legacy
|
||||
implementation of the protocol). You'll want to create a `JWProxy` object using the details required to
|
||||
connect to the remote server:
|
||||
Appium called `WebDriverProxy`. You'll want to create a `WebDriverProxy` object using the details
|
||||
required to connect to the remote server:
|
||||
|
||||
```js
|
||||
// import {JWProxy} from 'appium/driver';
|
||||
// import {WebDriverProxy} from 'appium/driver';
|
||||
|
||||
const proxy = new JWProxy({
|
||||
const proxy = new WebDriverProxy({
|
||||
server: 'remote.server',
|
||||
port: 1234,
|
||||
base: '/',
|
||||
@@ -541,8 +547,8 @@ this.proxyCommand = proxy.command.bind(proxy);
|
||||
|
||||
Here we are creating a proxy object and assigning some of its methods to `this` under the names
|
||||
`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget
|
||||
this step! The `JWProxy` has a variety of other options which you can check out in the source code,
|
||||
as well. (TODO: publish options as API docs and link here).
|
||||
this step! The `WebDriverProxy` has a variety of other options which you can check out in the
|
||||
source code as well.
|
||||
|
||||
Finally, we need a way to tell Appium when the proxy is active. For your driver it might always
|
||||
be active, or it might only be active when in a certain context. You can define the logic as an
|
||||
@@ -570,6 +576,33 @@ capability), and then to set an internal field to that value, so that it can be
|
||||
bidiProxyUrl`. Once all this is in place, Appium will proxy BiDi commands from the client straight
|
||||
to the upstream connection.
|
||||
|
||||
### Understand server-assigned driver properties and security flags
|
||||
|
||||
When your driver is running under the main Appium server, Appium assigns a small set of
|
||||
server-related properties on your driver instance when a session is created:
|
||||
|
||||
- `cliArgs`: Driver-specific configuration derived from the Appium server’s CLI flags and/or
|
||||
configuration files (for example via the `server.driver.<your-driver-name>` section). These
|
||||
options are **not** user capabilities and cannot be influenced directly by test code.
|
||||
- `server`, `serverHost`, `serverPort`, `serverPath`: Information about the HTTP server that is
|
||||
hosting your driver. These values reflect how the Appium server was started (for example the
|
||||
`--address`, `--port`, and `--base-path` flags) and are useful when your driver needs to construct
|
||||
URLs that point back to the Appium server itself (for example when setting up proxies, webhooks,
|
||||
or other callbacks).
|
||||
|
||||
`BaseDriver` and `AppiumDriver` also cooperate to expose security-related flags on your driver
|
||||
instance:
|
||||
|
||||
- `relaxedSecurityEnabled`: Indicates whether the server is running with relaxed security enabled
|
||||
(for example via `--relaxed-security`).
|
||||
- `allowInsecure`: A list of insecure features which are explicitly allowed for this driver (derived
|
||||
from server-level options like `--allow-insecure`).
|
||||
- `denyInsecure`: A list of insecure features which are explicitly disabled for this driver (derived
|
||||
from server-level options like `--deny-insecure`).
|
||||
|
||||
See [Hide behaviour behind security flags](#hide-behaviour-behind-security-flags) for how to use
|
||||
these flags in your driver (e.g. via `isFeatureEnabled` and `assertFeatureEnabled`).
|
||||
|
||||
### Extend the existing protocol with new commands
|
||||
|
||||
You may find that the existing commands don't cut it for your driver. If you want to expose
|
||||
@@ -772,6 +805,14 @@ that multiple simultaneous sessions don't use the same resources:
|
||||
3. Have each driver express what resources it is using, then examine currently-used resources from
|
||||
other drivers when a new session begins.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
```
|
||||
The `driverData`-based mechanism described below is deprecated. Prefer
|
||||
[IPC](#send-messages-to-plugins-running-on-the-same-session) for coordinating resources across
|
||||
concurrently-running sessions instead.
|
||||
```
|
||||
|
||||
To support this third strategy, you can implement `get driverData` in your driver to return what
|
||||
sorts of resources your driver is currently using, for example:
|
||||
|
||||
@@ -783,7 +824,7 @@ get driverData() {
|
||||
|
||||
Now, when a new session is started on your driver, the `driverData` response from any other
|
||||
simultaneously running drivers (of the same type) will also be included, as the last parameter of
|
||||
the `createSession` method:
|
||||
the deprecated, multi-argument form of the `createSession` method:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, driverData)
|
||||
@@ -864,3 +905,120 @@ this.onUnexpectedShutdown(handler)
|
||||
|
||||
`handler` should be a function which receives an error object (representing the reason for the
|
||||
unexpected shutdown).
|
||||
|
||||
### Send messages to plugins running on the same session
|
||||
|
||||
Appium's driver and plugin architecture means that a single driver and any number of plugins can be
|
||||
running together for a current session. The driver and plugins don't really know anything about
|
||||
each other though, which can make coordination potentially difficult. Without creating any kind of
|
||||
tight coupling between drivers or plugins, it's possible for drivers and plugins to communicate
|
||||
along a pub/sub style message bus. With Appium's IPC feature, "message" means a combination of
|
||||
"data" (the data intended to be published or received), and metadata (timestamp, the name of the
|
||||
publisher, etc...).
|
||||
|
||||
Drivers and plugins can implement an instance method called `async onIpcInit`, in which they will
|
||||
know that the IPC channel for the session is now active. At this point, they have access to the
|
||||
following methods:
|
||||
|
||||
#### `ipcSubscribe<T>(topic: string): IIpcSubscription`
|
||||
|
||||
This method allows a driver or plugin to subscribe to a topic on the IPC channel for the session.
|
||||
Topics are simply strings. To coordinate effectively, drivers or plugins would use the same topic
|
||||
string (so this would be something advertised in the driver/plugin documentation).
|
||||
|
||||
The result of this call is an `IpcSubscription` object that allows:
|
||||
|
||||
- Looping through messages on the topic via an async generator
|
||||
- Hooking up an event handler for new messages
|
||||
- Getting the last message sent on the topic
|
||||
- Publishing a message to the topic
|
||||
- Unsubscribing from the topic
|
||||
|
||||
#### `IpcSubscription` object
|
||||
|
||||
Here is an example of how subscribing and use of these subscription methods might work:
|
||||
|
||||
```ts
|
||||
async onIpcInit() {
|
||||
// we know at this point in our driver/plugin lifecycle that we can use IPC methods
|
||||
type MyMessageData = {myData: string}; // let's say the message data for this channel has this shape
|
||||
|
||||
const subscription = this.ipcSubscribe<MyMessageData>('coolTopic');
|
||||
|
||||
// listen for new messages on topic
|
||||
subscription.on('message', (message) => {
|
||||
console.log(message.data); // {myData: 'something'}
|
||||
});
|
||||
|
||||
// publish data to the topic; might throw if the data is larger than configured max size, or we
|
||||
// are no longer subscribed
|
||||
await subscription.publish({myData: 'hi'});
|
||||
|
||||
// get last message sent to topic
|
||||
const {data} = subscription.getMessage() ?? {data: null};
|
||||
// data = {myData: 'hi'}
|
||||
|
||||
// unsubscribe
|
||||
subscription.unsubscribe(); // returns true if we unsubscribed and false if no subscription existed
|
||||
}
|
||||
```
|
||||
|
||||
With a subscription object, we can also iterate async over it to receive new messages:
|
||||
|
||||
```ts
|
||||
for await (const message of subscription) {
|
||||
// here we have a message and can unwrap its data
|
||||
}
|
||||
```
|
||||
|
||||
Note that the iteration will stop when the subscription ends (i.e., when `unsubscribe` is called).
|
||||
|
||||
You can also check whether the subscription is still active (if your subscribe and unsubscribe
|
||||
logic is not locally connected):
|
||||
|
||||
```ts
|
||||
if (subscription.isActive) {
|
||||
// we know we have not yet unsubscribed
|
||||
}
|
||||
```
|
||||
|
||||
If the subscription is not active, attempts to call `subscription.publish` will throw an error.
|
||||
|
||||
#### `IpcMessage` object
|
||||
|
||||
When you get a message on a topic, it has the following shape:
|
||||
|
||||
```ts
|
||||
export type IpcMessage<T> = {
|
||||
publisher: string, // the id of the publishing object (typically of the form <ClassName>@<uniqueObjectId>)
|
||||
timestampMs: number, // when the message was published, in ms since epoch
|
||||
topic: string, // the topic the message was published on
|
||||
data: T, // the arbitrary message data. Must be serializable and a valid argument to 'structuredClone()'
|
||||
};
|
||||
```
|
||||
|
||||
#### IPC Notes
|
||||
|
||||
There are some important things to keep in mind when using Appium's IPC feature:
|
||||
|
||||
- IPC is only available once `onIpcInit` has been called, at the end of the `createSession` flow.
|
||||
It cannot be used statically or in `createSession` hooks
|
||||
- In sum, IPC is only for use during a session (this is also to prevent drivers/plugins from
|
||||
accessing or reading data sent on IPC channels in other sessions.)
|
||||
- The default max size of an IPC message is 1MB. This can be configured by the server-admin by
|
||||
using the `--max-ipc-data-size` arg (value is a number in bytes).
|
||||
- If a message exceeds the configured size, any call to `publish` methods will throw, so be
|
||||
sure to cover this case in your error handling.
|
||||
- The default max number of IPC topics per session is 1000. This can be configured by the
|
||||
server-admin using the `--max-ipc-topics` arg.
|
||||
- If the topic limit is reached, calls to `subscribe` or `publish` on a new topic will throw, so
|
||||
be sure to cover this case in your error handling.
|
||||
- Topic names exist within a global namespace per session. So if you don't want to clash with other
|
||||
drivers or plugins, make sure you prefix your topic names with something unique, akin to vendor
|
||||
prefixes in the WebDriver standard (for example: `fake-driver:some-topic`). We recommend the
|
||||
format `<namespace>:<topic>`.
|
||||
|
||||
To see examples of IPC in action, check out Appium's own
|
||||
[FakeDriver](https://github.com/appium/appium/blob/master/packages/fake-driver/lib/driver.ts) and
|
||||
[FakePlugin](https://github.com/appium/appium/blob/master/packages/fake-plugin/lib/plugin.ts)
|
||||
extensions, which showcase several ways of using IPC messages.
|
||||
|
||||
@@ -483,9 +483,9 @@ capability.
|
||||
You probably don't normally need to update the Appium server object (which is an
|
||||
[Express](https://expressjs.com/) server having already been
|
||||
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)
|
||||
in a variety of ways). But, for example, you could add new Express middleware to the server to
|
||||
support your plugin's requirements. To update the server you must implement the `static async
|
||||
updateServer` method in your class. This method takes three parameters:
|
||||
in a variety of ways). But, for example, you could add new routes to the server to support your
|
||||
plugin's requirements. To update the server you must implement the `static async updateServer`
|
||||
method in your class. This method takes three parameters:
|
||||
|
||||
- `expressApp`: the Express app object
|
||||
- `httpServer`: the Node HTTP server object
|
||||
@@ -498,6 +498,25 @@ results you'll need to test! Warning: this should be considered an advanced feat
|
||||
knowledge of Express, as well as the care not to do anything that could affect the operation of
|
||||
other parts of the Appium server!
|
||||
|
||||
`updateServer` runs _after_ Appium's own routes are registered, so `expressApp.use(...)` here
|
||||
won't see requests to paths Appium already owns — Express matches middleware and routes in
|
||||
registration order. For middleware that must see requests to those routes too (e.g. logging or
|
||||
auth), use `httpServer.frontRouter` instead: Appium mounts this
|
||||
[Router](https://expressjs.com/en/5x/api/router/) before any route is registered, so anything
|
||||
attached to it — even from inside `updateServer` — still runs ahead of route matching. Note this
|
||||
is still _after_ Appium's own baseline middleware (CORS, WebSocket upgrade handling, body
|
||||
parsing, etc.), so it won't see requests Appium itself has already rejected, e.g. a CORS
|
||||
preflight failure or a body that failed to parse:
|
||||
|
||||
```js
|
||||
static async updateServer(expressApp, httpServer, cliArgs) {
|
||||
httpServer.frontRouter.use((req, res, next) => {
|
||||
console.log(`Incoming request: ${req.method} ${req.url}`);
|
||||
next();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Handle unexpected session shutdown
|
||||
|
||||
When developing a plugin you may want to add some cleanup logic for when a session ends. You would
|
||||
@@ -518,3 +537,12 @@ async onUnexpectedShutdown(driver, cause) {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Send messages to the driver or other plugins running on the same session
|
||||
|
||||
Even though drivers and plugins don't know anything about each other, it's possible for them to
|
||||
send messages that other drivers or plugins can listen for, within the context of the same session,
|
||||
using an IPC channel. Given that the developer instructions for this feature are the same for
|
||||
drivers and plugins, please head over to the IPC development docs for
|
||||
drivers at the driver
|
||||
development guide.
|
||||
|
||||
@@ -29,7 +29,7 @@ In lieu of a separate file, configuration can be embedded in a project's `packag
|
||||
```
|
||||
|
||||
When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`
|
||||
will call into `lib/config-file.js` to load and/or search for a configuration file and in
|
||||
will call into `lib/bootstrap/config-file.js` to load and/or search for a configuration file and in
|
||||
`package.json`.
|
||||
|
||||
!!! note
|
||||
@@ -72,7 +72,7 @@ It is more straightforward to explain how config files are validated, so we'll s
|
||||
|
||||
### Validating Config Files
|
||||
|
||||
When a config file is found (`lib/config-file.js`), it will call the `validate` function exported
|
||||
When a config file is found (`lib/bootstrap/config-file.js`), it will call the `validate` function exported
|
||||
from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to
|
||||
validate the data against the schema that Appium has provided it.
|
||||
|
||||
|
||||
@@ -2,17 +2,14 @@
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Developing Appium Extensions
|
||||
title: 开发 Appium 扩展
|
||||
---
|
||||
|
||||
Appium is built with a modular structure, which means that Appium extensions (drivers and plugins)
|
||||
are decoupled from the main Appium module, and you only need to install the extensions that you
|
||||
want to use. This modular structure also unlocks the ability to develop entirely new extensions!
|
||||
Appium 采用模块化结构,这意味着 Appium 扩展(驱动和插件)与主 Appium 模块是解耦的;你只需要安装自己想要使用的扩展即可。 这种模块化结构还使得开发全新的扩展变得成为可能。
|
||||
|
||||
This section of the Appium documentation is intended to help aspiring developers with creating their
|
||||
own Appium extension:
|
||||
Appium 文档的这一部分,旨在帮助有志于开发者创建自己的 Appium 扩展:
|
||||
|
||||
- For creating a driver, see the [Build Drivers](./build-drivers.md) page
|
||||
- For creating a plugin, take a look at the [Build Plugins](build-plugins.md) page
|
||||
- Drivers and plugins both need documentation, so check out the [Build Documentation](./build-docs.md) page
|
||||
- For creating a doctor check, see the [Building Doctor Checks](./build-doctor-checks.md) page
|
||||
- 想要创建驱动,请查看 [构建驱动](./build-drivers.md) 页面
|
||||
- 想要创建插件,请查看 [构建插件](build-plugins.md) 页面
|
||||
- 驱动和插件都需要文档,因此请查看 [构建文档](./build-docs.md) 页面
|
||||
- 想要创建 Doctor check,请查看 [构建Doctor Checks](./build-doctor-checks.md) 页面
|
||||
|
||||
@@ -2,48 +2,38 @@
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Masking Sensitive Log Data
|
||||
title: 屏蔽敏感日志数据
|
||||
---
|
||||
|
||||
Since Appium server version 2.18.0 there is a possibility to mask sensitive
|
||||
values in logs. The below tutorial explains how to use this feature in third-party
|
||||
extensions.
|
||||
自 Appium server 2.18.0 版本起,已经具备了在日志中屏蔽敏感值的能力。 下面的教程将介绍如何在第三方扩展中使用这一功能。
|
||||
|
||||
## Why It Might Be Useful
|
||||
## 为什么这很有用
|
||||
|
||||
It is the right call to hide sensitive information, like passwords, tokens, etc.
|
||||
from server logs, so it does not accidentally leak if these logs end up in wrong hands.
|
||||
Appium server already provides a way to manipulate logs records via
|
||||
[filtering](../guides/log-filters.md), although it has its own limitations.
|
||||
The current approach is more sophisticated though, and requires some fine-tuning
|
||||
on the driver/plugin side.
|
||||
将密码、令牌等敏感信息从服务器日志中隐藏起来是合理且必要的,这样即使日志落入错误的人手中,也不会意外泄露敏感数据。
|
||||
Appium server 已经提供了一种通过 [过滤](../guides/log-filters.md) 来处理日志记录的方式,不过它本身存在一些限制。
|
||||
当前这种方法则更为先进,但需要驱动/插件侧进行一些细调。
|
||||
|
||||
## How To
|
||||
## 使用方法
|
||||
|
||||
The assumption is that your extension uses the standard built-in
|
||||
[@appium/logger](https://www.npmjs.com/package/@appium/logger).
|
||||
In order to get some value in logs replaced by a generic mask it is necessary:
|
||||
假设你的扩展使用的是标准内置的 [@appium/logger](https://www.npmjs.com/package/@appium/logger)。
|
||||
要让日志中的某个值被替换成通用的掩码,需要执行以下步骤:
|
||||
|
||||
- Change the logging expression to wrap sensitive values and format them, for example:
|
||||
- 将日志表达式改为包裹敏感值并进行格式化,例如:
|
||||
|
||||
```js
|
||||
this.log.info(`Value: ${value}`);
|
||||
this.log.info(`Value: ${value}`);
|
||||
```
|
||||
|
||||
becomes
|
||||
变为
|
||||
|
||||
```js
|
||||
import {logger} from '@appium/support';
|
||||
|
||||
this.log.info('Value: %s', logger.markSensitive(value));
|
||||
this.log.info('Value: %s', logger.markSensitive(value));
|
||||
```
|
||||
|
||||
The formatting happens via the standard Node.js's
|
||||
[util.format](https://nodejs.org/api/util.html#utilformatformat-args) API.
|
||||
格式化过程会通过标准的 Node.js [util.format](https://nodejs.org/api/util.html#utilformatformat-args) API 完成。
|
||||
|
||||
- While sending the appropriate server request, where this log line is used and should be masked,
|
||||
add the custom header `X-Appium-Is-Sensitive` with its value set to `1` or `true` (case-insensitive).
|
||||
Without such header the above log value is not going to be masked.
|
||||
This way it is possible to conditionally mask log records depending on which
|
||||
request is being handled by the extension if the log expression is used in the
|
||||
common section.
|
||||
- 在发送相应的服务器请求时,如果这个日志行被使用并且应该被掩码处理,请额外添加自定义请求头 `X-Appium-Is-Sensitive`,其值为 `1` 或 `true`(大小写不敏感)。
|
||||
如果没有这个请求头,上述日志值将不会被掩码处理。
|
||||
这样就可以根据扩展处理的具体请求来有条件地屏蔽日志记录;如果日志表达式位于公共部分,就可以在这里统一控制。
|
||||
|
||||
@@ -56,6 +56,13 @@ automation capabilities using Appium.
|
||||
}
|
||||
```
|
||||
|
||||
### [Skills](https://github.com/appium/skills)
|
||||
|
||||
A set of AI Agent skills to support Appium automation, for example:
|
||||
|
||||
- Help preparing Appium test environment from scratch, including common driver setup
|
||||
- Help preparing XCUITest driver and WebDriverAgent for real device automation
|
||||
|
||||
## Extension Tools
|
||||
|
||||
Appium driver or plugin developers can choose to include these tools in their driver/plugin:
|
||||
@@ -83,6 +90,18 @@ out the documentation on [Building Doctor Checks](../developing/build-doctor-che
|
||||
|
||||
These tools are not maintained by the Appium team:
|
||||
|
||||
### [AppClaw](https://github.com/AppiumTestDistribution/AppClaw)
|
||||
|
||||
AppClaw is a CLI-based agentic AI layer for mobile automation, powered by [Appium MCP](#appium-mcp).
|
||||
Agent instructions can be passed directly via CLI, or defined as YAML flows in either structured
|
||||
or natural language syntax.
|
||||
|
||||
Supported by: `@AppiumTestDistribution`
|
||||
|
||||
```sh title="Install This Tool"
|
||||
npm install -g appclaw
|
||||
```
|
||||
|
||||
### [Appium Installer](https://github.com/AppiumTestDistribution/appium-installer)
|
||||
|
||||
Appium Installer is a command-line tool for simplifying setups of new Appium test environments.
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
title: Session Capabilities
|
||||
---
|
||||
|
||||
"Capabilities" is the name given to the set of parameters used to start an Appium session. The
|
||||
information in the set describes what sort of "capabilities" you want your session to have, for
|
||||
example, a certain mobile operating system or a certain version of a device. Capabilities are
|
||||
represented as key-value pairs, with values allowed to be any valid JSON type, including
|
||||
other objects.
|
||||
Capabilities are the core parameters used to start an Appium session. They describe various
|
||||
features that you want your session to have, for example, a certain mobile operating system or a
|
||||
certain version of a device. Capabilities are represented as key-value pairs, with values allowed
|
||||
to be any valid JSON type, including other objects. Most importantly, they cannot be changed
|
||||
during the lifecycle of the session.
|
||||
|
||||
The W3C WebDriver spec's [section on Capabilities](https://w3c.github.io/webdriver/#capabilities)
|
||||
identifies a small set of 10 standard capabilities, including the following:
|
||||
The capabilities used in Appium follow [the W3C WebDriver specification of the same name](https://w3c.github.io/webdriver/#capabilities).
|
||||
The WebDriver spec defines a small set of standard capabilities, including the following:
|
||||
|
||||
| Capability Name | Type | Description |
|
||||
| ---------------- | -------- | ---------------------------------------------- |
|
||||
@@ -17,68 +17,64 @@ identifies a small set of 10 standard capabilities, including the following:
|
||||
| `browserVersion` | `string` | The specific version of the browser |
|
||||
| `platformName` | `string` | The type of platform hosting the browser |
|
||||
|
||||
While the above capabilities are commonly used by Appium drivers, they are not sufficient for
|
||||
describing Appium-specific features, such as the name of the driver to use, or the name of the app
|
||||
to launch. In order to achieve this, Appium defines its own [extension capabilities](https://w3c.github.io/webdriver/#dfn-extension-capability).
|
||||
|
||||
## Common Appium Capabilities
|
||||
|
||||
Appium understands these browser-focused capabilities, but introduces a number of additional
|
||||
capabilities. According to the WebDriver spec, any
|
||||
non-standard "extension capabilities" must include a namespace prefix (signifying the vendor
|
||||
introducing the capability), ending in a `:`. Appium's vendor prefix is
|
||||
`appium:`, and so any Appium-specific capabilities must include this prefix. Depending on which
|
||||
client you are using, the prefix may be added automatically or in conjunction with certain
|
||||
interfaces, but it is always a good practice to explicitly include it for clarity.
|
||||
According to the WebDriver spec, extension capabilities must include a namespace prefix (signifying
|
||||
the vendor introducing the capability), and the namespace must end a colon (`:`). Appium's vendor
|
||||
prefix is `appium:`, and so any Appium-specific capabilities must include this prefix. Depending on
|
||||
your Appium client, the prefix may be added automatically or in conjunction with certain interfaces,
|
||||
but it is always a good practice to explicitly include it for clarity.
|
||||
|
||||
Here is a list of all the globally-recognized Appium capabilities:
|
||||
Here are a few commonly (but not universally!) used Appium-specific capabilities:
|
||||
|
||||
!!! info
|
||||
| Capability Name | Type | Description |
|
||||
| ----------------------- | -------- | --------------------------------------------------------------- |
|
||||
| `appium:automationName` | `string` | The name of the Appium driver to use |
|
||||
| `appium:udid` | `string` | The unique device identifier of a particular device to automate |
|
||||
| `appium:app` | `string` | The path to an installable application |
|
||||
|
||||
```
|
||||
Individual drivers and plugins can support other capabilities, so refer to their documentation
|
||||
for lists of specific capability names. Some drivers may also not support all of these capabilities
|
||||
```
|
||||
All capabilities recognized by the Appium base driver (inherited by all drivers) can be found in the
|
||||
[Capabilities Reference document](../reference/session/caps.md). While this common capability set
|
||||
is fairly small, it can be greatly extended by Appium drivers and plugins, who can (and should)
|
||||
define their own capabilities. Make sure to reference their documentation to learn more about the
|
||||
capabilities they support. You can find a list of known drivers in the [Ecosystem Drivers](../ecosystem/drivers.md) document.
|
||||
|
||||
| <div style="width:12em">Capability</div> | Type | Required? | Description |
|
||||
| ---------------------------------------- | --------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `platformName` | `string` | yes | The type of platform hosting the app or browser |
|
||||
| `appium:automationName` | `string` | yes | The name of the Appium driver to use |
|
||||
| `browserName` | `string` | no | The name of the browser to launch and automate, if the driver supports web browsers as a special case |
|
||||
| `appium:app` | `string` | no | The path to an installable application |
|
||||
| `appium:deviceName` | `string` | no | The name of a particular device to automate, e.g., `iPhone 14` (currently only actually useful for specifying iOS simulators, since in other situations it's typically recommended to use a specific device id via the `appium:udid` capability). |
|
||||
| `appium:platformVersion` | `string` | no | The version of a platform, e.g., for iOS, `16.0` |
|
||||
| `appium:newCommandTimeout` | `number` | no | The number of seconds the Appium server should wait for clients to send commands before deciding that the client has gone away and the session should shut down. `60` seconds by default. Setting it to zero disables the timer. |
|
||||
| `appium:noReset` | `boolean` | no | If true, instruct an Appium driver to avoid its usual reset logic during session start and cleanup (default `false`) |
|
||||
| `appium:fullReset` | `boolean` | no | If true, instruct an Appium driver to augment its usual reset logic with additional steps to ensure maximum environmental reproducibility (default `false`) |
|
||||
| `appium:eventTimings` | `boolean` | no | If true, instruct an Appium driver to collect [Event Timings](./event-timing.md) (default `false`) |
|
||||
| `appium:printPageSourceOnFindFailure` | `boolean` | no | If true, collect the page source and print it to the Appium log whenever a request to find an element fails (default `false`) |
|
||||
Drivers are also able to place more complex constraints on capabilities as a group. For example,
|
||||
the XCUITest driver recommends that at least one of `browserName`, `appium:app`, or `appium:bundleId`
|
||||
is included in the capabilities, otherwise it will not be able to auto-install or auto-launch any
|
||||
application. Each driver will document how it interprets these capabilities and any other
|
||||
platform-specific requirements.
|
||||
|
||||
Some drivers place more complex constraints on capabilities as a group. For example, while the
|
||||
`appium:app` and `browserName` capabilities are listed above as optional, if you want to launch
|
||||
a session with a specific app, the XCUITest driver requires that at least one of `appium:app`,
|
||||
`browserName`, or `appium:bundleId` are included in the capabilities (otherwise it will not know
|
||||
what app to install and/or launch and will simply open a session on the home screen). Each driver
|
||||
will document how it interprets these capabilities and any other platform-specific requirements.
|
||||
The way to construct capabilities and start a session will likely differ depending on your Appium
|
||||
client. For examples of doing this in each client library, head to the [Ecosystem Clients](../ecosystem/clients.md)
|
||||
page and click through to the appropriate client documentation.
|
||||
|
||||
!!! note
|
||||
|
||||
```
|
||||
Capabilities are like parameters used when starting a session. After the capabilities are sent
|
||||
and the session is started, they cannot be changed. If a driver supports updating aspects of
|
||||
its behaviour in the course of a session, it will provide a [Setting](./settings.md) for this
|
||||
purpose instead of, or in addition to, a capability.
|
||||
Once your capabilities are sent to the server and the session is started, they cannot be
|
||||
changed. If a driver supports updating its behaviour during a session, it will use the
|
||||
[Settings API](./settings.md) for this purpose.
|
||||
```
|
||||
|
||||
Each Appium client has its own way of constructing capabilities and starting a session. For
|
||||
examples of doing this in each client library, head to the [Ecosystem](../ecosystem/index.md) page
|
||||
and click through to the appropriate client documentation.
|
||||
|
||||
## BiDi Protocol Support
|
||||
|
||||
Appium supports [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol since base–driver 9.5.0.
|
||||
The actual behavior depends on individual drivers while the Appium and the baseーdriver support the protocol.
|
||||
Please make sure if a driver supports the protocol and what kind of commands/events it supports in the documentation.
|
||||
In addition to the standard WebDriver protocol (now known as WebDriver Classic), Appium supports the
|
||||
[WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol. Support for this protocol is
|
||||
opt-in, and requires the use of the standard `webSocketUrl` capability.
|
||||
|
||||
| Capability Name | Type | Description |
|
||||
| --------------- | --------- | ------------------------------------------------------- |
|
||||
| `webSocketUrl` | `boolean` | To enable BiDi protocol in the session. |
|
||||
| Capability Name | Type | Description |
|
||||
| --------------- | --------- | ----------------------------------------------- |
|
||||
| `webSocketUrl` | `boolean` | Whether BiDi protocol is enabled in the session |
|
||||
|
||||
All BiDi commands supported by the Appium base driver (inherited by all drivers) can be found in the
|
||||
[BiDi Protocol API Reference document](../reference/api/bidi.md). Similarly to WebDriver Classic
|
||||
commands, individual Appium drivers and plugins can define their own supported standard and custom
|
||||
BiDi commands, so make sure to reference their documentation.
|
||||
|
||||
## Using `appium:options` to Group Capabilities
|
||||
|
||||
@@ -124,8 +120,7 @@ creates in response to a new session request. This is through the concept of "al
|
||||
!!! note
|
||||
|
||||
```
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or
|
||||
a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) for
|
||||
a more in-depth description of how capabilities are processed.
|
||||
```
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user