Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0095bfd47 | ||
|
|
15b783179d | ||
|
|
66ff497600 | ||
|
|
846dd52886 | ||
|
|
4a896b7dc8 | ||
|
|
e69f7fd1ad | ||
|
|
76cc279ad9 | ||
|
|
bdc0bf4670 | ||
|
|
db4ed63de4 | ||
|
|
46278a1752 | ||
|
|
958fca47c8 | ||
|
|
00cd1b4b0f | ||
|
|
809477c70c | ||
|
|
6bbb81724d | ||
|
|
4dc0a07884 | ||
|
|
438b9da543 | ||
|
|
de17d3762e | ||
|
|
e3f7bd07f7 | ||
|
|
ed6c6dd544 | ||
|
|
b56b180f34 | ||
|
|
12969268fe | ||
|
|
b312028d7e | ||
|
|
8d7cec96d8 | ||
|
|
0e443d2799 | ||
|
|
5c41112134 | ||
|
|
dd52d04b21 | ||
|
|
0e52da4b3a | ||
|
|
98eed2d13f | ||
|
|
371568da36 | ||
|
|
56618886ed | ||
|
|
ab12235483 | ||
|
|
08f05562c1 | ||
|
|
a1d35404a2 | ||
|
|
a16c4c9521 | ||
|
|
a2b0ba8773 | ||
|
|
796ca9f98f | ||
|
|
69e9abeed3 | ||
|
|
cabc114935 | ||
|
|
aa86ef9603 | ||
|
|
656ba166e1 | ||
|
|
e8886ae0d2 | ||
|
|
122a1863de | ||
|
|
0bbd2f8a76 | ||
|
|
f03816cca5 | ||
|
|
e1e478cf32 | ||
|
|
c799629b7d | ||
|
|
1d9821352a | ||
|
|
b8b0e42f69 | ||
|
|
6a8f26a9cb | ||
|
|
e65c1cdaed | ||
|
|
da7a4fdce8 | ||
|
|
f344504f15 | ||
|
|
f0de55da0d | ||
|
|
6704491be0 | ||
|
|
2a68d05b4d | ||
|
|
5553016582 | ||
|
|
9879d9f9b8 | ||
|
|
517828be57 | ||
|
|
e791a9b30c | ||
|
|
c2ccc80438 | ||
|
|
a56f0f820a | ||
|
|
b88ff49f80 | ||
|
|
5bde635d19 | ||
|
|
175b7acc27 | ||
|
|
507f2ba8b5 | ||
|
|
1ae1fe9c44 | ||
|
|
c70faded35 | ||
|
|
e922e9738c | ||
|
|
0899725aab | ||
|
|
62be085f95 | ||
|
|
cb9fb9c6fe | ||
|
|
82c5caf0b5 | ||
|
|
bcbb8ee86e | ||
|
|
980aa69b93 | ||
|
|
1cae549a7b | ||
|
|
ef163eb8df | ||
|
|
8c3b3005be | ||
|
|
056baba3a0 | ||
|
|
0ee7716cf0 | ||
|
|
3d674d0085 | ||
|
|
bbe3b6c6e5 | ||
|
|
42d7ed8afe | ||
|
|
5b8cb76ea3 | ||
|
|
d5959902bc | ||
|
|
1d066073dc | ||
|
|
048ce520d8 | ||
|
|
19fb9d608f | ||
|
|
38afce5ea5 | ||
|
|
63cb664af1 | ||
|
|
51c3063194 | ||
|
|
750872af47 | ||
|
|
32645ba726 | ||
|
|
f5f0aa5068 | ||
|
|
00dc1eddaa | ||
|
|
3bf1eaf5a9 | ||
|
|
75710ab823 | ||
|
|
7fe67a286a | ||
|
|
38cc8a343f | ||
|
|
511ff11220 | ||
|
|
ce36003edb | ||
|
|
0e51b9b8b9 | ||
|
|
da3f9ff881 | ||
|
|
dcb6de22ea | ||
|
|
8f20c973f4 | ||
|
|
89e8d2e4d4 | ||
|
|
b692914a95 | ||
|
|
a83f8eee9b | ||
|
|
f583e99e60 | ||
|
|
21dd13e5e5 | ||
|
|
45681602c0 | ||
|
|
efdb1ce6ce | ||
|
|
b6c97cd11e | ||
|
|
fedabb1fdc | ||
|
|
49ac8126a2 | ||
|
|
894c193150 | ||
|
|
688af4ddb4 | ||
|
|
c8e7fa642f | ||
|
|
449dbe9a5c | ||
|
|
2468aeca60 | ||
|
|
9a66f48001 | ||
|
|
ec04635925 | ||
|
|
035e30b892 | ||
|
|
893fc040e1 | ||
|
|
482a1f7bbf | ||
|
|
d17d022224 | ||
|
|
46085635a9 | ||
|
|
db28605532 | ||
|
|
a5ea99aacd | ||
|
|
880111b0ff | ||
|
|
d6cdd3b05f | ||
|
|
326942d8ac | ||
|
|
622b245ea3 | ||
|
|
5034f1afc6 | ||
|
|
a97f3893e6 | ||
|
|
edf2593e17 | ||
|
|
7a14f9f929 | ||
|
|
b4612e0c7a | ||
|
|
8a307a078b | ||
|
|
0ffca811ce | ||
|
|
89f2e25a6c | ||
|
|
7aac098d60 | ||
|
|
32f57500e8 | ||
|
|
1ca77c6ded | ||
|
|
92b32f8524 | ||
|
|
c1c3957cb7 | ||
|
|
885570e7ca | ||
|
|
8413ccb4fa | ||
|
|
82b7515867 | ||
|
|
2957b8344b | ||
|
|
ea86eff938 | ||
|
|
b98dc4f46f | ||
|
|
61276f2e7c | ||
|
|
9625052d05 | ||
|
|
0c755f503c | ||
|
|
a2294fa716 | ||
|
|
32fae41c03 | ||
|
|
0e8e3c7144 | ||
|
|
96b45a85cf | ||
|
|
e08e7ebec2 | ||
|
|
a0be939031 | ||
|
|
bb26085f7e | ||
|
|
75e0788784 | ||
|
|
7b3f0b5dbb | ||
|
|
9eb65f7ad4 | ||
|
|
47405dda8a | ||
|
|
5a9ab97924 | ||
|
|
4494fad3af | ||
|
|
6a97fe48ae | ||
|
|
d35ed1c8ac | ||
|
|
d5ef0f9c86 | ||
|
|
139dbaeef6 | ||
|
|
2d7b2c4b4c | ||
|
|
6488a0a4e1 | ||
|
|
6b9d844998 | ||
|
|
8ee816d0cf | ||
|
|
b1b7c33edd | ||
|
|
57dc6a045d | ||
|
|
75289711ee | ||
|
|
b7b97a24d6 | ||
|
|
715942845b | ||
|
|
8d79467da8 | ||
|
|
dcfec17d1c | ||
|
|
c38e639d52 | ||
|
|
74292e2292 | ||
|
|
8ccaf09877 | ||
|
|
d3d77a38df | ||
|
|
0149490522 | ||
|
|
16015de1b5 | ||
|
|
b7999aed03 | ||
|
|
1fa8c54765 | ||
|
|
8565209fda | ||
|
|
f8819836b5 | ||
|
|
ac912606e7 | ||
|
|
dcac55711c | ||
|
|
821ed01ae2 | ||
|
|
62fe09d563 | ||
|
|
8894b9adf7 | ||
|
|
44e423110a | ||
|
|
41a18f3b68 | ||
|
|
c2f3a618e4 | ||
|
|
5ce3b0c1aa | ||
|
|
177dff4f0e | ||
|
|
e7665d1cd9 | ||
|
|
34b636082f | ||
|
|
06607da92e | ||
|
|
9d6bbdb13e | ||
|
|
234ad59798 | ||
|
|
fe1b926886 | ||
|
|
5281f5a01a | ||
|
|
86f843b9e1 | ||
|
|
5226fa897b | ||
|
|
19928e9b90 | ||
|
|
e43c7a4dce | ||
|
|
82e40c1400 | ||
|
|
f3d959ef91 | ||
|
|
e8a838417a | ||
|
|
9773a23b26 | ||
|
|
cc10b65ee5 | ||
|
|
530045ec53 | ||
|
|
8e0fa2c1b3 | ||
|
|
d0d7548576 | ||
|
|
c7198b13e4 | ||
|
|
4279cc6cee | ||
|
|
a746eefbbb | ||
|
|
b6de85359d | ||
|
|
f2c8b69608 | ||
|
|
87fc50c2af | ||
|
|
f25079354b | ||
|
|
189bce88a0 | ||
|
|
15234bc055 | ||
|
|
073447ae4a | ||
|
|
dd070dc51d | ||
|
|
2882e71631 | ||
|
|
c106326169 | ||
|
|
5203480df6 | ||
|
|
52ae52a90a | ||
|
|
d5e5186cb7 | ||
|
|
541246184d | ||
|
|
faf9623a65 | ||
|
|
bc388db111 | ||
|
|
bdea13130c | ||
|
|
cc23c22b60 | ||
|
|
f675abc27b | ||
|
|
6fa0ed57ff | ||
|
|
57bbb7f46d | ||
|
|
d2b24daba0 | ||
|
|
14d27fe2a4 | ||
|
|
19845531f5 | ||
|
|
3cc878d835 | ||
|
|
4345a40a15 | ||
|
|
89e5f7e8db | ||
|
|
9469aaef0e | ||
|
|
2b12d5974a | ||
|
|
45cc948671 | ||
|
|
192f1f3793 | ||
|
|
5baf93672d | ||
|
|
c670010ec7 | ||
|
|
4a07f82cec | ||
|
|
b28b524957 | ||
|
|
f40598161c | ||
|
|
0ddedec0c4 | ||
|
|
def3474b05 | ||
|
|
1b9c1e96a3 | ||
|
|
e60e840316 | ||
|
|
6505d7921a | ||
|
|
def655cb39 | ||
|
|
1828501c66 | ||
|
|
6a08c95fc9 | ||
|
|
a156bc5bf5 | ||
|
|
dbc3b668a0 | ||
|
|
69bbb5370e | ||
|
|
ea00626091 | ||
|
|
1e86537e94 | ||
|
|
93c271ec5d | ||
|
|
0363aab8ba | ||
|
|
dd421b397b | ||
|
|
8ee7d07af4 | ||
|
|
1c19a8dbba | ||
|
|
1ed646cc8f | ||
|
|
d4ce2a82d9 | ||
|
|
40def9dbdb | ||
|
|
b3f8a47c2d | ||
|
|
5b043cc1ab | ||
|
|
3fbc4f1fe0 | ||
|
|
7492c3357e | ||
|
|
7fd9d5f626 | ||
|
|
5f25351c9d | ||
|
|
339acd345f | ||
|
|
21316e94d0 | ||
|
|
43fcc17b31 | ||
|
|
b1a4045bbd | ||
|
|
d2a8edbb7a | ||
|
|
6d67177e2f | ||
|
|
db62358dba | ||
|
|
4fd6893146 | ||
|
|
8915934270 | ||
|
|
ae7f74a014 | ||
|
|
ea9cf8d910 | ||
|
|
70449cd077 | ||
|
|
65c47acf59 | ||
|
|
96a7a3f23b | ||
|
|
c8f997973c | ||
|
|
bea47aacca | ||
|
|
10e5b37211 | ||
|
|
459f0a34b2 | ||
|
|
4c15dc6e5d | ||
|
|
848eb00afb | ||
|
|
de8b1c97dc | ||
|
|
092ebb2a69 | ||
|
|
dddc4aa8c0 | ||
|
|
425d3eac1d | ||
|
|
57b0406a33 | ||
|
|
e3e1757c56 | ||
|
|
17e271afff | ||
|
|
7718cd01d1 |
@@ -16,7 +16,7 @@ _Put an `x` in the boxes that apply_
|
||||
|
||||
_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
|
||||
|
||||
- [ ] I have read the [CONTRIBUTING](https://github.com/appium/appium/blob/master/CONTRIBUTING.md) doc
|
||||
- [ ] I have read the [Contributing Guide](https://appium.io/docs/en/latest/contributing/)
|
||||
- [ ] I have signed the CLA
|
||||
- [ ] Lint and unit tests pass locally with my changes
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
|
||||
@@ -48,16 +48,6 @@ labels:
|
||||
matcher:
|
||||
files: ['packages/base-driver/**']
|
||||
|
||||
- label: '@appium/eslint-config-appium'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/eslint-config-appium/**']
|
||||
|
||||
- label: '@appium/eslint-config-appium-ts'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/eslint-config-appium-ts/**']
|
||||
|
||||
- label: '@appium/base-plugin'
|
||||
sync: true
|
||||
matcher:
|
||||
@@ -78,6 +68,16 @@ labels:
|
||||
matcher:
|
||||
files: ['packages/driver-test-support/**']
|
||||
|
||||
- label: '@appium/eslint-config-appium'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/eslint-config-appium/**']
|
||||
|
||||
- label: '@appium/eslint-config-appium-ts'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/eslint-config-appium-ts/**']
|
||||
|
||||
- label: '@appium/execute-driver-plugin'
|
||||
sync: true
|
||||
matcher:
|
||||
@@ -98,6 +98,11 @@ labels:
|
||||
matcher:
|
||||
files: ['packages/images-plugin/**']
|
||||
|
||||
- label: '@appium/logger'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/logger/**']
|
||||
|
||||
- label: '@appium/opencv'
|
||||
sync: true
|
||||
matcher:
|
||||
@@ -123,6 +128,11 @@ labels:
|
||||
matcher:
|
||||
files: ['packages/support/**']
|
||||
|
||||
- label: '@appium/strongbox'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/strongbox/**']
|
||||
|
||||
- label: '@appium/test-support'
|
||||
sync: true
|
||||
matcher:
|
||||
@@ -142,8 +152,3 @@ labels:
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/universal-xml-plugin/**']
|
||||
|
||||
- label: '@appium/strongbox'
|
||||
sync: true
|
||||
matcher:
|
||||
files: ['packages/strongbox/**']
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
useRollingCache: true
|
||||
install-command: npm ci
|
||||
- name: Install dependencies (Python)
|
||||
run: pip install -r packages/docutils/requirements.txt
|
||||
run: PIP_BREAK_SYSTEM_PACKAGES=1 pip install -r packages/docutils/requirements.txt
|
||||
- name: Configure Git User
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
useRollingCache: true
|
||||
install-command: npm ci
|
||||
- name: Install dependencies (Python)
|
||||
run: pip install -r packages/docutils/requirements.txt
|
||||
run: PIP_BREAK_SYSTEM_PACKAGES=1 pip install -r packages/docutils/requirements.txt
|
||||
- name: Publish docs
|
||||
run: |
|
||||
cd packages/appium
|
||||
|
||||
@@ -37,6 +37,9 @@ certificate.key
|
||||
*.pdb
|
||||
.vs
|
||||
|
||||
#vscode
|
||||
.history
|
||||
|
||||
old
|
||||
.tern-project
|
||||
coverage
|
||||
@@ -60,5 +63,6 @@ appium.zip
|
||||
**/build-fixtures/**
|
||||
*.tsbuildinfo
|
||||
packages/*/LICENSE
|
||||
\!packages/*/LICENSE
|
||||
local_appium_home
|
||||
*.tgz
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
require: [require.resolve('./test/setup.js')],
|
||||
require: ['ts-node/register'],
|
||||
// forbids use of .only() in CI
|
||||
forbidOnly: Boolean(process.env.CI),
|
||||
color: true,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>appium/appium//renovate/default"],
|
||||
"schedule": ["after 10pm and before 5:00am"],
|
||||
"schedule": [
|
||||
"after 10pm",
|
||||
"before 5:00am"
|
||||
],
|
||||
"timezone": "America/Vancouver"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Appium contains many different modules and supports a variety of drivers, plugin
|
||||
|
||||
## Main Appium Module
|
||||
|
||||
* ### [Appium 2.0 Changelog](packages/appium/CHANGELOG.md)
|
||||
* ### [Appium 2 Changelog](packages/appium/CHANGELOG.md)
|
||||
* [Appium 1.x Changelog](https://github.com/appium/appium/blob/1.x/CHANGELOG.md)
|
||||
|
||||
## Appium Drivers / Clients / Plugins
|
||||
@@ -23,6 +23,7 @@ Appium contains many different modules and supports a variety of drivers, plugin
|
||||
* [fake-driver](packages/fake-driver/CHANGELOG.md)
|
||||
* [fake-plugin](packages/fake-plugin/CHANGELOG.md)
|
||||
* [images-plugin](packages/images-plugin/CHANGELOG.md)
|
||||
* [logger](packages/logger/CHANGELOG.md)
|
||||
* [opencv](packages/opencv/CHANGELOG.md)
|
||||
* [plugin-test-support](packages/plugin-test-support/CHANGELOG.md)
|
||||
* [relaxed-caps-plugin](packages/relaxed-caps-plugin/CHANGELOG.md)
|
||||
@@ -31,6 +32,5 @@ Appium contains many different modules and supports a variety of drivers, plugin
|
||||
* [support](packages/support/CHANGELOG.md)
|
||||
* [test-support](packages/test-support/CHANGELOG.md)
|
||||
* [tsconfig](packages/tsconfig/CHANGELOG.md)
|
||||
* [typedoc-plugin-appium](packages/typedoc-plugin-appium/CHANGELOG.md)
|
||||
* [types](packages/types/CHANGELOG.md)
|
||||
* [universal-xml-plugin](packages/universal-xml-plugin/CHANGELOG.md)
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
# Contributing to Appium
|
||||
|
||||
There are a lot of different ways to contribute to Appium. See below for
|
||||
everything you can do and the processes to follow for each contribution method.
|
||||
Note that no matter how you contribute, your participation is governed by our
|
||||
[Code of Conduct](CONDUCT.md).
|
||||
|
||||
### Make changes to the Appium code or docs
|
||||
|
||||
Fork the project, make a change, and send a pull request! Please have a look at
|
||||
our [Style Guide](/docs/en/contributing-to-appium/style-guide.md) before
|
||||
getting to work. Please make sure the unit and functional tests pass before
|
||||
sending a pull request; for more information on how to run tests, keep reading!
|
||||
|
||||
Make sure you read and follow the setup instructions in the README first. And note
|
||||
that all participation in the Appium community (including code submissions) is
|
||||
governed by our [Code of Conduct](CONDUCT.md). Then, have a look at our
|
||||
[running from source doc](/docs/en/contributing-to-appium/appium-from-source.md) for more
|
||||
information on how to get set up to run tests and start slinging code.
|
||||
|
||||
You will probably also want to have a look at this more in-depth [Developer's
|
||||
Overview](/docs/en/contributing-to-appium/developers-overview.md) of the Appium
|
||||
project, how Appium is architected, how to make changes to modules, and so on.
|
||||
|
||||
Finally, before we accept your code, you will need to have signed our
|
||||
[Contributor License
|
||||
Agreement](https://cla.js.foundation/appium/appium).
|
||||
|
||||
### Become an Appium Triager
|
||||
|
||||
You can help us manage our issue tracker! All you need is enough familiarity
|
||||
with Appium to try and reproduce bugs. We triage issues by having conversations
|
||||
with the issue creator and then either closing the issue or moving it into the
|
||||
[Bugs](https://github.com/appium/appium/milestones/Bugs) or
|
||||
[Features](https://github.com/appium/appium/milestones/Features) milestone. We
|
||||
use these buckets as the backlogs for our upcoming releases.
|
||||
|
||||
We use this "algorithm" for triaging issues, which anyone can jump in and follow:
|
||||
|
||||
1. If issue is a feature request, discuss amongst Appium devs.
|
||||
* If we decide to build it, add to the Features milestone.
|
||||
* If we decide not to build it, just close.
|
||||
2. If issue is a bug report, attempt to verify
|
||||
* If it's a duplicate, close with link to bug already reported.
|
||||
* If it ultimately can't be verified, close until we have enough information to verify (e.g., in most cases we need a full set of Appium logs to help diagnose an issue).
|
||||
* If the user hasn't provided enough information, keep asking for enough information to verify.
|
||||
* If it's a verified new bug, add it to the Bugs milestone.
|
||||
* If we have been waiting for a reply from the user for over 3 weeks, close.
|
||||
|
||||
If you're interested in joining our triage rotation, contact
|
||||
[@jlipps](https://github.com/jlipps) or
|
||||
[@imurchie](https://github.com/imurchie).
|
||||
|
||||
### Help out on our forums
|
||||
|
||||
We can always use help on our forums at
|
||||
[discuss.appium.io](https://discuss.appium.io)! Hop on over and see if there
|
||||
are any questions that you can answer.
|
||||
|
||||
### Submit bug reports or feature requests
|
||||
|
||||
Just use the GitHub issue tracker to submit your bug reports and feature
|
||||
requests. If you are submitting a bug report, please follow the [issue template](https://github.com/appium/appium/issues/new).
|
||||
@@ -67,10 +67,9 @@ significant contributions to the project but are no longer actively committing.
|
||||
|
||||
### Other Contributors
|
||||
|
||||
Other, less formal, kinds of contribution are outlined in our
|
||||
[CONTRIBUTING](/CONTRIBUTING.md) doc. We also very much appreciate those who spend their valuable
|
||||
time assisting with the [Appium forums](https://discuss.appium.io). Current high-level forum
|
||||
contributors and mods include:
|
||||
Other, less formal, kinds of contribution are outlined in our [Contributing Guide](https://appium.io/docs/en/latest/contributing/).
|
||||
We also very much appreciate those who spend their valuable time assisting with the [Appium forums](https://discuss.appium.io).
|
||||
Current high-level forum contributors and mods include:
|
||||
|
||||
* [aleksei](https://discuss.appium.io/u/aleksei/summary)
|
||||
* [wreed](https://discuss.appium.io/u/wreed/summary)
|
||||
@@ -83,7 +82,7 @@ related to contributions of funds. Both are extremely important to the ongoing h
|
||||
project. Financial sponsorship is mediated through our [OpenCollective page](https://opencollective.com/appium).
|
||||
Sponsorship tiers and benefits are described below:
|
||||
|
||||
- **Development Partners**: The primary need of any open source project is for sustained maintenance and contributorship. Companies that officially sponsor such development with dedicated employee time are recognized as Development Partners, and receive the same benefits as the highest tier of financial sponsorship. To be considered a Development Partner, a company must devote at least 50% of a full-time employee's time to Appium maintenance.
|
||||
- **Development Partners**: The primary need of any open source project is for sustained maintenance and contributorship. Companies that officially sponsor such development with dedicated employee time are recognized as Development Partners, and receive the same benefits as the highest tier of financial sponsorship. To be considered a Development Partner, a company must devote at least 50% of a full-time employee's time to Appium maintenance. This means that the contributors designated by the company must have been appointed as "committers" in good standing of one or more core Appium repositories. (See above for a description of how to become a committer).
|
||||
- **Strategic Partners**: Representing the highest tier of ongoing financial support for the project, Strategic Partners are what make our compensation scheme for contributors possible, and we thank them for their significant investment into the project! More than financial contribution, Strategic Partners help elevate Appium's position in the industry through marketing and evangelism efforts, and partner with the Appium team to help make Appium better. Along with the Development Partners, Strategic Partners have their logos displayed prominently on our website, and have the ability to link to their Appium-related products in a few relevant places in our documentation.
|
||||
- **Gold, Silver, and Bronze Sponsors**: these sponsorship levels correspond to different amounts of recurring financial contribution that generously support our contributor compensation scheme. Sponsors at these levels also have the opportunity to display their logo on our website.
|
||||
- **Backers**: individuals who benefit from the Appium project can also donate on a one-time or recurring basis, at any amount, and will be recognized as Backers for their contribution!
|
||||
@@ -91,7 +90,7 @@ Sponsorship tiers and benefits are described below:
|
||||
To become a sponsor at one of these levels, follow the process indicated at the [OpenCollective
|
||||
page](https://opencollective.com/appium).
|
||||
|
||||
### Compensation for TC Members, Committers, Contributors, and upstream projects
|
||||
### Compensation Scheme
|
||||
|
||||
With funds received through sponsorship, the Appium project wants to incentivize contributions of
|
||||
code, documentation efforts, maintenance, and project leadership. We have developed a scheme
|
||||
|
||||
@@ -2,18 +2,22 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://appium.io/">
|
||||
<img alt="Appium" src="https://raw.githubusercontent.com/appium/appium/master/packages/appium/docs/assets/images/appium-logo-horiz.png" width="500">
|
||||
<img alt="Appium" src="https://raw.githubusercontent.com/appium/appium/master/packages/appium/docs/overrides/assets/images/appium-logo-horiz.png" width="500">
|
||||
</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
Cross-platform test automation for native, hybrid, mobile web and desktop apps.
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
|
||||
[](https://github.com/vshymanskyy/StandWithUkraine/)
|
||||
|
||||
</div>
|
||||
|
||||
***
|
||||
|
||||
<p align="center"><b>
|
||||
@@ -21,7 +25,7 @@
|
||||
<a href="https://appium.io/docs/en/latest/intro/">Get Started</a> |
|
||||
<a href="https://appium.io/docs/en/latest/ecosystem/">Ecosystem</a> |
|
||||
<a href="https://github.com/appium/appium/blob/master/packages/appium/CHANGELOG.md">Changelog</a> |
|
||||
<a href="https://github.com/appium/appium/blob/master/ROADMAP.md">Roadmap</a> |
|
||||
<a href="https://appium.io/docs/en/latest/contributing/">Contributing Guide</a> |
|
||||
<a href="https://discuss.appium.io">Discussion Forum</a>
|
||||
</b></p>
|
||||
|
||||
@@ -178,8 +182,41 @@ cross-platform native app automation, for mobile and beyond!
|
||||
If you are looking for a more comprehensive description of what this is all about, please read our
|
||||
documentation on [How Does Appium Work?](https://appium.io/docs/en/latest/intro/appium/).
|
||||
|
||||
## Sponsors
|
||||
|
||||
Appium has a [Sponsorship Program](GOVERNANCE.md#sponsorship)! If you or your company uses Appium
|
||||
and wants to give back financially to the project, we use these funds to [encourage development and
|
||||
contributions](GOVERNANCE.md#compensation-scheme), as well as support other open source projects we
|
||||
rely on. [Become a sponsor](https://opencollective.com/appium) via our OpenCollective page.
|
||||
|
||||
### Development and Strategic Partners
|
||||
|
||||
Appium is incredibly grateful to our Development and Strategic Partners for their sustained
|
||||
contribution of project development and leadership!
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
|
||||
<picture>
|
||||
<source srcset="packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png" media="(prefers-color-scheme: dark)"/>
|
||||
<source srcset="packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-light.png" media="(prefers-color-scheme: light)"/>
|
||||
<img src="packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png" width="300" alt="Browserstack"/>
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner"><img src="packages/appium/docs/overrides/assets/images/sponsor-logo-sauce.png"
|
||||
width="300" alt="Sauce Labs" /></a>
|
||||
</p>
|
||||
|
||||
### Other Sponsors
|
||||
|
||||
A full list of sponsors is available at our [Sponsors page](https://appium.io/docs/en/latest/sponsors/).
|
||||
|
||||
## License
|
||||
|
||||
[Apache-2.0](./LICENSE)
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)
|
||||
|
||||
`@appium/logger` package is under [ISC](./packages/logger/LICENSE) License.
|
||||
|
||||
@@ -1,35 +1,3 @@
|
||||
# Sponsors & Backers
|
||||
|
||||
Appium is an Apache-2 licensed open source project whose development is made possible entirely by
|
||||
donations of time and money by individuals and companies who benefit from our software and our
|
||||
mission. If you'd like to join this amazing group and help ensure Appium's continued development
|
||||
and maintenance, you can contribute via [Appium's OpenCollective
|
||||
Hub](https://opencollective.com/appium).
|
||||
|
||||
## Development Partners
|
||||
|
||||
We are very grateful for the support of our Development Partners, who donate Appium development and
|
||||
maintenance as part of their employees' core job duties!
|
||||
|
||||
* *Coming Soon!*
|
||||
|
||||
## Strategic Partners
|
||||
|
||||
We are very grateful for the financial and marketing support of our exclusive Strategic Partners,
|
||||
who contribute a significant ongoing investment of funds to help the project attract and reward
|
||||
contributors!
|
||||
|
||||
* *Coming Soon!*
|
||||
|
||||
## Gold Sponsors
|
||||
|
||||
* [Become a Gold Sponsor](https://opencollective.com/appium/contribute/gold-sponsor-72877/checkout?interval=month&amount=500&contributeAs=me)
|
||||
|
||||
## Silver Sponsors
|
||||
|
||||
* [Become a Silver Sponsor](https://opencollective.com/appium/contribute/silver-sponsor-72876/checkout?interval=month&amount=250&contributeAs=me)
|
||||
|
||||
## Bronze Sponsors
|
||||
|
||||
- [MagicPod](https://magicpod.com/en/)
|
||||
* [Become a Bronze Sponsor](https://opencollective.com/appium/contribute/sponsors-70690/checkout?interval=month&amount=100&contributeAs=me)
|
||||
Please check [Sponsors & Backers](https://appium.io/docs/en/latest/sponsors/)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
This documentation is a note for the opencollective payout.
|
||||
|
||||
1. Select `Submit expense`
|
||||
|
||||
<img width="200" alt="Screenshot 2024-09-17 at 11 04 32 PM" src="https://github.com/user-attachments/assets/5d598a46-8aa3-41e0-aadc-ce3f34b10f6b">
|
||||
|
||||
2. Select `Invoice`
|
||||
3. Type proper account name in `Who is being paid for this expense?`
|
||||
- The form depends on the target user
|
||||
4. Select `Next`
|
||||
5. Input expense info and complete the form. Then, the user will recieve the expense info.
|
||||
- Expense title: `<year-month> contribution payout`
|
||||
- e.g. `2024-07 contribution payout`
|
||||
- Description in "Set invoice details"
|
||||
- for TCs:
|
||||
- `<year-month> contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`
|
||||
- i.e. `2024-07 contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`
|
||||
- for individuals
|
||||
- `PR contribution: <PRs>` for PRs. `Community contribution in Q&A forum at https://discuss.appium.io/` for appium forums
|
||||
- E.g.
|
||||
- `PR contribution: https://github.com/appium/dotnet-client/pull/810, https://github.com/appium/dotnet-client/pull/808`
|
||||
- `PR contribution: https://github.com/appium/java-client/pull/2206, https://github.com/appium/java-client/pull/2203 and a few PRs`
|
||||
- `Community contribution in Q&A forum at https://discuss.appium.io/`
|
||||
- Amount
|
||||
- Type the amount in `USD`
|
||||
6. Approve each expense after getting response for each expense
|
||||
|
||||
<img width="500" alt="Screenshot 2024-09-11 at 8 40 35 PM" src="https://github.com/user-attachments/assets/462cda69-1ce7-458c-b319-dda87cf10d65">
|
||||
@@ -42,8 +42,9 @@
|
||||
"dev:docs": "npm run -w packages/appium dev:docs",
|
||||
"docs": "npm run -w packages/appium build:docs",
|
||||
"docs:preview": "npm run -w packages/appium build:docs:preview",
|
||||
"docs:publish": "npm run -w packages/appium publish:docs",
|
||||
"doctor": "node ./packages/doctor",
|
||||
"generate-docs": "npm run --workspace=packages/appium generate-docs",
|
||||
"install-docs-deps": "npm run -w packages/appium install-docs-deps",
|
||||
"lint": "eslint .",
|
||||
"lint:ci": "eslint --quiet .",
|
||||
"lint:fix": "run-s \"lint -- --fix\"",
|
||||
@@ -59,12 +60,13 @@
|
||||
"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": "sync-monorepo-packages --fields=author,license,bugs,homepage,engines",
|
||||
"sync-pkgs:common-fields:default": "sync-monorepo-packages --packages=\"!packages/logger\" --fields=author,license,bugs,homepage,engines",
|
||||
"sync-pkgs:common-fields:logger": "sync-monorepo-packages --packages=\"packages/logger\" --fields=author,bugs,homepage,engines",
|
||||
"sync-pkgs:keywords": "sync-monorepo-packages --field=keywords --packages=\"packages/*\" --packages=\"!packages/eslint-config-appium\" --packages=\"!packages/types\" --packages=\"!packages/eslint-config-appium-ts\" ",
|
||||
"sync-pkgs:license": "sync-monorepo-packages --force --no-package-json LICENSE",
|
||||
"sync-pkgs:license": "sync-monorepo-packages --force --no-package-json --packages=\"!packages/logger\" LICENSE",
|
||||
"test": "run-s test:quick",
|
||||
"test:ci": "run-s test:smoke test:unit test:types test:e2e",
|
||||
"test:e2e": "lerna run --concurrency=2 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",
|
||||
@@ -82,59 +84,54 @@
|
||||
"devDependencies": {
|
||||
"@colors/colors": "1.6.0",
|
||||
"@tsconfig/node14": "14.1.2",
|
||||
"@types/chai": "4.3.16",
|
||||
"@types/chai-as-promised": "7.1.8",
|
||||
"@types/diff": "5.2.1",
|
||||
"@types/mocha": "10.0.6",
|
||||
"@types/node": "20.12.12",
|
||||
"@types/chai": "5.0.0",
|
||||
"@types/chai-as-promised": "8.0.1",
|
||||
"@types/diff": "5.2.3",
|
||||
"@types/mocha": "10.0.9",
|
||||
"@types/node": "20.17.0",
|
||||
"@types/semver": "7.5.8",
|
||||
"@types/sinon": "17.0.3",
|
||||
"@types/sinon-chai": "3.2.12",
|
||||
"@types/sinon-chai": "4.0.0",
|
||||
"@types/source-map-support": "0.5.10",
|
||||
"@types/teen_process": "2.0.4",
|
||||
"@types/ws": "8.5.10",
|
||||
"@types/yargs": "17.0.32",
|
||||
"@typescript-eslint/eslint-plugin": "7.10.0",
|
||||
"@typescript-eslint/parser": "7.10.0",
|
||||
"@types/ws": "8.5.12",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@typescript-eslint/eslint-plugin": "7.18.0",
|
||||
"@typescript-eslint/parser": "7.18.0",
|
||||
"asyncbox": "3.0.0",
|
||||
"chai": "4.4.1",
|
||||
"chai-as-promised": "7.1.2",
|
||||
"chai-webdriverio-async": "3.0.0",
|
||||
"chai": "5.1.2",
|
||||
"chai-as-promised": "8.0.0",
|
||||
"conventional-changelog-conventionalcommits": "7.0.2",
|
||||
"cpy-cli": "5.0.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-find-rules": "4.1.0",
|
||||
"eslint-import-resolver-typescript": "3.6.1",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-mocha": "10.4.3",
|
||||
"eslint-plugin-promise": "6.2.0",
|
||||
"fancy-log": "2.0.0",
|
||||
"finalhandler": "1.2.0",
|
||||
"eslint-find-rules": "4.2.0",
|
||||
"eslint-import-resolver-typescript": "3.6.3",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-mocha": "10.5.0",
|
||||
"eslint-plugin-promise": "6.6.0",
|
||||
"finalhandler": "1.3.1",
|
||||
"get-port": "5.1.1",
|
||||
"json-schema-to-typescript": "14.0.4",
|
||||
"lerna": "8.1.3",
|
||||
"json-schema-to-typescript": "15.0.2",
|
||||
"lerna": "8.1.8",
|
||||
"log-symbols": "4.1.0",
|
||||
"midnight-smoker": "8.0.0",
|
||||
"mjpeg-consumer": "2.0.0",
|
||||
"mjpeg-server": "0.3.1",
|
||||
"mocha": "10.4.0",
|
||||
"mocha-chai-jest-snapshot": "1.1.4",
|
||||
"npm-run-all2": "6.2.0",
|
||||
"prettier": "3.2.5",
|
||||
"mocha": "10.7.3",
|
||||
"npm-run-all2": "6.2.6",
|
||||
"prettier": "3.3.3",
|
||||
"rewiremock": "3.14.5",
|
||||
"rimraf": "5.0.7",
|
||||
"serve-static": "1.15.0",
|
||||
"sinon": "18.0.0",
|
||||
"sinon-chai": "3.7.0",
|
||||
"rimraf": "5.0.10",
|
||||
"serve-static": "1.16.2",
|
||||
"sinon": "19.0.2",
|
||||
"sync-monorepo-packages": "1.0.2",
|
||||
"through2": "4.0.2",
|
||||
"ts-node": "10.9.2",
|
||||
"tsd": "0.31.0",
|
||||
"typescript": "5.4.5",
|
||||
"tsd": "0.31.2",
|
||||
"typescript": "5.6.3",
|
||||
"validate.js": "0.13.1",
|
||||
"webdriverio": "8.38.0",
|
||||
"ws": "8.17.0",
|
||||
"webdriverio": "8.40.6",
|
||||
"ws": "8.18.0",
|
||||
"yaml-js": "0.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -146,10 +143,10 @@
|
||||
},
|
||||
"overrides": {
|
||||
"@sidvind/better-ajv-errors": {
|
||||
"ajv": "8.14.0"
|
||||
"ajv": "8.17.1"
|
||||
},
|
||||
"ajv-formats": {
|
||||
"ajv": "8.14.0"
|
||||
"ajv": "8.17.1"
|
||||
},
|
||||
"http-cache-semantics": "4.1.1"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,215 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.12.1](https://github.com/appium/appium/compare/appium@2.12.0...appium@2.12.1) (2024-10-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **docutils:** restore support for Python <3.12 ([#20675](https://github.com/appium/appium/issues/20675)) ([00cd1b4](https://github.com/appium/appium/commit/00cd1b4b0fcf24d0014dac780223e5866f39c9ce))
|
||||
* **support:** update definitelytyped ([#20691](https://github.com/appium/appium/issues/20691)) ([846dd52](https://github.com/appium/appium/commit/846dd5288608d886f924d2791291475c956d53f7))
|
||||
|
||||
|
||||
|
||||
## [2.12.0](https://github.com/appium/appium/compare/appium@2.11.5...appium@2.12.0) (2024-10-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** Make server graceful shutdown timeout configurable via command line args ([#20641](https://github.com/appium/appium/issues/20641)) ([5661888](https://github.com/appium/appium/commit/56618886ed007df3c28ce98beb4ff91bc47da2a2))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** update dependency winston to v3.15.0 ([ab12235](https://github.com/appium/appium/commit/ab12235483262a1c5a1dd8a32b1792a4b096bfc6))
|
||||
* **docutils:** support Python 3.12+ ([#20666](https://github.com/appium/appium/issues/20666)) ([8d7cec9](https://github.com/appium/appium/commit/8d7cec96d8df60644493a7e2f735b4bb0d3783be))
|
||||
* **docutils:** update dependency yaml to v2.6.0 ([ed6c6dd](https://github.com/appium/appium/commit/ed6c6dd5441e26fc1eb58de9b78def49d930a128))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v8.40.6 ([796ca9f](https://github.com/appium/appium/commit/796ca9f98f69616b9c890325bbfb0c573a8bc765))
|
||||
|
||||
|
||||
|
||||
## [2.11.5](https://github.com/appium/appium/compare/appium@2.11.4...appium@2.11.5) (2024-09-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Return hostname as web socket url for BiDi if a broadcast address is assigned to the server ([#20603](https://github.com/appium/appium/issues/20603)) ([f0de55d](https://github.com/appium/appium/commit/f0de55da0da2fc0305876a948704c1f0a2a5990f))
|
||||
|
||||
|
||||
|
||||
## [2.11.4](https://github.com/appium/appium/compare/appium@2.11.3...appium@2.11.4) (2024-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Fix the condition for secure websocket ([#20497](https://github.com/appium/appium/issues/20497)) ([efdb1ce](https://github.com/appium/appium/commit/efdb1ce6ce1de5120f2f35ebe84abfa73ed5198a))
|
||||
* **appium:** update dependency @sidvind/better-ajv-errors to v3 ([#20552](https://github.com/appium/appium/issues/20552)) ([0ee7716](https://github.com/appium/appium/commit/0ee7716cf0644cfc6795f0949d8253d4c0b36597))
|
||||
* **appium:** update dependency winston to v3.14.2 ([#20465](https://github.com/appium/appium/issues/20465)) ([893fc04](https://github.com/appium/appium/commit/893fc040e16ec07c83d12c7c89180d962b0f6e68))
|
||||
* **base-driver:** Add a server flag to check if it operates a secure protocol ([#20449](https://github.com/appium/appium/issues/20449)) ([622b245](https://github.com/appium/appium/commit/622b245ea38793280d9785a59a0416ce025862fe))
|
||||
* **docutils:** update dependency yaml to v2.5.1 ([750872a](https://github.com/appium/appium/commit/750872af4756d2efcd19fe98762f82ecaa59d59a))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v8.40.3 ([4608563](https://github.com/appium/appium/commit/46085635a92c3a2b2b1b3ecf3966a174248a2829))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v8.40.5 ([dcb6de2](https://github.com/appium/appium/commit/dcb6de22eaabdcea2517cd9b7db120d681f0e38e))
|
||||
* **support:** update dependency axios to v1.7.4 ([d17d022](https://github.com/appium/appium/commit/d17d0222245ab94a78e578c0398734e65a89ba68))
|
||||
* **support:** update dependency axios to v1.7.5 ([fedabb1](https://github.com/appium/appium/commit/fedabb1fdc7af10f9e4b06ea23815c4bc7c6bf5e))
|
||||
* **support:** update dependency axios to v1.7.7 ([7fe67a2](https://github.com/appium/appium/commit/7fe67a286a15a917ce3b1b47a08e982e65bbd9e4))
|
||||
* **types:** update dependency type-fest to v4 ([#20467](https://github.com/appium/appium/issues/20467)) ([482a1f7](https://github.com/appium/appium/commit/482a1f7bbfbf6478ee09bb1668b830ddbf13b143))
|
||||
* **types:** update dependency type-fest to v4 ([#20471](https://github.com/appium/appium/issues/20471)) ([9a66f48](https://github.com/appium/appium/commit/9a66f4800141cc86c90d58ca1103bab0066081bc))
|
||||
* **types:** update dependency type-fest to v4 ([#20548](https://github.com/appium/appium/issues/20548)) ([5b8cb76](https://github.com/appium/appium/commit/5b8cb76ea3cda75095e79c91539be73feeadf869))
|
||||
* **types:** update dependency type-fest to v4.26.0 ([#20511](https://github.com/appium/appium/issues/20511)) ([8f20c97](https://github.com/appium/appium/commit/8f20c973f4a6d3380163b6afd7f113808453a62d))
|
||||
|
||||
|
||||
|
||||
## [2.11.3](https://github.com/appium/appium/compare/appium@2.11.2...appium@2.11.3) (2024-08-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** update dependency ajv to v8.17.1 ([7528971](https://github.com/appium/appium/commit/75289711ee344ac9a11a572f13ddb0471e2cbf79))
|
||||
* **appium:** update dependency winston to v3.13.1 ([dcfec17](https://github.com/appium/appium/commit/dcfec17d1ceab90939b5f199854ba630829e3d1f))
|
||||
* **docutils:** update dependency yaml to v2.5.0 ([0c755f5](https://github.com/appium/appium/commit/0c755f503c49e459315616e51be0c0776089b2bb))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v8.40.0 ([#20442](https://github.com/appium/appium/issues/20442)) ([b4612e0](https://github.com/appium/appium/commit/b4612e0c7a21902a3cab658fbdc05f3b48c55d0d))
|
||||
* **logger:** update dependency lru-cache to v10.4.3 ([#20364](https://github.com/appium/appium/issues/20364)) ([8d79467](https://github.com/appium/appium/commit/8d79467da8a0733ac3e49b9152bd6905989a57ca))
|
||||
* **support:** update dependency axios to v1.7.3 ([1ca77c6](https://github.com/appium/appium/commit/1ca77c6dedbff4552aba9c97cf5406c7552d1a01))
|
||||
* **support:** update dependency semver to v7.6.3 ([5a9ab97](https://github.com/appium/appium/commit/5a9ab9792402e31d3903fb1a3b08329a67b6a2a2))
|
||||
* **types:** update dependency type-fest to v4.22.0 ([#20387](https://github.com/appium/appium/issues/20387)) ([47405dd](https://github.com/appium/appium/commit/47405dda8a5de17c72fb721b0c043e0dd4f6b35a))
|
||||
* **types:** update dependency type-fest to v4.23.0 ([#20396](https://github.com/appium/appium/issues/20396)) ([0e8e3c7](https://github.com/appium/appium/commit/0e8e3c71441d02d22f015f08df5223909f5fbb93))
|
||||
|
||||
|
||||
|
||||
## [2.11.2](https://github.com/appium/appium/compare/appium@2.11.1...appium@2.11.2) (2024-07-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** update dependency ws to v8.18.0 ([44e4231](https://github.com/appium/appium/commit/44e423110ad6c8bd7d846cc334fafe931fea43f9))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v8.39.1 ([c2f3a61](https://github.com/appium/appium/commit/c2f3a618e413c7f21057ba6d9002dc1fe4507e6f))
|
||||
* **support:** update dependency teen_process to v2.1.10 ([86f843b](https://github.com/appium/appium/commit/86f843b9e1fc56576d7a08bf95838a58971e98b3))
|
||||
* **support:** update dependency teen_process to v2.1.7 ([5226fa8](https://github.com/appium/appium/commit/5226fa897b90e9fec9be3e79a7d48fc7b4e0016d))
|
||||
* **support:** update dependency teen_process to v2.2.0 ([06607da](https://github.com/appium/appium/commit/06607da92e93d015747fd6d6d5bdabe1b3ac58d2))
|
||||
* **types:** update dependency type-fest to v4.21.0 ([#20335](https://github.com/appium/appium/issues/20335)) ([8894b9a](https://github.com/appium/appium/commit/8894b9adf709646108cc8d6426bbb690550609f2))
|
||||
|
||||
|
||||
|
||||
## [2.11.1](https://github.com/appium/appium/compare/appium@2.11.0...appium@2.11.1) (2024-06-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **images-plugin:** update dependency lru-cache to v10.3.0 ([#20306](https://github.com/appium/appium/issues/20306)) ([e43c7a4](https://github.com/appium/appium/commit/e43c7a4dce1f50fbd4d028cbeac5677422210b20))
|
||||
|
||||
|
||||
|
||||
## [2.11.0](https://github.com/appium/appium/compare/appium@2.10.3...appium@2.11.0) (2024-06-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** Improve context logging ([#20250](https://github.com/appium/appium/issues/20250)) ([f675abc](https://github.com/appium/appium/commit/f675abc27b3e6beac2431cc71afb5fc2c2f70534))
|
||||
* **appium:** show extension update info message for newer major versions ([#20283](https://github.com/appium/appium/issues/20283)) ([f2c8b69](https://github.com/appium/appium/commit/f2c8b696085ba862553476f23509cac0674a447c))
|
||||
* **appium:** show spinner during extension uninstall ([#20282](https://github.com/appium/appium/issues/20282)) ([f250793](https://github.com/appium/appium/commit/f25079354bfd646810813ae47244a1e2e962dbfb))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** update dependency ws to v8.17.1 ([d2b24da](https://github.com/appium/appium/commit/d2b24daba056373160d680ec5f017b28e9cbde1a))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v8.39.0 ([faf9623](https://github.com/appium/appium/commit/faf9623a65868a6330d062076074da7c1c3acb2a))
|
||||
* **support:** update dependency teen_process to v2.1.5 ([bc388db](https://github.com/appium/appium/commit/bc388db1116f411f4b241105f5feae30418c9a27))
|
||||
* **support:** update dependency teen_process to v2.1.6 ([5412461](https://github.com/appium/appium/commit/541246184dc7521c825ec1902775e681ea6f0db3))
|
||||
* **types:** update dependency type-fest to v4.20.1 ([#20255](https://github.com/appium/appium/issues/20255)) ([1984553](https://github.com/appium/appium/commit/19845531f558e2b16dfae807c768e1b9f2cab25d))
|
||||
|
||||
|
||||
|
||||
## [2.10.3](https://github.com/appium/appium/compare/appium@2.10.2...appium@2.10.3) (2024-06-11)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.10.2](https://github.com/appium/appium/compare/appium@2.10.1...appium@2.10.2) (2024-06-11)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.10.1](https://github.com/appium/appium/compare/appium@2.10.0...appium@2.10.1) (2024-06-11)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.10.0](https://github.com/appium/appium/compare/appium@2.9.0...appium@2.10.0) (2024-06-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** Add a possibility to print logs in json format ([#20224](https://github.com/appium/appium/issues/20224)) ([1e86537](https://github.com/appium/appium/commit/1e86537e944f6beb7dbe72b35c267ae1dd9ebd36))
|
||||
* **appium:** Add session signature to all logs ([#20202](https://github.com/appium/appium/issues/20202)) ([#20214](https://github.com/appium/appium/issues/20214)) ([0363aab](https://github.com/appium/appium/commit/0363aab8ba4fe0ec49845db2f493001aa873578b)), closes [#20222](https://github.com/appium/appium/issues/20222)
|
||||
* **logger:** Add the debug level to the default logger ([#20219](https://github.com/appium/appium/issues/20219)) ([8ee7d07](https://github.com/appium/appium/commit/8ee7d07af4e2375d2eb7c23badaaac34685bc59c))
|
||||
* **support:** Move SecureValuesPreprocessor to @appum/logger ([#20228](https://github.com/appium/appium/issues/20228)) ([dbc3b66](https://github.com/appium/appium/commit/dbc3b668a0a7a815d23f1cae4207d435fc09034d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **docutils:** update dependency lilconfig to v3.1.2 ([1828501](https://github.com/appium/appium/commit/1828501c66d0c5f8f295c67cd12d6691f8020780))
|
||||
* **docutils:** update dependency yaml to v2.4.5 ([6a08c95](https://github.com/appium/appium/commit/6a08c95fc9bda5cf39b8a6d98e5394658355a38e))
|
||||
* **types:** update dependency type-fest to v4.20.0 ([#20227](https://github.com/appium/appium/issues/20227)) ([ea00626](https://github.com/appium/appium/commit/ea00626091e3ce87f6e3ed7a61003295272835e3))
|
||||
|
||||
|
||||
|
||||
## [2.9.0](https://github.com/appium/appium/compare/appium@2.8.0...appium@2.9.0) (2024-06-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** Add session signature to all logs ([#20202](https://github.com/appium/appium/issues/20202)) ([b3f8a47](https://github.com/appium/appium/commit/b3f8a47c2d3fa029bdb5592d7130c6d1664e53b5))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Revert changes in 20203 and 20202 ([#20209](https://github.com/appium/appium/issues/20209)) ([40def9d](https://github.com/appium/appium/commit/40def9dbdbde64706111900967d66735257b7404)), closes [#20202](https://github.com/appium/appium/issues/20202) [#20203](https://github.com/appium/appium/issues/20203)
|
||||
|
||||
|
||||
|
||||
## [2.8.0](https://github.com/appium/appium/compare/appium@2.7.0...appium@2.8.0) (2024-06-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **logger:** Add the 'debug' level to the default logger ([#20203](https://github.com/appium/appium/issues/20203)) ([7fd9d5f](https://github.com/appium/appium/commit/7fd9d5f6261b385c234580c2bfee4d576905458b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add logger dependencies in package.json ([#20205](https://github.com/appium/appium/issues/20205)) ([3fbc4f1](https://github.com/appium/appium/commit/3fbc4f1fe07eadf9c7a2ef8fc9f4ba78dc3486a3))
|
||||
|
||||
|
||||
|
||||
## [2.7.0](https://github.com/appium/appium/compare/appium@2.6.0...appium@2.7.0) (2024-06-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** Replace npmlog with the local fork ([#20190](https://github.com/appium/appium/issues/20190)) ([8915934](https://github.com/appium/appium/commit/8915934270243bfb46c4d104a098ce1cc481b0ff))
|
||||
* **base-driver:** Make addition of search query params to cache optional ([#20195](https://github.com/appium/appium/issues/20195)) ([21316e9](https://github.com/appium/appium/commit/21316e94d05b2f97aa0349a82da229713e92446c))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** ensure ws close code is valid ([#20178](https://github.com/appium/appium/issues/20178)) ([65c47ac](https://github.com/appium/appium/commit/65c47acf5954bbf1947e896ef79c81a9b3c712a5))
|
||||
* **appium:** update dependency ajv to v8.16.0 ([ae7f74a](https://github.com/appium/appium/commit/ae7f74a0144d233653443622a84d49b1cb4e6222))
|
||||
* **docutils:** update dependency yaml to v2.4.3 ([848eb00](https://github.com/appium/appium/commit/848eb00afbd1cab76a6a1c3d0f4a2a0b1acee0d0))
|
||||
* **execute-driver-plugin:** update dependency webdriverio to v8.38.2 ([c8f9979](https://github.com/appium/appium/commit/c8f997973cc21673f95d02c92d43a2981b8713b8))
|
||||
* **support:** update dependency teen_process to v2.1.4 ([96a7a3f](https://github.com/appium/appium/commit/96a7a3f23bead7c1d18700550138cd2d70ce5e3c))
|
||||
* **types:** update dependency type-fest to v4.19.0 ([#20193](https://github.com/appium/appium/issues/20193)) ([db62358](https://github.com/appium/appium/commit/db62358dbac25de2a75fdc7493338d98b1422c84))
|
||||
|
||||
|
||||
|
||||
## [2.6.0](https://github.com/appium/appium/compare/appium@2.5.4...appium@2.6.0) (2024-05-27)
|
||||
|
||||
|
||||
|
||||
@@ -2,18 +2,22 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://appium.io/">
|
||||
<img alt="Appium" src="https://raw.githubusercontent.com/appium/appium/master/packages/appium/docs/assets/images/appium-logo-horiz.png" width="500">
|
||||
<img alt="Appium" src="https://raw.githubusercontent.com/appium/appium/master/packages/appium/docs/overrides/assets/images/appium-logo-horiz.png" width="500">
|
||||
</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
Cross-platform test automation for native, hybrid, mobile web and desktop apps.
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
|
||||
[](https://github.com/vshymanskyy/StandWithUkraine/)
|
||||
|
||||
</div>
|
||||
|
||||
***
|
||||
|
||||
<p align="center"><b>
|
||||
@@ -21,7 +25,7 @@
|
||||
<a href="https://appium.io/docs/en/latest/intro/">Get Started</a> |
|
||||
<a href="https://appium.io/docs/en/latest/ecosystem/">Ecosystem</a> |
|
||||
<a href="https://github.com/appium/appium/blob/master/packages/appium/CHANGELOG.md">Changelog</a> |
|
||||
<a href="https://github.com/appium/appium/blob/master/ROADMAP.md">Roadmap</a> |
|
||||
<a href="https://appium.io/docs/en/latest/contributing/">Contributing Guide</a> |
|
||||
<a href="https://discuss.appium.io">Discussion Forum</a>
|
||||
</b></p>
|
||||
|
||||
@@ -178,8 +182,41 @@ cross-platform native app automation, for mobile and beyond!
|
||||
If you are looking for a more comprehensive description of what this is all about, please read our
|
||||
documentation on [How Does Appium Work?](https://appium.io/docs/en/latest/intro/appium/).
|
||||
|
||||
## Sponsors
|
||||
|
||||
Appium has a [Sponsorship Program](GOVERNANCE.md#sponsorship)! If you or your company uses Appium
|
||||
and wants to give back financially to the project, we use these funds to [encourage development and
|
||||
contributions](GOVERNANCE.md#compensation-scheme), as well as support other open source projects we
|
||||
rely on. [Become a sponsor](https://opencollective.com/appium) via our OpenCollective page.
|
||||
|
||||
### Development and Strategic Partners
|
||||
|
||||
Appium is incredibly grateful to our Development and Strategic Partners for their sustained
|
||||
contribution of project development and leadership!
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
|
||||
<picture>
|
||||
<source srcset="packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png" media="(prefers-color-scheme: dark)"/>
|
||||
<source srcset="packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-light.png" media="(prefers-color-scheme: light)"/>
|
||||
<img src="packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png" width="300" alt="Browserstack"/>
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner"><img src="packages/appium/docs/overrides/assets/images/sponsor-logo-sauce.png"
|
||||
width="300" alt="Sauce Labs" /></a>
|
||||
</p>
|
||||
|
||||
### Other Sponsors
|
||||
|
||||
A full list of sponsors is available at our [Sponsors page](https://appium.io/docs/en/latest/sponsors/).
|
||||
|
||||
## License
|
||||
|
||||
[Apache-2.0](./LICENSE)
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)
|
||||
|
||||
`@appium/logger` package is under [ISC](./packages/logger/LICENSE) License.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
en/latest
|
||||
en/assets
|
||||
ja/assets
|
||||
zh/assets
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
.md-source__fact--version {
|
||||
display: none;
|
||||
}
|
||||
.md-source__fact:nth-child(1n + 2):before {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ copyright: Copyright © 2012 OpenJS Foundation - <a href="#__consent">Change
|
||||
theme:
|
||||
logo: assets/images/appium-logo-white.png
|
||||
favicon: assets/images/appium-logo.png
|
||||
custom_dir: overrides
|
||||
|
||||
plugins:
|
||||
blog:
|
||||
@@ -24,6 +25,8 @@ plugins:
|
||||
'reference/commands/images-plugin.md': 'commands/images-plugin.md'
|
||||
'reference/commands/relaxed-caps-plugin.md': 'commands/relaxed-caps-plugin.md'
|
||||
'reference/commands/universal-xml-plugin.md': 'commands/universal-xml-plugin.md'
|
||||
'contributing/config-system.md': 'developing/config-system.md'
|
||||
'contributing/develop.md': 'contributing.md'
|
||||
|
||||
extra_css:
|
||||
- assets/stylesheets/extra.css
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
authors:
|
||||
jlipps:
|
||||
name: "Jonathan Lipps"
|
||||
description: "Appium project lead. Learn more about Jonathan at https://jlipps.com"
|
||||
avatar: "https://gravatar.com/avatar/fdaadd825d92709bcf7fe76dffa12c40681c6108c67bcddf19478b2d00e3794b.jpg"
|
||||
slug: "jlipps"
|
||||
url: "https://jlipps.com"
|
||||
|
||||
name: 'Jonathan Lipps'
|
||||
description: 'Appium project lead. Learn more about Jonathan at https://jlipps.com'
|
||||
avatar: 'https://gravatar.com/avatar/fdaadd825d92709bcf7fe76dffa12c40681c6108c67bcddf19478b2d00e3794b.jpg'
|
||||
slug: 'jlipps'
|
||||
url: 'https://jlipps.com'
|
||||
srini:
|
||||
name: 'Srinivasan Sekar'
|
||||
description: 'Appium Maintainer'
|
||||
avatar: 'https://avatars.githubusercontent.com/u/8896549?v=4'
|
||||
slug: 'srini'
|
||||
url: 'https://srini.codes'
|
||||
sai:
|
||||
name: 'Sai krishna'
|
||||
description: 'Appium Maintainer'
|
||||
avatar: 'https://avatars.githubusercontent.com/u/4045041?v=4'
|
||||
slug: 'sai'
|
||||
url: 'https://saikrishna.tech'
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
authors:
|
||||
- srini
|
||||
- sai
|
||||
date: 2024-07-13
|
||||
---
|
||||
|
||||
# Appium Conf 2024: Call for Proposals Now Open!
|
||||
|
||||
We're thrilled to announce that Appium Conf is back and going online for 2024! This is the official Appium conference where you can learn all about what's new in Appium 2.0 and explore the latest in automating tests for devices, mobile apps, and desktop applications.
|
||||
|
||||
<!-- more -->
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch">
|
||||
<img id="image-36-42" alt="Appium Conf logo" src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" data-src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" decoding="async">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
## Mark Your Calendars: September 13, 2024
|
||||
|
||||
Join us on September 13, 2024, for a full day of inspiring and practical talks from the Appium team and the world's top mobile testing and automation experts. With Appium 2.0 now well-established, this is your opportunity to dive deep and learn how to maximize its potential.
|
||||
|
||||
## Why Attend Appium Conf 2024?
|
||||
|
||||
1. **Gain Insights**: Hear interesting insights and inspiring case studies from global experts and the core Appium team.
|
||||
2. **Improve Your Strategy**: Gain valuable knowledge to enhance your own automation strategy.
|
||||
3. **Network**: Make connections with Appium users from around the globe.
|
||||
4. **Learn from Specialists**: Benefit from Appium specialists' expertise on a variety of topics.
|
||||
|
||||
## Call for Proposals: Share Your Knowledge!
|
||||
|
||||
We're looking for a diverse range of speakers from around the globe who are eager to share innovative ideas and use-cases of mobile test automation. If you have experience with Appium and insights that could benefit the community of test practitioners, we want to hear from you!
|
||||
|
||||
Don't miss this chance to contribute to the Appium community and showcase your expertise on a global stage.
|
||||
|
||||
## How to Submit Your Proposal
|
||||
|
||||
Visit our website at [https://appiumconf.com/](https://appiumconf.com/) and [Submit a Proposal](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!
|
||||
|
||||
## Stay Tuned
|
||||
|
||||
Keep an eye on our website and social media channels for updates on the conference schedule, keynote speakers, and more exciting details about Appium Conf 2024.
|
||||
|
||||
Join us in shaping the future of mobile and device test automation. Submit your proposal today and be part of this exciting event!
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-06-10
|
||||
---
|
||||
|
||||
# Announcing BrowserStack as Appium's Strategic Partner
|
||||
|
||||
We have another exciting announcement for you! As part of our recently-announced [sponsorship and
|
||||
contributor compensation
|
||||
program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/),
|
||||
we are obviously in need of significant funding to support giving back to our contributor
|
||||
community. We are therefore extremely happy to announce one of our brand new exclusive Strategic Partners: <a
|
||||
href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">BrowserStack</a>!
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-browserstack-dark.png#only-dark" width="300" />
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-browserstack-light.png#only-light" width="300" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
BrowserStack has long been recognized in the industry as having extensive support for Appium,
|
||||
allowing you to run functional and visual regression tests for your native and hybrid apps at scale
|
||||
across a variety of devices and platforms.
|
||||
|
||||
As a token of this collaboration, BrowserStack is extending a special premium access of
|
||||
BrowserStack App Automate product to Appium users. Discover more about this special offer at
|
||||
[browserstack.com](https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium&utm_term=partannouncement)
|
||||
|
||||
With the decision to come on board as Strategic Partner, BrowserStack is making a huge investment
|
||||
in Appium and the Appium community. BrowserStack is very interested in supporting the development
|
||||
of the Appium contributor base, and is proud to be a key part of our contributor compensation
|
||||
scheme. Without Strategic Partners like BrowserStack, we would not be able to maintain such
|
||||
a program! We welcome them with gratitude!
|
||||
|
||||
**About BrowserStack**
|
||||
|
||||
<em>BrowserStack is the world’s leading software testing platform powering over two million tests every
|
||||
day across 19 global data centers. BrowserStack helps Tesco, Shell, NVIDIA, Discovery, Wells Fargo,
|
||||
and over 50,000 customers deliver quality software at speed by moving testing to their Cloud.
|
||||
BrowserStack’s platform provides instant access to 20,000+ real mobile devices on a highly reliable
|
||||
cloud infrastructure that effortlessly scales as testing needs grow. With BrowserStack, Dev and QA
|
||||
teams can move fast while delivering an amazing experience for every customer.</em>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-06-06
|
||||
---
|
||||
|
||||
# Announcing HeadSpin as Appium's Development Partner
|
||||
|
||||
Recently, we announced a new [sponsorship and contributor compensation program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/) for the Appium
|
||||
project. As part of this program, we felt it was important to have a place to recognize those
|
||||
companies who make an extremely valuable kind of contribution to the project: dedicated maintainer
|
||||
time. Appium only survives because of the tireless efforts of the core maintainers, and some of us
|
||||
are only able to do this work because it is donated on behalf of our day jobs. We're therefore very
|
||||
excited to announce our first Development Partner: <a
|
||||
href="https://www.headspin.io/solutions/appium-mobile-test-automation">HeadSpin</a>!
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://www.headspin.io/solutions/appium-mobile-test-automation"><img
|
||||
src="/docs/en/latest/assets/images/sponsor-logo-headspin.png" style="width: 300px"/></a>
|
||||
</div>
|
||||
|
||||
HeadSpin is a real device performance and UX analysis cloud, with full support for Appium. When you
|
||||
run your Appium tests on HeadSpin, you get access to comprehensive performance reports about your
|
||||
app, including potential network, system resource, or user experience issues. HeadSpin supports
|
||||
a variety of complex testing modes, including hooking up your own devices to the cloud, injecting
|
||||
and receiving video and audio to/from devices, working with media (streaming) platforms, and more.
|
||||
|
||||
HeadSpin has been one of the Appium project's biggest supporters for a long time, and currently
|
||||
employs two of Appium's core maintainers, donating a significant portion of their time towards the
|
||||
development, maintenance, support, and leadership of open source Appium repos. HeadSpin has also
|
||||
worked hard towards Appium's vision of a robust Appium ecosystem, contributing several
|
||||
HeadSpin-maintained Appium drivers and plugins to the community:
|
||||
|
||||
- A [Roku TV driver](https://github.com/headspinio/appium-roku-driver)
|
||||
- A [Tizen TV driver](https://github.com/headspinio/appium-tizen-tv-driver/)
|
||||
- A [LG webOS TV driver](https://github.com/headspinio/appium-lg-webos-driver/)
|
||||
- A [Unity game automation plugin](https://github.com/headspinio/appium-altunity-plugin)
|
||||
|
||||
These are all free and open source Appium components that HeadSpin has donated to the community
|
||||
with the goal of fostering collaboration in these areas of media app automation.
|
||||
|
||||
Looking to the future, HeadSpin plans to continue supporting Appium in significant ways, both as
|
||||
a Development Partner and a significant contributor to the Appium ecosystem. The Appium project is
|
||||
deeply indebted to HeadSpin for all of its support, and is proud to take this moment to recognize
|
||||
HeadSpin as our first official Development Partner!
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-06-10
|
||||
---
|
||||
|
||||
# Announcing Sauce Labs as Appium's Strategic Partner
|
||||
|
||||
The good news surrounding our new [sponsorship and contributor compensation
|
||||
program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/)
|
||||
just keeps coming! Effective immediately we are fortunate and excited to be able to welcome a new Strategic Partner to
|
||||
the Appium project: <a href="https://saucelabs.com/resources/blog/appium-strategic-partner">Sauce Labs</a>!
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner"><img src="/docs/en/latest/assets/images/sponsor-logo-sauce.png" style="width: 300px"/></a>
|
||||
</div>
|
||||
|
||||
Sauce Labs has a long history of support for the Appium project. In fact, Appium was initially
|
||||
incubated at Sauce Labs under the direction of [@jlipps](https://github.com/jlipps), in the early
|
||||
days of mobile automation. Sauce Labs always envisioned Appium as being a project for and by the
|
||||
community, and cemented this perspective in 2016 with the donation of Appium to the JS Foundation
|
||||
(now the [OpenJS Foundation](https://openjsf.org/)). To this day, developers associated with Sauce
|
||||
Labs continue to help maintain various parts of the Appium project.
|
||||
|
||||
Now, Sauce Labs is making a further commitment to support Appium financially as a way to enable
|
||||
our new contributor compensation program. We're very excited about this program as a vehicle for
|
||||
getting more people involved in Appium's development and maintenance. With the help of Strategic
|
||||
Partners like Sauce Labs, our project will be better able to meet the needs of our constantly
|
||||
growing userbase, and attract new developers (like you?) to build the Appium ecosystem together.
|
||||
Needless to say, we are extremely grateful for Sauce Labs's support!
|
||||
|
||||
**About Sauce Labs**
|
||||
|
||||
<em>Sauce Labs is the leader in continuous quality. Our Platform for Test helps organizations transform software testing from a chore to a competitive advantage. With decades of expertise and deep roots in the Selenium and Appium open source communities, high performing software teams use our platform to execute any testing workload across thousands of different devices, browsers, and operating systems—anywhere, any time, and at any scale. For more information, please visit [saucelabs.com](https://saucelabs.com).</em>
|
||||
@@ -38,6 +38,7 @@ below.
|
||||
|`--log`|Also send log output to this file|string||`-g`|
|
||||
|`--log-filters`|One or more log filtering rules|array|||
|
||||
|`--log-level`|Log level (console[:file]) (Value must be one of: `info`, `info:debug`, `info:info`, `info:warn`, `info:error`, `warn`, `warn:debug`, `warn:info`, `warn:warn`, `warn:error`, `error`, `error:debug`, `error:info`, `error:warn`, `error:error`, `debug`, `debug:debug`, `debug:info`, `debug:warn`, `debug:error`)|string|`debug`||
|
||||
|`--log-format`|Log format (Value must be to one of: `text`, `json`, `pretty_json`). If logs are printed as JSON then the text coloring is always disabled.|string|`text`||
|
||||
|`--log-no-colors`|Do not use color in console output|boolean|`false`||
|
||||
|`--log-timestamp`|Show timestamps in console output|boolean|`false`||
|
||||
|`--long-stacktrace`|Add long stack traces to log entries. Recommended for debugging only.|boolean|`false`||
|
||||
|
||||
@@ -21,3 +21,6 @@ environment variables that the Appium server understands:
|
||||
|`APPIUM_OMIT_PEER_DEPS`|Adds `--omit=peer` to all the NPM commands run internally by Appium. Mostly an internal feature.|
|
||||
|`APPIUM_APPS_CACHE_MAX_AGE`|Allows to set the maximum age (in minutes) for [cached applications](../guides/caching.md). The default value is `60 * 24` (24 hours). Do not set it to a lower number than the duration of a single session startup.|
|
||||
|`APPIUM_APPS_CACHE_MAX_ITEMS`|Allows to set the maximum amount of [cached applications](../guides/caching.md). The default value is `1024`. Do not set it to a lower number than the amount of apps in all parallel sessions per process.|
|
||||
|`APPIUM_APPS_CACHE_IGNORE_URL_QUERY`| If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys. See the corresponding
|
||||
[feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713)
|
||||
for more details. Disabled by default.|
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
hide:
|
||||
- navigation
|
||||
|
||||
title: Contributing to Appium
|
||||
---
|
||||
|
||||
The Appium project would not exist without the many contributions of code, documentation,
|
||||
maintenance, and support from companies and volunteers. As such, we welcome contributions!
|
||||
|
||||
There are a lot of different ways to help the project - see below for everything you can do and the
|
||||
processes to follow for each contribution method. Note that no matter how you contribute, your
|
||||
participation is governed by our [Code of Conduct](https://github.com/appium/appium/blob/master/CONDUCT.md).
|
||||
|
||||
## Join the Discussion Forum
|
||||
|
||||
You don't need to know the internals of Appium to be able to contribute! If you have experience with
|
||||
using Appium and feel like sharing your knowledge with others, consider helping out users on the
|
||||
Appium forums at [discuss.appium.io](https://discuss.appium.io/). Hop on over and see if there are
|
||||
any questions that you can answer.
|
||||
|
||||
## Report Bugs or Feature Requests
|
||||
|
||||
If you've encountered a bug, or have a cool feature in mind that you think Appium should support,
|
||||
make sure to let us know at our [GitHub issue tracker](https://github.com/appium/appium/issues).
|
||||
Please use the appropriate issue form template when creating your issue.
|
||||
|
||||
## Triage Issues
|
||||
|
||||
In addition to creating issues, you can also help us investigate already reported issues. All you
|
||||
need is enough familiarity with Appium to try and reproduce bugs.
|
||||
|
||||
You can get started by checking our [GitHub issue tracker](https://github.com/appium/appium/issues)
|
||||
for issues with labels such as `Needs Triage` or `Needs Info`, and leaving relevant comments:
|
||||
|
||||
- If the issue is a duplicate, drop a link to the original issue
|
||||
- If the user has not provided enough information (such as Appium logs), ask them for more details
|
||||
- If you can reproduce the problem on your own environment, provide all the information that you think
|
||||
would help us track down the cause of the issue
|
||||
|
||||
For further information on triaging Appium issues (for any Appium project repository), please contact
|
||||
any member of the [Technical Committee](https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee).
|
||||
|
||||
## Contribute Code
|
||||
|
||||
We are always open to pull requests for improving the Appium code or documentation!
|
||||
|
||||
!!! info
|
||||
|
||||
Developer information may not be kept up to date as frequently as user-facing information, or
|
||||
it may be most relevant in its current form on the online repository, not in this published
|
||||
version. Make sure to check the repo or discuss with maintainers. We would be glad to help
|
||||
new contributors get started!
|
||||
|
||||
Start by cloning the repository (we recommend [forking](https://github.com/appium/appium/fork)
|
||||
it first):
|
||||
```sh
|
||||
git clone https://github.com/appium/appium.git
|
||||
cd appium
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
If you are VS Code user, you can easily check out the project using [Runme](https://runme.dev/api/runme?repository=https%3A%2F%2Fgithub.com%2Fappium%2Fappium.git&fileToOpen=packages%2Fappium%2Fdocs%2Fen%2Fcontributing%2Findex.md).
|
||||
|
||||
Install dependencies:
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
From here on there are several things you can do.
|
||||
|
||||
Build the project:
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
Build the project and watch for changes:
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Start the locally built Appium server:
|
||||
```sh
|
||||
npm start
|
||||
```
|
||||
|
||||
Run various tests:
|
||||
```sh
|
||||
npm run lint
|
||||
npm run test:unit
|
||||
npm run test:types
|
||||
npm run test:smoke
|
||||
npm run test:e2e
|
||||
npm run test:quick # unit and types
|
||||
npm run test:slow # everything
|
||||
```
|
||||
|
||||
You can also run tests for specific workspaces, e.g.:
|
||||
|
||||
```sh
|
||||
export APPIUM_WORKSPACE=@appium/base-driver
|
||||
npm run test:unit -w $APPIUM_WORKSPACE
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
The documentation for this project is [available in the project repository itself](https://github.com/appium/appium/tree/master/packages/appium/docs).
|
||||
It is contained in Markdown files, which are built by our documentation system in the
|
||||
`@appium/docutils` module. This module is based on [MkDocs](https://www.mkdocs.org/) and therefore
|
||||
requires [Python](https://www.python.org/) to be installed on your system.
|
||||
|
||||
Install Python dependencies:
|
||||
```sh
|
||||
npm run install-docs-deps
|
||||
```
|
||||
|
||||
After making your changes, you can run the documentation server in dev mode:
|
||||
```sh
|
||||
npm run dev:docs
|
||||
```
|
||||
|
||||
You can then view the documentation at `http://127.0.0.1:8000/docs/en`.
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Contributing to Appium
|
||||
---
|
||||
|
||||
Appium is open source, available under an Apache 2.0 license. Appium's copyright is held by the
|
||||
[OpenJS Foundation](https://openjsf.org), and Appium receives contributions from many companies
|
||||
across several software industries, regardless of their competitive status. (3rd-party drivers and
|
||||
plugins are available under the licenses provided by their authors.)
|
||||
|
||||
As such, we welcome contributions! The project moves forward in relation to the investment of
|
||||
contributions of code, documentation, maintenance, and support from companies and volunteers.
|
||||
|
||||
This section of Appium's documentation is for those who are interested in contributing to Appium's
|
||||
development. It contains developer overviews, guides, and notes. Use the navigation menu to find
|
||||
a specific topic. All the information in these guides assumes in-depth familiarity with Appium
|
||||
already.
|
||||
|
||||
!!! warning
|
||||
|
||||
Developer information may not be kept up to date as frequently as user-facing information, or
|
||||
it may be most relevant in its current form on the online repository, not in this published
|
||||
version. Always be sure to check the repo or discuss with maintainers. We're always happy to
|
||||
help new contributors get started!
|
||||
|
||||
## Ways to Contribute
|
||||
|
||||
The project offers a variety of ways to contribute, e.g.:
|
||||
|
||||
- [contributing code](./develop.md)
|
||||
- improving documentation
|
||||
- creating educational content (blog posts, tutorials, videos, etc.)
|
||||
- spreading the good word about the project (e.g. via Twitter)
|
||||
- filing bugs if you discover them while using Appium
|
||||
- making feature requests if you are missing something in the project or help triaging bugs
|
||||
- supporting users in the [Appium forum](https://discuss.appium.io/)
|
||||
@@ -37,12 +37,15 @@ These drivers are not maintained by the Appium team and can be used to target ad
|
||||
|Driver|Installation Key|Platform(s)|Mode(s)|Supported By|
|
||||
|--|--|--|--|--|
|
||||
|[Flutter](https://github.com/appium/appium-flutter-driver)|`--source=npm appium-flutter-driver`|iOS, Android|Native|Community|
|
||||
|[Flutter Integration](https://github.com/AppiumTestDistribution/appium-flutter-integration-driver)|`--source=npm appium-flutter-integration-driver`|iOS, Android|Native|Community / `@AppiumTestDistribution`|
|
||||
|[LG WebOS](https://github.com/headspinio/appium-lg-webos-driver)|`--source=npm appium-lg-webos-driver`|LG TV|Web|HeadSpin|
|
||||
|[Linux](https://github.com/fantonglang/appium-linux-driver)|`--source=npm @stdspa/appium-linux-driver`|Linux|Native|`@fantonglang`|
|
||||
|[Roku](https://github.com/headspinio/appium-roku-driver)|`--source=npm @headspinio/appium-roku-driver`|Roku|Native|HeadSpin|
|
||||
|[Tizen](https://github.com/Samsung/appium-tizen-driver)|`--source=npm appium-tizen-driver`|Android|Native|Community / Samsung|
|
||||
|[TizenTV](https://github.com/headspinio/appium-tizen-tv-driver)|`--source=npm appium-tizen-tv-driver`|Samsung TV|Web|HeadSpin|
|
||||
|[Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver)|`--source=npm appium-youiengine-driver`|iOS, Android, macOS, Linux, tvOS|Native|Community / You.i|
|
||||
|[axe UiAutomator2](https://docs.deque.com/devtools-mobile/appium-setup)|`--source=npm @axe-devtools/axe-appium-uiautomator2-driver`|Android|Native|[Deque](https://www.deque.com)|
|
||||
|[axe XCUITest](https://docs.deque.com/devtools-mobile/appium-setup)|`--source=npm @axe-devtools/axe-appium-xcuitest-driver`|iOS|Native|[Deque](https://www.deque.com)|
|
||||
|
||||
!!! note
|
||||
|
||||
|
||||
@@ -32,9 +32,12 @@ These plugins are not maintained by the Appium team and can provide additional f
|
||||
|<div style="width:6em">Plugin</div>|<div style="width:19em">Installation Key</div>|Description|<div style="width:13em">Supported By</div>|
|
||||
|---|---|---|---|
|
||||
|[AltUnity](https://github.com/headspinio/appium-altunity-plugin)|`--source=npm appium-altunity-plugin`|Target Unity games and apps for automation with a new context, via the AltUnityTester framework|HeadSpin|
|
||||
|[Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)|`--source=npm appium-device-farm`|Manage and create driver session on connected android devices and iOS Simulators.|`@AppiumTestDistribution`|
|
||||
|[Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)|`--source=npm appium-device-farm`|Manage and create driver sessions on connected Android devices and iOS simulators|`@AppiumTestDistribution`|
|
||||
|[Gestures](https://github.com/AppiumTestDistribution/appium-gestures-plugin)|`--source=npm appium-gestures-plugin`|Perform basic gestures using W3C Actions|`@AppiumTestDistribution`|
|
||||
|[Interceptor](https://github.com/AppiumTestDistribution/appium-interceptor-plugin)|`--source=npm appium-interceptor`|Intercept and mock API requests and responses|`@AppiumTestDistribution`|
|
||||
|[OCR](https://github.com/jlipps/appium-ocr-plugin)|`--source=npm appium-ocr-plugin`|Find elements via OCR text|`@jlipps`|
|
||||
|[Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)|`--source=npm appium-reporter-plugin`|Generates standalone consolidated html report with screenshots. Reports can be fetched from appium server, without worrying about heavy lifting such as screenshot capturing, report generation etc.|`@AppiumTestDistribution`|
|
||||
|[Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)|`--source=npm appium-reporter-plugin`|Generate standalone consolidated HTML reports with screenshots|`@AppiumTestDistribution`|
|
||||
|[Wait](https://github.com/AppiumTestDistribution/appium-wait-plugin)|`--source=npm appium-wait-plugin`|Manage global element wait timeouts|`@AppiumTestDistribution`|
|
||||
|
||||
!!! note
|
||||
|
||||
|
||||
@@ -63,6 +63,11 @@ of it. It is a [LRU Cache](https://www.npmjs.com/package/lru-cache) with the fol
|
||||
[APPIUM_APPS_CACHE_MAX_AGE](../cli/env-vars.md) environment variable.
|
||||
Do not set it to a lower number than the duration of a single session startup.
|
||||
- TTL is refreshed for each entry upon access
|
||||
- By default the full application URL is used as cache key. You may change this behavior
|
||||
by enabling the [APPIUM_APPS_CACHE_IGNORE_URL_QUERY](../cli/env-vars.md) environment variable.
|
||||
If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys.
|
||||
See the corresponding [feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713)
|
||||
for more details.
|
||||
|
||||
!!! warning
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ property in your `package.json` and it will be automatically discovered.
|
||||
Appium will search _up_ the directory tree from the current working directory for one of these
|
||||
files. If it reaches the current user's home directory or filesystem root, it will stop looking.
|
||||
|
||||
To specify a _custom_ location for your config file, use `appium --config-file /path/to/config/file`.
|
||||
To specify a _custom_ location for your config file, use `appium --config /path/to/config/file`.
|
||||
|
||||
#### Configuration File Format
|
||||
|
||||
|
||||
@@ -6,10 +6,19 @@ hide:
|
||||
title: Welcome
|
||||
---
|
||||
<style>
|
||||
.md-typeset h1 {
|
||||
.md-typeset h1,
|
||||
.appium-sponsor-thanks {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div style="text-align:center;width:100%;background-color:#ec366d;margin-top:-3em;margin-bottom:2em;">
|
||||
<h3 style="color:#ffffff;padding: 8px;">
|
||||
AppiumConf 2025 is partnering with SeleniumConf<br/> <span style="font-size:0.8em;">March 26-28 in Valencia, Spain. Join us to learn and connect with the community!<span><br/>
|
||||
<a style="color:#fcba12" href="https://seleniumconf.com/" target="_blank">Register Now</a>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center">
|
||||
<img src="assets/images/appium-logo-horiz.png" style="max-width: 400px;" />
|
||||
</div>
|
||||
@@ -19,6 +28,26 @@ software, designed to facilitate UI automation of many app platforms, including
|
||||
Android, Tizen), browser (Chrome, Firefox, Safari), desktop (macOS, Windows), TV (Roku, tvOS,
|
||||
Android TV, Samsung), and more!
|
||||
|
||||
|
||||
<div style="text-align: center; margin-top: 2rem; font-style: italic;">
|
||||
Appium is extremely grateful for the support of its key partners! (Learn more about our
|
||||
sponsorship program and contributor compensation scheme <a
|
||||
href="https://github.com/appium/appium/blob/master/GOVERNANCE.md#sponsorship">here</a>)
|
||||
<div class="homepageSponsors">
|
||||
<div class="homepageSponsor">
|
||||
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
|
||||
<img src="assets/images/sponsor-logo-browserstack-dark.png#only-dark" style="width: 220px;" />
|
||||
<img src="assets/images/sponsor-logo-browserstack-light.png#only-light" style="width: 220px;" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="homepageSponsor">
|
||||
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner">
|
||||
<img src="assets/images/sponsor-logo-sauce.png" style="width: 200px;" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Explore the Documentation
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
@@ -31,6 +60,6 @@ Android TV, Samsung), and more!
|
||||
- Read the different [__Guides__](./guides/migrating-1-to-2.md) for a variety of instructions, tips and tricks
|
||||
- Check out various third-party [__Resources__](./resources.md) to explore Appium around the web
|
||||
- For creating your own Appium extensions, see the [__Developer__](./developing/index.md) documentation
|
||||
- For contributions to Appium itself, refer to the [__Contributing__](./contributing/index.md) page
|
||||
- For contributions to Appium itself, refer to the [__Contributing__](./contributing.md) page
|
||||
|
||||
</div>
|
||||
|
||||
@@ -40,14 +40,14 @@ but it is certainly a good one! So let's dive in.
|
||||
## Appium's choice of API
|
||||
|
||||
Appium is very fortunate to have been preceded by a technology which has been a long-standing
|
||||
pioneer in the field of UI automation, namely [Selenium](https://seleniumhq.org). The goal of the
|
||||
pioneer in the field of UI automation, namely [Selenium](https://selenium.dev). The goal of the
|
||||
Selenium project has been to support UI automation of web browsers, and in this way we can think of
|
||||
it as occupying a subset of Appium's goals. Along the way, Selenium (and, after they merged,
|
||||
another project called WebDriver) developed a relatively stable API for browser automation.
|
||||
|
||||
Over the years, Selenium worked with various web browser vendors and the [W3C](https://w3c.org)
|
||||
Over the years, Selenium worked with various web browser vendors and the [W3C](https://w3.org)
|
||||
standards group to turn its API into an official web browser standard, called the [WebDriver
|
||||
specification](https://w3c.github.io/webdriver/webdriver-spec.html). All the main browsers now
|
||||
specification](https://w3c.github.io/webdriver/). All the main browsers now
|
||||
implement automation capabilities inline with the WebDriver spec, without the Selenium team having
|
||||
to maintain any software that performs actual automation; standards for the win!
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ title: Intro to Appium Clients
|
||||
---
|
||||
|
||||
For all the reasons discussed in the [main Overview](./appium.md), Appium is based on the [W3C
|
||||
WebDriver specification](https://w3c.github.io/webdriver/webdriver-spec.html). This means that
|
||||
WebDriver specification](https://w3c.github.io/webdriver/). This means that
|
||||
Appium implements a client-server architecture. The server (consisting of Appium itself along with
|
||||
any drivers or plugins you are using for automation) is connected to the devices under test, and
|
||||
is actually responsible for making automation happen on those devices. The client (driven by *you*,
|
||||
|
||||
@@ -37,7 +37,7 @@ their WebDriver protocol equivalents.
|
||||
|
||||
So let's say I wanted to do something with this empty driver; first I have to decide which
|
||||
WebDriver command I want to implement. For our example, let's take the [Navigate
|
||||
To](https://www.w3.org/TR/webdriver1/#navigate-to) WebDriver command. Leave aside for the moment
|
||||
To](https://w3c.github.io/webdriver/#navigate-to) WebDriver command. Leave aside for the moment
|
||||
what I want to have the driver *do* when this command is executed. To tell Appium the driver can
|
||||
handle the command, all we have to do is define a method like this in our driver class:[^1]
|
||||
|
||||
@@ -96,7 +96,7 @@ a driver becomes the task of mapping the WebDriver protocol to this underlying A
|
||||
a set of different underlying APIs--for example, the UiAutomator2 driver relies not only on the
|
||||
[UiAutomator2](https://developer.android.com/training/testing/other-components/ui-automator)
|
||||
technology from Google, but also functions only available through
|
||||
[ADB](https://developer.android.com/studio/command-line/adb), as well as functions only available
|
||||
[ADB](https://developer.android.com/tools/adb), as well as functions only available
|
||||
via the Android SDK inside a helper app). Tying it all together into a single, usable, WebDriver
|
||||
interface is the incredibly useful (but incredibly challenging) art of driver development!
|
||||
|
||||
|
||||
@@ -137,8 +137,8 @@ already had well over 1,000 commits.
|
||||
Appium began to grow and mature significantly. In May 2014,
|
||||
we released Appium 1.0, which stood as a milestone in Appium's development.
|
||||
Appium was given
|
||||
[various](http://sauceio.com/index.php/2014/01/appium-selected-as-a-black-duck-open-source-rookie-of-the-year/)
|
||||
[awards](http://sauceio.com/index.php/2014/10/appium-wins-a-bossy-award-from-infoworld/)
|
||||
[various](https://www.prnewswire.com/news-releases/black-duck-announces-black-duck-open-source-rookies-of-the-year-winners-242383341.html)
|
||||
[awards](https://www.infoworld.com/article/2241247/164642-bossie-awards-2014-the-best-open-source-application-development-tools.html)
|
||||
and became the most popular open-source cross-platform mobile automation
|
||||
framework. Stability improved, bugs were prioritized and fixed, and features
|
||||
added. Sauce Labs increased the number of developers it donated to working
|
||||
|
||||
@@ -22,7 +22,7 @@ According to the driver, in addition to a working Appium server, we also need to
|
||||
### Android SDK
|
||||
|
||||
- The easiest way to set up the Android SDK requirements is by downloading [Android Studio](https://developer.android.com/studio).
|
||||
We need to use its SDK manager (_Settings -> Appearance & Behavior -> System Settings -> Android SDK_)
|
||||
We need to use its SDK manager (_Settings -> Languages & Frameworks -> Android SDK_)
|
||||
to download the following items:
|
||||
- Android SDK Platform (select whichever Android platform we want to automate, for example, API level 30)
|
||||
- Android SDK Platform-Tools
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
hide:
|
||||
- navigation
|
||||
- toc
|
||||
|
||||
title: Sponsors & Backers
|
||||
---
|
||||
|
||||
<style>
|
||||
.appium-sponsor-thanks { display: none; }
|
||||
.sponsor-section img { height: 64px; padding-right: 1em; }
|
||||
</style>
|
||||
|
||||
Appium is an Apache-2 licensed open source project whose development is made possible entirely by
|
||||
donations of time and money by individuals and companies who benefit from our software and our
|
||||
mission. If you'd like to join this amazing group and help ensure Appium's continued development
|
||||
and maintenance, you can contribute via [Appium's OpenCollective
|
||||
Hub](https://opencollective.com/appium).
|
||||
|
||||
## Development Partners
|
||||
|
||||
We are very grateful for the support of our Development Partners, who donate Appium development and
|
||||
maintenance as part of their employees' core job duties!
|
||||
|
||||
## Strategic Partners
|
||||
|
||||
We are very grateful for the financial and marketing support of our exclusive Strategic Partners,
|
||||
who contribute a significant ongoing investment of funds to help the project attract and reward
|
||||
contributors!
|
||||
|
||||
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
|
||||
<picture>
|
||||
<source srcset="../assets/images/sponsor-logo-browserstack-dark.png" media="(prefers-color-scheme: dark)"/>
|
||||
<source srcset="../assets/images/sponsor-logo-browserstack-light.png" media="(prefers-color-scheme: light)"/>
|
||||
<img src="../assets/images/sponsor-logo-browserstack-dark.png" width="250" alt="Browserstack"/>
|
||||
</picture>
|
||||
</a>
|
||||
<a style="padding-left: 1em" href="https://saucelabs.com/resources/blog/appium-strategic-partner" target="_blank"><img src="../assets/images/sponsor-logo-sauce.png" width="250"/></a>
|
||||
|
||||
## Gold Sponsors
|
||||
|
||||
<a href="https://opencollective.com/appium" target="_blank"><img src="https://opencollective.com/appium/tiers/gold-sponsor.svg?avatarHeight=100&button=false&random=1"/></a>
|
||||
|
||||
[Become a Gold Sponsor](https://opencollective.com/appium/contribute/gold-sponsor-72877/checkout?interval=month&amount=500&contributeAs=me)
|
||||
|
||||
## Silver Sponsors
|
||||
|
||||
<a href="https://opencollective.com/appium" target="_blank"><img src="https://opencollective.com/appium/tiers/silver-sponsor.svg?avatarHeight=80&button=false&random=1"/></a>
|
||||
|
||||
[Become a Silver Sponsor](https://opencollective.com/appium/contribute/silver-sponsor-72876/checkout?interval=month&amount=250&contributeAs=me)
|
||||
|
||||
## Bronze Sponsors
|
||||
|
||||
<div class="sponsor-section">
|
||||
<a href="https://magicpod.com/" target="_blank"><img src="https://images.opencollective.com/magicpod/722b7e4/avatar/64.png" alt="MagicPod" /></a>
|
||||
<a href="https://route4me.com/" target="_blank"><img src="../assets/images/sponsor-logo-route4me.png" alt="Route Planning and Route Mapping" /></a>
|
||||
<a href="https://webdriver.io/" target="_blank"><img src="https://images.opencollective.com/webdriverio/bbdd6c3/logo/64.png" alt="WebdriverIO" /></a>
|
||||
</div>
|
||||
|
||||
[Become a Bronze Sponsor](https://opencollective.com/appium/contribute/sponsors-70690/checkout?interval=month&amount=100&contributeAs=me)
|
||||
@@ -72,7 +72,7 @@ nav:
|
||||
- developing/build-plugins.md
|
||||
- developing/build-docs.md
|
||||
- developing/build-doctor-checks.md
|
||||
- Contributing:
|
||||
- contributing/index.md
|
||||
- contributing/develop.md
|
||||
- contributing/config-system.md
|
||||
- Developer Reference:
|
||||
- developing/config-system.md
|
||||
- Contributing: contributing.md
|
||||
- Sponsors: sponsors.md
|
||||
|
||||
@@ -8,6 +8,7 @@ theme:
|
||||
language: zh
|
||||
nav:
|
||||
- 首页: index.md
|
||||
- 博客: blog/index.md
|
||||
- 简介:
|
||||
- intro/index.md
|
||||
- 背景:
|
||||
@@ -17,40 +18,61 @@ nav:
|
||||
- intro/history.md
|
||||
- 快速开始:
|
||||
- quickstart/index.md
|
||||
- quickstart/requirements.md
|
||||
- quickstart/install.md
|
||||
- quickstart/uiauto2-driver.md
|
||||
- 编写测试:
|
||||
- Write a Test:
|
||||
- quickstart/test-js.md
|
||||
- quickstart/test-py.md
|
||||
- quickstart/test-java.md
|
||||
- quickstart/test-rb.md
|
||||
- quickstart/test-dotnet.md
|
||||
- quickstart/next-steps.md
|
||||
- 生态系统:
|
||||
- ecosystem/index.md
|
||||
- 开发 Appium 扩展:
|
||||
- ecosystem/build-drivers.md
|
||||
- ecosystem/build-plugins.md
|
||||
- ecosystem/build-docs.md
|
||||
- 命令行参考:
|
||||
- ecosystem/drivers.md
|
||||
- ecosystem/clients.md
|
||||
- ecosystem/plugins.md
|
||||
- ecosystem/tools.md
|
||||
- CLI Reference:
|
||||
- cli/index.md
|
||||
- cli/args.md
|
||||
- cli/env-vars.md
|
||||
- cli/extensions.md
|
||||
- cli/setup.md
|
||||
- Command Reference:
|
||||
- ../en/commands/base-driver.md
|
||||
- ../en/commands/execute-driver-plugin.md
|
||||
- ../en/commands/images-plugin.md
|
||||
- ../en/commands/relaxed-caps-plugin.md
|
||||
- ../en/commands/universal-xml-plugin.md
|
||||
- commands/index.md
|
||||
- commands/base-driver.md
|
||||
- commands/execute-driver-plugin.md
|
||||
- commands/images-plugin.md
|
||||
- commands/relaxed-caps-plugin.md
|
||||
- commands/universal-xml-plugin.md
|
||||
- 指南:
|
||||
- guides/migrating-1-to-2.md
|
||||
- guides/managing-exts.md
|
||||
- guides/config.md
|
||||
- guides/security.md
|
||||
- guides/caps.md
|
||||
- guides/context.md
|
||||
- guides/settings.md
|
||||
- guides/execute-script-overload.md
|
||||
- guides/event-timing.md
|
||||
- guides/log-filters.md
|
||||
- guides/grid.md
|
||||
- 更多 Appium 资源: resources.md
|
||||
- 贡献: contributing/index.md
|
||||
- Migration:
|
||||
- guides/migrating-1-to-2.md
|
||||
- Server/Driver Configuration:
|
||||
- guides/managing-exts.md
|
||||
- guides/branch-testing.md
|
||||
- guides/config.md
|
||||
- guides/security.md
|
||||
- guides/log-filters.md
|
||||
- guides/grid.md
|
||||
- guides/caching.md
|
||||
- guides/tls.md
|
||||
- Session Configuration:
|
||||
- guides/caps.md
|
||||
- guides/settings.md
|
||||
- guides/execute-methods.md
|
||||
- guides/context.md
|
||||
- guides/event-timing.md
|
||||
- 更多资源: resources.md
|
||||
- 开发:
|
||||
- developing/index.md
|
||||
- developing/build-drivers.md
|
||||
- developing/build-plugins.md
|
||||
- developing/build-docs.md
|
||||
- developing/build-doctor-checks.md
|
||||
- 贡献:
|
||||
- contributing/index.md
|
||||
- contributing/develop.md
|
||||
- contributing/config-system.md
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
@@ -0,0 +1,31 @@
|
||||
.md-source__fact--version {
|
||||
display: none;
|
||||
}
|
||||
.md-source__fact:nth-child(1n + 2):before {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.appium-sponsor-thanks {
|
||||
width: 100%;
|
||||
margin: 0.5rem 0.6rem auto 0.6rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.appium-sponsor-thanks img {
|
||||
margin: auto 6px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.homepageSponsors {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 10px auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.homepageSponsor {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<!-- Footer -->
|
||||
<footer class="md-footer">
|
||||
|
||||
<!-- Link to previous and/or next page -->
|
||||
{% if "navigation.footer" in features %}
|
||||
{% if page.previous_page or page.next_page %}
|
||||
{% if page.meta and page.meta.hide %}
|
||||
{% set hidden = "hidden" if "footer" in page.meta.hide %}
|
||||
{% endif %}
|
||||
<nav
|
||||
class="md-footer__inner md-grid"
|
||||
aria-label="{{ lang.t('footer') }}"
|
||||
{{ hidden }}
|
||||
>
|
||||
|
||||
<!-- Link to previous page -->
|
||||
{% if page.previous_page %}
|
||||
{% set direction = lang.t("footer.previous") %}
|
||||
<a
|
||||
href="{{ page.previous_page.url | url }}"
|
||||
class="md-footer__link md-footer__link--prev"
|
||||
aria-label="{{ direction }}: {{ page.previous_page.title | e }}"
|
||||
>
|
||||
<div class="md-footer__button md-icon">
|
||||
{% set icon = config.theme.icon.previous or "material/arrow-left" %}
|
||||
{% include ".icons/" ~ icon ~ ".svg" %}
|
||||
</div>
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
{{ direction }}
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
{{ page.previous_page.title }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Link to next page -->
|
||||
{% if page.next_page %}
|
||||
{% set direction = lang.t("footer.next") %}
|
||||
<a
|
||||
href="{{ page.next_page.url | url }}"
|
||||
class="md-footer__link md-footer__link--next"
|
||||
aria-label="{{ direction }}: {{ page.next_page.title | e }}"
|
||||
>
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
{{ direction }}
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
{{ page.next_page.title }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
{% set icon = config.theme.icon.next or "material/arrow-right" %}
|
||||
{% include ".icons/" ~ icon ~ ".svg" %}
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Further information -->
|
||||
<div class="md-footer-meta md-typeset">
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
<!-- Sponsor thanks -->
|
||||
{% include "partials/sponsors.html" %}
|
||||
|
||||
{% include "partials/copyright.html" %}
|
||||
|
||||
<!-- Social links -->
|
||||
{% if config.extra.social %}
|
||||
{% include "partials/social.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="appium-sponsor-thanks">
|
||||
Supported by
|
||||
|
||||
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-browserstack-dark.png" />
|
||||
</a>
|
||||
|
||||
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner">
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-sauce.png" />
|
||||
</a>
|
||||
</div>
|
||||
@@ -20,7 +20,6 @@ const {
|
||||
DOCS_REMOTE,
|
||||
LATEST_ALIAS,
|
||||
} = require('./utils');
|
||||
const copyAssets = require('./copy-assets');
|
||||
const path = require('path');
|
||||
const semver = require('semver');
|
||||
const {version} = require('../../package.json');
|
||||
@@ -35,8 +34,6 @@ const push = Boolean(process.env.APPIUM_DOCS_PUBLISH);
|
||||
async function main() {
|
||||
log.info(`Building Appium docs and committing to ${DOCS_BRANCH}`);
|
||||
|
||||
await copyAssets();
|
||||
|
||||
const semVersion = semver.parse(version);
|
||||
if (!semVersion) {
|
||||
throw new Error(`Could not parse Appium version "${version}" as semver`);
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* This script copies generic assets from `ASSETS_DIR` to each docs language dir.
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
// for simplicity this file is not transpiled and is run directly via an npm script
|
||||
/* eslint-disable promise/prefer-await-to-callbacks */
|
||||
/* eslint-disable promise/prefer-await-to-then */
|
||||
|
||||
const {fs} = require('@appium/support');
|
||||
const {log, LANGS, DOCS_DIR, ASSETS_DIR} = require('./utils');
|
||||
const path = require('path');
|
||||
|
||||
async function main() {
|
||||
log.info('Copying generic assets to docs language dirs');
|
||||
|
||||
for (const lang of LANGS) {
|
||||
const langPath = path.join(DOCS_DIR, lang);
|
||||
const langAssetPath = path.join(langPath, 'assets');
|
||||
log.info(`Deleting ${langAssetPath}`);
|
||||
await fs.rimraf(langAssetPath);
|
||||
log.info(`Copying assets into ${langAssetPath}`);
|
||||
await fs.copyFile(ASSETS_DIR, langAssetPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = main;
|
||||
@@ -0,0 +1,19 @@
|
||||
authors:
|
||||
jlipps:
|
||||
name: 'Jonathan Lipps'
|
||||
description: 'Appium project lead. Learn more about Jonathan at https://jlipps.com'
|
||||
avatar: 'https://gravatar.com/avatar/fdaadd825d92709bcf7fe76dffa12c40681c6108c67bcddf19478b2d00e3794b.jpg'
|
||||
slug: 'jlipps'
|
||||
url: 'https://jlipps.com'
|
||||
srini:
|
||||
name: 'Srinivasan Sekar'
|
||||
description: 'Appium Maintainer'
|
||||
avatar: 'https://avatars.githubusercontent.com/u/8896549?v=4'
|
||||
slug: 'srini'
|
||||
url: 'https://srini.codes'
|
||||
sai:
|
||||
name: 'Sai krishna'
|
||||
description: 'Appium Maintainer'
|
||||
avatar: 'https://avatars.githubusercontent.com/u/4045041?v=4'
|
||||
slug: 'sai'
|
||||
url: 'https://saikrishna.tech'
|
||||
@@ -1,2 +1,2 @@
|
||||
# Blog
|
||||
# 博客
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
authors:
|
||||
- srini
|
||||
- sai
|
||||
date: 2024-07-13
|
||||
---
|
||||
|
||||
# Appium Conf 2024: Call for Proposals Now Open!
|
||||
|
||||
We're thrilled to announce that Appium Conf is back and going online for 2024! This is the official Appium conference where you can learn all about what's new in Appium 2.0 and explore the latest in automating tests for devices, mobile apps, and desktop applications.
|
||||
|
||||
<!-- more -->
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://confengine.com/conferences/appium-conf-2024/proposals?utm_medium=referal&utm_source=appium.io&utm_campaign=launch">
|
||||
<img id="image-36-42" alt="Appium Conf logo" src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" data-src="https://appiumconf.com/wp-content/uploads/2021/06/Appium-Conf-Logo.svg" decoding="async">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
## Mark Your Calendars: September 13, 2024
|
||||
|
||||
Join us on September 13, 2024, for a full day of inspiring and practical talks from the Appium team and the world's top mobile testing and automation experts. With Appium 2.0 now well-established, this is your opportunity to dive deep and learn how to maximize its potential.
|
||||
|
||||
## Why Attend Appium Conf 2024?
|
||||
|
||||
1. **Gain Insights**: Hear interesting insights and inspiring case studies from global experts and the core Appium team.
|
||||
2. **Improve Your Strategy**: Gain valuable knowledge to enhance your own automation strategy.
|
||||
3. **Network**: Make connections with Appium users from around the globe.
|
||||
4. **Learn from Specialists**: Benefit from Appium specialists' expertise on a variety of topics.
|
||||
|
||||
## Call for Proposals: Share Your Knowledge!
|
||||
|
||||
We're looking for a diverse range of speakers from around the globe who are eager to share innovative ideas and use-cases of mobile test automation. If you have experience with Appium and insights that could benefit the community of test practitioners, we want to hear from you!
|
||||
|
||||
Don't miss this chance to contribute to the Appium community and showcase your expertise on a global stage.
|
||||
|
||||
## How to Submit Your Proposal
|
||||
|
||||
Visit our website at [https://appiumconf.com/](https://appiumconf.com/) and [Submit a Proposal](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!
|
||||
|
||||
## Stay Tuned
|
||||
|
||||
Keep an eye on our website and social media channels for updates on the conference schedule, keynote speakers, and more exciting details about Appium Conf 2024.
|
||||
|
||||
Join us in shaping the future of mobile and device test automation. Submit your proposal today and be part of this exciting event!
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-06-10
|
||||
---
|
||||
|
||||
# Announcing BrowserStack as Appium's Strategic Partner
|
||||
|
||||
We have another exciting announcement for you! As part of our recently-announced [sponsorship and
|
||||
contributor compensation
|
||||
program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/),
|
||||
we are obviously in need of significant funding to support giving back to our contributor
|
||||
community. We are therefore extremely happy to announce one of our brand new exclusive Strategic Partners: <a
|
||||
href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">BrowserStack</a>!
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium">
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-browserstack-dark.png#only-dark" width="300" />
|
||||
<img src="/docs/en/latest/assets/images/sponsor-logo-browserstack-light.png#only-light" width="300" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
BrowserStack has long been recognized in the industry as having extensive support for Appium,
|
||||
allowing you to run functional and visual regression tests for your native and hybrid apps at scale
|
||||
across a variety of devices and platforms.
|
||||
|
||||
As a token of this collaboration, BrowserStack is extending a special premium access of
|
||||
BrowserStack App Automate product to Appium users. Discover more about this special offer at
|
||||
[browserstack.com](https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium&utm_term=partannouncement)
|
||||
|
||||
With the decision to come on board as Strategic Partner, BrowserStack is making a huge investment
|
||||
in Appium and the Appium community. BrowserStack is very interested in supporting the development
|
||||
of the Appium contributor base, and is proud to be a key part of our contributor compensation
|
||||
scheme. Without Strategic Partners like BrowserStack, we would not be able to maintain such
|
||||
a program! We welcome them with gratitude!
|
||||
|
||||
**About BrowserStack**
|
||||
|
||||
<em>BrowserStack is the world’s leading software testing platform powering over two million tests every
|
||||
day across 19 global data centers. BrowserStack helps Tesco, Shell, NVIDIA, Discovery, Wells Fargo,
|
||||
and over 50,000 customers deliver quality software at speed by moving testing to their Cloud.
|
||||
BrowserStack’s platform provides instant access to 20,000+ real mobile devices on a highly reliable
|
||||
cloud infrastructure that effortlessly scales as testing needs grow. With BrowserStack, Dev and QA
|
||||
teams can move fast while delivering an amazing experience for every customer.</em>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-06-06
|
||||
---
|
||||
|
||||
# Announcing HeadSpin as Appium's Development Partner
|
||||
|
||||
Recently, we announced a new [sponsorship and contributor compensation program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/) for the Appium
|
||||
project. As part of this program, we felt it was important to have a place to recognize those
|
||||
companies who make an extremely valuable kind of contribution to the project: dedicated maintainer
|
||||
time. Appium only survives because of the tireless efforts of the core maintainers, and some of us
|
||||
are only able to do this work because it is donated on behalf of our day jobs. We're therefore very
|
||||
excited to announce our first Development Partner: <a
|
||||
href="https://www.headspin.io/solutions/appium-mobile-test-automation">HeadSpin</a>!
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://www.headspin.io/solutions/appium-mobile-test-automation"><img
|
||||
src="/docs/en/latest/assets/images/sponsor-logo-headspin.png" style="width: 300px"/></a>
|
||||
</div>
|
||||
|
||||
HeadSpin is a real device performance and UX analysis cloud, with full support for Appium. When you
|
||||
run your Appium tests on HeadSpin, you get access to comprehensive performance reports about your
|
||||
app, including potential network, system resource, or user experience issues. HeadSpin supports
|
||||
a variety of complex testing modes, including hooking up your own devices to the cloud, injecting
|
||||
and receiving video and audio to/from devices, working with media (streaming) platforms, and more.
|
||||
|
||||
HeadSpin has been one of the Appium project's biggest supporters for a long time, and currently
|
||||
employs two of Appium's core maintainers, donating a significant portion of their time towards the
|
||||
development, maintenance, support, and leadership of open source Appium repos. HeadSpin has also
|
||||
worked hard towards Appium's vision of a robust Appium ecosystem, contributing several
|
||||
HeadSpin-maintained Appium drivers and plugins to the community:
|
||||
|
||||
- A [Roku TV driver](https://github.com/headspinio/appium-roku-driver)
|
||||
- A [Tizen TV driver](https://github.com/headspinio/appium-tizen-tv-driver/)
|
||||
- A [LG webOS TV driver](https://github.com/headspinio/appium-lg-webos-driver/)
|
||||
- A [Unity game automation plugin](https://github.com/headspinio/appium-altunity-plugin)
|
||||
|
||||
These are all free and open source Appium components that HeadSpin has donated to the community
|
||||
with the goal of fostering collaboration in these areas of media app automation.
|
||||
|
||||
Looking to the future, HeadSpin plans to continue supporting Appium in significant ways, both as
|
||||
a Development Partner and a significant contributor to the Appium ecosystem. The Appium project is
|
||||
deeply indebted to HeadSpin for all of its support, and is proud to take this moment to recognize
|
||||
HeadSpin as our first official Development Partner!
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-06-10
|
||||
---
|
||||
|
||||
# Announcing Sauce Labs as Appium's Strategic Partner
|
||||
|
||||
The good news surrounding our new [sponsorship and contributor compensation
|
||||
program](https://appium.io/docs/en/latest/blog/2024/05/14/announcing-appiums-sponsorship-program/)
|
||||
just keeps coming! Effective immediately we are fortunate and excited to be able to welcome a new Strategic Partner to
|
||||
the Appium project: <a href="https://saucelabs.com/resources/blog/appium-strategic-partner">Sauce Labs</a>!
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<div style="text-align:center;width:100%">
|
||||
<a href="https://saucelabs.com/resources/blog/appium-strategic-partner"><img src="/docs/en/latest/assets/images/sponsor-logo-sauce.png" style="width: 300px"/></a>
|
||||
</div>
|
||||
|
||||
Sauce Labs has a long history of support for the Appium project. In fact, Appium was initially
|
||||
incubated at Sauce Labs under the direction of [@jlipps](https://github.com/jlipps), in the early
|
||||
days of mobile automation. Sauce Labs always envisioned Appium as being a project for and by the
|
||||
community, and cemented this perspective in 2016 with the donation of Appium to the JS Foundation
|
||||
(now the [OpenJS Foundation](https://openjsf.org/)). To this day, developers associated with Sauce
|
||||
Labs continue to help maintain various parts of the Appium project.
|
||||
|
||||
Now, Sauce Labs is making a further commitment to support Appium financially as a way to enable
|
||||
our new contributor compensation program. We're very excited about this program as a vehicle for
|
||||
getting more people involved in Appium's development and maintenance. With the help of Strategic
|
||||
Partners like Sauce Labs, our project will be better able to meet the needs of our constantly
|
||||
growing userbase, and attract new developers (like you?) to build the Appium ecosystem together.
|
||||
Needless to say, we are extremely grateful for Sauce Labs's support!
|
||||
|
||||
**About Sauce Labs**
|
||||
|
||||
<em>Sauce Labs is the leader in continuous quality. Our Platform for Test helps organizations transform software testing from a chore to a competitive advantage. With decades of expertise and deep roots in the Selenium and Appium open source communities, high performing software teams use our platform to execute any testing workload across thousands of different devices, browsers, and operating systems—anywhere, any time, and at any scale. For more information, please visit [saucelabs.com](https://saucelabs.com).</em>
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-05-14
|
||||
---
|
||||
|
||||
# Announcing Appium's Sponsorship Program
|
||||
|
||||
Over the last several months, the Appium team has been working on a sponsorship program that is
|
||||
designed to help give back to Appium's contributors as well as to recognize important partner
|
||||
individuals or companies in the industry. This program is now officially launching! Let's dive into
|
||||
some of the details.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
First of all, the details and fine print will always be available at Appium's [Governance
|
||||
document](https://github.com/appium/appium/blob/master/GOVERNANCE.md), which outlines how the
|
||||
project is run, who makes project decisions, etc... This document will be kept up to date with the
|
||||
latest details of the program, so that's the place to bookmark for reference!
|
||||
|
||||
As of now, Appium has opened up sponsorship opportunities via our [OpenCollective
|
||||
page](https://opencollective.com/appium). OpenCollective is a service which allows people to donate
|
||||
to open source groups. We've defined a number of giving tiers for donations, within a very wide
|
||||
range, and welcome any financial amount with gratitude! Based on the donation tier, sponsorship
|
||||
comes with a variety of benefits, including recognition at different places in the Appium repo,
|
||||
docs, and website. In addition to financial sponsorship, the project has decided to recognize
|
||||
significant donations of project leadership and maintenance efforts from companies who have
|
||||
invested heavily into Appium with their employees' time (we call these "Development Partners").
|
||||
|
||||
What will the project do with the funds raised through this sponsorship program? We aim to give it
|
||||
all back to the Appium community! With the details again available at our [Governance document](https://github.com/appium/appium/blob/master/GOVERNANCE.md),
|
||||
we have implemented a scheme very much inspired by our friends at [WebdriverIO](https://webdriver.io/blog/2024/02/15/new-contributor-stipend-program) (thanks WDIO
|
||||
friends!) There are three groups of contributors to Appium that this scheme supports: (1) project
|
||||
maintainers (those who devote consistent time to leading the project), (2) project contributors
|
||||
(anyone in the wider community that contributes code or documentation), and (3) upstream projects
|
||||
(other open source projects Appium relies heavily on to work well). Each month, the funds raised
|
||||
via sponsorship will be distributed in different amounts to each of these groups. So if you
|
||||
make a valuable contribution to Appium moving forward, you'll be eligible to get some cash as
|
||||
a thank-you! (You'll need to have your own OpenCollective account in good standing to receive
|
||||
funds).
|
||||
|
||||
We're very excited about this new program, and hope that it helps existing and new contributors to
|
||||
feel even better about donating their time to making Appium better. And of course, none of this
|
||||
would be possible without the amazing Partners and Sponsors we hope to attract! On that note, stay
|
||||
tuned over the next few weeks as we unveil some of our initial program launch Partners! And if you
|
||||
or your company would like to participate by supporting Appium financially, you are most welcome.
|
||||
Just head over to our OpenCollective page and choose the tier that reflects your desired
|
||||
contribution level.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
authors:
|
||||
- jlipps
|
||||
date: 2024-03-07
|
||||
---
|
||||
|
||||
# Hello World!
|
||||
|
||||
This is the first post in the Appium blog. There's not much to see here yet. We're creating this
|
||||
space so we can make announcements or post other news, or information about events, that don't
|
||||
really fit inside the documentation itself.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
Stay tuned for more!
|
||||
@@ -1,5 +1,69 @@
|
||||
---
|
||||
title: Server CLI Args
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Server Command-Line Arguments
|
||||
---
|
||||
|
||||
TODO
|
||||
To start the Appium server, you may either run `appium` or `appium server`. The `server` subcommand
|
||||
is considered to be the default, so if you omit it, Appium will interpret this as your request to
|
||||
run the Appium server.
|
||||
|
||||
The invocation of `appium` (or `appium server`) can take a number of arguments, which are detailed
|
||||
below.
|
||||
|
||||
!!! note
|
||||
|
||||
All of these arguments can be set via a [Configuration File](../guides/config.md) instead if
|
||||
you want. Any arguments set on the command line will override any arguments found in
|
||||
a configuration file.
|
||||
|
||||
|
||||
|<div style="width:12em">Argument</div>|Description|Type|<div style="width:8em">Default</div>|Aliases|
|
||||
|--|--|--|--|--|
|
||||
|`--address`|IP address to listen on|string|`0.0.0.0`|`-a`|
|
||||
|`--allow-cors`|Whether the Appium server should allow web browser connections from any host|boolean|`false`||
|
||||
|`--allow-insecure`|Set which insecure features are allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Note that features defined via `--deny-insecure` will be disabled, even if also listed here. If string, a path to a text file containing policy or a comma-delimited list.|array<string>|`[]`||
|
||||
|`--base-path`|Base path to use as the prefix for all webdriver routes running on the server|string|`""`|`-pa`|
|
||||
|`--callback-address`|Callback IP address (default: same as `--address`)|string||`-ca`|
|
||||
|`--callback-port`|Callback port (default: same as `--port`) (Value must be between `1` and `65535`)|integer|`4723`|`-cp`|
|
||||
|`--config`|Path to an [Appium configuration JSON file](../guides/config.md)|string|||
|
||||
|`--debug-log-spacing`|Add exaggerated spacing in logs to help with visual inspection|boolean|`false`||
|
||||
|`--default-capabilities`|Set the default desired capabilities, which will be set on each session unless overridden by received capabilities. If a string, a path to a JSON file containing the capabilities, or raw JSON.|object||`-dc`|
|
||||
|`--deny-insecure`|Set which insecure features are not allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Features listed here will not be enabled even if also listed in `--allow-insecure`, and even if `--relaxed-security` is enabled. If string, a path to a text file containing policy or a comma-delimited list.|array<string>|`[]`||
|
||||
|`--driver`|Driver-specific configuration. Keys should correspond to driver package names|object|||
|
||||
|`--drivers-import-chunk-size`|The maximum amount of drivers that could be imported in parallel on server startup|number|`3`||
|
||||
|`--keep-alive-timeout`|Number of seconds the Appium server should apply as both the keep-alive timeout and the connection timeout for all requests. Setting this to `0` disables the timeout.|integer|`600`|`-ka`|
|
||||
|`--local-timezone`|Use local timezone for timestamps|boolean|`false`||
|
||||
|`--log`|Also send log output to this file|string||`-g`|
|
||||
|`--log-filters`|One or more log filtering rules|array|||
|
||||
|`--log-level`|Log level (console[:file]) (Value must be one of: `info`, `info:debug`, `info:info`, `info:warn`, `info:error`, `warn`, `warn:debug`, `warn:info`, `warn:warn`, `warn:error`, `error`, `error:debug`, `error:info`, `error:warn`, `error:error`, `debug`, `debug:debug`, `debug:info`, `debug:warn`, `debug:error`)|string|`debug`||
|
||||
|`--log-format`|Log format (Value must be to one of: `text`, `json`, `pretty_json`). If logs are printed as JSON then the text coloring is always disabled.|string|`text`||
|
||||
|`--log-no-colors`|Do not use color in console output|boolean|`false`||
|
||||
|`--log-timestamp`|Show timestamps in console output|boolean|`false`||
|
||||
|`--long-stacktrace`|Add long stack traces to log entries. Recommended for debugging only.|boolean|`false`||
|
||||
|`--no-perms-check`|Skip various permission checks on the server startup|boolean|`false`||
|
||||
|`--nodeconfig`|Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself|string|||
|
||||
|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object|||
|
||||
|`--plugins-import-chunk-size`|The maximum amount of plugins that could be imported in parallel on server startup|number|`7`||
|
||||
|`--port`|Port to listen on (Value must be between `1` and `65535`)|integer|`4723`|`-p`|
|
||||
|`--relaxed-security`|Disable additional security checks, so it is possible to use some advanced features, provided by drivers supporting this option. Only enable it if all the clients are in the trusted network and it's not the case if a client could potentially break out of the session sandbox. Specific features can be overridden by using `--deny-insecure`|boolean|`false`||
|
||||
|`--session-override`|Enables session override (clobbering)|boolean|`false`||
|
||||
|`--ssl-cert-path`|Absolute path to the `.cert` file if TLS is used. Must be provided together with `--ssl-key-path`. See the [SSL/TLS/SPDY Support guide](../guides/tls.md) for details|string|||
|
||||
|`--ssl-key-path`|Absolute path to the `.key` file if TLS is used. Must be provided together with `--ssl-cert-path`. See the [SSL/TLS/SPDY Support guide](../guides/tls.md) for details|string|||
|
||||
|`--strict-caps`|Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device|boolean|`false`||
|
||||
|`--tmp`|Absolute path to directory Appium can use to manage temp files|string|Windows: `C:\Windows\Temp`<br>Others: `/tmp`||
|
||||
|`--trace-dir`|Absolute path to directory Appium can use to save iOS instrument traces|string|`<tmp>/appium-instruments`||
|
||||
|`--use-drivers`|A list of drivers to activate. By default, all installed drivers will be activated.|array<string>|`[]`||
|
||||
|`--use-plugins`|A list of plugins to activate. To activate all plugins, the value should be an array with a single item `"all"`.|array<string>|`[]`||
|
||||
|`--webhook`|Also send log output to this http listener|string||`-G`|
|
||||
|
||||
The following arguments are used for information retrieval, after which the server will automatically exit. They are therefore meant for reference or debug purposes.
|
||||
|
||||
|<div style="width:10em">Argument</div>|Description|Alias|
|
||||
|--|--|--|
|
||||
|`--help`|Print instructions on using the Appium command-line. This argument can also be used for any Appium subcommands.|`-h`|
|
||||
|`--show-build-info`|Print detailed information on the Appium server version||
|
||||
|`--show-config`|Print the current Appium server configuration details||
|
||||
|`--show-debug-info`|Print information on the current environment: details about the operating system, Node.js, and Appium itself||
|
||||
|`--version`|Print the Appium server version|`-v`|
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Server Environment Variables
|
||||
---
|
||||
|
||||
The primary way of configuring the Appium server is via [Command-Line Arguments](./args.md). However, some more
|
||||
advanced features are toggled or configured via environment variables. To set environment
|
||||
variables, refer to the documentation for your operating system and terminal. These are the
|
||||
environment variables that the Appium server understands:
|
||||
|
||||
|Variable |Description|
|
||||
|--------|-----------|
|
||||
|`APPIUM_HOME`|By default, Appium creates a directory called `.appium` in the home directory for your system user. You can adjust the directory with this variable, as detailed in the [Managing Extensions](../guides/managing-exts.md) guide.|
|
||||
|`APPIUM_TMP_DIR`|By default, Appium uses a random temporary directory for many of its operations. If you wish to use a specific directory, you may do so by including an absolute path as the value of this variable. The behaviour is equivalent to using the `--tmp` CLI arg.|
|
||||
|`APPIUM_PREFER_SYSTEM_UNZIP`|Set to `0` or `false` to request that Appium not use the `unzip` binary included on your system for unzipping downloaded apps or other artifacts. Instead it will use a JS-based unzip library. This could help on some systems with non-existent or non-standard `unzip` commands. Note that if unzipping fails using the system library, the fallback library will be attempted in any case, so setting this env var merely saves time in the event you know the system unzip will fail.|
|
||||
|`APPIUM_HOST`|Same as the `--address` CLI arg|
|
||||
|`APPIUM_PORT`|Same as the `--port` CLI arg|
|
||||
|`APPIUM_RELOAD_EXTENSIONS`|Set to `1` to cause Appium to re-require extensions when new sessions are created. This is mostly useful for [building extensions](../developing/build-drivers.md)|
|
||||
|`APPIUM_OMIT_PEER_DEPS`|Adds `--omit=peer` to all the NPM commands run internally by Appium. Mostly an internal feature.|
|
||||
|`APPIUM_APPS_CACHE_MAX_AGE`|Allows to set the maximum age (in minutes) for [cached applications](../guides/caching.md). The default value is `60 * 24` (24 hours). Do not set it to a lower number than the duration of a single session startup.|
|
||||
|`APPIUM_APPS_CACHE_MAX_ITEMS`|Allows to set the maximum amount of [cached applications](../guides/caching.md). The default value is `1024`. Do not set it to a lower number than the amount of apps in all parallel sessions per process.|
|
||||
|`APPIUM_APPS_CACHE_IGNORE_URL_QUERY`| If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys. See the corresponding
|
||||
[feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713)
|
||||
for more details. Disabled by default.|
|
||||
@@ -1,5 +1,226 @@
|
||||
---
|
||||
title: The Extension CLI
|
||||
title: Extension Command-Line Usage
|
||||
---
|
||||
|
||||
TODO
|
||||
Appium allows for the flexible installation and management of various _extensions_, such as _drivers_
|
||||
(which provide Appium with the capability to automate a given platform) and _plugins_ (which can
|
||||
augment or alter the way individual Appium commands work). For a conceptual understanding of these
|
||||
entities, please review the [Introduction](../intro/index.md).
|
||||
|
||||
Management of drivers and plugins is handled by Appium's Extension CLI (command-line interface).
|
||||
|
||||
!!! note
|
||||
|
||||
This reference uses placeholders to refer to various options. Anywhere you see one of these
|
||||
placeholders in the reference, ensure you replace it with the correct type of actual content.
|
||||
|
||||
|Placeholder|Meaning|
|
||||
|--|--|
|
||||
|`<ext-type>`|"Extension type". It should be either `driver` or `plugin`. All the Extension CLI commands can be used with either drivers or plugins, so you must specify which type of extension will be used|
|
||||
|`<ext-name>`|"Extension name". This is the short name of the extension found in a call to `appium <ext-type> list`. This is distinct from the NPM package name of the extension or, in general, the "install spec" of the extension.|
|
||||
|`<install-spec>`|"Install specification". This refers to the string used to indicate what extension Appium should install.|
|
||||
|`<install-source>`|This refers to the method that Appium should use to install an extension.|
|
||||
|
||||
## Commands
|
||||
|
||||
All Extension CLI commands begin with `appium <ext-type>`, i.e., either `appium driver` or `appium
|
||||
plugin`.
|
||||
|
||||
All Extension CLI commands can take an optional `--json` argument, which will return the result of
|
||||
the command as a machine-readable JSON string rather than the standard output, which is colourized
|
||||
and tuned for human consumption.
|
||||
|
||||
### `doctor`
|
||||
|
||||
Run doctor checks for the given extension, which validate whether the extension has its prerequisites
|
||||
configured correctly. Note that not all extensions include doctor checks. See the
|
||||
[Building Doctor Checks](../developing/build-doctor-checks.md) tutorial for more details on
|
||||
how to create them.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> doctor <ext-name>
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<ext-name>`: the name of the extension whose doctor checks you want to run
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
Example (run doctor checks for the UiAutomator2 driver):
|
||||
|
||||
```
|
||||
appium driver doctor uiautomator2
|
||||
```
|
||||
|
||||
### `install`
|
||||
|
||||
Install an extension. If successful, respond with the short name of the extension which can be used
|
||||
in other invocations of the Extension CLI. If the extension is a driver, also note which platforms
|
||||
may be used with the driver.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> install <install-spec> [--source=<install-source>] [--package=<package-name>] [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<install-spec>`: this is the name, location, and/or version of the extension you want to
|
||||
install. Its possible values are dependent on the `<install-source>` (see below).
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--source`: this directs Appium where to find your extension. See below for a table of possible
|
||||
source types and corresponding install specification.
|
||||
- `--package`: when `<install-source>` is `git` or `github`, `--package` is required. It should be
|
||||
the Node.js package name of the extension. Without this information, Appium will not be able to
|
||||
find the installed package.
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
|Install source type|Behaviour|
|
||||
|--|--|
|
||||
|None|This is the default behaviour when no `--source` is used. In this case, Appium will look at `<install-spec>` and match it against the name of extensions available when running `appium <ext-type> list`, i.e., against the officially recognized extension names. If found, it will install that extension at the latest version via NPM|
|
||||
|`npm`|Install an extension based on its NPM package name. Here, `<install-spec>` must be the NPM package name with any additional NPM installation modifiers, like version (see below)|
|
||||
|`github`|Install an extension via a GitHub spec of the form `<org>/<repo>`|
|
||||
|`git`|Install an extension via a Git URL (e.g., `git+ssh://git-host.com/repo.git`)|
|
||||
|`local`|Install an extension via a local path. This must be a path to the directory where the Node.js package information for the driver is located.|
|
||||
|
||||
#### NPM-based `<install-spec>`
|
||||
|
||||
When Appium is installing an extension via NPM (as is the case when `--source` is either omitted or
|
||||
set to `npm`), the `<install-spec>` can be complex, and can include any kind of information allowed
|
||||
by `npm install`:
|
||||
|
||||
- `[@scope]/<name>`
|
||||
- `[@scope]/<name>@<version>`
|
||||
- `[@scope]/<name>@<tag>`
|
||||
- `[@scope]/<name>@<version range>`
|
||||
|
||||
#### Examples
|
||||
|
||||
- Install the latest XCUITest driver:
|
||||
|
||||
```
|
||||
appium driver install xcuitest
|
||||
```
|
||||
|
||||
- Install the XCUITest driver at version 4.11.1:
|
||||
|
||||
```
|
||||
appium driver install xcuitest@4.11.1
|
||||
```
|
||||
|
||||
- Install the `beta` version of the `@appium/fake-driver` from NPM:
|
||||
|
||||
```
|
||||
appium driver install --source=npm @appium/fake-driver@beta
|
||||
```
|
||||
|
||||
- Install a locally-developed plugin:
|
||||
|
||||
```
|
||||
appium plugin install --source=local /path/to/my/plugin
|
||||
```
|
||||
|
||||
### `list`
|
||||
|
||||
List installed and available extensions. "Available" extensions include those which are officially
|
||||
recognized by the Appium team, but you are not limited to installing only the extensions displayed
|
||||
in this list.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> list [--installed] [--updates] [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--installed`: show only installed extensions, not installed plus available extensions
|
||||
- `--updates`: for extensions installed via NPM, display a message if there are any updates
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
### `run`
|
||||
|
||||
Run a script included in an extension package. Extension authors can include runnable scripts that
|
||||
assist with setup or perform other tasks. These scripts are given names (called the `<script-name>`
|
||||
in this reference) by extension authors and will generally be documented in extension
|
||||
documentation.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> run <ext-name> [--json] <script-name> [script-args]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<ext-name>`: the name of the extension whose script you want to run
|
||||
- `<script-name>`: the name of the script the extension has published
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `script-args`: any arguments that Appium does not interpret as belonging to its own set of
|
||||
arguments will be passed along to the extension script
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
Example (run the `reset` script included with the UiAutomator2 driver):
|
||||
|
||||
```
|
||||
appium driver run uiautomator2 reset
|
||||
```
|
||||
|
||||
### `update`
|
||||
|
||||
Update one or more extensions that have been installed via NPM. By default, Appium will not
|
||||
automatically update any extension past a major version boundary, so as to prevent
|
||||
unintended breaking changes.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> update <ext-name> [--unsafe] [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<ext-name>`: the name of the extension to update, or the string `installed` (which will update
|
||||
all installed extensions)
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--unsafe`: direct Appium to go ahead and update past a major version boundary
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
### `uninstall`
|
||||
|
||||
Remove an installed extension.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> uninstall <ext-name> [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<ext-name>`: the name of the extension to uninstall
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
---
|
||||
title: 命令行介绍
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Command-Line Overview
|
||||
---
|
||||
|
||||
TODO
|
||||
Appium provides a command-line executable (`appium`), which will likely be your main way of interacting with
|
||||
the Appium server. This section of the Appium documentation describes how to use this executable.
|
||||
|
||||
To start off, you can run `appium -v` or `appium --version` to return the installed version,
|
||||
or run `appium -h` or `appium --help` to return the help message.
|
||||
|
||||
The main `appium` executable provides the following subcommands:
|
||||
|
||||
1. `appium server` (or simply `appium`) - launch an Appium server
|
||||
- [See here for accepted arguments](./args.md)
|
||||
- For advanced features, [see here for accepted environment variables](./env-vars.md)
|
||||
2. `appium driver` - manage Appium drivers
|
||||
- [See here for details](./extensions.md)
|
||||
3. `appium plugin` - manage Appium plugins
|
||||
- [See here for details](./extensions.md)
|
||||
4. `appium setup` - batch install a preset of drivers and plugins
|
||||
- [See here for details](./setup.md)
|
||||
|
||||
Like the main command, you can also run each subcommand with the `-h` or `--help` flag to learn more about it.
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Setup Command-Line Usage
|
||||
---
|
||||
|
||||
The `setup` command aims to simplify the initial procedure of setting up Appium. It allows to install
|
||||
multiple extensions (drivers/plugins) in one go, without the need to run
|
||||
`appium <ext-name> install <ext-name>` multiple times.
|
||||
|
||||
The command has several presets that can be used to install different sets of extensions.
|
||||
The presets are as follows:
|
||||
|
||||
|Preset|Installation Command|Included Drivers|Included Plugins|
|
||||
|--|--|--|--|
|
||||
|Mobile|`appium setup mobile` or `appium setup`|`uiautomator2`, `xcuitest`[^1], `espresso`|`images`|
|
||||
|Desktop application|`appium setup desktop`|`mac2`[^1], `windows`[^2]|`images`|
|
||||
|Desktop browser|`appium setup browser`|`safari`[^1], `gecko`, `chromium`|`images`|
|
||||
|
||||
Attempting to install a preset while already having one or more of its included extensions installed
|
||||
will only install the missing extensions.
|
||||
|
||||
Refer to the [Ecosystem documentation](../ecosystem/index.md) to learn more about the extensions
|
||||
listed above.
|
||||
|
||||
[^1]: Only installed if the host machine is running macOS.
|
||||
[^2]: Only installed if the host machine is running Windows.
|
||||
@@ -0,0 +1,542 @@
|
||||
# Driver: base-driver
|
||||
|
||||
### `createSession`
|
||||
|
||||
`POST` **`/session`**
|
||||
|
||||
Historically the first two arguments were reserved for JSONWP capabilities.
|
||||
Appium 2 has dropped the support of these, so now we only accept capability
|
||||
objects in W3C format and thus allow any of the three arguments to represent
|
||||
the latter.
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#new-session](https://w3c.github.io/webdriver/#new-session)
|
||||
|
||||
<!-- comment source: multiple -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `desiredCapabilities?` | `W3CDriverCaps`<`C`\> | the new session capabilities |
|
||||
| `requiredCapabilities?` | `W3CDriverCaps`<`C`\> | another place the new session capabilities could be sent (typically left undefined) |
|
||||
| `capabilities?` | `W3CDriverCaps`<`C`\> | another place the new session capabilities could be sent (typically left undefined) |
|
||||
|
||||
#### Response
|
||||
|
||||
`CreateResult`
|
||||
|
||||
The capabilities object representing the created session
|
||||
|
||||
### `deleteSession`
|
||||
|
||||
`DELETE` **`/session/:sessionId`**
|
||||
|
||||
Returns capabilities for the session and event history (if applicable)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
`SingularSessionData`<`C`, `SessionData`\>
|
||||
|
||||
A session data object
|
||||
|
||||
### `getSession`
|
||||
|
||||
`GET` **`/session/:sessionId`**
|
||||
|
||||
Returns capabilities for the session and event history (if applicable)
|
||||
|
||||
<!-- comment source: multiple -->
|
||||
|
||||
#### Response
|
||||
|
||||
`SingularSessionData`<`C`, `SessionData`\>
|
||||
|
||||
A session data object
|
||||
|
||||
### `findElement`
|
||||
|
||||
`POST` **`/session/:sessionId/element`**
|
||||
|
||||
Find a UI element given a locator strategy and a selector, erroring if it can't be found
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `string` | the locator strategy |
|
||||
| `value` | `string` | the selector to combine with the strategy to find the specific element |
|
||||
|
||||
#### Response
|
||||
|
||||
`Element`<`string`\>
|
||||
|
||||
The element object encoding the element id which can be used in element-related
|
||||
commands
|
||||
|
||||
### `findElementFromElement`
|
||||
|
||||
`POST` **`/session/:sessionId/element/:elementId/element`**
|
||||
|
||||
Find a UI element given a locator strategy and a selector, erroring if it can't be found. Only
|
||||
look for elements among the set of descendants of a given element
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-element-from-element](https://w3c.github.io/webdriver/#find-element-from-element)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `string` | the locator strategy |
|
||||
| `value` | `string` | the selector to combine with the strategy to find the specific element |
|
||||
|
||||
#### Response
|
||||
|
||||
`Element`<`string`\>
|
||||
|
||||
The element object encoding the element id which can be used in element-related
|
||||
commands
|
||||
|
||||
### `findElementFromShadowRoot`
|
||||
|
||||
`POST` **`/session/:sessionId/shadow/:shadowId/element`**
|
||||
|
||||
Find an element from a shadow root
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-element-from-shadow-root](https://w3c.github.io/webdriver/#find-element-from-shadow-root)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `string` | the locator strategy |
|
||||
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
|
||||
|
||||
#### Response
|
||||
|
||||
`Element`<`string`\>
|
||||
|
||||
The element inside the shadow root matching the selector
|
||||
|
||||
### `findElements`
|
||||
|
||||
`POST` **`/session/:sessionId/elements`**
|
||||
|
||||
Find a a list of all UI elements matching a given a locator strategy and a selector
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `string` | the locator strategy |
|
||||
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
|
||||
|
||||
#### Response
|
||||
|
||||
`Element`<`string`\>[]
|
||||
|
||||
A possibly-empty list of element objects
|
||||
|
||||
### `findElementsFromElement`
|
||||
|
||||
`POST` **`/session/:sessionId/element/:elementId/elements`**
|
||||
|
||||
Find a a list of all UI elements matching a given a locator strategy and a selector. Only
|
||||
look for elements among the set of descendants of a given element
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-elements-from-element](https://w3c.github.io/webdriver/#find-elements-from-element)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `string` | the locator strategy |
|
||||
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
|
||||
|
||||
#### Response
|
||||
|
||||
`Element`<`string`\>[]
|
||||
|
||||
A possibly-empty list of element objects
|
||||
|
||||
### `findElementsFromShadowRoot`
|
||||
|
||||
`POST` **`/session/:sessionId/shadow/:shadowId/elements`**
|
||||
|
||||
Find elements from a shadow root
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-element-from-shadow-root](https://w3c.github.io/webdriver/#find-element-from-shadow-root)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `string` | the locator strategy |
|
||||
| `value` | `string` | the selector to combine with the strategy to find the specific elements |
|
||||
|
||||
#### Response
|
||||
|
||||
`Element`<`string`\>[]
|
||||
|
||||
A possibly empty list of elements inside the shadow root matching the selector
|
||||
|
||||
### `getLog`
|
||||
|
||||
`POST` **`/session/:sessionId/log`**
|
||||
|
||||
Get the log for a given log type.
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use the `/session/:sessionId/se/log` endpoint instead
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `type` | `string` | Name/key of log type as defined in ILogCommands.supportedLogTypes. |
|
||||
|
||||
#### Response
|
||||
|
||||
`any`
|
||||
|
||||
### `getLog`
|
||||
|
||||
`POST` **`/session/:sessionId/se/log`**
|
||||
|
||||
Get the log for a given log type.
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `type` | `string` | Name/key of log type as defined in ILogCommands.supportedLogTypes. |
|
||||
|
||||
#### Response
|
||||
|
||||
`any`
|
||||
|
||||
### `getLogEvents`
|
||||
|
||||
`POST` **`/session/:sessionId/appium/events`**
|
||||
|
||||
Get a list of events that have occurred in the current session
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `type?` | `string` \| `string`[] | filter the returned events by including one or more types |
|
||||
|
||||
#### Response
|
||||
|
||||
`EventHistory` \| `Record`<`string`, `number`\>
|
||||
|
||||
The event history for the session
|
||||
|
||||
### `getLogTypes`
|
||||
|
||||
`GET` **`/session/:sessionId/log/types`**
|
||||
|
||||
Get available log types as a list of strings
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use the `/session/:sessionId/se/log/types` endpoint instead
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
`string`[]
|
||||
|
||||
### `getLogTypes`
|
||||
|
||||
`GET` **`/session/:sessionId/se/log/types`**
|
||||
|
||||
Get available log types as a list of strings
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
`string`[]
|
||||
|
||||
### `getPageSource`
|
||||
|
||||
`GET` **`/session/:sessionId/source`**
|
||||
|
||||
Get the current page/app source as HTML/XML
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#get-page-source](https://w3c.github.io/webdriver/#get-page-source)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
`string`
|
||||
|
||||
The UI hierarchy in a platform-appropriate format (e.g., HTML for a web page)
|
||||
|
||||
### `getSessions`
|
||||
|
||||
`GET` **`/sessions`**
|
||||
|
||||
Get data for all sessions running on an Appium server
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
A list of session data objects.
|
||||
Each session data object will be returned with `id` and the session's capabilities as `capabilities` keys like an example below:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id":"ba30c6da-c266-4734-8ddb-c16f5bb53e16",
|
||||
"capabilities":{ "platformName":"ios","browserName":"safari","automationName":"xcuitest","platformVersion":"17.2","deviceName":"iPhone 15" }
|
||||
},
|
||||
{
|
||||
"id":"1441110c-1ece-4e45-abbf-ebf404f45f0a",
|
||||
"capabilities":{ "platformName":"ios","browserName":"safari","automationName":"xcuitest","platformVersion":"17.0","deviceName":"iPhone 14" }
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
### `getSettings`
|
||||
|
||||
`GET` **`/session/:sessionId/appium/settings`**
|
||||
|
||||
Update the session's settings dictionary with a new settings object
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
``null``
|
||||
|
||||
### `updateSettings`
|
||||
|
||||
`POST` **`/session/:sessionId/appium/settings`**
|
||||
|
||||
Update the session's settings dictionary with a new settings object
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `settings` | `Settings` | A key-value map of setting names to values. Settings not named in the map will not have their value adjusted. |
|
||||
|
||||
#### Response
|
||||
|
||||
``null``
|
||||
|
||||
### `getStatus`
|
||||
|
||||
`GET` **`/status`**
|
||||
|
||||
**`Summary`**
|
||||
|
||||
Retrieve the server's current status.
|
||||
|
||||
**`Description`**
|
||||
|
||||
Returns information about whether a remote end is in a state in which it can create new sessions and can additionally include arbitrary meta information that is specific to the implementation.
|
||||
|
||||
The readiness state is represented by the ready property of the body, which is false if an attempt to create a session at the current time would fail. However, the value true does not guarantee that a New Session command will succeed.
|
||||
|
||||
Implementations may optionally include additional meta information as part of the body, but the top-level properties ready and message are reserved and must not be overwritten.
|
||||
|
||||
<!-- comment source: builtin-interface -->
|
||||
|
||||
#### Examples
|
||||
|
||||
<!-- BEGIN:EXAMPLES -->
|
||||
##### JavaScript
|
||||
<!-- BEGIN:EXAMPLE lang=JavaScript -->
|
||||
|
||||
```js
|
||||
// webdriver.io example
|
||||
await driver.status();
|
||||
```
|
||||
|
||||
<!-- END:EXAMPLE -->
|
||||
##### Python
|
||||
<!-- BEGIN:EXAMPLE lang=Python -->
|
||||
|
||||
```python
|
||||
driver.get_status()
|
||||
```
|
||||
|
||||
<!-- END:EXAMPLE -->
|
||||
##### Java
|
||||
<!-- BEGIN:EXAMPLE lang=Java -->
|
||||
|
||||
```java
|
||||
driver.getStatus();
|
||||
```
|
||||
|
||||
<!-- END:EXAMPLE -->
|
||||
##### Ruby
|
||||
<!-- BEGIN:EXAMPLE lang=Ruby -->
|
||||
|
||||
```ruby
|
||||
# ruby_lib example
|
||||
remote_status
|
||||
|
||||
# ruby_lib_core example
|
||||
@driver.remote_status
|
||||
```
|
||||
|
||||
<!-- END:EXAMPLE -->
|
||||
<!-- END:EXAMPLES -->
|
||||
|
||||
#### Response
|
||||
|
||||
`Object`
|
||||
|
||||
### `getTimeouts`
|
||||
|
||||
`GET` **`/session/:sessionId/timeouts`**
|
||||
|
||||
Set the various timeouts associated with a session
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#set-timeouts](https://w3c.github.io/webdriver/#set-timeouts)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
``null``
|
||||
|
||||
### `timeouts`
|
||||
|
||||
`POST` **`/session/:sessionId/timeouts`**
|
||||
|
||||
Set the various timeouts associated with a session
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#set-timeouts](https://w3c.github.io/webdriver/#set-timeouts)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `type?` | `string` | used only for the old (JSONWP) command, the type of the timeout |
|
||||
| `ms?` | `string` \| `number` | used only for the old (JSONWP) command, the ms for the timeout |
|
||||
| `script?` | `number` | the number in ms for the script timeout, used for the W3C command |
|
||||
| `pageLoad?` | `number` | the number in ms for the pageLoad timeout, used for the W3C command |
|
||||
| `implicit?` | `string` \| `number` | the number in ms for the implicit wait timeout, used for the W3C command |
|
||||
|
||||
#### Response
|
||||
|
||||
``null``
|
||||
|
||||
### `implicitWait`
|
||||
|
||||
`POST` **`/session/:sessionId/timeouts/implicit_wait`**
|
||||
|
||||
Set the implicit wait timeout
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use the `/session/:sessionId/timeouts` endpoint instead
|
||||
|
||||
Use `timeouts` instead
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `ms` | `string` \| `number` | the timeout in ms |
|
||||
|
||||
#### Response
|
||||
|
||||
``null``
|
||||
|
||||
### `logCustomEvent`
|
||||
|
||||
`POST` **`/session/:sessionId/appium/log_event`**
|
||||
|
||||
Add a custom-named event to the Appium event log
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `vendor` | `string` | the name of the vendor or tool the event belongs to, to namespace the event |
|
||||
| `event` | `string` | the name of the event itself |
|
||||
|
||||
#### Response
|
||||
|
||||
``null``
|
||||
|
||||
### `reset`
|
||||
|
||||
`POST` **`/session/:sessionId/appium/app/reset`**
|
||||
|
||||
Reset the current session (run the delete session and create session subroutines)
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
Please use each driver's launch, activate, terminate or cleanup method.
|
||||
|
||||
Use explicit session management commands instead
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
``null``
|
||||
@@ -0,0 +1,22 @@
|
||||
# Plugin: execute-driver
|
||||
|
||||
### `executeDriverScript`
|
||||
|
||||
`POST` **`/session/:sessionId/appium/execute_driver`**
|
||||
|
||||
Implementation of a command within a plugin
|
||||
|
||||
At minimum, `D` must be `ExternalDriver`, but a plugin can be more narrow about which drivers it supports.
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `script` | [script: string, scriptType: string, timeoutMs: number] |
|
||||
| `type?` | [script: string, scriptType: string, timeoutMs: number] |
|
||||
|
||||
#### Response
|
||||
|
||||
`unknown`
|
||||
@@ -0,0 +1,67 @@
|
||||
# Plugin: images
|
||||
|
||||
### `compareImages`
|
||||
|
||||
`POST` **`/session/:sessionId/appium/compare_images`**
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `mode` | `any`[] |
|
||||
| `options?` | `any`[] |
|
||||
|
||||
#### Response
|
||||
|
||||
`ComparisonResult`
|
||||
|
||||
### `findElement`
|
||||
|
||||
`POST` **`/session/:sessionId/element`**
|
||||
|
||||
Find a UI element given a locator strategy and a selector, erroring if it can't be found
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `any` | the locator strategy |
|
||||
| `value` | `any` | the selector to combine with the strategy to find the specific element |
|
||||
|
||||
#### Response
|
||||
|
||||
`any`
|
||||
|
||||
The element object encoding the element id which can be used in element-related
|
||||
commands
|
||||
|
||||
### `findElements`
|
||||
|
||||
`POST` **`/session/:sessionId/elements`**
|
||||
|
||||
Find a a list of all UI elements matching a given a locator strategy and a selector
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `any` | the locator strategy |
|
||||
| `value` | `any` | the selector to combine with the strategy to find the specific elements |
|
||||
|
||||
#### Response
|
||||
|
||||
`any`
|
||||
|
||||
A possibly-empty list of element objects
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Intro to Commands
|
||||
---
|
||||
|
||||
Here you can find various commands exposed by the main Appium module through its base driver, as
|
||||
well as the commands available in several plugins.
|
||||
|
||||
!!! note
|
||||
|
||||
The Appium base driver only exposes a few commands, as it is not meant to be used on its own.
|
||||
Please refer to the documentation of your [Appium driver](../ecosystem/drivers.md) to learn
|
||||
about the commands it exposes, and then check your [Appium client](../ecosystem/clients.md)
|
||||
documentation for the exact syntax of that command.
|
||||
|
||||
The command listings can be found here:
|
||||
|
||||
* [Base Driver](./base-driver.md)
|
||||
* [Execute Driver Plugin](./execute-driver-plugin.md)
|
||||
* [Images Plugin](./images-plugin.md)
|
||||
* [Relaxed Caps Plugin](./relaxed-caps-plugin.md)
|
||||
* [Universal XML Plugin](./universal-xml-plugin.md)
|
||||
@@ -0,0 +1,27 @@
|
||||
# Plugin: relaxed-caps
|
||||
|
||||
### `createSession`
|
||||
|
||||
`POST` **`/session`**
|
||||
|
||||
Start a new automation session
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#new-session](https://w3c.github.io/webdriver/#new-session)
|
||||
|
||||
<!-- comment source: multiple -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `desiredCapabilities?` | `any` | the new session capabilities |
|
||||
| `requiredCapabilities?` | `any` | another place the new session capabilities could be sent (typically left undefined) |
|
||||
| `capabilities?` | `any` | another place the new session capabilities could be sent (typically left undefined) |
|
||||
|
||||
#### Response
|
||||
|
||||
`any`
|
||||
|
||||
The capabilities object representing the created session
|
||||
@@ -0,0 +1,68 @@
|
||||
# Plugin: universal-xml
|
||||
|
||||
### `findElement`
|
||||
|
||||
`POST` **`/session/:sessionId/element`**
|
||||
|
||||
Find a UI element given a locator strategy and a selector, erroring if it can't be found
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-element](https://w3c.github.io/webdriver/#find-element)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `any`[] | the locator strategy |
|
||||
|
||||
#### Response
|
||||
|
||||
`any`
|
||||
|
||||
The element object encoding the element id which can be used in element-related
|
||||
commands
|
||||
|
||||
### `findElements`
|
||||
|
||||
`POST` **`/session/:sessionId/elements`**
|
||||
|
||||
Find a a list of all UI elements matching a given a locator strategy and a selector
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#find-elements](https://w3c.github.io/webdriver/#find-elements)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `using` | `any`[] | the locator strategy |
|
||||
|
||||
#### Response
|
||||
|
||||
`any`
|
||||
|
||||
A possibly-empty list of element objects
|
||||
|
||||
### `getPageSource`
|
||||
|
||||
`GET` **`/session/:sessionId/source`**
|
||||
|
||||
Get the current page/app source as HTML/XML
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://w3c.github.io/webdriver/#get-page-source](https://w3c.github.io/webdriver/#get-page-source)
|
||||
|
||||
<!-- comment source: method-signature -->
|
||||
|
||||
#### Response
|
||||
|
||||
`string`
|
||||
|
||||
The UI hierarchy in a platform-appropriate format (e.g., HTML for a web page)
|
||||
@@ -0,0 +1,451 @@
|
||||
---
|
||||
title: Appium's Config System
|
||||
---
|
||||
|
||||
Appium 2 supports [configuration files](../guides/config.md). A configuration file is intended to
|
||||
have (nearly) 1:1 parity with command-line arguments. An end user can supply Appium 2 with
|
||||
a configuration file, CLI args, or both (the args have precedence over the config file).
|
||||
|
||||
This document will be a technical overview of how the configuration system works. It is intended
|
||||
for Appium contributors, but will also explain the system's fundamental features.
|
||||
|
||||
## Reading a Config File
|
||||
|
||||
A config file is a JSON, JavaScript, or YAML file which can be validated against a schema. By
|
||||
default, this file will be named `.appiumrc.{json,js,yaml,yml}` and should be in the root of the
|
||||
project which depends upon `appium`. Other filenames and locations are supported via the `--config
|
||||
<file>` flag. For obvious reasons, the `config` argument is disallowed within config files.
|
||||
|
||||
In lieu of a separate file, configuration can be embedded in a project's `package.json` using the
|
||||
`appiumConfig` property, e.g.,:
|
||||
|
||||
```json
|
||||
{
|
||||
"appiumConfig": {
|
||||
"server": {
|
||||
"port": 12345
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`
|
||||
will call into `lib/config-file.js` to load and/or search for a configuration file and in
|
||||
`package.json`.
|
||||
|
||||
!!! note
|
||||
|
||||
It is not an error if configuration isn't found!
|
||||
|
||||
The [`lilconfig`](https://npm.im/lilconfig) package provides the search & load functionality; refer
|
||||
to its documentation for more information about the search paths. Additionally, Appium provides
|
||||
support for config files written in YAML via the package [`yaml`](https://npm.im/yaml).
|
||||
|
||||
If a config file is found and successfully [validated](#validation), the result will be merged with
|
||||
a set of defaults and any additionall CLI arguments. CLI arguments have precedence over config
|
||||
files, and config files have precedence over defaults.
|
||||
|
||||
## Validation
|
||||
|
||||
The same system is used for _both_ validation of config files _and_ command-line arguments.
|
||||
|
||||
The package [`ajv`](https://npm.im/ajv) provides validation. Of course, to make `ajv` validate
|
||||
anything, it must be provided a _schema_.
|
||||
|
||||
The _base_ schema is a [JSON Schema
|
||||
Draft-7](https://json-schema.org/draft/2020-12/json-schema-core.html)-compliant object exported by
|
||||
`lib/schema/appium-config-schema.js`. This schema defines configuration _native to Appium_, and
|
||||
only concerns its behavior as a _server_; it does not define configuration for any other
|
||||
functionality (e.g., the `plugin` or `driver` subcommands).
|
||||
|
||||
!!! warning
|
||||
|
||||
Note that this file is the _base_ schema; this will become painfully relevant.
|
||||
|
||||
This file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
|
||||
especially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files.
|
||||
|
||||
It is more straightforward to explain how config files are validated, so we'll start there.
|
||||
|
||||
### Validating Config Files
|
||||
|
||||
When a config file is found (`lib/config-file.js`), it will call the `validate` function exported
|
||||
from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to
|
||||
validate the data against the schema that Appium has provided it.
|
||||
|
||||
If the config file is invalid, errors will be generated to be displayed to the user. Finally, the
|
||||
`init` function will detect these errors, display them, and the process will exit.
|
||||
|
||||
I hope that made sense, because this is the easy part.
|
||||
|
||||
### Validating CLI Arguments
|
||||
|
||||
As mentioned earlier, the same system is used for validating both config files and CLI arguments.
|
||||
|
||||
Totally not judging, but Appium uses [`argparse`](https://npm.im/argparse) for its CLI argument
|
||||
parsing. This package, and others like it, provides an API to define the arguments a command-line
|
||||
Node.js script accepts, and will ultimately return an object representation of the user-supplied
|
||||
arguments.
|
||||
|
||||
Just as the schema defines what's allowed in a config file, it also defines what's allowed on the
|
||||
command-line.
|
||||
|
||||
#### Defining CLI Arguments via Schema
|
||||
|
||||
CLI arguments must be _defined_ before their values can be validated.
|
||||
|
||||
A JSON schema isn't a natural fit for defining CLI args--it needs some grease to make it work--but
|
||||
it's close enough that we can do so with an adapter and some custom metadata.
|
||||
|
||||
In `lib/cli/parser.js`, there's a wrapper around `argparse`'s `ArgumentParser`; it's called (wait
|
||||
for it)... `ArgParser`. The wrapper exists because we're doing some custom things with `argparse`,
|
||||
but is has nothing to do with the schema directly.
|
||||
|
||||
An `ArgParser` instance is created and its `parseArgs()` method is called with the raw CLI
|
||||
arguments. The definition of the accepted arguments comes from `lib/cli/args.js` in part--here, all
|
||||
of the arguments _not_ intended for use with the `server` subcommand are hard-coded (e.g., the
|
||||
`driver` subcommand and _its_ subcommands). `args.js` also contains a function `getServerArgs()`,
|
||||
which in turn calls into `toParserArgs` in `lib/schema/cli-args.js`. `lib/schema/cli-args.js` can
|
||||
be considered the "adapter" layer between `argparse` and the schema.
|
||||
|
||||
`toParserArgs` uses the `flattenSchema` function exported by `lib/schema/schema.js`, which
|
||||
"squashes" the schema into a key/value representation. Then, `toParserArgs` iterates over each
|
||||
key/value pair and "converts" it into a suitable `ArgumentOption` object for final handoff to
|
||||
`ArgParser`.
|
||||
|
||||
This adapter (`cli-args.js`) is where most of the mess is hidden; let's explore this rat's nest
|
||||
a bit further.
|
||||
|
||||
##### CLI & Schema Incongruities
|
||||
|
||||
The conversion algorithm (see function `subSchemaToArgDef` in `lib/schema/cli-args.js`) is mostly
|
||||
just hacks and special cases neatly packed into a function. Things that don't cleanly map from
|
||||
`argparse` to a JSON schema include, but are not limited to:
|
||||
|
||||
- A schema cannot natively express "store the value of `--foo=<value>` in a property called `bar`" in a schema (this corresponds to the `ArgumentOption['dest']` prop).
|
||||
- A schema cannot natively express aliases; e.g., `--verbose` can also be `-v`
|
||||
- A schema `enum` is not restricted to multiple types, but `argparse`'s equivalent `ArgumentOption['choices']` prop _is_
|
||||
- A schema does not know about `argparse`'s concept of "actions" (note that Appium is not currently using custom actions--though it did, and it could again).
|
||||
- `argparse` has no native type for `email`, `hostname`, `ipv4`, `uri` etc., and the schema does
|
||||
- Schema validation only _validates_, it does not perform translation, transformation, or coercion (mostly). `argparse` allows this.
|
||||
- Schemas allow the `null` type, for whatever reason. Ever pass `null` on the CLI?
|
||||
- `argparse` does not understand anything other than primitives; no objects, arrays, etc., and certainly not arrays of a particular type.
|
||||
|
||||
All of the above cases and others are handled by the adapter.
|
||||
|
||||
!!! warning
|
||||
|
||||
Some decisions made in the adapter were arrived at via coin toss. If you are curious about why
|
||||
something is the way it is, it's likely that it had to do _something_.
|
||||
|
||||
Let's look more closely at handling types.
|
||||
|
||||
#### Argument Types via `ajv`
|
||||
|
||||
While `argparse` allows consumers, via its API, to define the _type_ of various arguments (e.g.,
|
||||
a string, number, boolean flag, etc.), Appium mostly avoids these built-in types. _Why is that?_
|
||||
Well:
|
||||
|
||||
1. We already know the type of an argument, because we've defined it in a schema.
|
||||
2. `ajv` provides validation against a schema.
|
||||
3. A schema allows for greater expression of types, allowed values, etc., than `argparse` can provide natively.
|
||||
4. The expressiveness of a schema allows for better error messaging.
|
||||
|
||||
To that end, the adapter eschews `argparse`'s built-in types (see allowed string values of
|
||||
`ArgumentOption['type']`) and instead abuses the ability to provide a _function_ as a `type`. The
|
||||
exception is _boolean_ flags, which do not have a `type`, but rather `action: 'store_true'`. The
|
||||
world may never know why.
|
||||
|
||||
##### Types as Functions
|
||||
|
||||
When a `type` is a function, the function performs both validation _and_ coercion (if necessary).
|
||||
So what are these functions?
|
||||
|
||||
> Note: `type` is _omitted_ (and thus _not_ a function) from the `ArgumentOption` if the property
|
||||
> type is `boolean`, and is instead provided an `action` property of `store_true`. Yes, this is
|
||||
> weird. No, I don't know why.
|
||||
|
||||
Well... it depends upon the schema. But generally speaking, we create a _pipeline_ of functions,
|
||||
each corresponding to a keyword in the schema. Let's take the example of the `port` argument. In
|
||||
lieu of asking the OS which ports the `appium`-running user can bind to, this argument is expected
|
||||
to be an integer between 1 and 65535. This turns out to be two functions which we combine into
|
||||
a pipeline:
|
||||
|
||||
1. Convert the value to an integer, if possible. Because _every value in `process.argv` is a string_, we must coerce if we want a number.
|
||||
2. Use `ajv` to validate the integer against the schema for `port`. A schema lets us define a range via the `minimum` and `maximum` keywords. Read more about how this works in
|
||||
|
||||
Much like the config file validation, if errors are detected, Appium nicely tells the end-user and
|
||||
the process exits w/ some help text.
|
||||
|
||||
For other arguments which are naturally of non-primitive types, things are not so straightforward.
|
||||
|
||||
##### Transformers
|
||||
|
||||
Remember how `argparse` doesn't understand arrays? What if the most ergonomic way to express
|
||||
a value is, in fact, an array?
|
||||
|
||||
Well, Appium can't accept an array on the CLI, even though it can accept one in the config file.
|
||||
But Appium _can_ accept a comma-delimited string (a CSV "line"). Or a string filepath referring to
|
||||
a file which _contains_ a delimited list. Either way: by the time the value gets out of the
|
||||
argument parser, it should be an array.
|
||||
|
||||
And as mentioned above, the native facilities of a JSON schema cannot express this. However, it's
|
||||
possible to define a _custom keyword_ which Appium can then detect and handle accordingly. So
|
||||
that's what Appium does.
|
||||
|
||||
In this case, a custom keyword `appiumCliTransformer` is registered with `ajv`. The value of
|
||||
`appiumCliTransformer` (at the time of this writing) can be `csv` or `json`. In the base schema
|
||||
file, `appium-config-schema.js`, Appium uses `appiumCliTransformer: 'csv'` if this behavior is
|
||||
desired.
|
||||
|
||||
!!! note
|
||||
|
||||
Any property defined in the schema having type `array` will _automatically_ uses the `csv`
|
||||
transformer. Likewise, a property having type `object` will use the `json` transformer. It's
|
||||
conceivable that `array` may want to use the `json` transformer, but otherwise, the presence of
|
||||
the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not stricly
|
||||
necessary.
|
||||
|
||||
The adapter (remember the adapter?) creates a pipeline function including a special "CSV
|
||||
transformer" (transformers are defined in `lib/schema/cli-transformers.js`), and uses this function
|
||||
as the `type` property of the `ArgumentOption` passed into `argparse`. In this case, the `type:
|
||||
'array'` in the schema is ignored.
|
||||
|
||||
!!! note
|
||||
|
||||
The config file doesn't _need_ to perform any complex transformation of values, because it
|
||||
naturally allows Appium to define exactly what it expects. So Appium does no post-processing of
|
||||
config file values.
|
||||
|
||||
Properties that do not need this special treatment use `ajv` directly for validation. How this
|
||||
works requires some explanation, so that's next.
|
||||
|
||||
#### Validation of Individual Arguments via `ajv`
|
||||
|
||||
When we think of a JSON schema, we tend to think, "I have this JSON file and I want to validate it
|
||||
against the schema". That's valid, and in fact Appium does just that with config files! However,
|
||||
Appium does not do this when validating arguments.
|
||||
|
||||
!!! note
|
||||
|
||||
During implementation, I was tempted to mash all of the arguments together into
|
||||
a config-file-like data structure and then validate it all at once. I think that would have
|
||||
been _possible_, but since an object full of CLI arguments is a flat key/value structure and
|
||||
the schema is not, this seemed like trouble.
|
||||
|
||||
Instead, Appium validates a value against a specific property _within_ the schema. To do this, it
|
||||
maintains a mapping between a CLI argument definition and its corresponding property. The mapping
|
||||
itself is a `Map` with a unique identifier for the argument as the key, and an `ArgSpec`
|
||||
(`lib/schema/arg-spec.js`) object as the value.
|
||||
|
||||
An `ArgSpec` object stores the following metadata:
|
||||
|
||||
| Property Name | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------- |
|
||||
| `name` | Canonical name of the argument, corresponding to the property name in the schema. |
|
||||
| `extType?` | `driver` or `plugin`, if appropriate |
|
||||
| `extName?` | Extension name, if appropriate |
|
||||
| `ref` | Computed `$id` of the property in the schema |
|
||||
| `arg` | Argument as accepted on CLI, without leading dashes |
|
||||
| `dest` | Property name in parsed arguments object (as returned by `argparse`'s `parse_args()`) |
|
||||
| `defaultValue?` | Value of the `default` keyword in schema, if appropriate |
|
||||
|
||||
When a schema is [finalized](#schema-finalization), the `Map` is populated with `ArgSpec` objects
|
||||
for all known arguments.
|
||||
|
||||
So when the adapter is creating the pipeline of functions for the argument's `type`, it already has
|
||||
an `ArgSpec` for the argument. It creates a function which calls `validate(value, ref)` (in
|
||||
`lib/schema/schema.js`) where `value` is whatever the user provided, and `ref` is the `ref`
|
||||
property of the `ArgSpec`. The concept is that `ajv` can validate using _any_ `ref` it knows about;
|
||||
each property in a schema can be referenced by this `ref` whether it's defined or not. To help
|
||||
visualize, if a schema is:
|
||||
|
||||
```json
|
||||
{
|
||||
"$id": "my-schema.json",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ref` of `foo` would be `my-schema.json#/properties/foo`. Assuming our `Ajv` instance knows
|
||||
about this `my-schema.json`, then we can call its `getSchema(ref)` method (which has a `schema`
|
||||
property, but is a misnomer nonetheless) to get a validation function; `validate(value, ref)` in
|
||||
`schema.js` calls this validation function.
|
||||
|
||||
!!! note
|
||||
|
||||
The schema spec says a schema author can supply an explicit `$id` keyword to override this;
|
||||
it's unsupported by Appium at this time. If needed, extension authors must carefully use `$ref`
|
||||
without custom `$id`s. It's highly unlikely an extension would have a schema so complicated as
|
||||
to need this, however; Appium itself doesn't even use `$ref` to define its own properties!
|
||||
|
||||
Next, let's take a look at how Appium loads schemas. This actually happens _before_ any argument
|
||||
validation.
|
||||
|
||||
## Schema Loading
|
||||
|
||||
Let's ignore extensions for a moment, and start with the base schema.
|
||||
|
||||
When something first imports the `lib/schema/schema.js` module, an instance of an `AppiumSchema` is
|
||||
created. This is a singleton, and its methods are exported from the module (all of which are bound
|
||||
to the instance).
|
||||
|
||||
The constructor does very little; it instantiates an `Ajv` instance and configures it with Appium's
|
||||
[custom keywords](#custom-keyword-reference) and adds support for the `format` keyword via the
|
||||
[ajv-formats](https://npm.im/ajv-formats) module.
|
||||
|
||||
Otherwise, the `AppiumSchema` instance does not interact with the `Ajv` instance until its
|
||||
`finalize()` method (exported as `finalizeSchema()`) is called. When this method is called, we're
|
||||
saying "we are not going to add any more schemas; go ahead and create `ArgSpec` objects and
|
||||
register schemas with `ajv`".
|
||||
|
||||
When does finalization happen? Well:
|
||||
|
||||
1. When the `appium` executable begins, it _checks for and configures extensions_ (hand-wave) in `APPIUM_HOME`.
|
||||
2. Only then does it start to think about arguments--it instantiates an `ArgParser`, which (as you'll recall) runs the adapter to convert the schema to arguments.
|
||||
3. _Finalization happens here_--when creating the parser. Appium need the schema(s) to be registered with `ajv` in order to create validation functions for arguments.
|
||||
4. Thereafter, Appium parses the arguments with the `ArgParser`.
|
||||
5. Finally, decides what to do with the returned object.
|
||||
|
||||
Without extensions, `finalize()` still knows about the Appium base schema
|
||||
(`appium-config-schema.js`), and just registers that. However, step 1. above is doing a _lot of
|
||||
work_, so let's look at how extensions come into play.
|
||||
|
||||
## Extension Support
|
||||
|
||||
One of the design goals of this system is the following:
|
||||
|
||||
_An extension should be able to register custom CLI arguments with the Appium, and a user should be
|
||||
able to use them like any other argument_.
|
||||
|
||||
Previously, Appium 2 accepted arguments in this manner (via `--driverArgs`), but validation was
|
||||
hand-rolled and required extension implementors to use a custom API. It also required the user to
|
||||
awkwardly pass a JSON string as the configuration on the command-line. Further, no contextual help
|
||||
(via `--help`) existed for these arguments.
|
||||
|
||||
Now, by providing a schema for its options, a driver or plugin can register CLI arguments and
|
||||
config file schemas with Appium.
|
||||
|
||||
To register a schema, an extension must provide the `appium.schema` property in its `package.json`.
|
||||
The value may be a schema or a path to a schema. If the latter, the schema should be JSON or
|
||||
a CommonJS module (ESM not supported at this time, nor is YAML).
|
||||
|
||||
For any property in this schema, the property will appear as a CLI argument of the form
|
||||
`--<extension-type>-<extension-name>-<property-name>`. For example, if the `fake` driver provides
|
||||
a property `foo`, the argument will be `--driver-fake-foo`, and will show in `appium server --help`
|
||||
like any other CLI argument.
|
||||
|
||||
The corresponding property in a config file would be
|
||||
`server.<extension-type>.<extension-name>.<property-name>`, e.g.:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"fake": {
|
||||
"foo": "bar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The naming convention described above avoids problems of one extension type having a name conflict
|
||||
with a different extension type.
|
||||
|
||||
!!! note
|
||||
|
||||
While an extension can provide aliases via `appiumCliAliases`, "short" flags are disallowed,
|
||||
since all arguments from extensions are prefixed with `--<extension-type>-<extension-name>-`.
|
||||
The extension name and argument name will be kebab-cased for the CLI, according to [Lodash's
|
||||
rules](https://lodash.com/docs/4.17.15#kebabCase) around kebab-casing.
|
||||
|
||||
The schema object will look much like Appium's base schema, but it will only have top-level
|
||||
properties (nested properties are currently unsupported). Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "my rad schema for the cowabunga driver",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fizz": {
|
||||
"type": "string",
|
||||
"default": "buzz",
|
||||
"$comment": "corresponds to CLI --driver-cowabunga-fizz"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As written in a user's config file, this would be the `server.driver.cowabunga.fizz` property.
|
||||
|
||||
When extensions are loaded, the `schema` property is verified and the schema is registered with the
|
||||
`AppiumSchema` (it is _not_ registered with `Ajv` until `finalize()` is called).
|
||||
|
||||
During finalization, each registered schema is added to the `Ajv` instance. The schema is assigned
|
||||
an `$id` based on the extension type and name (which overrides whatever the extension provides, if
|
||||
anything). Schemas are also forced to disallowed unknown arguments via the `additionalProperties:
|
||||
false` keyword.
|
||||
|
||||
Behind the scenes, the base schema has `driver` and `plugin` properties which are objects. When
|
||||
finalized, a property is added to each--corresponding to an extension name--and the value of this
|
||||
property is a reference to the `$id` of a property in the extension schema. For example, the
|
||||
`server.driver` property will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"driver": {
|
||||
"cowabunga": {
|
||||
"$ref": "driver-cowabunga.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is why we call it the "base" schema--it is _mutated_ when extensions provide schemas. The
|
||||
extension schemas are kept separately, but the _references_ are added to the schema before it's
|
||||
ultimately added to `ajv`. This works because an `Ajv` instance understands references _from_ any
|
||||
schema it knows about _to_ any schema it knows about.
|
||||
|
||||
!!! note
|
||||
|
||||
This makes it impossible to provide a complete static schema for Appium _and_ the installed
|
||||
extensions (as of Nov 5 2021). A static `.json` schema _is_ generated from the base (via a Gulp
|
||||
task), but it does not contain any extension schemas. The static schema also has uses beyond
|
||||
Appium; e.g., IDEs can provide contextual error-checking of config files this way. Let's solve
|
||||
this?
|
||||
|
||||
Just like how we look up the reference ID of a particular argument in the base schema, validation
|
||||
of arguments from extensions happens the exact same way. If the `cowabunga` driver has the schema
|
||||
ID `driver-cowabunga.json`, then the `fizz` property can be referenced from any schema registered
|
||||
with `ajv` via `driver-cowabunga.json#/properties/fizz`. "Base" schema arguments begin with
|
||||
`appium.json#properties/` instead.
|
||||
|
||||
## Development Environment Support
|
||||
|
||||
During the flow of development, a couple extra tasks have been automated to maintain the base
|
||||
schema:
|
||||
|
||||
- As a post-transpilation step, a `lib/appium-config.schema.json` gets generated from
|
||||
- `lib/schema/appium-config-schema.js` (in addition to its CJS counterpart generated by Babel).
|
||||
- This file is under version control. It ends up being _copied_ to
|
||||
- `build/lib/appium-config.schema.json` in this step. A pre-commit hook (see
|
||||
- `scripts/generate-schema-declarations.js` in the root monorepo) generates
|
||||
- a `types/appium-config-schema.d.ts` from the above JSON file. The types in `types/types.d.ts`
|
||||
- depend upon this file. This file is under version control.
|
||||
|
||||
## Custom Keyword Reference
|
||||
|
||||
Keywords are defined in `lib/schema/keywords.js`.
|
||||
|
||||
- `appiumCliAliases`: allows a schema to express aliases (e.g., a CLI argument can be `--verbose` or `-v`). This is an array of strings. Strings shorter than three (3) characters will begin with a single dash (`-`) instead of a double-dash (`--`). Note that any argument provided by an extension will begin with a double-dash, because these are required to have the `--<extension-type>-<extension-name>-` prefix.
|
||||
- `appiumCliDest`: allows a schema to specify a custom property name in the post-`argprase` arguments objects. If not set, this becomes a camelCased string.
|
||||
- `appiumCliDescription`: allows a schema to override the description of the argument when displayed on the command-line. This is useful paired with `appiumCliTransformer` (or `array`/`object`-typed properties), since there's a substantial difference between what a CLI-using user can provide vs. what a config-file-using user can provide.
|
||||
- `appiumCliTransformer`: currently a choice between `csv` and `json`. These are custom functions which post-process a value. They are not used when loading & validating config files, but the idea should be that they result in the same object you'd get if you used whatever the config file wanted (e.g., an array of strings). `csv` is for comma-delimited strings and CSV files; `json` is for raw JSON strings and `.json` files.
|
||||
- `appiumCliIgnore`: If `true`, do not support this property on the CLI.
|
||||
- `appiumDeprecated`: If `true`, the property is considered "deprecated", and will be displayed as such to the user (e.g., in the `--help` output). Note the JSON Schema draft-2019-09 introduces a new keyword `deprecated` which we should use instead if upgrading to this metaschema. When doing so, `appiumDeprecated` should itself be marked as `deprecated`.
|
||||
@@ -76,7 +76,7 @@ Our documentation system uses [MKDocs](https://www.mkdocs.org/) and therefore re
|
||||
|
||||
```sh
|
||||
# installing needed Python dependencies
|
||||
pip install -r packages/docutils/requirements.txt
|
||||
PIP_BREAK_SYSTEM_PACKAGES=1 pip install -r packages/docutils/requirements.txt
|
||||
# build the project
|
||||
npm run build
|
||||
# run dev server
|
||||
@@ -1,5 +1,38 @@
|
||||
---
|
||||
title: 为Appium做贡献
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Contributing to Appium
|
||||
---
|
||||
|
||||
TODO
|
||||
Appium is open source, available under an Apache 2.0 license. Appium's copyright is held by the
|
||||
[OpenJS Foundation](https://openjsf.org), and Appium receives contributions from many companies
|
||||
across several software industries, regardless of their competitive status. (3rd-party drivers and
|
||||
plugins are available under the licenses provided by their authors.)
|
||||
|
||||
As such, we welcome contributions! The project moves forward in relation to the investment of
|
||||
contributions of code, documentation, maintenance, and support from companies and volunteers.
|
||||
|
||||
This section of Appium's documentation is for those who are interested in contributing to Appium's
|
||||
development. It contains developer overviews, guides, and notes. Use the navigation menu to find
|
||||
a specific topic. All the information in these guides assumes in-depth familiarity with Appium
|
||||
already.
|
||||
|
||||
!!! warning
|
||||
|
||||
Developer information may not be kept up to date as frequently as user-facing information, or
|
||||
it may be most relevant in its current form on the online repository, not in this published
|
||||
version. Always be sure to check the repo or discuss with maintainers. We're always happy to
|
||||
help new contributors get started!
|
||||
|
||||
## Ways to Contribute
|
||||
|
||||
The project offers a variety of ways to contribute, e.g.:
|
||||
|
||||
- [contributing code](./develop.md)
|
||||
- improving documentation
|
||||
- creating educational content (blog posts, tutorials, videos, etc.)
|
||||
- spreading the good word about the project (e.g. via Twitter)
|
||||
- filing bugs if you discover them while using Appium
|
||||
- making feature requests if you are missing something in the project or help triaging bugs
|
||||
- supporting users in the [Appium forum](https://discuss.appium.io/)
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
title: Building Documentation
|
||||
---
|
||||
|
||||
Once you've [built a driver](./build-drivers.md) or [built a plugin](./build-plugins.md) for Appium,
|
||||
you will hopefully want to document how that extension works for your users. The most basic way of
|
||||
doing this is to write up a quick `README.md` and keep it in the root of your project's repository.
|
||||
However, this can involve a lot of effort.
|
||||
|
||||
The Appium project has built tools to help with this, and we've packaged up these tools so our
|
||||
ecosystem developers building drivers and plugins can _also_ use them. The best way to get going
|
||||
with these tools is probably to look at an existing Appium driver repo to see how it's done, for
|
||||
example the [XCUITest driver repo](https://github.com/appium/appium-xcuitest-driver). But this guide
|
||||
will outline the basic approach.
|
||||
|
||||
### Conceptual architecture
|
||||
|
||||
Appium settled on [MkDocs](https://www.mkdocs.org/) as a Markdown-based documentation site
|
||||
generator. It uses a Python toolchain (and not Node.js), but it turned out to be the best option
|
||||
for our purposes. You can adjust this, but by default Appium's utilities also assume that you'll be
|
||||
using the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) theme/extension for
|
||||
MkDocs.
|
||||
|
||||
In order to make different versions of your docs available (one for each minor release of your
|
||||
extension, typically), we also bundle [Mike](https://github.com/jimporter/mike).
|
||||
|
||||
From here, building a basic docs site is as easy as collecting your Markdown files together and
|
||||
defining how you want them to be organized.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
To take advantage of Appium's documentation utilities, you'll need to install:
|
||||
|
||||
- [Python v3+](https://www.python.org/downloads/)
|
||||
- [pip](https://pip.pypa.io/en/stable/installation/) (this may be installed automatically with Python)
|
||||
- The `@appium/docutils` package:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @appium/docutils
|
||||
```
|
||||
|
||||
### Initializing an Extension for Building Docs
|
||||
|
||||
To prepare your extension for generating documentation, run the following command:
|
||||
|
||||
```bash
|
||||
npx appium-docs init
|
||||
```
|
||||
|
||||
This will:
|
||||
|
||||
1. Create a `tsconfig.json` if one does not already exist. This is necessary even if your extension
|
||||
is not written in TypeScript.
|
||||
2. Create a `mkdocs.yml` with the necessary configuration for MkDocs.
|
||||
|
||||
### Documenting Your Extension
|
||||
|
||||
At this point, you can begin documenting your extension. By default, MkDocs will look for Markdown
|
||||
files in the `docs` directory. You can therefore create your Markdown documentation files, place
|
||||
them in `docs`, and add links to these files in `mkdocs.yml`.
|
||||
|
||||
Refer to the [MkDocs documentation](https://www.mkdocs.org/user-guide/writing-your-docs/) for
|
||||
information on how to organize and structure your documentation.
|
||||
|
||||
### Building the Docs
|
||||
|
||||
At this point, you can use the `appium-docs` CLI tool. Run this tool with no arguments to get the
|
||||
full help output and see all the available subcommands and parameters. Here are a few usage
|
||||
examples:
|
||||
|
||||
```bash
|
||||
# Generate reference and build the mkdocs site into the site dir
|
||||
npx appium-docs build
|
||||
|
||||
# Same as build, but host the docs on a local dev server
|
||||
# and watch for changes and rebuild when files change
|
||||
npx appium-docs build --serve
|
||||
|
||||
# Build the docs and deploy them with mike versioning to the docs-site branch
|
||||
# using the included commit message.
|
||||
# This is particularly useful for pushing content to a GitHub pages branch!
|
||||
npx appium-docs build \
|
||||
--deploy \
|
||||
-b docs-site \
|
||||
-m 'docs: auto-build docs for appium-xcuitest-driver@%s'
|
||||
```
|
||||
@@ -0,0 +1,141 @@
|
||||
---
|
||||
title: Building Doctor Checks
|
||||
---
|
||||
|
||||
The idea of Appium Doctor is to assist users with driver or plugin preconditions setup. Sometimes such
|
||||
preconditions might be quite complicated and require non-trivial technical knowledge. Doctor checks,
|
||||
which are vanilla Node.js class instances written by extension authors, simplify
|
||||
the setup process by automating diagnostics and possible fixes for the found issues. These checks
|
||||
might also be interactive to ensure better usage experience.
|
||||
|
||||
This tutorial is supposed to be used by plugin or driver authors that would like to help their users
|
||||
to deal with complicated setup or configuration steps.
|
||||
|
||||
## Adding Doctor Checks
|
||||
|
||||
### Typing Requirements
|
||||
|
||||
The term `Doctor Check` literally describes a single javascript class instance that implements the
|
||||
[IDoctorCheck interface](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts).
|
||||
The interface defines the following methods and properties:
|
||||
|
||||
- `diagnose(): Promise<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.
|
||||
|
||||
The `DoctorCheckResult` object returned by the `diagnose()` method must contain the following properties:
|
||||
|
||||
- `ok: boolean`: Whether the diagnosis found no issues
|
||||
- `optional: boolean`: Whether the diagnosed issue is safe to ignore
|
||||
- `message: string`: The text message describing the diagnostic result
|
||||
|
||||
### Manifest Requirements
|
||||
|
||||
A single extension may export multiple Doctor checks to Appium. In order for these checks to be properly
|
||||
picked up by the server CLI after the corresponding extension is installed they might be listed in the
|
||||
package .json manifest under the `appium.doctor.checks` section similar to the definition below:
|
||||
|
||||
```json
|
||||
// ...
|
||||
"appium": {
|
||||
"driverName": "fake",
|
||||
"automationName": "Fake",
|
||||
"platformNames": [
|
||||
"Fake"
|
||||
],
|
||||
"mainClass": "FakeDriver",
|
||||
"schema": "./build/lib/fake-driver-schema.js",
|
||||
"scripts": {
|
||||
"fake-error": "./build/lib/scripts/fake-error.js",
|
||||
"fake-success": "./build/lib/scripts/fake-success.js",
|
||||
"fake-stdin": "./build/lib/scripts/fake-stdin.js"
|
||||
},
|
||||
"doctor": {
|
||||
"checks": [
|
||||
"./doctor/fake1.js",
|
||||
"./doctor/fake2.js"
|
||||
// ...
|
||||
]
|
||||
}
|
||||
},
|
||||
// ...
|
||||
```
|
||||
|
||||
Also, it makes sense to include the [@appium/types](https://www.npmjs.com/package/@appium/types) import
|
||||
to the package dev dependencies.
|
||||
|
||||
### Implementation Example
|
||||
|
||||
The below example is a "raw" Node.JS implementation that does not use any transpilation:
|
||||
|
||||
```js
|
||||
const {fs, doctor} = require('@appium/support');
|
||||
|
||||
/** @satisfies {import('@appium/types').IDoctorCheck} */
|
||||
class EnvVarAndPathCheck {
|
||||
/**
|
||||
* @param {string} varName
|
||||
*/
|
||||
constructor(varName) {
|
||||
this.varName = varName;
|
||||
}
|
||||
|
||||
async diagnose() {
|
||||
const varValue = process.env[this.varName];
|
||||
if (typeof varValue === 'undefined') {
|
||||
return doctor.nok(`${this.varName} environment variable is NOT set!`);
|
||||
}
|
||||
|
||||
if (await fs.exists(varValue)) {
|
||||
return doctor.ok(`${this.varName} is set to: ${varValue}`);
|
||||
}
|
||||
|
||||
return doctor.nok(`${this.varName} is set to '${varValue}' but this is NOT a valid path!`);
|
||||
}
|
||||
|
||||
async fix() {
|
||||
return (
|
||||
`Make sure the environment variable ${this.varName} is properly configured for the Appium server process`
|
||||
);
|
||||
}
|
||||
|
||||
hasAutofix() {
|
||||
return false;
|
||||
}
|
||||
|
||||
isOptional() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const androidHomeCheck = new EnvVarAndPathCheck('ANDROID_HOME');
|
||||
|
||||
module.exports = {androidHomeCheck};
|
||||
|
||||
/**
|
||||
* @typedef {import('@appium/types').DoctorCheckResult} CheckResult
|
||||
*/
|
||||
```
|
||||
|
||||
This file could be saved as `doctor/android-home-check.js` and then added to the package.json manifest
|
||||
as
|
||||
|
||||
```json
|
||||
// ...
|
||||
"appium": {
|
||||
// ...
|
||||
"doctor": {
|
||||
"checks": [
|
||||
"./doctor/android-home-check.js",
|
||||
]
|
||||
}
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
```
|
||||
@@ -0,0 +1,460 @@
|
||||
---
|
||||
title: Building Plugins
|
||||
---
|
||||
|
||||
This is a high-level guide for developing Appium plugins, which is not something most Appium users
|
||||
need to know or care about. If you are not familiar with Appium plugins yet from a user
|
||||
perspective, check out the [list of plugins](../ecosystem/plugins.md) to play around with some and get
|
||||
an idea of the sorts of things that plugins can do. Plugins are a powerful system for augmenting
|
||||
Appium's functionality or changing the way Appium works. They can be distributed to other Appium
|
||||
users and can extend Appium's ecosystem in all kinds of interesting ways! (There is also
|
||||
a significant amount of overlap here with developing Appium drivers, so you may also want to check
|
||||
out the [building drivers](./build-drivers.md) guide for further inspiration.)
|
||||
|
||||
## Before you create your plugin
|
||||
|
||||
Before creating your plugin, it's good to have a general idea of what you want your plugin to
|
||||
accomplish and whether it will be possible to implement it given the restrictions of the Appium
|
||||
platform. Reading through this guide will help you understand what's possible. In general, Appium's
|
||||
plugin system is extremely powerful and no attempts have been made to artificially limit what's
|
||||
possible with them (which is a main reason that all plugins are opt-in by the system administrator
|
||||
responsible for starting the Appium server---plugins are powerful and should only be used when
|
||||
explicitly trusted!).
|
||||
|
||||
## Other plugins to reference
|
||||
|
||||
There are a wide variety of open source Appium plugins available for perusal. It's definitely
|
||||
recommended to explore the code for some other plugins before embarking on writing your own. The
|
||||
Appium team maintains a set of official plugins in the [Appium GitHub
|
||||
repo](https://github.com/appium/appium). Links to other open source plugins can be found in the
|
||||
[Plugin list](../ecosystem/plugins.md)
|
||||
|
||||
## Basic requirements for plugins
|
||||
|
||||
These are the things your plugin *must* do (or be), if you want it to be a valid Appium plugin.
|
||||
|
||||
### Node.js package with Appium extension metadata
|
||||
|
||||
All Appium plugins are fundamentally Node.js packages, and therefore must have a valid
|
||||
`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in
|
||||
Node.js so it can be loaded by Appium.
|
||||
|
||||
Your `package.json` must include `appium` as a `peerDependency`. The requirements for the
|
||||
dependency versions should be as loose as possible (unless you happen to know your plugin will only
|
||||
work with certain versions of Appium). For Appium 2, for example, this would look something like
|
||||
`^2.0.0`, declaring that your plugin works with any version of Appium that starts with 2.x.
|
||||
|
||||
Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension
|
||||
metadata'):
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"appium": {
|
||||
"pluginName": "fake",
|
||||
"mainClass": "FakePlugin"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The required subfields are:
|
||||
|
||||
* `pluginName`: this should be a short name for your plugin.
|
||||
* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
|
||||
class which extends Appium's `BasePlugin` (see below).
|
||||
|
||||
### Extend Appium's `BasePlugin` class
|
||||
|
||||
Ultimately, your plugin is much easier to write because most of the hard work of defining patterns
|
||||
for overriding commands is done for you. This is
|
||||
all encoded up as a class which Appium exports for you to use, called `BasePlugin`. It is exported
|
||||
from `appium/plugin`, so you can use one of these styles to import it and create your *own* class
|
||||
that extends it:
|
||||
|
||||
```js
|
||||
import {BasePlugin} from 'appium/plugin';
|
||||
// or: const {BasePlugin} = require('appium/plugin');
|
||||
|
||||
export class MyPlugin extends BasePlugin {
|
||||
// class methods here
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
In all the code samples below, whenever we reference an example method, it is assumed
|
||||
that it is defined _within_ the class, though this is not explicitly written, for the sake of
|
||||
clarity and space.
|
||||
|
||||
### Make your plugin available
|
||||
|
||||
That's basically it! With a Node.js package exporting a plugin class and with correct Appium
|
||||
extension metadata, you've got yourself an Appium plugin! Now it doesn't *do* anything, but you can
|
||||
load it up in Appium, activate it, etc...
|
||||
|
||||
To make it available to users, you could publish it via NPM. When you do so, your plugin will be
|
||||
installable via the Appium CLI:
|
||||
|
||||
```
|
||||
appium plugin install --source=npm <plugin-package-on-npm>
|
||||
```
|
||||
|
||||
It's a good idea to test your plugin first, of course. One way to see how it works within Appium is
|
||||
to install it locally first:
|
||||
|
||||
```
|
||||
appium plugin install --source=local /path/to/your/plugin
|
||||
```
|
||||
|
||||
And of course, plugins must be "activated" during Appium server start, so make sure you direct your
|
||||
users to do so:
|
||||
|
||||
```
|
||||
appium --use-plugins=plugin-name
|
||||
```
|
||||
|
||||
### Developing your plugin
|
||||
|
||||
How you develop your plugin is up to you. It is convenient, however, to run it from within Appium
|
||||
without having to do lots of publishing and installing. The most straightforward way to do this is
|
||||
to include the most recent version of Appium as a `devDependency` (although its being already
|
||||
included as a `peerDependency` is sufficient in newer versions of NPM), and then also your own plugin,
|
||||
like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
...,
|
||||
"appium": "^2.0.0",
|
||||
"your-plugin": "file:.",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your plugin is
|
||||
listed as a dependency alongside it, it will be automatically "installed" and available. You can
|
||||
design your e2e tests this way, or if you're writing them in Node.js, you can simply import
|
||||
Appium's start server methods to handle starting and stopping the Appium server in Node.
|
||||
|
||||
Of course, you can always install it locally as described above as well.
|
||||
|
||||
Anytime you make changes to your plugin code, you'll need to restart the Appium server to make sure
|
||||
it picks up the latest code. As with drivers, you can set the `APPIUM_RELOAD_EXTENSIONS`
|
||||
environment variable if you wish Appium to try to re-require your plugin module when a new session
|
||||
starts.
|
||||
|
||||
## Standard plugin implementation ideas
|
||||
|
||||
These are things you will probably find yourself wanting to do when creating a plugin.
|
||||
|
||||
### Set up state in a constructor
|
||||
|
||||
If you define your own constructor, you'll need to call `super` to make sure all the standard state
|
||||
is set up correctly:
|
||||
|
||||
```js
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
// now do your own thing
|
||||
}
|
||||
```
|
||||
|
||||
The `args` parameter here is the object containing all the CLI args used to start the Appium
|
||||
server.
|
||||
|
||||
### Intercept and handle specific Appium commands
|
||||
|
||||
This is the most normal behavior for Appium plugins -- to modify or replace the execution of one or
|
||||
more commands that would normally be handled by the active driver. To override the default command
|
||||
handling, you need to implement `async` methods in your class with the same name as the Appium
|
||||
commands to be handled (just exactly how [drivers themselves are
|
||||
implemented](./build-drivers.md#implement-webdriver-commands)). Curious what command names there
|
||||
are? They are defined in the Appium base driver's
|
||||
[routes.js](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js) file,
|
||||
and of course you can add more as defined in the next section.
|
||||
|
||||
Each command method is sent the following arguments:
|
||||
|
||||
1. `next`: This is a reference to an `async` function which encapsulates the chain of behaviors which would take place if this plugin were not handling the command. You can choose to call the next behavior in the chain at any point in your logic (by making sure to include `await next()` somewhere), or not. If you don't, it means the default behavior (or any plugins registered after this one) won't be run.
|
||||
1. `driver`: This is the object representing the driver handling the current session. You have access to it for any work you need to do, for example calling other driver methods, checking capabilities or settings, etc...
|
||||
1. `...args`: A spread array with any arguments that have been applied to the command by the user.
|
||||
|
||||
For example, if we wanted to override the `setUrl` command to simply add some extra logging on top,
|
||||
we would implement as follows:
|
||||
|
||||
```js
|
||||
async setUrl(next, driver, url) {
|
||||
this.log(`Let's get the page source for some reason before navigating to '${url}'!`);
|
||||
await driver.getPageSource();
|
||||
const result = await next();
|
||||
this.log(`We can also log after the original behaviour`);
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### Intercept and handle _all_ Appium commands
|
||||
|
||||
You might find yourself in a position where you want to handle *all* commands, in order to inspect
|
||||
payloads to determine whether or not to act in some way. If so, you can implement `async handle`,
|
||||
and any command that is not handled by one of your named methods will be handled by this method
|
||||
instead. It takes the following parameters (with all the same semantics as above):
|
||||
|
||||
1. `next`
|
||||
1. `driver`
|
||||
1. `cmdName` - string representing the command being run
|
||||
1. `...args`
|
||||
|
||||
For example, let's say we want to log timing for all Appium commands as part of a plugin. We could
|
||||
do this by implementing `handle` in our plugin class as follows:
|
||||
|
||||
```js
|
||||
async handle(next, driver, cmdName, ...args) {
|
||||
const start = Date.now();
|
||||
try {
|
||||
const result = await next();
|
||||
} finally {
|
||||
const elapsedMs = Date.now() - start;
|
||||
this.log(`Command '${cmdName}' took ${elapsedMs}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### Work around driver proxies
|
||||
|
||||
There is a bit of a gotcha with handling Appium commands. Appium drivers have the ability to turn
|
||||
on a special 'proxy' mode, wherein the Appium server process takes a look at incoming URLs, and
|
||||
decides whether to forward them on to some upstream WebDriver server. It could happen that
|
||||
a command which a plugin wants to handle is designated as a command which is being proxied to an
|
||||
upstream server. In this case, we run into a problem, because the plugin never gets a chance to
|
||||
handle that command! For this reason, plugins can implement a special member function called
|
||||
`shouldAvoidProxy`, which takes the following parameters:
|
||||
|
||||
1. `method` - string denoting HTTP method (`GET`, `POST`, etc...)
|
||||
2. `route` - string denoting the requested resource, for example `/session/8b3d9aa8-a0ca-47b9-9ab7-446e818ec4fc/source`
|
||||
3. `body` - optional value of any type representing the WebDriver request body
|
||||
|
||||
These parameters define an incoming request. If you want to handle a command in your plugin which
|
||||
would normally be proxied directly through a driver, you could disable or 'avoid' proxying the
|
||||
request, and instead have the request fall into the typical Appium command execution flow (and
|
||||
thereby your own command function). To avoid proxying a request, just return `true` from
|
||||
`shouldAvoidProxy`. Some examples of how this method is used are in the [Universal XML
|
||||
plugin](https://github.com/appium/appium/blob/master/packages/universal-xml/lib/plugin.js) (where
|
||||
we want to avoid proxying the `getPageSource` command, or in the [Images
|
||||
plugin](https://github.com/appium/appium/blob/master/packages/images-plugin/lib/plugin.js) (where
|
||||
we want to conditionally avoid proxying any command if it looks like it contains an image element).
|
||||
|
||||
|
||||
### Throw WebDriver-specific errors
|
||||
|
||||
The WebDriver spec defines a [set of error
|
||||
codes](https://github.com/jlipps/simple-wd-spec#error-codes) to accompany command responses if an
|
||||
error occurred. Appium has created error classes for each of these codes, so you can throw the
|
||||
appropriate error from inside a command, and it will do the right thing in terms of the protocol
|
||||
response to the user. To get access to these error classes, import them from `appium/driver`:
|
||||
|
||||
```js
|
||||
import {errors} from 'appium/driver';
|
||||
|
||||
throw new errors.NoSuchElementError();
|
||||
```
|
||||
|
||||
### Log messages to the Appium log
|
||||
|
||||
You can always use `console.log`, of course, but Appium provides a nice logger for you as
|
||||
`this.logger` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log
|
||||
levels). If you want to create an Appium logger outside of a plugin context (say in a script or
|
||||
helper file), you can always construct your own too:
|
||||
|
||||
```js
|
||||
import {logging} from 'appium/support';
|
||||
const log = logging.getLogger('MyPlugin');
|
||||
```
|
||||
|
||||
## Further possibilities for Appium plugins
|
||||
|
||||
These are things your plugin *can* do to take advantage of extra plugin features or do its job more
|
||||
conveniently.
|
||||
|
||||
### Add a schema for custom command line arguments
|
||||
|
||||
You can add custom CLI args if you want your plugin to receive data from the command line when the
|
||||
Appium server is started (for example, ports that a server administrator should set that should not
|
||||
be passed in as capabilities).
|
||||
|
||||
This works largely the same for plugins as it does for drivers, so for more details have a look at
|
||||
[the equivalent section in the building drivers
|
||||
doc](./build-drivers.md#add-a-schema-for-custom-command-line-arguments).
|
||||
|
||||
The only difference is that to construct the CLI argument name, you prefix it with
|
||||
`--plugin-<name>`. So for example, if you have a plugin named `pluggo` and a CLI arg defined with
|
||||
the name `electro-port`, you can set it when starting Appium via `--plugin-pluggo-electro-port`.
|
||||
|
||||
Setting args via a configuration file is also supported, as it is for drivers, but under the
|
||||
`plugin` field instead. For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"plugin": {
|
||||
"pluggo": {
|
||||
"electro-port": 1234
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Add plugin scripts
|
||||
|
||||
Sometimes you might want users of your plugin to be able to run scripts outside the context of
|
||||
a session (for example, to run a script that pre-builds aspects of your plugin). To support this,
|
||||
you can add a map of script names and JS files to the `scripts` field within your Appium extension
|
||||
metadata. So let's say you've created a script in your project that lives in a `scripts` directory
|
||||
in your project, named `plugin-prebuild.js`. Then you could add a `scripts` field like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"prebuild": "./scripts/plugin-prebuild.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, assuming your plugin is named `myplugin`, users of your plugin can run `appium plugin run
|
||||
myplugin prebuild`, and your script will execute.
|
||||
|
||||
### Add new Appium commands
|
||||
|
||||
If you want to offer functionality that doesn't map to any of the existing commands supported by
|
||||
drivers, you can create new commands in one of two ways, just as is possible for drivers:
|
||||
|
||||
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
|
||||
1. Overloading the Execute Script command by defining [Execute
|
||||
Methods](../guides/execute-methods.md)
|
||||
|
||||
If you want to follow the first path, you can direct Appium to recognize new methods and add them
|
||||
to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`
|
||||
static variable in your driver class to an object of the same form as Appium's `routes.js` object.
|
||||
For example, here is part of the `newMethodMap` for the `FakePlugin` example driver:
|
||||
|
||||
```js
|
||||
static newMethodMap = {
|
||||
'/session/:sessionId/fake_data': {
|
||||
GET: {command: 'getFakeSessionData', neverProxy: true},
|
||||
POST: {
|
||||
command: 'setFakeSessionData',
|
||||
payloadParams: {required: ['data']},
|
||||
neverProxy: true,
|
||||
},
|
||||
},
|
||||
'/session/:sessionId/fakepluginargs': {
|
||||
GET: {command: 'getFakePluginArgs', neverProxy: true},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
If you're using TypeScript, static member objects like these should be defined `as const`.
|
||||
|
||||
In this example we're adding a few new routes and a total of 3 new commands. For more examples of
|
||||
how to define commands in this way, it's best to have a look through `routes.js`. Now all you need
|
||||
to do is implement the command handlers in the same way you'd implement any other Appium command.
|
||||
|
||||
Note also the special `neverProxy` key for commands; this is generally a good idea to set to `true`
|
||||
for plugins, since your plugin might be active for a driver that is put into proxy mode but hasn't
|
||||
bothered to decline proxying for these (new and therefore unknown) commands. Setting `neverProxy`
|
||||
to `true` here will cause Appium to never proxy these routes and therefore ensure your plugin
|
||||
handles them, even if a driver is in proxy mode.
|
||||
|
||||
The downside of adding new commands via `newMethodMap` is that people using the standard Appium
|
||||
clients won't have nice client-side functions designed to target these endpoints. So you would need
|
||||
to create and release client-side plugins for each language you want to support (directions or
|
||||
examples can be found at the relevant client docs).
|
||||
|
||||
An alternative to this way of doing things is to overload a command which all WebDriver clients
|
||||
have access to already: Execute Script. Make sure to read the section on [adding new
|
||||
commands](./build-drivers.md#extend-the-existing-protocol-with-new-commands) in
|
||||
the Building Drivers guide to understand the way this works in general. The way it works with
|
||||
plugins is only slightly different. Let's look at an example taken from Appium's `fake-plugin`:
|
||||
|
||||
```js
|
||||
static executeMethodMap = {
|
||||
'fake: plugMeIn': {
|
||||
command: 'plugMeIn',
|
||||
params: {required: ['socket']},
|
||||
},
|
||||
};
|
||||
|
||||
async plugMeIn(next, driver, socket) {
|
||||
return `Plugged in to ${socket}`;
|
||||
}
|
||||
|
||||
async execute(next, driver, script, args) {
|
||||
return await this.executeMethod(next, driver, script, args);
|
||||
}
|
||||
```
|
||||
|
||||
We have three important components shown here which make this system work, all of which are defined
|
||||
inside the plugin class:
|
||||
|
||||
1. The `executeMethodMap`, defined in just the same way as for drivers
|
||||
1. The implementation of the command method as defined in `executeMethodMap` (in this case,
|
||||
`plugMeIn`)
|
||||
1. The overriding/handling of the `execute` command. Just like any plugin command handlers, the
|
||||
first two arguments are `next` and `driver`, followed by the script name and args. `BasePlugin`
|
||||
implements a helper method which we can simply call with all of these arguments.
|
||||
|
||||
Overriding Execute Methods from drivers works as you'd expect: if your plugin defines an Execute
|
||||
Method with the same name as that of a driver, your command (in this case `plugMeIn`) will be
|
||||
called first. You can choose to run the driver's original behaviour via `next` if you want.
|
||||
|
||||
### Build Appium Doctor checks
|
||||
|
||||
Your users can run `appium plugin doctor <pluginName>` to run installation and health checks. Visit
|
||||
the [Building Doctor Checks](./build-doctor-checks.md) guide for more information on this
|
||||
capability.
|
||||
|
||||
### Update the Appium server object
|
||||
|
||||
You probably don't normally need to update the Appium server object (which is an
|
||||
[Express](https://expressjs.com/) server having already been
|
||||
[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)
|
||||
in a variety of ways). But, for example, you could add new Express middleware to the server to
|
||||
support your plugin's requirements. To update the server you must implement the `static async
|
||||
updateServer` method in your class. This method takes three parameters:
|
||||
|
||||
* `expressApp`: the Express app object
|
||||
* `httpServer`: the Node HTTP server object
|
||||
* `cliArgs`: a map of the CLI args used to start the Appium server
|
||||
|
||||
You can do whatever you want with them inside the `updateServer` method. You might want to
|
||||
reference how these objects are created and worked with in the BaseDriver code, so that you know
|
||||
you're not undoing or overriding anything standard and important. But if you insist, you can, with
|
||||
results you'll need to test! Warning: this should be considered an advanced feature and requires
|
||||
knowledge of Express, as well as the care not to do anything that could affect the operation of
|
||||
other parts of the Appium server!
|
||||
|
||||
### Handle unexpected session shutdown
|
||||
|
||||
When developing a plugin you may want to add some cleanup logic for when a session ends. You would
|
||||
naturally do this by adding a handler for `deleteSession`. This works in most cases, except when
|
||||
the session does not finish cleanly. Appium sometimes determines that a session has finished
|
||||
unexpectedly, and in these situations, Appium will look for a method called `onUnexpectedShutdown`
|
||||
in your plugin class, which will be called (passing the current session driver as the first
|
||||
parameter, and the error object representing the cause of the shutdown as the second), giving you
|
||||
an opportunity to take any steps that might be necessary to clean up from the session. For example,
|
||||
keeping in mind that the function is not `await`ed you could implement something like this:
|
||||
|
||||
```js
|
||||
async onUnexpectedShutdown(driver, cause) {
|
||||
try {
|
||||
// do some cleanup
|
||||
} catch (e) {
|
||||
// log any errors; don't allow anything to be thrown as they will be unhandled rejections
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Intro to Development
|
||||
---
|
||||
|
||||
Appium 2 is built with a modular structure, which means that Appium extensions (drivers and plugins)
|
||||
are decoupled from the main Appium module, and you only need to install the extensions that you
|
||||
want to use. This modular structure also unlocks the ability to develop entirely new extensions!
|
||||
|
||||
This section of the Appium documentation is intended to help aspiring developers with creating their
|
||||
own Appium extension:
|
||||
|
||||
* For creating a driver, see the [Build Drivers](./build-drivers.md) page
|
||||
* For creating a plugin, take a look at the [Build Plugins](build-plugins.md) page
|
||||
* Drivers and plugins both need documentation, so check out the [Build Documentation](./build-docs.md) page
|
||||
* For creating a doctor check, see the [Building Doctor Checks](./build-doctor-checks.md) page
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Building Docs for Appium Extensions
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Building Appium Plugins
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Appium客户端
|
||||
---
|
||||
|
||||
您需要一个客户端来编写和运行Appium脚本。您需要非常熟悉您的客户端文档(以及Appium客户端所依赖的任何Selenium客户端的文档),因为这将是您与Appium的主要接口。
|
||||
|
||||
要了解更多关于客户端的信息,请阅读我们的[客户端简介](../intro/clients.md)。
|
||||
|
||||
### 官方客户端
|
||||
|
||||
这些客户端目前由Appium团队维护:
|
||||
|
||||
|客户端|编程语言|
|
||||
|-|-|
|
||||
|[Appium Java client](https://github.com/appium/java-client)|Java|
|
||||
|[Appium Python client](https://github.com/appium/python-client)|Python|
|
||||
|[Appium Ruby Core client](https://github.com/appium/ruby_lib_core) (Recommended)<br>[Appium Ruby client](https://github.com/appium/ruby_lib)|Ruby|
|
||||
|[Appium .NET client](https://github.com/appium/dotnet-client)|C#|
|
||||
|
||||
### 其他客户端
|
||||
|
||||
这些客户端不由Appium团队维护,可以与其他语言一起使用:
|
||||
|
||||
|客户端|编程语言|
|
||||
|-|-|
|
||||
|[WebdriverIO](https://webdriver.io/docs/appium)|Node.js|
|
||||
|[Nightwatch.js](https://nightwatchjs.org/guide/mobile-app-testing/introduction.html)|Node.js|
|
||||
|[RobotFramework](https://github.com/serhatbolsu/robotframework-appiumlibrary)|DSL|
|
||||
|[multicatch's appium-client](https://github.com/multicatch/appium-client)|Rust|
|
||||
|
||||
一般来说,任何兼容W3C WebDriver规范的客户端,也可以和Appium很好地集成,尽管某些Appium特定的命令可能无法在其他客户端中实现。
|
||||
|
||||
!!! 注意
|
||||
|
||||
如果您维护了一个Appium客户端,并希望在Appium文档中列出,请随时进行PR,将其添加到本部分,并附上客户端文档的链接。
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Appium驱动
|
||||
---
|
||||
|
||||
如果没有至少一个驱动程序,您就无法使用Appium!单击每个驱动程序的链接,查看该驱动程序的具体安装说明和文档。
|
||||
|
||||
通常,可以使用下面列出的驱动名称,使用以下命令安装驱动程序:
|
||||
```
|
||||
appium driver install <驱动名称>
|
||||
```
|
||||
|
||||
要了解有关驱动的更多信息,请查看[驱动简介](../intro/drivers.md)。
|
||||
|
||||
### 官方驱动
|
||||
|
||||
这些驱动程序目前由Appium团队维护:
|
||||
|
||||
|驱动|驱动名称|支持的平台|支持的形式|
|
||||
|--|--|--|--|
|
||||
|[Chromium](https://github.com/appium/appium-chromium-driver)|`chromium`|macOS, Windows, Linux|Web|
|
||||
|[Espresso](https://github.com/appium/appium-espresso-driver)|`espresso`|Android|Native|
|
||||
|[Gecko](https://github.com/appium/appium-geckodriver)|`gecko`|macOS, Windows, Linux, Android|Web|
|
||||
|[Mac2](https://github.com/appium/appium-mac2-driver)|`mac2`|macOS|Native|
|
||||
|[Safari](https://github.com/appium/appium-safari-driver)|`safari`|macOS, iOS|Web|
|
||||
|[UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)|`uiautomator2`|Android|Native, Hybrid, Web|
|
||||
|[Windows](https://github.com/appium/appium-windows-driver)|`windows`|Windows|Native|
|
||||
|[XCUITest](https://github.com/appium/appium-xcuitest-driver)|`xcuitest`|iOS|Native, Hybrid, Web|
|
||||
|
||||
### 其他驱动
|
||||
|
||||
这些驱动程序不由Appium团队维护,可用于针对其他平台:
|
||||
|
||||
|驱动|驱动名称|支持的平台|支持的形式|维护者|
|
||||
|--|--|--|--|--|
|
||||
|[Flutter](https://github.com/appium/appium-flutter-driver)|`--source=npm appium-flutter-driver`|iOS, Android|Native|Community|
|
||||
|[Flutter Integration](https://github.com/AppiumTestDistribution/appium-flutter-integration-driver)|`--source=npm appium-flutter-integration-driver`|iOS, Android|Native|Community / `@AppiumTestDistribution`|
|
||||
|[LG WebOS](https://github.com/headspinio/appium-lg-webos-driver)|`--source=npm appium-lg-webos-driver`|LG TV|Web|HeadSpin|
|
||||
|[Linux](https://github.com/fantonglang/appium-linux-driver)|`--source=npm @stdspa/appium-linux-driver`|Linux|Native|`@fantonglang`|
|
||||
|[Roku](https://github.com/headspinio/appium-roku-driver)|`--source=npm @headspinio/appium-roku-driver`|Roku|Native|HeadSpin|
|
||||
|[Tizen](https://github.com/Samsung/appium-tizen-driver)|`--source=npm appium-tizen-driver`|Android|Native|Community / Samsung|
|
||||
|[TizenTV](https://github.com/headspinio/appium-tizen-tv-driver)|`--source=npm appium-tizen-tv-driver`|Samsung TV|Web|HeadSpin|
|
||||
|[Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver)|`--source=npm appium-youiengine-driver`|iOS, Android, macOS, Linux, tvOS|Native|Community / You.i|
|
||||
|
||||
!!! 注意
|
||||
|
||||
如果您维护了一个Appium驱动程序,并希望在Appium文档中列出,请随时进行PR,将其添加到本部分,并附上驱动程序文档的链接。
|
||||
@@ -1,6 +1,44 @@
|
||||
---
|
||||
title: Appium生态系统
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: 生态系统概述
|
||||
---
|
||||
|
||||
Appium拥有广泛的相关软件和工具生态系统。文档的这一部分旨在编制各种官方支持和社区支持的Appium项目的列表:
|
||||
|
||||
TODO
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-car: __驱动__
|
||||
|
||||
---
|
||||
|
||||
将Appium链接到您的测试设备
|
||||
|
||||
[:octicons-arrow-right-24: 查看所有驱动](./drivers.md)
|
||||
|
||||
- :octicons-code-16: __客户端__
|
||||
|
||||
---
|
||||
|
||||
将Appium链接到您的自动化代码
|
||||
|
||||
[:octicons-arrow-right-24: 查看所有客户端](./clients.md)
|
||||
|
||||
- :fontawesome-solid-plug: __插件__
|
||||
|
||||
---
|
||||
|
||||
修改和扩展Appium功能
|
||||
|
||||
[:octicons-arrow-right-24: 查看所有插件](./plugins.md)
|
||||
|
||||
- :material-wrench: __工具__
|
||||
|
||||
---
|
||||
|
||||
以其他方式与Appium交互
|
||||
|
||||
[:octicons-arrow-right-24: 查看所有工具](./tools.md)
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Appium插件
|
||||
---
|
||||
|
||||
插件提供了各种方法来扩展或修改Appium的行为。它们是完全可选的,不是标准自动化功能所必需的,但您可能会发现它们对更专业的自动化工作流程很有用。
|
||||
|
||||
通常,可以使用下面列出的插件名称,使用以下命令安装插件:
|
||||
|
||||
```
|
||||
appium plugin install <插件名称>
|
||||
```
|
||||
|
||||
### 官方插件
|
||||
|
||||
这些插件目前由Appium团队维护:
|
||||
|
||||
|<div style="width:7em">插件</div>|<div style="width:8em">插件名称</div>|简介|
|
||||
|---|---|---|
|
||||
|[Execute Driver](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin)|`execute-driver`|在对Appium服务器的一次调用中运行整批命令|
|
||||
|[Images](https://github.com/appium/appium/tree/master/packages/images-plugin)|`images`|图像匹配和比较功能|
|
||||
|[Relaxed Caps](https://github.com/appium/appium/tree/master/packages/relaxed-caps-plugin)|`relaxed-caps`|放宽Appium对功能上供应商前置的要求|
|
||||
|[Universal XML](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin)|`universal-xml`|使用在两个平台上都相同的XML定义,而不是iOS和Android的标准XML格式|
|
||||
|
||||
### 其他插件
|
||||
|
||||
这些插件不由Appium团队维护,可以提供其他功能:
|
||||
|
||||
|<div style="width:6em">插件</div>|<div style="width:19em">插件名称</div>|简介|<div style="width:13em">维护者</div>|
|
||||
|---|---|---|---|
|
||||
|[AltUnity](https://github.com/headspinio/appium-altunity-plugin)|`--source=npm appium-altunity-plugin`|通过AltUnityTester框架,为Unity游戏和应用程序提供新的自动化环境|HeadSpin|
|
||||
|[Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)|`--source=npm appium-device-farm`|在连接的Android设备和iOS模拟器上管理和创建驱动程序会话|`@AppiumTestDistribution`|
|
||||
|[Gestures](https://github.com/AppiumTestDistribution/appium-gestures-plugin)|`--source=npm appium-gestures-plugin`|使用W3C操作执行基本手势|`@AppiumTestDistribution`|
|
||||
|[Interceptor](https://github.com/AppiumTestDistribution/appium-interceptor-plugin)|`--source=npm appium-interceptor`|拦截和模拟API请求和响应|`@AppiumTestDistribution`|
|
||||
|[OCR](https://github.com/jlipps/appium-ocr-plugin)|`--source=npm appium-ocr-plugin`|通过OCR文本查找元素|`@jlipps`|
|
||||
|[Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)|`--source=npm appium-reporter-plugin`|通过屏幕截图生成独立的合并HTML报告|`@AppiumTestDistribution`|
|
||||
|[Wait](https://github.com/AppiumTestDistribution/appium-wait-plugin)|`--source=npm appium-wait-plugin`|管理全局元素等待超时|`@AppiumTestDistribution`|
|
||||
|
||||
!!! 注意
|
||||
|
||||
如果您维护了一个Appium插件,并希望在Appium文档中列出,请随时进行PR,将其添加到本部分,并附上插件文档的链接。
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Appium相关工具
|
||||
---
|
||||
|
||||
这里有几个Appium工具来帮助处理与测试没有直接关系的事情,例如Appium安装、测试开发等。
|
||||
|
||||
### [Appium Inspector](https://appium.github.io/appium-inspector/latest/)
|
||||
|
||||
Appium有一个图形客户端,可用于检查应用程序屏幕截图、查看应用程序层次结构、运行Appium命令、记录应用程序交互等。它对Appium测试开发非常有用。
|
||||
|
||||
在其GitHub页面上查找下载和更多信息:[Appium Inspector](https://github.com/appium/appium-inspector)
|
||||
|
||||
### Appium Doctor
|
||||
|
||||
Appium Doctor是一个内置于Appium驱动程序和插件中的命令行工具。如果驱动程序/插件作者实现了`doctor`命令,
|
||||
则该命令将用于验证驱动程序或插件是否正确设置了所有先决条件和其他环境详细信息。
|
||||
|
||||
例如,`uiautomator2`驱动程序提供以下`doctor`命令。
|
||||
|
||||
```
|
||||
appium driver doctor uiautomator2
|
||||
```
|
||||
|
||||
如果驱动程序/插件作者没有实现它们,则不会显示任何结果。
|
||||
|
||||
有关此命令的更多信息,请参阅[命令行使用文档](../cli/extensions.md#doctor)。
|
||||
对于驱动程序/插件开发人员,请阅读[构建医生检查](../developing/build-doctor-checks.md)。
|
||||
|
||||
### 其他工具
|
||||
|
||||
这些工具不由Appium团队维护,可以用于协助解决其他问题:
|
||||
|
||||
|名字|简介|维护者|
|
||||
|---|---|---|
|
||||
|[appium-installer](https://github.com/AppiumTestDistribution/appium-installer)|为Android和iOS设置Appium环境|`@AppiumTestDistribution`|
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: Local Validation Of Extension PRs
|
||||
---
|
||||
|
||||
Sometimes it might be necessary to validate if a remote driver or a plugin PR works for the particular local
|
||||
environment before it is merged or published. This tutorial describes how to achieve that.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Recent LTS version of NodeJS. Check [Node.js main page](https://nodejs.org) for the download link.
|
||||
- Recent version of the Appium server. Use the following commands to ensure you have
|
||||
the latest version installed: `npm uninstall appium` and `npm install -g appium`.
|
||||
- [Git](https://git-scm.com/) should be available locally.
|
||||
|
||||
## Installation
|
||||
|
||||
- [Check out]((https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally)) the PR locally.
|
||||
There is also an option (although it is less flexible, because you won't be able to easily fetch
|
||||
any changes to this PR later) to simply [download](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives) and unzip the sources
|
||||
locally. If you choose the later option then no `git` tool would be necessary.
|
||||
- Navigate to the local driver or plugin folder and run `npm i` from that folder.
|
||||
- Make sure you don't have the given driver or plugin already installed. Use the `appium driver uninstall <driver_name>`
|
||||
or `appium plugin uninstall <plugin_name>` CLI in order to delete any leftovers. The value of
|
||||
`<driver_name>`/`<plugin_name>` depends on the actual driver or plugin name the PR has been prepared for.
|
||||
If you are not sure which name you need to use then check the content of the `package.json` manifest,
|
||||
which must be always located under the root folder of the fetched sources. You should be looking for
|
||||
the `"appium" -> "driverName"` entry value there.
|
||||
- Change the current folder to the one, which is NOT the driver/plugin folder root or its subfolder.
|
||||
Also, make sure your current working folder does not contain any extra `package.json` file. If
|
||||
it does then simply navigate to any other folder that does not.
|
||||
- Run the following command in order to link the driver/plugin sources to the Appium server:
|
||||
`appium driver install --source=local <full_path_to_driver_folder_with_fetched_sources>` or
|
||||
`appium plugin install --source=local <full_path_to_plugin_folder_with_fetched_sources>`.
|
||||
- Stop the Appium server if it is running and start it again (`appium server --use-drivers=<driver_name>`)
|
||||
to check the list of loaded drivers. If the linking succeeded then you must see the driver name and the path to its
|
||||
parent folder in the server logs. In case of a plugin it is required to explicitly request
|
||||
this plugin to be loaded upon server startup: `appium server --use-plugins=<plugin_name>`.
|
||||
|
||||
## Update
|
||||
|
||||
After you have tested the PR and there are issues it might be necessary to update the local branch with
|
||||
the recent changes from Git. Follow the next steps for that:
|
||||
|
||||
- Navigate to the parent folder of your local driver/plugin and run `git pull`.
|
||||
- Stop Appium server if it is running.
|
||||
- Run `npm i` in the parent folder of your local driver/plugin to rebuild it and update any dependencies if necessary.
|
||||
- Start Appium server again similarly to how this is done in the corresponding [Installation](#installation) step above.
|
||||
|
||||
## Switching Back To a Stable Release
|
||||
|
||||
After the PR is merged there is no need to use the local plugin/driver deployment anymore, and it makes sense
|
||||
to switch back to the package managed by NPM. Follow the next steps for that:
|
||||
|
||||
- Unlink the installed driver/plugin from the server by running `appium driver uninstall <driver_name>` or
|
||||
`appium plugin uninstall <driver_name>`.
|
||||
- Delete the local source folder (`rm -rf <full_path_to_plugin_or_driver_folder_with_fetched_sources>`).
|
||||
- Install the driver or the plugin from NPM. Check the component README in order to find a proper command for that.
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: Caching of Application Bundles
|
||||
---
|
||||
|
||||
Appium's base driver provides a feature which enables caching of application builds provided, for example,
|
||||
as `app` capability value or to endpoints similar to the `installApp` one. This article explains common caching
|
||||
principles, so you could create more performant and efficient test suite execution strategies.
|
||||
|
||||
## Why Caching Is Necessary
|
||||
|
||||
Mobile application bundles could reach hundreds of megabytes is size. This could become a serious
|
||||
performance issue if a test suite is executed, and it is necessary to fetch/extract the same application
|
||||
bundle for each test.
|
||||
|
||||
## What Is Cached
|
||||
|
||||
Caching could be applied to application bundles generated by
|
||||
[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.js#L107) helper call.
|
||||
Inherited drivers can customize their caching logic by providing own `onPostProcess`
|
||||
(or both `inDownload` and `onPostProcess`) property definition, but the general
|
||||
rule of thumb is that we need to cache locally all application bundles need to be downloaded and/or extracted
|
||||
first before they could be actually installed on the device under test. On iOS, for example, these are `.ipa` or
|
||||
`.zip` compressed application bundles, or .`aab` on Android.
|
||||
|
||||
## Caching of Remote Application Bundles
|
||||
|
||||
In order to validate whether an app bundle downloaded from the given URL could be (re)used from the cache the following
|
||||
steps are applied:
|
||||
|
||||
1. The script checks if the given URL is already present in the cache.
|
||||
If yes then it tries to fetch previously remembered
|
||||
[Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified)
|
||||
or [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) header values for it.
|
||||
2. If `ETag` value is present then it is put into
|
||||
[If-None-Match request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match).
|
||||
Else if `Last-Modified` header value is present then it is put into
|
||||
[If-Modified-Since request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since).
|
||||
Otherwise, no caching is applied.
|
||||
3. If the response status is equal to `304` then the previously cached binary is used,
|
||||
otherwise the cached entry is reset and refreshed.
|
||||
|
||||
## Caching of Local Application Bundles
|
||||
|
||||
It only makes sense to cache application bundles if they need some preprocessing before being installed on the device under test.
|
||||
For example, on iOS `.ipa` bundles must be unzipped, because the system installer only works with `.app` folders.
|
||||
|
||||
1. The script verifies if the given bundle path is already present in the cache. If the bundle was not in the cache yet
|
||||
then it gets preprocessed and added there.
|
||||
2. The script validates the hashsum of the bundle and compares it to the previously stored one. If hash sums don't match
|
||||
then the cached item gets deleted and the preprocessing of the bundle repeats.
|
||||
|
||||
## How The Cache File System Is Configured
|
||||
|
||||
The cache where the base driver keeps all application bundles is located in the system temp folder. It is configured
|
||||
on per-process basis, so each test session initialized in scope of the same Appium server process takes advantages
|
||||
of it. It is a [LRU Cache](https://www.npmjs.com/package/lru-cache) with the following limitations:
|
||||
|
||||
- Max items: 1024. You may customize it by providing a new value to
|
||||
the [APPIUM_APPS_CACHE_MAX_ITEMS](../cli/env-vars.md) environment variable.
|
||||
Do not set it to a lower number than the amount of apps in all parallel sessions per process.
|
||||
- Max time to live (TTL) for each entry: 24 hours.
|
||||
You may customize it by providing a new value to the
|
||||
[APPIUM_APPS_CACHE_MAX_AGE](../cli/env-vars.md) environment variable.
|
||||
Do not set it to a lower number than the duration of a single session startup.
|
||||
- TTL is refreshed for each entry upon access
|
||||
- By default the full application URL is used as cache key. You may change this behavior
|
||||
by enabling the [APPIUM_APPS_CACHE_IGNORE_URL_QUERY](../cli/env-vars.md) environment variable.
|
||||
If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys.
|
||||
See the corresponding [feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713)
|
||||
for more details.
|
||||
|
||||
!!! warning
|
||||
|
||||
Note: The cache root folder is set up for automatic deletion on Appium process termination. This would only
|
||||
work if Appium server is killed with `SIGINT` or `SIGTERM`. If `SIGKILL` is used then no cache cleanup
|
||||
would be performed.
|
||||
@@ -1,5 +1,265 @@
|
||||
---
|
||||
title: Capabilities
|
||||
title: Session Capabilities
|
||||
---
|
||||
|
||||
TODO
|
||||
"Capabilities" is the name given to the set of parameters used to start an Appium session. The
|
||||
information in the set describes what sort of "capabilities" you want your session to have, for
|
||||
example, a certain mobile operating system or a certain version of a device. Capabilities are
|
||||
represented as key-value pairs, with values allowed to be any valid JSON type, including
|
||||
other objects.
|
||||
|
||||
The W3C WebDriver spec's [section on Capabilities](https://w3c.github.io/webdriver/#capabilities)
|
||||
identifies a small set of 10 standard capabilities, including the following:
|
||||
|
||||
| Capability Name | Type | Description |
|
||||
|------------------|----------|------------------------------------------------|
|
||||
| `browserName` | `string` | The name of the browser to launch and automate |
|
||||
| `browserVersion` | `string` | The specific version of the browser |
|
||||
| `platformName` | `string` | The type of platform hosting the browser |
|
||||
|
||||
## Common Appium Capabilities
|
||||
|
||||
Appium understands these browser-focused capabilities, but introduces a number of additional
|
||||
capabilities. According to the WebDriver spec, any
|
||||
non-standard "extension capabilities" must include a namespace prefix (signifying the vendor
|
||||
introducing the capability), ending in a `:`. Appium's vendor prefix is
|
||||
`appium:`, and so any Appium-specific capabilities must include this prefix. Depending on which
|
||||
client you are using, the prefix may be added automatically or in conjunction with certain
|
||||
interfaces, but it is always a good practice to explicitly include it for clarity.
|
||||
|
||||
Here is a list of all the globally-recognized Appium capabilities:
|
||||
|
||||
!!! info
|
||||
|
||||
Individual drivers and plugins can support other capabilities, so refer to their documentation
|
||||
for lists ofspecific capability names. Some drivers may also not support all of these capabilities
|
||||
|
||||
| <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 |
|
||||
| `appium:noReset` | `boolean` | no | If true, instruct an Appium driver to avoid its usual reset logic during session start and cleanup (default `false`) |
|
||||
| `appium:fullReset` | `boolean` | no | If true, instruct an Appium driver to augment its usual reset logic with additional steps to ensure maximum environmental reproducibility (default `false`) |
|
||||
| `appium:eventTimings` | `boolean` | no | If true, instruct an Appium driver to collect [Event Timings](./event-timing.md) (default `false`) |
|
||||
| `appium:printPageSourceOnFindFailure` | `boolean` | no | If true, collect the page source and print it to the Appium log whenever a request to find an element fails (default `false`) |
|
||||
|
||||
|
||||
Some drivers place more complex constraints on capabilities as a group. For example, while the
|
||||
`appium:app` and `browserName` capabilities are listed above as optional, if you want to launch
|
||||
a session with a specific app, the XCUITest driver requires that at least one of `appium:app`,
|
||||
`browserName`, or `appium:bundleId` are included in the capabilities (otherwise it will not know
|
||||
what app to install and/or launch and will simply open a session on the home screen). Each driver
|
||||
will document how it interprets these capabilities and any other platform-specific requirements.
|
||||
|
||||
!!! note
|
||||
|
||||
Capabilities are like parameters used when starting a session. After the capabilities are sent
|
||||
and the session is started, they cannot be changed. If a driver supports updating aspects of
|
||||
its behaviour in the course of a session, it will provide a [Setting](./settings.md) for this
|
||||
purpose instead of, or in addition to, a capability.
|
||||
|
||||
Each Appium client has its own way of constructing capabilities and starting a session. For
|
||||
examples of doing this in each client library, head to the [Ecosystem](../ecosystem/index.md) page
|
||||
and click through to the appropriate client documentation.
|
||||
|
||||
## Using `appium:options` to Group Capabilities
|
||||
|
||||
If you use a lot of `appium:` capabilities in your tests, it can get a little repetitive. You can
|
||||
combine all capabilities as an object value of a single `appium:options` capability instead, in
|
||||
which case you don't need to use prefixes on the capabilities inside the object. For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:options": {
|
||||
"automationName": "XCUITest",
|
||||
"platformVersion": "16.0",
|
||||
"app": "/path/to/your.app",
|
||||
"deviceName": "iPhone 12",
|
||||
"noReset": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that constructing a capability value which is itself an object differs by language; refer to
|
||||
your client documentation for further examples on how to achieve this.
|
||||
|
||||
!!! warning
|
||||
|
||||
If you include the same capabilities both inside and outside of `appium:options`, the values
|
||||
inside of `appium:options` take precedence.
|
||||
|
||||
## Always-Match and First-Match Capabilities
|
||||
|
||||
The W3C spec allows clients to give the Appium server some flexibility in the kind of session it
|
||||
creates in response to a new session request. This is through the concept of "always-match" and
|
||||
"first-match" capabilities:
|
||||
|
||||
- Always-match capabilities consist of a single set of capabilities, every member of which must
|
||||
be satisfied by the server in order for the new session request to proceed.
|
||||
- First-match capabilities consist of an array of capability sets. Each set is merged with the
|
||||
always-match capabilities, and the first set that the server knows how to handle will be the set
|
||||
that is used to start the session.
|
||||
|
||||
!!! note
|
||||
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or
|
||||
a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for
|
||||
a more in-depth description of how capabilities are processed.
|
||||
|
||||
In practice, use of first-match capabilities is not necessary or recommended for use with Appium.
|
||||
Instead, we recommend that you define the explicit set of capabilities you want the Appium
|
||||
server to handle. These will be encoded as the always-match capabilities, and the array of
|
||||
first-match capabilities will be empty.
|
||||
|
||||
That being said, Appium _does_ understand always-match and first-match capabilities as
|
||||
defined in the W3C spec, so if you use these features, Appium will work as expected. The process of
|
||||
defining always-match and first-match capabilities is unique to each client library, so refer to
|
||||
the documentation for your client library to see examples of how it works.
|
||||
|
||||
## Special Notes for Cloud Providers
|
||||
|
||||
!!! warning
|
||||
|
||||
This section is not intended for end-users of Appium; it is intended for developers building
|
||||
Appium-compatible cloud services.
|
||||
|
||||
When managing an Appium cloud, your users may wish to target various independent versions of Appium
|
||||
drivers and plugins. It is of course up to each service provider how they wish to implement the
|
||||
discovery, installation, and availability of any official or third party drivers or plugins. But
|
||||
the Appium team does provide several suggestions, for consistency across the industry. _These are
|
||||
recommendations only,_ and not a standard, but adopting it will help users to navigate the increased
|
||||
complexity that working with Appium 2 in a cloud environment may bring.
|
||||
|
||||
### Suggested capabilities
|
||||
|
||||
In addition to the standard `platformName`, `appium:deviceName`, `appium:automationName`, and
|
||||
`appium:platformVersion`, we recommend adopting the capability `$cloud:appiumOptions`, where the
|
||||
label `$cloud` is not meant to be interpreted literally but instead should be replaced by your
|
||||
vendor prefix (so for HeadSpin it would be `headspin`, Sauce Labs it would be `sauce`, and
|
||||
BrowserStack it would be `browserstack`, to name just a few examples). The `$cloud:appiumOptions`
|
||||
capability would itself be a JSON object, with the following internal keys:
|
||||
|
||||
| <div style="width:10em">Capability</div> | Usage | Example |
|
||||
| ---------------------------------------- | ------ | ------- |
|
||||
| `version` | The version of the Appium server that is used to host and manage drivers. If omitted, the behavior is left up to the provider, but the recommendation would be to provide the latest official version. | `2.0.0` |
|
||||
| `automationVersion` | The version of the driver (as specified by `appium:automationName`) that should be used. | `1.55.2` |
|
||||
| `automation` | The name of a custom driver to use (see below for more info). This would override `appium:automationName` and `$cloud:automationVersion`. | `{"name": "@org/custom-driver", "source": "github", "package": "custom-driver"}` |
|
||||
| `plugins` | The list of plugins (and potentially versions of plugins) that should be activated (see below for more info). | `["images", "universal-xml"]` |
|
||||
|
||||
### Basic example
|
||||
|
||||
Appium extensions (drivers and plugins) have a set of properties that specify where they can be
|
||||
installed from. Cloud providers are obviously under no obligation to provide support for
|
||||
arbitrarily specified extensions, seeing as these may represent untrusted code running in a managed
|
||||
environment. In the case where arbitrary extensions are not supported, the `appium:automationName`,
|
||||
`$cloud:automationVersion`, and `$cloud:appiumPlugins` capabilities should be sufficient. See the
|
||||
following JSON object representing capabilities for a session:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:platformVersion": "14.4",
|
||||
"appium:deviceName": "iPhone 11",
|
||||
"appium:app": "Some-App.app.zip",
|
||||
"appium:automationName": "XCUITest",
|
||||
"$cloud:appiumOptions": {
|
||||
"version": "2.0.0",
|
||||
"automationVersion": "3.52.0",
|
||||
"plugins": ["images"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This set of capabilities requests an Appium 2+ server supporting the XCUITest driver at version
|
||||
`3.52.0`, and the `images` plugin active. This set is easy for a cloud provider to verify. The
|
||||
cloud provider can obviously do anything it wants in response to these capabilities, including
|
||||
downloading Appium and driver and plugin packages on the fly, or erroring out if the versions
|
||||
requested are not in a supported set, or if the plugin is not supported, etc...
|
||||
|
||||
### Basic example with `appium:options`
|
||||
|
||||
The previous example still looks a bit disorganized, so of course we also recommend that cloud
|
||||
providers support the `appium:options` capability as detailed above, which could turn the previous
|
||||
set of capabilities into the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:options": {
|
||||
"platformVersion": "14.4",
|
||||
"deviceName": "iPhone 11",
|
||||
"app": "Some-App.app.zip",
|
||||
"automationName": "XCUITest"
|
||||
},
|
||||
"$cloud:appiumOptions": {
|
||||
"version": "2.0.0",
|
||||
"automationVersion": "3.52.0",
|
||||
"plugins": ["images"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Extension objects
|
||||
|
||||
Some service providers may wish to dynamically allow access to all of the features of the Appium
|
||||
2 CLI, including downloading arbitrary drivers and plugins. To represent these extensions, we can
|
||||
define special JSON "extension objects", with the following keys:
|
||||
|
||||
- `name`: the name of the extension. This would be an `npm` package name (if downloading from `npm`),
|
||||
or a `git` or GitHub spec (if downloading from a `git` server or GitHub).
|
||||
- `version`: the version of the extension, e.g., the `npm` package version or `git` SHA.
|
||||
- (optional) `source`: a denotation of where the extension can be downloaded from. It is recommended
|
||||
to support the following values: `appium`, `npm`, `git`, `github`. Here, `appium` means "Appium's
|
||||
own official list", and should be the default value if this key is not included.
|
||||
- (optional) `package`: when downloading extensions from `git` or GitHub, the `npm` package name of
|
||||
the extension must also be provided. This is optional for non-`git` sources.
|
||||
|
||||
Since each session is handled by a single driver, the `$cloud:appiumOptions`/`$automation`
|
||||
capability could be used with an extension object value to denote this driver, for example:
|
||||
|
||||
```json
|
||||
{
|
||||
"$cloud:appiumOptions": {
|
||||
"automation": {
|
||||
"name": "git+https://some-git-host.com/custom-driver-project.git",
|
||||
"version": "some-git-sha",
|
||||
"source": "git",
|
||||
"package": "driver-npm-package-name"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And since sessions can handle multiple plugins, each value in the list of `$cloud:appiumPlugins`
|
||||
could also be an extension object rather than a string, so that specific versions could be
|
||||
requested:
|
||||
|
||||
```json
|
||||
{
|
||||
"$cloud:appiumOptions": {
|
||||
"plugins": [{
|
||||
"name": "images",
|
||||
"version": "1.1.0"
|
||||
}, {
|
||||
"name": "my-github-org/my-custom-plugin",
|
||||
"version": "a83f2e",
|
||||
"source": "github",
|
||||
"package": "custom-plugin"
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These serve as illustrative examples for the recommendations here. Of course, it is up to the
|
||||
service providers to implement the handling of these capabilities at their front end / load
|
||||
balancer, to perform any error checking, or to actually run any of the `appium driver` or `appium
|
||||
plugin` CLI commands that support the end user's request. This section is merely a suggestion as to
|
||||
how service providers might design their user-facing capabilities API in a way which in principle
|
||||
supports all of the capabilities that Appium itself would provide to the end user if they were
|
||||
running Appium on their own.
|
||||
|
||||
@@ -2,4 +2,97 @@
|
||||
title: The Appium Config File
|
||||
---
|
||||
|
||||
TODO
|
||||
Instead of passing arguments on the command line to Appium, you may add them to a special config
|
||||
file. Appium will read values from this config file when it runs. (Please note that CLI arguments
|
||||
have _precedence_ over configuration files; if a value is set in a config file _and_ via CLI
|
||||
argument, the CLI argument is preferred.)
|
||||
|
||||
## Supported Config File Formats
|
||||
|
||||
You can store your config data in the following kinds of files:
|
||||
|
||||
- JSON
|
||||
- YAML
|
||||
- JS (a JavaScript file exporting a JS object)
|
||||
- CJS (the same as above; the extension is for common JS)
|
||||
|
||||
!!! warning
|
||||
|
||||
Note: Configuration files in ESM format are not currently supported.
|
||||
|
||||
## Supported Config File Locations
|
||||
|
||||
Configuration files can be named anything, but the following filenames will be automatically
|
||||
discovered and loaded by Appium:
|
||||
|
||||
- `.appiumrc.json` (recommended)
|
||||
- `.appiumrc.yaml`
|
||||
- `.appiumrc.yml`
|
||||
- `.appiumrc.js`
|
||||
- `.appiumrc.cjs`
|
||||
- `appium.config.js`
|
||||
- `appium.config.cjs`
|
||||
- `.appiumrc` (which is considered to be JSON)
|
||||
|
||||
Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium`
|
||||
property in your `package.json` and it will be automatically discovered.
|
||||
|
||||
### Config File Search
|
||||
|
||||
Appium will search _up_ the directory tree from the current working directory for one of these
|
||||
files. If it reaches the current user's home directory or filesystem root, it will stop looking.
|
||||
|
||||
To specify a _custom_ location for your config file, use `appium --config-file /path/to/config/file`.
|
||||
|
||||
#### Configuration File Format
|
||||
|
||||
First, you might want to look at some examples:
|
||||
|
||||
- [Appium Configuration - JSON](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.json)
|
||||
- [Appium Configuration - YAML](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.yaml)
|
||||
- [Appium Configuration - JS](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.js)
|
||||
|
||||
A description of the format is available, as well:
|
||||
|
||||
- [Appium Configuration File JSON Schema](https://github.com/appium/appium/blob/master/packages/schema/lib/appium-config.schema.json)
|
||||
- [TypeScript declarations for Appium Configuration](https://github.com/appium/appium/blob/master/packages/types/lib/config.ts)
|
||||
|
||||
To describe in words, the config file will have a root `server` property, and all arguments are
|
||||
child properties. For certain properties which must be supplied on the command-line as
|
||||
comma-delimited lists, JSON strings, and/or external filepaths, these instead will be of their
|
||||
"native" type. For example, `--use-plugins <value>` needs `<value>` to be comma-delimited string
|
||||
or path to a delimited file. However, the config file just wants an array, e.g.,:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"use-plugins": ["my-plugin", "some-other-plugin"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuring extensions (drivers and plugins)
|
||||
|
||||
For `driver`-and-`plugin`-specific configuration, these live under the `server.driver` and
|
||||
`server.plugin` properties, respectively. Each driver or plugin will have its own named property,
|
||||
and the values of any specific configuration it provides are under this. For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"xcuitest": {
|
||||
"webkit-debug-proxy-port": 5400
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
The above configuration corresponds to the `--driver-xcuitest-webkit-debug-proxy-port` CLI argument.
|
||||
|
||||
All properties are case-sensitive and will be in
|
||||
[kebab-case](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Delimiter-separated_words).
|
||||
For example, `callback-port` is allowed, but `callbackPort` is not.
|
||||
|
||||
@@ -1,5 +1,44 @@
|
||||
---
|
||||
title: The Context API
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Managing Contexts
|
||||
---
|
||||
|
||||
TODO
|
||||
A common feature of many app platforms is the ability for developers to embed web content inside of
|
||||
the platform-native app frame. This allows developers to leverage web technologies or existing web
|
||||
content for some or all of the app functionality. However, the additional complexity of mixing
|
||||
"modes" within a single application can make it difficult for automation tools that are designed to
|
||||
target the "native" elements and behaviours.
|
||||
|
||||
Appium provides a set of APIs for working with different app modes, called "contexts", that Appium
|
||||
drivers can implement if they support automation commands in these different modes. There are three
|
||||
basic commands that Appium has added to the W3C WebDriver spec for this purpose:
|
||||
|
||||
| Command Name | Method/Route | Params | Description | Returns |
|
||||
|-----------------------|-----------------------------|-------------------|-----------------------------------------------|-----------------|
|
||||
| `Get Contexts` | `GET /session/:id/contexts` | | Get a list of the available contexts | `array<string>` |
|
||||
| `Get Current Context` | `GET /session/:id/context` | | Get the name of the active context | `string` |
|
||||
| `Set Context` | `POST /session/:id/context` | `name` (`string`) | Switch into the context with the given `name` | `null` |
|
||||
|
||||
This API is flexible enough to handle a variety of semantic interpretations on the part of the
|
||||
driver. For example, the XCUITest driver includes two kinds of contexts: the native app context and
|
||||
any active webviews, as one context per webview. A call to `Get Contexts` will return the list of
|
||||
names, which you as a test author can sift through and use to switch into the appropriate context.
|
||||
As another example, the [Appium Altunity
|
||||
Plugin](https://github.com/headspinio/appium-altunity-plugin) introduces the concept of a `UNITY`
|
||||
context, which encapsulates all the plugin's specific behaviour to ensure that when outside of the
|
||||
`UNITY` context, the active driver's usual command implementations are used.
|
||||
|
||||
It is important to note that a call to `Get Contexts` will always contain at least one context,
|
||||
conventionally but not necessarily named `NATIVE_APP`. This is the default active context.
|
||||
|
||||
Depending on the type of context you're in, the operation of the driver might change. The XCUITest
|
||||
driver, when targeting a webview context, will not run its typical routines for finding and
|
||||
interacting with elements. Instead, it will run a different set of routines appropriate to web
|
||||
elements. This might have a variety of consequences, like supporting a different set of locator
|
||||
strategies.
|
||||
|
||||
The command names in the table above are generic references to the commands and not code examples.
|
||||
For examples of how to access the Context API in the language-specific client libraries, please
|
||||
visit the documentation for a given library.
|
||||
|
||||
@@ -1,5 +1,74 @@
|
||||
---
|
||||
title: The Event Timing API
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Retrieving Event Timings
|
||||
---
|
||||
|
||||
TODO
|
||||
Appium comes with the ability to retrieve timing information about startup
|
||||
information and command length. This is an advanced feature that is controlled
|
||||
by the use of the `appium:eventTimings` capability (set it to `true` to log event
|
||||
timings).
|
||||
|
||||
With this capability turned on, the `GET /session/:id` response (i.e., the
|
||||
response to `driver.getSessionDetails()` or similar, depending on client) will
|
||||
be decorated with an `events` property. This is the structure of that `events`
|
||||
property:
|
||||
|
||||
```
|
||||
{
|
||||
"<event_type>": [<occurence_timestamp_1>, ...],
|
||||
"commands": [
|
||||
{
|
||||
"cmd": "<command_name>",
|
||||
"startTime": <js_timestamp>,
|
||||
"endTime": <js_timestamp>
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In other words, the `events` property has 2 kinds of properties of its own:
|
||||
|
||||
* Properties which are the names of event types
|
||||
* The `commands` property
|
||||
|
||||
Properties which are names of event types correspond to an array of timestamps
|
||||
when that event happened. It's an array because events might happen multiple
|
||||
times in the course of a session. Examples of event types include:
|
||||
|
||||
* `newSessionRequested`
|
||||
* `newSessionStarted`
|
||||
|
||||
(Individual drivers will define their own event types, so we do not have an
|
||||
exhaustive list to share here. It's best to actually get one of these responses
|
||||
from a real session to inspect the possible event types.)
|
||||
|
||||
The `commands` property is an array of objects. Each object has the name of the
|
||||
Appium-internal command (for example `click`), as well as the time the command
|
||||
started processing and the time it finished processing.
|
||||
|
||||
With this data, you can calculate the time between events, or a strict timeline
|
||||
of events, or statistical information about average length of a certain type of
|
||||
command, and so on.
|
||||
|
||||
You can only receive data about events that have happened when you make the
|
||||
call to `/session/:id`, so the best time to get data about an entire session is
|
||||
right before quitting it.
|
||||
|
||||
The Appium team maintains an event timings parser tool that can be used to
|
||||
generate various kinds of reports from event timings output:
|
||||
[appium/appium-event-parser](https://github.com/appium/appium-event-parser).
|
||||
|
||||
## Add a custom event
|
||||
|
||||
!!! warning "TODO"
|
||||
|
||||
The links to the commands in the following paragraph do not yet work since these docs are under
|
||||
construction.
|
||||
|
||||
You can add custom events that will show up in the event timings data. You can send a custom event
|
||||
name to the Appium server using the [Log Event API](#TODO), and the server will store the
|
||||
timestamp. The [Get Events](#TODO) command can be used to retrieve named events' timestamps later
|
||||
on.
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
hide:
|
||||
- toc
|
||||
|
||||
title: Execute Methods
|
||||
---
|
||||
|
||||
Because the scope of commands implemented in Appium drivers is broader than the scope of commands
|
||||
defined by the W3C WebDriver spec, Appium needs a way for these "extended" commands to be accessible
|
||||
by client libraries. There are two main strategies for this:
|
||||
|
||||
1. Appium drivers define new W3C-compatible API routes, and Appium clients are updated to include
|
||||
support for those new routes.
|
||||
2. Appium drivers define so-called "Execute Methods" which provide new functionality by
|
||||
overloading the existing `Execute Script` command which is already available in any WebDriver-
|
||||
based client library (including all Selenium and Appium clients).
|
||||
|
||||
There are pros and cons for each strategy, but it is ultimately up to the extension author to
|
||||
decide how they wish implement new commands.
|
||||
|
||||
This guide is designed to specifically help you understand the "Execute Method" strategy. This
|
||||
pattern is commonly used in official Appium drivers and other third-party extensions.
|
||||
Here's an example of how the `Execute Script` command is designed to work in the world of WebDriver
|
||||
and browser automation:
|
||||
|
||||
=== "JS (WebDriverIO)"
|
||||
|
||||
```js
|
||||
await driver.executeScript('return arguments[0] + arguments[1]', [3, 4])
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
|
||||
jsDriver.executeScript("return arguments[0] + arguments[1]", 3, 4);
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
driver.execute_script('return arguments[0] + arguments[1]', 3, 4)
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```rb
|
||||
driver.execute_script 'return arguments[0] + arguments[1]', 3, 4
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```dotnet
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0] + arguments[1]", 3, 4);
|
||||
```
|
||||
|
||||
What's happening here is that we are defining a snippet of Javascript (technically,
|
||||
a function body) to be executed within the web browser. The client can send arguments which are
|
||||
serialized, sent over HTTP, and finally provided to the function as parameters. In this example,
|
||||
we are essentially defining an addition function. The return value of the `Execute Script` command
|
||||
is whatever the return value of the Javascript snippet is! In the case of this example, that value
|
||||
would be the number `7` (`3` + `4`).
|
||||
|
||||
Each client library has its own way of calling the command and providing any arguments to the script
|
||||
function, but the function itself—the snippet—is always a string and is the same across all languages.
|
||||
|
||||
In the world of Appium, we are usually not automating a web browser, which means this command is
|
||||
not particularly useful. But it *is* useful as a way to encode the name of an arbitrary command and
|
||||
to provide parameters. For example, the [XCUITest
|
||||
Driver](https://github.com/appium/appium-xcuitest-driver) has implemented a command that lets a client
|
||||
terminate a running application if you know the ID (the `bundleId`) of the app. The way that the
|
||||
driver makes this command available is via the Execute Method `mobile: terminateApp`. Instead of
|
||||
providing a JavaScript function to the "Execute Script" command, the user provides a _known string_
|
||||
as defined by the driver. The only other thing a client needs to know is the set of
|
||||
parameters for the method, which are documented by the driver. In this case, we have a parameter
|
||||
named `bundleId`, whose value should be a string encoding the ID of the app to terminate. Here is
|
||||
how this Execute Method would be called:
|
||||
|
||||
=== "JS (WebDriverIO)"
|
||||
|
||||
```js
|
||||
await driver.executeScript('mobile: terminateApp', [{bundleId: 'com.my.app'}])
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
|
||||
jsDriver.executeScript("mobile: terminateApp", ImmutableMap.of("bundleId", "com.my.app"));
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
driver.execute_script('mobile: terminateApp', {'bundleId': 'com.my.app'})
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```rb
|
||||
driver.execute_script 'mobile: terminateApp', { bundleId: 'com.my.app' }
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```dotnet
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: terminateApp",
|
||||
new Dictionary<string, string> { { "bundleId", "com.my.app" } });
|
||||
|
||||
```
|
||||
|
||||
There are two important differences in using Appium Execute Methods from vanilla Selenium
|
||||
Javascript execution:
|
||||
|
||||
1. The script string is just a command name; it will be provided by the driver documentation
|
||||
1. The standard way to provide parameters is as a *single* object with keys representing parameter
|
||||
names and values representing parameter values. So in this case, we had to specify both the
|
||||
parameter name (`bundleId`) as the key of the parameters object, and the parameter value
|
||||
(`com.my.app`) as the value for that key. A driver can define parameters as _required_ or _optional_.
|
||||
|
||||
Of course, always refer to the documentation for the particular Execute Method in case the author
|
||||
has made any alterations to the standard access method.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Execute Script Overloads
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -2,4 +2,165 @@
|
||||
title: Appium and Selenium Grid
|
||||
---
|
||||
|
||||
TODO
|
||||
## Using Selenium Grid 4+
|
||||
|
||||
The
|
||||
[relay](https://www.selenium.dev/documentation/grid/configuration/toml_options/#relaying-commands-to-a-service-endpoint-that-supports-webdriver)
|
||||
feature in Grid 4 allows you to proxy Appium requests to an Appium server instance. Here is
|
||||
an example walkthrough of how you would connect two different Appium instances to a Selenium Grid.
|
||||
|
||||
### Define the Appium configs
|
||||
|
||||
Each Appium instance should have a config file that can be easily updated. It should contain any
|
||||
information which needs to be unique to that particular server (e.g., ports its drivers should use
|
||||
that others should not). We are going to have 2 Appium servers, so we will need 2 config files:
|
||||
|
||||
```yaml
|
||||
# appium1.yml
|
||||
server:
|
||||
port: 4723
|
||||
use-drivers:
|
||||
- xcuitest
|
||||
default-capabilities:
|
||||
wdaLocalPort: 8100
|
||||
mjpegServerPort: 9100
|
||||
mjpegScreenshotUrl: "http://localhost:9100"
|
||||
```
|
||||
|
||||
In the above YAML config file, we specify the Appium server port, the driver used, and parameters
|
||||
for the driver that will be sent in as default capabilities. Our goal is to ensure that any other
|
||||
drivers running on this host will not compete with system ports or other resources. The second
|
||||
config file could look like the following, where we simply adjust a few ports to prevent clashes:
|
||||
|
||||
```yaml
|
||||
# appium2.yml
|
||||
server:
|
||||
port: 4733
|
||||
use-drivers:
|
||||
- xcuitest
|
||||
default-capabilities:
|
||||
wdaLocalPort: 8110
|
||||
mjpegServerPort: 9110
|
||||
mjpegScreenshotUrl: "http://localhost:9110"
|
||||
```
|
||||
|
||||
### Define the Grid node configs
|
||||
|
||||
We will be launching one Grid "node" per Appium server, to manage relaying commands and determining
|
||||
capacity and online status, etc... So we should have one config file per Grid node as well. Each
|
||||
node config should include the address of the Appium server it will target, as well as a list of
|
||||
capability "configs" it should accept to relay a session request to Appium. Here is what the config
|
||||
could look like for the two nodes:
|
||||
|
||||
```toml
|
||||
# node1.toml
|
||||
[server]
|
||||
port = 5555
|
||||
|
||||
[node]
|
||||
detect-drivers = false
|
||||
|
||||
[relay]
|
||||
url = "http://localhost:4723"
|
||||
status-endpoint = "/status"
|
||||
configs = [
|
||||
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 13\", \"appium:automationName\": \"XCUITest\"}"
|
||||
]
|
||||
```
|
||||
|
||||
```toml
|
||||
# node2.toml
|
||||
[server]
|
||||
port = 5565
|
||||
|
||||
[node]
|
||||
detect-drivers = false
|
||||
|
||||
[relay]
|
||||
url = "http://localhost:4733"
|
||||
status-endpoint = "/status"
|
||||
configs = [
|
||||
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 12\", \"appium:automationName\": \"XCUITest\"}"
|
||||
]
|
||||
```
|
||||
|
||||
Note that each node config also specifies a different port itself for the node to run on.
|
||||
|
||||
### Putting it together
|
||||
|
||||
The Grid nodes aren't enough--you'll also want a Grid "hub" that acts as a load balancer and
|
||||
manager for all the nodes. So in the end we'll have 5 processes running at once: 2 Appium servers,
|
||||
2 Grid nodes, and 1 Grid hub. It's best to run each of these in a separate terminal window to avoid
|
||||
confusion of logs. Here is how you'd start each process:
|
||||
|
||||
0. `appium --config appium1.yml`
|
||||
0. `appium --config appium2.yml`
|
||||
0. `java -jar /path/to/selenium.jar node --config node1.toml`
|
||||
0. `java -jar /path/to/selenium.jar node --config node2.toml`
|
||||
0. `java -jar /path/to/selenium.jar hub`
|
||||
|
||||
Once you wait a few moments for the nodes to detect their Appium servers, and to register with the
|
||||
hub, you'll be able to send all your Appium traffic via the single hub endpoint (defaulting to
|
||||
`http://localhost:4444`).
|
||||
|
||||
And of course, you're able to link up Appium servers and nodes running on different machines in
|
||||
your network to form a larger grid.
|
||||
|
||||
## Using Selenium Grid 3
|
||||
|
||||
It is possible to register your Appium server with a local [Selenium Grid 3](https://www.selenium.dev/documentation/legacy/selenium_3/grid_3/)
|
||||
([setup docs](https://www.selenium.dev/documentation/legacy/grid_3/setting_up_your_own_grid/)) instance by using the
|
||||
`--nodeconfig` server argument.
|
||||
|
||||
```bash
|
||||
appium server --nodeconfig /path/to/nodeconfig.json --base-path=/wd/hub
|
||||
```
|
||||
|
||||
In the referenced config file you have to define the `browserName`, `version` and `platform`
|
||||
capabilities and based on these parameters the grid will re-direct your test to the right device.
|
||||
You will also need to configure your host details and the Selenium Grid details. For a full list of
|
||||
all parameters and descriptions see
|
||||
[here](https://www.selenium.dev/documentation/legacy/selenium_3/grid_setup/).
|
||||
|
||||
Once you start the Appium server it will register with the grid, and you will see your device on
|
||||
the grid console page:
|
||||
|
||||
`http://**\<grid-ip-adress\>**:**\<grid-port\>**/grid/console`
|
||||
|
||||
### Example Grid Node Configuration JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities":
|
||||
[
|
||||
{
|
||||
"browserName": "<e.g._iPhone5_or_iPad4>",
|
||||
"version":"<version_of_iOS_e.g._7.1>",
|
||||
"maxInstances": 1,
|
||||
"platform":"<platform_e.g._MAC_or_ANDROID>"
|
||||
}
|
||||
],
|
||||
"configuration":
|
||||
{
|
||||
"cleanUpCycle":2000,
|
||||
"timeout":30000,
|
||||
"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
|
||||
"url":"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub",
|
||||
"host": "<host_name_appium_server_or_ip-address_appium_server>",
|
||||
"port": <appium_port>,
|
||||
"maxSession": 1,
|
||||
"register": true,
|
||||
"registerCycle": 5000,
|
||||
"hubPort": <grid_port>,
|
||||
"hubHost": "<Grid_host_name_or_grid_ip-address>",
|
||||
"hubProtocol": "<Protocol_of_Grid_defaults_to_http>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If `url`, `host`, and `port` are not given, the config will be auto updated to point to
|
||||
`localhost:<appium-port>`.
|
||||
|
||||
If your Appium server is running on a different machine to your Selenium Grid server, make sure you
|
||||
use an external name/IP address in your `host` and `url` configuration; `localhost` and `127.0.0.1`
|
||||
will prevent Selenium Grid from connecting correctly.
|
||||
|
||||
@@ -1,5 +1,86 @@
|
||||
---
|
||||
title: Log Filtering
|
||||
title: Filtering the Appium Log
|
||||
---
|
||||
|
||||
TODO
|
||||
Sometimes it might be necessary to hide sensitive information, like passwords, device identifiers,
|
||||
hashes, etc..., from the server log. Appium makes it possible to ensure such information is
|
||||
redacted in logs via the `--log-filters` command line argument. This argument allows you to provide
|
||||
the path to a special config file, containing one or more log obfuscation rules.
|
||||
|
||||
## Config Format
|
||||
|
||||
The filtering config must be one of:
|
||||
|
||||
- a path to a valid JSON file containing an array of filtering rules
|
||||
- a `log-filters` entry in an [Appium Config](./config.md) file, with the rules array inline
|
||||
|
||||
Each rule is an object with a set of predefined properties. The following rule properties are
|
||||
supported:
|
||||
|
||||
- `pattern`: A valid Javascript RegExp pattern to replace. Must be a valid non-empty pattern.
|
||||
- `text`: A simple non-empty exact text match to replace. Either this property or the above one must
|
||||
be provided. `pattern` has priority over `text` if both are provided.
|
||||
- `flags`: Regular expression flags for the given pattern. Supported flags are the same as for the
|
||||
standard JavaScript [RegExp constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2).
|
||||
Note that the `g` (global matching) flag is always enabled.
|
||||
- `replacer`: The replacer value to use. By default it is `**SECURE**`. Empty values are allowed.
|
||||
|
||||
### Config Examples
|
||||
|
||||
Replace all occurrences of `my.magic.app` string with the default replacer:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"text": "my.magic.app"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Replace all occurrences of `my.magic.<any char>` string with a custom replacer (case insensitive):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"pattern": "my\\.magic\\.\\w",
|
||||
"flags": "i",
|
||||
"replacer": "***"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Replace all occurrences of `my.magic.<any chars>` and/or `your.magic` strings with a custom
|
||||
replacer (case insensitive):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"pattern": "my\\.magic\\.\\w+",
|
||||
"flags": "i",
|
||||
"replacer": "***"
|
||||
},
|
||||
{
|
||||
"pattern": "your\\.magic",
|
||||
"flags": "i",
|
||||
"replacer": "***"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Truncate all log lines to max 15 chars (advanced):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"pattern": "(.{1,15}).*",
|
||||
"flags": "s",
|
||||
"replacer": "$1"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Config Errors Handling
|
||||
|
||||
If any of the config rules contains invalid items (such as empty/invalid pattern, empty rule, etc.)
|
||||
then Appium will print the detailed report about collected errors and will fail to start until
|
||||
these errors are addressed.
|
||||
|
||||