Compare commits

..
Author SHA1 Message Date
Jonathan Lipps 172a739904 1.0.1 2015-12-22 11:42:28 -08:00
Jonathan Lipps a781c8f232 remove unused dependencies 2015-12-22 11:40:11 -08:00
Isaac A. Murchie 72c3d02ae2 Update LICENSE 2015-11-25 08:36:47 -08:00
Scott Dixon 3bef783bc5 Bumping to 1.0.0 2015-10-19 14:35:59 -07:00
Isaac A. Murchie 2b1929768f Merge pull request #7 from scottdixon/1.5-cleanup
1.5 Cleanup
2015-10-19 14:28:29 -07:00
Scott Dixon 861193e39b Updated readme, bumped to 0.0.8 2015-10-14 14:51:52 -07:00
Scott Dixon 4a9b23889a Comments + style 2015-10-14 14:11:13 -07:00
Scott Dixon d30edd49cb Using FS from appium-support 2015-10-14 14:01:10 -07:00
Scott Dixon 3afeb76e88 Style tweaks 2015-10-14 13:32:37 -07:00
Scott Dixon 925d5998ba Moved macOsxVersion() to appium-support 2015-10-14 13:07:32 -07:00
Isaac Murchie 48882df199 0.0.7 2015-09-25 10:19:27 -07:00
sebv d7e0ef76a3 0.0.6 2015-07-20 21:05:22 +02:00
sebv b8e78c8449 test fix 2015-07-20 21:05:11 +02:00
sebv 97ed6be4d9 0.0.5 2015-07-20 20:41:14 +02:00
sebv 3cdfecae7d added osx 10.11 to iOS version check 2015-07-20 20:41:03 +02:00
sebv 43992824a4 integrating with authorize-ios package 2015-07-08 12:06:17 +08:00
sebv db036e9ea8 0.0.4 2015-07-07 19:25:06 +08:00
sebv 51eee6e4f2 integrated with appium-test-support 2015-07-07 19:24:47 +08:00
sebv 7c0b9cf861 0.0.3 2015-07-05 23:53:48 +08:00
sebv 9137040334 README update 2015-07-05 23:53:36 +08:00
sebv 9d4606cb21 README update 2015-07-05 23:43:54 +08:00
sebv 299cc6ce7a 0.0.2 2015-07-05 23:39:47 +08:00
sebv b8af2e11d1 package fix 2015-07-05 23:38:39 +08:00
sebv d6e1abdb2a README update 2015-07-05 23:36:09 +08:00
sebv 486c0e7448 reimplementing doctor
squashing
2015-07-05 23:24:57 +08:00
sebv ccfb631e21 configures travis 2015-06-26 15:50:14 +08:00
sebv 14663fbbd3 cleanup 2015-06-26 15:46:23 +08:00
sebv 1f5c6a7010 first commit 2015-06-24 23:49:49 +08:00
720 changed files with 1756 additions and 115196 deletions
-10
View File
@@ -1,10 +0,0 @@
**/coverage/**
**/node_modules/**
examples/javascript-wd
**/build/**
**/*.min.js
sample-code
**/*.d.ts
**/build-fixtures/**
**/*.ts
packages/appium/docs/**/assets/**
-53
View File
@@ -1,53 +0,0 @@
{
"extends": "@appium/eslint-config-appium",
"overrides": [
{
"files": "packages/fake-driver/**/*",
"rules": {"require-await": "off"}
},
{"files": "packages/support/**/*", "globals": {"BigInt": "readonly"}},
{
"files": "packages/*/test/**/*",
"rules": {"func-names": "off"}
},
{
"files": ["packages/*/index.js", "packages/*/scripts/**/*.js", "test/*.js"],
"parserOptions": {
"sourceType": "script"
}
},
{
"files": [
"packages/appium/support.js",
"packages/appium/driver.js",
"packages/appium/plugin.js"
],
"parserOptions": {
"sourceType": "script"
}
},
{
"files": "./packages/*/test/**/*.js",
"rules": {
"no-restricted-properties": [
"error",
{
"object": "sinon",
"property": "spy",
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.spy()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
},
{
"object": "sinon",
"property": "stub",
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.stub()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
},
{
"object": "sinon",
"property": "mock",
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.mock()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
}
]
}
}
]
}
-60
View File
@@ -1,60 +0,0 @@
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
# Visit https://fossa.com to learn more
version: 3
project:
id: appium
name: appium
paths:
exclude:
- ./sample-code
- '**/fixtures/**'
- '**/demo/**'
- '**/example/**'
- '**/examples/**'
targets:
only:
- type: npm
path: .
- type: npm
path: ./packages/appium
- type: npm
path: ./packages/base-driver
- type: npm
path: ./packages/doctor
- type: npm
path: ./packages/eslint-config-appium
- type: npm
path: ./packages/fake-driver
- type: npm
path: ./packages/gulp-plugins
- type: npm
path: ./packages/support
- type: npm
path: ./packages/test-support
- type: npm
path: ./packages/types
- type: npm
path: ./packages/schema
- type: npm
path: ./packages/universal-xmlplugin
- type: npm
path: ./packages/opencv
- type: npm
path: ./packages/images-plugin
- type: npm
path: ./packages/base-plugin
- type: npm
path: ./packages/relaxed-caps-plugin
- type: npm
path: ./packages/fake-plugin
- type: npm
path: ./packages/docutils
revision:
branch: master
-1
View File
@@ -1 +0,0 @@
* text=auto eol=lf
-33
View File
@@ -1,33 +0,0 @@
## The problem
Briefly describe the issue you are experiencing (or the feature you want to see added to Appium). Tell us what you were trying to do and what happened instead. Remember, this is _not_ a place to ask questions. For that, go to http://discuss.appium.io!
## Environment
* Appium version (or git revision) that exhibits the issue:
* Last Appium version that did not exhibit the issue (if applicable):
* Desktop OS/version used to run Appium:
* Node.js version (unless using Appium.app|exe):
* Npm or Yarn package manager:
* Mobile platform/version under test:
* Real device or emulator/simulator:
* Appium CLI or Appium.app|exe:
## Details
If necessary, describe the problem you have been experiencing in more detail.
## Link to Appium logs
Create a [GIST](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here.
Do _NOT_ paste your full Appium logs here, as it will make this issue very long and hard to read!
If you are reporting a bug, _always_ include Appium logs!
## Code To Reproduce Issue [ Good To Have ]
Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it.
Please git clone https://github.com/appium/appium and from the `examples` directory, use one of your favourite languages and sample apps to reproduce the issue.
In case a similar scenario is missing in examples, please submit a PR with one of the sample apps provided.
-28
View File
@@ -1,28 +0,0 @@
## Proposed changes
Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
## Types of changes
What types of changes does your code introduce to Appium?
_Put an `x` in the boxes that apply_
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation Update (if none of the other choices apply)
## Checklist
_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 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
- [ ] I have added necessary documentation (if appropriate)
- [ ] Any dependent changes have been merged and published in downstream modules
## Further comments
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
-26
View File
@@ -1,26 +0,0 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 365
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: false
# Limit to only `issues` or `pulls`
only: issues
-59
View File
@@ -1,59 +0,0 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Appium Build
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
name: Tests
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install latest npm
run: npm install -g npm
- name: Install dependencies
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
with:
useRollingCache: true
- name: Run smoke, unit & E2E tests
run: npm run test:ci
lint:
name: Lint & Check Types
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
- name: Install dependencies
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
with:
useRollingCache: true
- name: ESLint
run: npm run lint
- name: Check types
run: npm run build:types
docs:
name: Build Command Documentation
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
- name: Install dependencies
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
with:
useRollingCache: true
- name: Generate docs
run: npm run generate-docs
-60
View File
@@ -1,60 +0,0 @@
name: Appium Deploy
on:
push:
tags:
- appium@2*
workflow_dispatch:
permissions:
contents: read
jobs:
check:
name: Check
runs-on: ${{ matrix.os }}
strategy:
matrix:
# node-version: [14.x, 16.x, 18.x]
node-version: [16.x, 18.x]
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
with:
node-version: ${{ matrix.node-version }}
- name: Install Appium
run: |
if [[ "$GITHUB_REF_TYPE" == tag ]]; then
npm i -g $GITHUB_REF_NAME
else
npm i -g appium@next
fi
shell: bash
- name: Install drivers and plugins
run: |
if grep -q macos <<< ${{ matrix.os }}; then
appium driver install xcuitest
fi
appium driver install uiautomator2
appium plugin install images
shell: bash
- name: Verify installation
run: |
installed_drivers=$(appium driver list --installed 2>&1)
if grep -q macos <<< ${{ matrix.os }}; then
grep -q xcuitest <<< $installed_drivers
fi
grep -q uiautomator2 <<< $installed_drivers
installed_plugins=$(appium plugin list --installed 2>&1)
grep -q images <<< $installed_plugins
shell: bash
- name: Verify Appium could be executed
run: |
appium --use-plugins=images &
pid=$(echo $!)
sleep 5
ps -p $pid || exit 1
kill -2 $pid
shell: bash
-25
View File
@@ -1,25 +0,0 @@
name: License Checks
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
permissions:
contents: read
jobs:
fossa-check:
name: Run FOSSA Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
with:
ref: master
- name: Install dependencies
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
- name: Install fossa-cli
run: ./scripts/install-fossa.sh -d
- name: Run FOSSA analysis
fossa analyze
fossa test
env:
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
+3 -60
View File
@@ -1,63 +1,6 @@
.irb-history
*.swp
.DS_Store
node_modules
*.trace
xcuserdata
*.sublime-*
test/functional/_joined
*.iml
!examples/java/*.iml
*.autosave
.idea/
!examples/java/.idea/
build
*.log
*.t
artifacts
input
output
lib/devices/android/bootstrap/bin/*
lib/devices/android/bootstrap/local.properties
lib/devices/android/bootstrap/project.properties
lib/devices/android/bootstrap/.classpath
lib/devices/android/bootstrap/target/
.*~
*~
org.eclipse.ltk.core.refactoring.prefs
.appiumconfig*
build/
.idea
*DerivedData
__pycache__
# csharp
*.pyc
*.pdb
.vs
old
.tern-project
working
.DS_Store
coverage
docs/mkdocs.yml
examples/javascript-wd/node_modules
examples/php/vendor
examples/php/composer.lock
examples/java/out/
examples/ruby/Gemfile.lock
examples/python/test/results/
examples/python/test/input
examples/python/.pytest_cache/
examples/csharp/test/bin
examples/csharp/test/obj
examples/csharp/test/bin
examples/csharp/packages
appium.zip
.vscode/settings.json
.nyc_output
*.lerna_backup
**/build-fixtures/**
*.tsbuildinfo
packages/*/LICENSE
local_appium_home
jsdoc-out
*.tgz
+11
View File
@@ -0,0 +1,11 @@
{
"excludeFiles": ["node_modules/**"],
"requireCurlyBraces": ["for", "while", "do", "try", "catch"],
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch",
"return", "try", "catch", "function"],
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"laxcomma": true,
"undef": true,
"unused": true,
"node": true,
"eqeqeq": true,
"trailing": true,
"indent": 2,
"esnext": true,
"experimental": ["asyncawait"]
}
-10
View File
@@ -1,10 +0,0 @@
// @ts-check
'use strict';
module.exports = {
require: [require.resolve('./test/setup.js')],
// forbids use of .only() in CI
forbidOnly: Boolean(process.env.CI),
color: true,
};
+2
View File
@@ -0,0 +1,2 @@
node_modules
*.log
-4
View File
@@ -1,4 +0,0 @@
# Do not disable package-lock. Disabling package-lock also disables npm-shrinkwrap
package-lock=true
save-exact=true
-12
View File
@@ -1,12 +0,0 @@
**/node_modules/**
**/build/**
**/fixtures/**
**/*.min.*
**/*.md
**/*.yml
**/*.json
**/.vscode/**
**/*.html
**/generated/**
# generated
packages/types/lib/appium-config.ts
+5
View File
@@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.12"
after_success:
- gulp coveralls
-23
View File
@@ -1,23 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"args": ["--colors", "--timeout", "0", "${file}"],
"internalConsoleOptions": "openOnSessionStart",
"name": "Test - Current File",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"runtimeArgs": ["--require", "@babel/register"],
"request": "launch",
"skipFiles": ["<node_internals>/**", "**/node_modules/mocha/**"],
"type": "pwa-node",
"sourceMaps": true,
"cwd": "${workspaceFolder}",
"outfiles": [],
"env": {
"NODE_ENV": "test",
"BABEL_ENV": "test"
},
"autoAttachChildProcesses": true,
}
]
}
-14
View File
@@ -1,14 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "dev",
"group": {"kind": "build", "isDefault": true},
"problemMatcher": ["$tsc-watch"],
"label": "npm: dev",
"detail": "npm run dev",
"isBackground": true
}
]
}
-61
View File
@@ -1,61 +0,0 @@
'use strict';
module.exports = (wallaby) => {
return {
compilers: {
'**/*.js': wallaby.compilers.babel(),
},
debug: true,
env: {
type: 'node',
},
files: [
'./packages/**/*.js',
'./packages/**/*.json',
'!./packages/**/build/**',
'!./packages/**/test/**/*-specs.js',
'!./packages/**/test/**/*.spec.js',
'!./packages/*/node_modules/**',
'!./packages/*/gulpfile.js',
'!./packages/*/scripts/**',
'./packages/*/test/**/fixtures/**/*',
'./babel.config.json',
// below this are fixtures
{
binary: true,
pattern: './packages/support/test/unit/assets/sample_binary.plist',
},
{
instrument: false,
pattern: './packages/support/test/unit/assets/sample_text.plist',
},
{
instrument: false,
pattern: './packages/base-driver/static/**/*',
},
'!**/local_appium_home/**',
],
testFramework: 'mocha',
tests: ['./packages/*/test/unit/**/*.spec.js', '!**/local_appium_home/**'],
workers: {
restart: true,
},
setup() {
// This copied out of `./test/setup.js`, which uses `@babel/register`.
// Wallaby doesn't need `@babel/register` (and it probably makes Wallaby slow),
// but we need the other stuff, so here it is.
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const sinonChai = require('sinon-chai');
// The `chai` global is set if a test needs something special.
// Most tests won't need this.
global.chai = chai.use(chaiAsPromised).use(sinonChai);
// `should()` is only necessary when working with some `null` or `undefined` values.
global.should = chai.should();
},
runMode: 'onsave',
};
};
-21
View File
@@ -1,21 +0,0 @@
Authors ordered by first contribution
Dan Cuellar <dancuellar@me.com>
E. James Infusino <jinfusino@gmail.com>
Jason Huggins <hugs@saucelabs.com>
Jason Carr <jcarr@saucelabs.com>
Jayme Deffenbaugh <jdeffenbaugh@me.com>
Roman Salvador <roman.salvador@gmail.com>
Luke Inman-Semerau <luke.semerau@gmail.com>
Pradeep Bishnoi <pradeepbishnoi@gmail.com>
Charles Nowacek <charlie.nowacek@gmail.com>
Jayakumar Chinnappan <jayakumareee21@gmail.com>
Robin Keller <robinthekeller@gmail.com>
Adam Christian <adam.christian@gmail.com>
Jonathan Lipps <jlipps@gmail.com>
Sebastian Tiedtke <sebastiantiedtke@gmail.com>
Christian Bromann <mail@christian-bromann.com>
Jeremy Avnet <>
Bernard Kobos <bkobos@extensa.pl>
Santiago Suarez Ordoñez <santiycr@gmail.com>
Joe Mathes <>
-3917
View File
File diff suppressed because it is too large Load Diff
-48
View File
@@ -1,48 +0,0 @@
## Code of Conduct
### What is this code of conduct for?
Appium is a piece of technology, but **the core of the Appium community is the people in it**. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, socioeconomic status, religion (or lack thereof), or other marginalized aspect of comunity members. We expect all members of the Appium community to abide by this Code of Conduct whenever interacting in Appium venues (pull requests, GitHub issues, 1-1 or group chat, meetups, conferences, etc...)
### Examples of inappropriate behavior
Because we come from a variety of backgrounds, we don't want to assume that everyone has the same assumptions about what is and isn't appropriate. Here are some examples of inappropriate behavior that are incompatible with our community's ethos:
* Spamming, trolling, intentionally disrupting conversations, or irrelevant solicitation or advertisement
* Making demeaning or discriminatory comments
* Making negative assumptions about someone's background, abilities, or intentions
* Harassing or stalking individuals (online or in person)
* Giving someone unwelcome sexual attention or making unwelcome physical contact (in the case of an IRL event)
* Sharing sexual images or using sexually explicit language
In general: treat others how you would like to be treated, were you in their place. Don't be a jerk. _Do_ ask questions. _Do_ keep conflicts productively focused on technical issues. _Do_ think before you speak; remember that what is perceived as a funny witticism in your group of friends might be hurtful or reinforce hurtful stereotypes in the context of our diverse online community. _Do_ remember that we are all people, not robots, and all equally deserving of sensitivity and respect. (If and when robots join our community, let's treat them with respect too!)
### What will organizers do about inappropriate behavior?
If we notice you doing or saying something inappropriate, an organizer will explain why it's inappropriate and ask you to stop. We won't demonize or vilify you. But please do stop the inappropriate behavior so we can get back to writing and discussing code in a safe environment. If you have philosophical disagreements about what's actually inappropriate, please take them to a separate public or private conversation with an Appium maintainer so we don't turn pull requests into an ethics debate.
If you keep doing unacceptable things, we'll likely ban you, report you to GitHub, or take other appropriate action.
### What if I see or am subject to what feels like inappropriate behavior?
Let us know! Please notify a community organizer as soon as possible. Full contact information is listed in the [Contact Info](#contact-info) section of this document. All communications will be kept strictly confidential, unless otherwise required by law. No issue will be considered too inconsequential or unimportant for us to have a conversation about.
### Contact Info
If you need to report an incident, please contact any of the following organizers directly:
* Isaac Murchie [email](mailto:isaac@saucelabs.com) [twitter](https://twitter.com/imurchie)
* Jonathan Lipps [email](mailto:jlipps@saucelabs.com) [twitter](https://twitter.com/jlipps)
### Credit, License, and Attribution
This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).
It's inspired among other things by:
* [Citizen Code of Conduct](http://citizencodeofconduct.org/)
* [npmjs](https://www.npmjs.com/policies/conduct)
* [Geek Feminism](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy)
* [Ashe Dryden](http://www.ashedryden.com/blog/codes-of-conduct-101-faq)
* [Model View Culture](https://modelviewculture.com/issues/events)
* [Open Source & Feelings](http://osfeels.com/conduct).
-63
View File
@@ -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).
-100
View File
@@ -1,100 +0,0 @@
# Appium Project Governance
The Appium Project wants as much as possible to operate using procedures that
are fair, open, inviting, and ultimately good for the community. For that
reason we find it valuable to codify some of the ways that the Project goes
about its day-to-day business. We want to make sure that no matter who you are,
you have the opportunity to contribute to Appium. We want to make sure that no
one corporation can exert undue influence on the community or hold the Project
hostage. And likewise we want to make sure that corporations which benefit from
Appium are also incentivized to give back.
### The Technical Committee
The project is officially led by a Technical Committee (TC), currently
consisting of:
* [@jlipps](https://github.com/jlipps)
* [@bootstraponline](https://github.com/bootstraponline)
* [@penguinho](https://github.com/penguinho)
* [@dandoveralba](https://github.com/dandoveralba)
* [@mykola-mokhnach](https://github.com/mykola-mokhnach)
* [@imurchie](https://github.com/imurchie)
* [@TikhomirovSergey](https://github.com/TikhomirovSergey)
* [@KazuCocoa](https://github.com/KazuCocoa)
They all represent different companies and different types of contribution to
the Appium Project. The TC is responsible for high-level decisions (like
establishing a feature roadmap, accepting sponsorship, organizing conferences,
etc...), adjudicating conflicts between members of the community, and making
changes to the project's governance processes.
* Membership in the TC is granted by unanimous vote of current TC members.
* TC members can step down at any time.
* No more than 1/3 of TC members may belong to the same company.
* Changes to project governance require unanimous vote of the TC.
### Project Committers
Most of the project maintenance is handled by committers, community members who
have been granted commit access to the Appium organization on GitHub. The
responsibilities of committers include: reviewing and merging pull requests,
walking through changes with developers, weighing in on architectural issues,
and so on.
* Any two TC members can decide to make someone a project committer, providing that person has shown an appropriate understanding of the Appium codebase through prior contributions of code.
* In general any committer can review and merge a PR. In general committers should only merge code they are qualified to review, which might entail pinging another committer who has greater ownership over a specific code area.
* Debates between committers about whether code should be merged should happen in GitHub pull requests.
* Proposals for large changes to the project's code (architectural changes, etc...) should be brought forward as a GitHub issue (with the label `Proposal`), and all committers should be pinged so they can weigh in on the discussion if desired. Substantial changes, whether in proposal stage or in pull request stage should be signed off on by 1 TC member and at least 2 other committers. To assist in the discussion, a small proof of concept can be undertaken on a subset of the Appium ecosystem and raised as a strawman PR, to give flesh to the proposal and make discussion more helpfully concrete.
* In general disputes about code should be resolved by discussion, not votes. If there is substantial disagreement, aim for consensus. If that is not possible, committers can bring the dispute to the TC for a vote, with the outcome determined by a majority.
* Any committer can decide to close a PR or issue if they determine the change doesn't suit the project.
* Appium has a large ecosystem of repositories. Some are 'core' in the sense of being central subpackages with a lot of traffic like `appium/appium` or `appium/appium-ios-driver`. Others are 'peripheral' in the sense of receiving few changes, being maintained by 1 person or no one, etc..., like `appium/ruby_lib` or `appium/appium_thor` For 'core' repos, committers should not merge their own code straightaway. Like all contributors they should open a PR and get a +1 from another committer. For 'peripheral' repos for which they are the sole maintainer or for which they have a good understanding, it is obtuse to insist on another contributor's +1 and this rule should be relaxed in that case. In sum: use good judgment and don't ram code through without a review when you can help it.
The current committers are (in addition to the TC members above):
* [@hugs](https://github.com/hugs)
* [@filmaj](https://github.com/filmaj)
* [@aluedeke](https://github.com/aluedeke)
* [@sebv](https://github.com/sebv)
* [@vgrigoruk](https://github.com/vgrigoruk)
* [@DylanLacey](https://github.com/DylanLacey)
* [@maudineormsby](https://github.com/maudineormsby)
* [@titusfortner](https://github.com/titusfortner)
* [@bayandin](https://github.com/bayandin)
* [@jdeff](https://github.com/jdeff)
* [@moizjv](https://github.com/moizjv)
* [@gempesaw](https://github.com/gempesaw)
* [@Jonahss](https://github.com/Jonahss)
* [@JamieEdge](https://github.com/JamieEdge)
* [@saikrishna321](https://github.com/saikrishna321)
* [@sravanmedarapu](https://github.com/sravanmedarapu)
* [@peepa](https://github.com/peepa)
* [@scottdixon](https://github.com/scottdixon)
* [@drpy](https://github.com/drpy)
* [@Astro03](https://github.com/Astro03)
* [@sbonebrake](https://github.com/sbonebrake)
* [@SrinivasanTarget](https://github.com/SrinivasanTarget)
* [@triager](https://github.com/triager)
* [@ddkjin](https://github.com/ddkjin)
* [@stuartbrussell-intuit](https://github.com/stuartbrussell-intuit)
* [@vmaxim](https://github.com/vmaxim)
### Contributors
Other, less formal, kinds of contribution are outlined in our
[CONTRIBUTING](/CONTRIBUTING.md) doc.
### Sponsorship
The Appium project welcomes sponsorship of various organizations. Specific
details are not yet available but in general we will accept monetary donations,
contribution of code, contribution of dedicated committers, or donations of
other goods or service (internet hosting, etc...). To begin the conversation,
reach out to one of the TC members.
### Raising Issues Related to Governance
This governance model necessarily leaves many situations unspecified. If
questions arise as to how a given situation should proceed according to the
overall goals of the project, the best thing to do is to open a GitHub issue
and ping the TC members.
-16
View File
@@ -1,16 +0,0 @@
Google Summer of Code Ideas
=====
Appium is excited to participate as a [Google Summer of Code](https://summerofcode.withgoogle.com/) sponsor project. Here's a fun list of ideas that a Summer of Code student participant can use as a foundation for thinking about what to contribute to Appium!
|Idea|Description|
|----|-----------|
|Apple tvOS Support|Our users have been asking for an Appium driver for Apple tvOS apps. Is this possible? We're not entirely sure! Why not be awesome and build it?|
|Test App revamp|Appium uses a number of poorly-designed mobile applications in its own testing. We have to use a variety of apps because we need to test that Appium can automate all the various controls and platform features that mobile vendors provide. Really what we need is one cross-platform app (or one app per platform) that exhibit all and only the features we need to test. This would be a fun project to build some mobile apps used for testing and also demoing Appium at events and in training videos, etc...|
|Tooling and Performance|We haven't instrumented Appium with very many performance metrics, and don't really know if we're missing some low-hanging fruit in terms of performance. Maybe you can help us do that?|
|Babel|We have a lot of repos, and they're all on a really old version of Babel. They all need to stay in sync. How can we make this situation better, and upgrade to the latest and greatest?|
|Unity3d Driver|Historically, Appium hasn't been great at automating games. We don't have any particular support for the frameworks used to create games. Unity is a popular one, for example. What if we could write an Appium driver that talked to an embedded process in a test version of a Unity game, that allowed us to find and interact with 3d elements? It would be amazing! You can also be amazing and lead Appium into this new world.|
|Testing the Internet of Things|Appium's architecture makes it dead simple to integrate drivers for automating new technologies. What about _really_ new technologies like IoT devices? Help to redefine the semantics of the WebDriver protocol for use with IoT, and build a driver for an IoT device to prove it out.|
|Driver for X|Have an idea of something else Appium could automate that it doesn't already? Build a driver for it! This would involve some awesome Node.js code, plus whatever else is needed to integrate with the platform you have in mind.|
Hopefully this gives you some ideas of fun projects that would be substantial and long-lasting contributions to the Appium community.
+1 -189
View File
@@ -1,192 +1,4 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright JS Foundation and other contributors, https://js.foundation
Copyright 2012-2015 Sauce Labs, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+32 -252
View File
@@ -1,273 +1,53 @@
## Appium
appium-doctor
===================
Attempts to diagnose and fix common Node, iOS and Android configuration issues before starting Appium.
[![NPM version](https://badge.fury.io/js/appium.svg)](https://npmjs.org/package/appium)
[![Monthly Downloads](https://img.shields.io/npm/dm/appium.svg)](https://npmjs.org/package/appium)
[![Build Status](https://travis-ci.org/appium/appium-doctor.svg?branch=master)](https://travis-ci.org/appium/appium-doctor)
[![Coverage Status](https://coveralls.io/repos/appium/appium-doctor/badge.svg?branch=master&service=github)](https://coveralls.io/github/appium/appium-doctor?branch=master)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
### Install
[![StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://github.com/vshymanskyy/StandWithUkraine/)
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine/)
Appium is an open-source, cross-platform test automation tool for native,
hybrid, mobile web and desktop apps. Initially created to automate iOS and Android mobile
applications Appium has grown to a full-featured platform that provides [WebDriver](https://www.w3.org/TR/webdriver/)-based automation possibilities for the whole set of different mobile and desktop platforms.
See [Drivers Maintained By The Appium Team](#drivers-maintained-by-the-appium-team)
and [Drivers Provided By Third Parties](#drivers-provided-by-third-parties) sections below for more details.
:bangbang: Major documentation revision in progress
:bangbang: Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022. All recent versions of officially supported platform drivers are not compatible to Appium 1.x anymore, and require Appium 2 to run.
Appium is in the final stages of a major revision (to version 2.0). As such, the documentation
found around the web may not be correct. The current Appium 2.0 documentation is very much in
progress. Currently, it can be found [here](https://appium.github.io/appium/docs/en/2.0/).
### Requirements
- macOS, Linux or Windows operating system
- Node.js 14+
- NPM (Node Package Manager) 8+
These are only server requirements. Each driver might have its own requirements. Consider checking the corresponding driver tutorial for more details.
### Server
To install Appium 2 server using Node Package Manager (npm) run the following command:
```bash
npm install -g appium@next
```
npm install appium-doctor -g
```
:bangbang: Running `npm install -g appium` would still install Appium 1 because version 2 is in its late beta stage.
### Usage
### Drivers
```
➜ appium-doctor -h
Appium supports app automation across a variety of platforms, like iOS,
Android, and Windows. Each platform is supported by one or more "drivers",
which know how to automate that particular platform. Since version 2.0
all drivers have been isolated from the Appium server app and can
be managed independently using the [appium driver](https://appiumpro.com/editions/122-installing-appium-20-and-the-driver-and-plugins-cli) command line interface.
Usage: appium-doctor.js [options, defaults: --ios --android]
In general, the drivers management in Appium 2 is as simple as:
```bash
# To install a new driver from npm
appium driver install --source=npm appium-xcuitest-driver[@<version>]
# To install a driver from a local folder (useful for developers)
appium driver install --source=local /Users/me/sources/appium-xcuitest-driver
# To install a new driver from github (hm, maybe it's time to publish it to NPM?)
appium driver install --source=github appium/appium-xcuitest-driver
# To list already installed drivers
appium driver list --installed
# To update a driver (it must be already installed)
appium driver update xcuitest
# To uninstall a driver (it won't last forever, wouldn't it?)
appium driver uninstall xcuitest
Options:
--ios Check iOS setup [boolean]
--android Check Android setup [boolean]
--dev Check dev setup [boolean]
--debug Show debug messages [boolean]
--yes Always respond yes [boolean]
--no Always respond no [boolean]
--demo Run appium-doctor demo (for dev). [boolean]
-h, --help Show help [boolean]
```
#### Drivers Maintained By The Appium Team
## Dev
These drivers are supported by Appium core members. Please report any issues
or suggestions regarding them to the corresponding GitHub issue tracker.
Refer to the corresponding driver Readme to know more on how to use it and its requirements.
## Watch
Name | Description
--- | ---
[appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver) | Allows automation of iOS native and web apps (via hybrid mode). Also supports tvOS. This driver is based on Apple's [XCTest framework](https://developer.apple.com/documentation/xctest) and can only use macOS as the host system.
[appium-uiautomator2-driver](https://github.com/appium/appium-uiautomator2-driver) | Allows automation of Android native and web apps (via hybrid mode). The driver is based on Google's [UiAutomator](https://developer.android.com/training/testing/other-components/ui-automator) framework.
[appium-espresso-driver](https://github.com/appium/appium-espresso-driver) | Allows automation of Android native apps. The driver is based on Google's [Espresso](https://developer.android.com/training/testing/espresso) framework.
[appium-mac2-driver](https://github.com/appium/appium-mac2-driver) | Allows automation of macOS native apps. Also supports tvOS. This driver is based on Apple [XCTest framework](https://developer.apple.com/documentation/xctest) and can only use macOS as the host system.
[appium-windows-driver](https://github.com/appium/appium-windows-driver) | Allows automation of Windows native and UWP apps. This driver is based on Microsoft's [WinAppDriver](https://github.com/microsoft/WinAppDriver) implementation and can only use Windows 10 as the host system.
[appium-gecko-driver](https://github.com/appium/appium-geckodriver) | Allows automation of Gecko-engine-based browsers, like Firefox on mobile and desktop platforms. Uses [geckodriver](https://github.com/mozilla/geckodriver/releases) command line tool provided by Mozilla for various platforms.
[appium-safari-driver](https://github.com/appium/appium-safari-driver) | Allows automation of Safari browser on mobile and desktop platforms . Uses the [safaridriver](https://www.manpagez.com/man/1/safaridriver/) command line tool provided by Apple as part of macOS.
#### Drivers Provided By Third Parties
These drivers are supported by different companies or communities.
Please report any issues related to their functionality to their
respective maintainers. If you are a developer yourself and have created a new useful
Appium2-compatible driver then don't hesitate to create a PR and add a link to
your driver into the below list.
<details>
<summary>Drivers List</summary>
Name | Description
--- | ---
[appium-youiengine-driver](https://github.com/YOU-i-Labs/appium-youiengine-driver) | Appium You.i Engine Driver is a test automation tool for devices of various platforms running applications built with [You.i Engine](http://www.youi.tv/youi-engine/)
[appium-flutter-driver](https://github.com/appium-userland/appium-flutter-driver) | Allows automation of apps built using [Flutter](https://flutter.dev/) framework
[appium-tizen-driver](https://github.com/Samsung/appium-tizen-driver) | Allows automation of apps built for devices running [Tizen OS](https://www.tizen.org/)
[appium-linux-driver](https://github.com/fantonglang/appium-linux-driver) | Allows automation of Linux applications using [AtSpi2](https://www.freedesktop.org/wiki/Accessibility/AT-SPI2/) framework
</details>
### Plugins
The concept of plugins is something new that has been added exclusively to Appium2. Plugins allow you to extend server functionality without changing the server code. Plugins could be managed similarly to drivers:
```bash
# To install an officially supported plugin
appium plugin install images
# To install a plugin from a local folder (useful for developers)
appium plugin install --source=local /Users/me/sources/images
# To install a new plugin from npm
appium plugin install --source=npm appium-device-farm
# To list already installed plugins
appium plugin list --installed
# To update a plugins (it must be already installed)
appium plugin update appium-device-farm
# To uninstall a plugin
appium plugin uninstall appium-device-farm
```
npm run watch
```
The main difference between drivers and plugins is that the latter must be explicitly enabled on server startup after it was installed (drivers are enabled by default after installation):
## Test
```bash
appium server --use-plugins=device-farm,images
```
npm test
```
#### Plugins Maintained By The Appium Team
## Hack Cli
These plugins are supported by Appium core members. Please report any issues
or suggestions regarding them to the corresponding GitHub issue tracker.
Refer to the corresponding plugin Readme to know more on how to use it.
Use the `--demo` option to simulate the fix process.
Name | Description
--- | ---
[images](https://github.com/appium/appium/tree/master/packages/images-plugin) | This is an official Appium plugin designed to facilitate image comparison, visual testing, and image-based functional testing.
[relaxed-caps](https://github.com/appium/appium/tree/master/packages/relaxed-caps-plugin) | With the advent of Appium 2.0, the Appium server begins to require that all capabilities conform to the W3C requirements for capabilities. Among these requirements is one that restricts capabilities to those found in a predetermined set. Appium supports many additional capabilities as extension capabilities, and these must be accessed with the prefix appium: in front of the capability name. There are a lot of test scripts out there that don't conform to the requirement, and so this plugin is designed to make it easy to keep running these scripts even with the new stricter capabilities requirements beginning with Appium 2.0. Basically, it inserts the appium: prefix for you!
[universal-xml](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin) | This is an official Appium plugin designed to make XML source retrieved from iOS and Android use the same node and attribute names, to facilitate cross-platform test writing.
#### Plugins Provided By Third Parties
These plugins are supported by different companies or communities.
Please report any issues related to their functionality to their
respective maintainers. If you are a developer yourself and have created a new useful
plugin then don't hesitate to create a PR and add a link to your plugin into the below list.
<details>
<summary>Plugins List</summary>
Name | Description
--- | ---
[appium-device-farm](https://github.com/AppiumTestDistribution/appium-device-farm) | This is an Appium plugin designed to manage and create driver session on connected android devices and iOS Simulators.
[appium-reporter-plugin](https://github.com/AppiumTestDistribution/appium-reporter-plugin) | This Plugin generates standalone consolidated html report with screenshots. Report can be fetched from appium server, without worrying about heavy lifting such as screenshot capturing, report generation etc.
</details>
### Server Command Line Interface
In order to start sending commands to Appium over the wire it must be listening
on the URL where your client library expects it to listen.
Use the following commands to run and configure Appium server:
```bash
# Start the server on the default port and host (e.g. http://0.0.0.0:4723/)
appium server
# Start the server on the given port, host and use the base path prefix (the default prefix is /)
appium server -p 9000 -a 127.0.0.1 -pa /wd/hub
# Get the list of all supported command line parameters.
# This list would also include descriptions of driver-specific
# command line arguments for all installed drivers.
# Each driver and plugin must have their command line arguments
# exposed in a special JSON schema declared as a part of the corresponding
# package.json file.
appium server --help
```
appium-doctor --demo
```
Appium supports execution of parallel server processes as well as parallel driver sessions within
single server process. Refer the corresponding driver documentations regarding which mode is optimal
for the particular driver or whether it supports parallel sessions.
### Why Appium?
1. You usually don't have to recompile your app or modify it in any way, due
to the use of standard automation APIs on all platforms.
2. You can write tests with your favorite dev tools using any
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html)-compatible
language such as [Java](https://github.com/appium/java-client),
[JavaScript](https://webdriver.io/), [Python](https://github.com/appium/python-client),
[Ruby](https://github.com/appium/ruby_lib), [C#](https://github.com/appium/appium-dotnet-driver)
with the Selenium WebDriver API. There are also various third party
client implementations for other languages.
3. You can use any testing framework.
4. Some drivers, like xcuitest and uiautomator2 ones have built-in mobile web and
hybrid app support. Within the same script, you can switch seamlessly between native
app automation and webview automation, all using the WebDriver model that's already
the standard for web automation.
5. You can run your automated tests locally and in a cloud. There are multiple
cloud providers that support various Appium drivers (mostly
targeting iOS and Android mobile automation).
6. [Appium Inspector](https://github.com/appium/appium-inspector) allows
visual debugging of automated tests and could be extremely useful for
beginners.
Investing in the
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means
you are betting on a single, free, and open protocol for testing that has become
a web standard. Don't lock yourself into a proprietary stack.
For example, if you use Apple's XCUITest library without Appium you can only
write tests using Obj-C/Swift, and you can only run tests through Xcode.
Similarly, with Google's UiAutomator or Espresso, you can only write tests in
Java/Kotlin. Appium opens up the possibility of true cross-platform native app
automation, for mobile and beyond. Finally!
If you're new to Appium or want a more comprehensive description of what this is all
about, please read our [Introduction to Appium Concepts](/docs/en/about-appium/intro.md).
### Get Started
Check out our [Getting Started](http://appium.io/docs/en/about-appium/getting-started) guide
to get going with Appium.
There is also a sample code that contains [many examples of tests in a variety
of different languages](https://github.com/appium/appium/tree/master/sample-code)!
### Documentation
For prettily-rendered docs, please visit [appium.io](http://appium.io). You can
always find the full list of Appium doc pages at [Appium's GitHub
Repo](https://github.com/appium/appium/tree/master/docs/en/) as well.
[update-appium-io.yml](https://github.com/appium/appium/blob/master/ci-jobs/update-appium-io.yml) creates a PR
by [CI job](https://dev.azure.com/AppiumCI/Appium%20CI/_build?definitionId=37).
in the appium.io repository with the documentation update.
Once the PR has been merged, the latest documentation will be in [appium.io](http://appium.io)
### Contributing
Please take a look at our [contribution documentation](CONTRIBUTING.md)
for instructions on how to build, test, and run Appium from the source.
### Roadmap
Interested in where Appium is heading in the future? Check out the [Roadmap](ROADMAP.md)
### Project History, Credits & Inspiration
* [History](http://appium.io/history)
* [Credits](/docs/en/contributing-to-appium/credits.md)
### User Forums
Announcements and debates often take place on the [Discussion Group](https://discuss.appium.io),
be sure to sign up!
### Troubleshooting
We put together a [troubleshooting guide](/docs/en/writing-running-appium/other/troubleshooting.md).
Please have a look here first if you run into any problems. It contains instructions for checking
a lot of common errors and how to get in touch with the community if you're
stumped.
### License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)
BIN
View File
Binary file not shown.
-59
View File
@@ -1,59 +0,0 @@
Appium Roadmap
---------------
This document is designed to be a living record of the current and projected
priorities for the Appium project. It is, of course, always subject to change
and exists solely to give the community an idea of where we're going. The
roadmap is set by the Appium core team. If you have feature suggestions for
Appium, please submit a [GitHub issue](https://github.com/appium/appium/issues)
and, if of sufficient size and approved by the team, it will be added here. If
you have concerns about the roadmap, you can e-mail the Appium devs at
`appium-developers@googlegroups.com` or raise a GitHub issue. Note that
bugfixes and miscellaneous features are not considered "roadmap projects", and
will be addressed in the due course of normal Appium development. This page
exists to outline large-scale future plans for Appium.
## Current Roadmap Projects
| Project | Description | ETD | Projected Appium Release |
|---------|-------------|-----|--------------------------|
|[Appium CI + Metrics Improvements](https://github.com/appium/appium/issues/7168)|We have CI servers running via Cloudbees that we don't understand and which break. Let's document and own them so they work reliably. Also, let's implement gathering various metrics about driver performance so we can track this over time and ensure we're not releasing a driver which has decreased in performance or reliability.|Q2 2017|N/A|
## Upcoming Projects (in rough order of priority)
| Project | Description |
|---------|-------------|
|[Appium Client Library Updates](https://github.com/appium/appium/issues/7170)|It's been too long since we ensured that Appium's client libraries were up to date with the server|
|[Test App Overhaul](https://github.com/appium/appium/issues/7172)|Our current test applications (the ones used to test Appium's iOS and Android support) are not ideal. We use too many of them and the ones we use have a random hodgepodge of app SDK features, sometimes not enough to sufficiently test automation support. It'd be great to find a way to ensure our test app(s) have all the features we need to test, and keep in sync with our requirements.|
|[iOS Test Startup Time Improvement](https://github.com/appium/appium/issues/7173)|iOS startup times have gotten progressively longer with each iOS release. In part this is Apple's fault and there's not anything we can do about it. But we should investigate and see if we can be more efficient in how we start, especially given that we can now focus on XCUITest and leave Instruments behind|
|[Appium Dearchitecture](https://github.com/appium/appium/issues/7174)|OK, we went a bit overboard in Appium 1.5 by exploding Appium into 40+ repos and NPM packages. Let's think a little more critically about it and consolidate into the minimal number of repos/packages that make sense for our code and community patterns.|
|[Appium 2.0](https://github.com/appium/appium/issues/7175)|Appium, rather than bundling all the separate drivers by default, becomes a driver management interface (in addition to continuing to play the role of automation frontend server). Appium gets a set of CLI tools for users to pick and choose which drivers and versions of drivers they want to use via Appium|
## Projects Under Consideration (unplanned and unprioritized)
| Project | Description |
|---------|-------------|
|Windows Phone Support|There has been some work done on automating Windows Phone apps. We could take this all the way to integration with Appium in the form of a WindowsDriver.|
|Apple Watch support|Appium should support Apple Watch apps via the Watch simulator|
|Unity3d backend POC|This is a research project to determine whether we can add some kind of support for 3d game automation, probably based on the Unity3d game development platform.|
## Completed Roadmap Projects
| Project | Description | Completed | Appium Release | Notes |
|---------|-------------|-----------|----------------|-------|
|[Sample Code Overhaul](https://github.com/appium/appium/issues/7171)|Our sample code repo has grown tangled and broken. Let's make a new one with minimal examples which are the same across every language, and actually maintain the repo so as not to let it become overgrown.|
|[Onboarding Overhaul](https://github.com/appium/appium/issues/7169)|Have a new site built with MkDocs that documents all of the Selenium and Appium commands with code samples|1/2018|n/a|appium.io|
|[New Appium GUIs](https://github.com/appium/appium/issues/7167)|The current Appium GUIs (Appium.app and Appium.exe) have a number of issues. They aren't maintained by the core Appium team. They're written in Objective-C and C# respectively: two languages, and specifically, two languages other than Appium's core language. Because of this they lag behind the Appium server and are often broken. However, users love them primarily because of the Inspector feature (the thing that lets them graphically navigate their app), so we have to field a ton of complaints about these projects. There's an opportunity to start over. With [Electron](http://electron.atom.io/), we'd be able to take the new version of Appium we're working on and embed it directly inside a Node-based GUI app written using the languages and technologies the core team is experienced with. We'd have one codebase and could distribute the app on Mac, Windows, and Linux. The GUIs would become an official part of Appium's release cycle so they wouldn't be broken.|3/2017|N/A|[Appium Desktop website](https://github.com/appium/appium-desktop)|
|[Android 7.1.1 Support](https://github.com/appium/appium/issues/7165)|Google has released Android 7.1.1 (API Level 25). Ensure it works with UiAutomator 1/2|2/2017|1.6.4||
|[Android 7.0 Support](https://github.com/appium/appium/issues/7156)|Support Android 7 (Nougat)|11/2016|1.6.3||
|[iOS 10.2 Support](https://github.com/appium/appium/issues/7166)|Support iOS 10.2|11/2016|1.6.1||
|[iOS 10.1 Support](https://github.com/appium/appium/issues/7105)|Support iOS 10.1|11/2016|1.6.1||
|UiAutomator2 integration|Google has released [UiAutomator 2](http://developer.android.com/reference/android/support/test/uiautomator/package-summary.html), and it promises to fix some issues and limitations with the previous UiAutomator support. We will build this inside of Selendroid since it requires an instrumentation context.|10/2016?|1.6.0|
|XCUITest integration / iOS 10 support|Instruments + UIAutomation has been working well for many Appium users, but requires crazy workarounds to deal with bugs which remain unfixed on the Apple side. Also, UIAutomation has been removed in favor of XCUITest for iOS 10+. This new backend would exist alongside the UIAutomation backend.|10/2016|1.6.0||
|iOS 9.3 support|Appium should support iOS 9.3 / Xcode 7.3|3/2016|1.5.1||
|[Architecture Overhaul](https://github.com/appium/appium/issues/5169)|Appium's architecture has grown unwieldy enough that adding new features and preventing regressions has become difficult. A rearchitecture is in order to solve these issues as well as migrate the codebase to a form of JS much easier to work in and understand.|2/2015|1.5.0||
|iOS 9.2 support|Appium should support iOS 9.2 / Xcode 7.2|11/2015|1.4.14||
|iOS 9.1 support|Appium should support iOS 9.1 / Xcode 7.1|10/2015|1.4.12||
|iOS 9.0 support|Appium should support iOS 9.0 / Xcode 7.0|10/2015|1.4.11||
|iOS 8.4 support|Appium should support iOS 8.4 / Xcode 6.2|5/2015|1.4.0||
|Appium CI|Appium has unique needs for Continuous Integration because of the highly specialized environments required (iOS simulators, Xcode, Android emulators, the Android SDK, etc...). We therefore need to create a custom CI solution (perhaps sitting underneath Cloudbees or some other OSS-friendly CI server) that can be used for all Appium projects which need integration tests.|5/2015|_N/A_|Usage instructions at [appium/appium-ci](https://github.com/appium/appium-ci)|
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/env node
require('./build/bin/appium-doctor');
-32
View File
@@ -1,32 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "14"
},
"shippedProposals": true
}
]
],
"plugins": ["source-map-support"],
"comments": false,
"sourceMaps": "both",
"env": {
"coverage": {
"plugins": [
[
"istanbul",
{
"exclude": ["test", "build"]
}
]
]
},
"test": {
"retainLines": true,
"comments": true
}
}
}
@@ -1,10 +1,10 @@
// transpile:main
import yargs from 'yargs';
//import _ from 'lodash';
import newDoctor from '../lib/factory';
import {configureBinaryLog} from '../lib/utils';
import {configure as configurePrompt} from '../lib/prompt';
import {system} from '@appium/support';
import { configureBinaryLog } from '../lib/utils';
import { configure as configurePrompt } from '../lib/prompt';
yargs
.strict()
@@ -25,27 +25,15 @@ yargs
.describe('demo', 'Run appium-doctor demo (for dev).')
.help('h')
.alias('h', 'help')
.check(function (argv) {
if (!argv.ios && !argv.android && !argv.demo) {
argv.ios = system.isMac();
.check(function(argv) {
if(!argv.ios && !argv.android && !argv.demo) {
argv.ios = true;
argv.android = true;
}
return true;
});
// make sure we use the general checks for every test
let opts = Object.assign(
{
general: true,
},
yargs.argv
);
let opts = yargs.argv;
configurePrompt(opts);
configureBinaryLog(opts);
newDoctor(opts)
.run()
.catch(function (e) {
console.error(e); // eslint-disable-line no-console
process.exit(1);
});
newDoctor(opts).run();
-18
View File
@@ -1,18 +0,0 @@
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"composite": true,
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true,
"module": "es2015",
"moduleResolution": "node",
"resolveJsonModule": true,
"strictNullChecks": true,
"removeComments": false,
"target": "es2015",
"types": ["node", "mocha", "chai", "sinon-chai", "chai-as-promised"]
}
}
-17
View File
@@ -1,17 +0,0 @@
{
"compilerOptions": {
"paths": {
"appium": ["../packages/appium"],
"appium/plugin": ["../packages/appium/plugin"],
"@appium/plugin-test-support": ["../packages/plugin-test-support"]
},
"types": ["webdriverio/async"]
},
"extends": "./tsconfig.base.json",
"references": [
{"path": "../packages/appium"},
{"path": "../packages/base-plugin"},
{"path": "../packages/types"},
{"path": "../packages/plugin-test-support"}
]
}
-6
View File
@@ -1,6 +0,0 @@
# Docs moved
The old Appium 1.x docs used to be in this directory. Now, they are available only on the [1.x
branch](https://github.com/appium/appium/tree/1.x/docs).
Appium 2.x docs are located in [packages/appium/docs](../packages/appium/docs) in this repo.
+11
View File
@@ -0,0 +1,11 @@
"use strict";
var gulp = require('gulp'),
boilerplate = require('appium-gulp-plugins').boilerplate.use(gulp),
DEFAULTS = require('appium-gulp-plugins').boilerplate.DEFAULTS;
boilerplate({
build: 'appium-doctor',
files: DEFAULTS.files.concat('bin/**/*.js'),
jscs: false,
});
+4
View File
@@ -0,0 +1,4 @@
import newDoctor from './lib/factory';
import { Doctor, DoctorCheck } from './lib/doctor';
export { newDoctor, Doctor, DoctorCheck };
-27
View File
@@ -1,27 +0,0 @@
{
"command": {
"exec": {
"ignore": ["@appium/eslint-config-appium", "appium"]
},
"run": {
"prefix": false,
"concurrency": 1,
"stream": true
},
"version": {
"conventionalCommits": true,
"createRelease": "github"
},
"add": {
"exact": true
}
},
"ignoreChanges": [
"**/test/**",
"**/*.md"
],
"packages": [
"packages/*"
],
"version": "independent"
}
+63
View File
@@ -0,0 +1,63 @@
import { DoctorCheck } from './doctor';
import { ok, nok } from './utils';
import { fs, system } from 'appium-support';
import path from 'path';
let checks = [];
// Check env variables
class EnvVarAndPathCheck extends DoctorCheck {
constructor (varName) {
super();
this.varName = varName;
}
async diagnose () {
let varValue = process.env[this.varName];
if (typeof varValue === 'undefined') {
return nok(`${this.varName} is NOT set!`);
}
return await fs.exists(varValue) ? ok(`${this.varName} is set to: ${varValue}`) :
nok(`${this.varName} is set to \'${varValue}\' but this is NOT a valid path!`);
}
fix () {
return `Manually configure ${this.varName}.`;
}
}
checks.push(new EnvVarAndPathCheck('ANDROID_HOME'));
checks.push(new EnvVarAndPathCheck('JAVA_HOME'));
// Check tools
class AndroidToolCheck extends DoctorCheck {
constructor (toolName, toolPath) {
super();
this.toolName = toolName;
this.toolPath = toolPath;
}
async diagnose () {
if (typeof process.env.ANDROID_HOME === 'undefined') {
return nok(`${this.toolName} could not be found because ANDROID_HOME is NOT set!`);
}
let fullPath = path.resolve(process.env.ANDROID_HOME, this.toolPath);
return await fs.exists(fullPath) ? ok(`${this.toolName} exists at: ${fullPath}`) :
nok(`${this.toolName} could NOT be found at \'${fullPath}\'!`);
}
fix () {
if (typeof process.env.ANDROID_HOME === 'undefined') {
return 'Manually configure ANDROID_HOME and run appium-doctor again.';
}
return `Manually install ${this.toolName} and add it to PATH.`;
}
}
checks.push(new AndroidToolCheck('adb',
path.join("platform-tools", system.isWindows() ? 'adb.exe' : 'adb')));
checks.push(new AndroidToolCheck('android',
path.join("tools", system.isWindows() ? 'android.bat' : 'android')));
checks.push(new AndroidToolCheck('emulator',
path.join("tools", system.isWindows() ? 'emulator.exe' : 'emulator')));
export { EnvVarAndPathCheck, AndroidToolCheck };
export default checks;
+19 -20
View File
@@ -1,31 +1,31 @@
// demo rule to test the gui
import {ok, nok} from './utils';
import {fs} from '@appium/support';
import {exec} from 'teen_process';
import {DoctorCheck, FixSkippedError} from './doctor';
import { ok, nok } from './utils';
import { fs } from 'appium-support';
import { exec } from 'teen_process';
import { DoctorCheck } from './doctor';
import log from './logger';
import {fixIt} from './prompt';
import { fixIt } from './prompt';
import { FixSkippedError } from './doctor';
let checks = [];
class DirCheck extends DoctorCheck {
constructor(path) {
constructor (path) {
super({autofix: false});
this.path = path;
}
async diagnose() {
if (!(await fs.exists(this.path))) {
return nok(`Could NOT find directory at '${this.path}'!`);
async diagnose () {
if(!await fs.exists(this.path)) {
return nok(`Could NOT find directory at \'${this.path}\'!`);
}
let stats = await fs.lstat(this.path);
return stats.isDirectory()
? ok(`Found directory at: ${this.path}`)
: nok(`'${this.path}' is NOT a directory!`);
return stats.isDirectory() ?
ok(`Found directory at: ${this.path}`) : nok(`\'${this.path}\' is NOT a directory!`);
}
// eslint-disable-next-line require-await
async fix() {
async fix () {
return `Manually create a directory at: ${this.path}`;
}
}
@@ -39,13 +39,12 @@ class FileCheck extends DoctorCheck {
this.path = path;
}
async diagnose() {
return (await fs.exists(this.path))
? ok(`Found file at: ${this.path}`)
: nok(`Could NOT find file at '${this.path}'!`);
async diagnose () {
return await fs.exists(this.path) ?
ok(`Found file at: ${this.path}`) : nok(`Could NOT find file at \'${this.path}\'!`);
}
async fix() {
async fix () {
log.info(`The following command need be executed: touch '${this.path}'`);
let yesno = await fixIt();
if (yesno === 'yes') {
@@ -61,5 +60,5 @@ checks.push(new FileCheck('/tmp/appium-doctor/demo/apple.fruit'));
checks.push(new FileCheck('/tmp/appium-doctor/demo/pear.fruit'));
checks.push(new FileCheck('/tmp/appium-doctor/demo/orange.fruit'));
export {DirCheck, FileCheck};
export { DirCheck, FileCheck };
export default checks;
+70
View File
@@ -0,0 +1,70 @@
import { exec } from 'teen_process';
import { DoctorCheck } from './doctor';
import { ok, nok } from './utils';
import { fs, system } from 'appium-support';
import path from 'path';
import { EOL } from 'os';
let checks = [];
// Check PATH binaries
class BinaryIsInPathCheck extends DoctorCheck {
constructor (binary) {
super();
this.binary = binary;
}
async diagnose () {
let resolvedPath;
try {
let executable = system.isWindows() ? 'where' : 'which';
let {stdout} = await exec(executable, [this.binary]);
if (stdout.match(/not found/gi)) {
throw new Error('Not Found');
}
resolvedPath = system.isWindows() ? stdout.split(EOL)[0] : stdout.replace(EOL, '');
} catch (err) {
return nok(`${this.binary} is MISSING in PATH!`);
}
return await fs.exists(resolvedPath) ? ok(`${this.binary} was found at ${resolvedPath}`) :
nok(`${this.binary} was found in PATH at '${resolvedPath}', but this is NOT a valid path!`);
}
fix() {
return `Manually install the ${this.binary} binary and add it to PATH.`;
}
}
checks.push(new BinaryIsInPathCheck(system.isWindows() ? 'mvn.bat' : 'mvn'));
checks.push(new BinaryIsInPathCheck(system.isWindows() ? 'ant.bat' : 'ant'));
checks.push(new BinaryIsInPathCheck(system.isWindows() ? 'adb.exe' : 'adb'));
// Check Android SDKs
class AndroidSdkExists extends DoctorCheck {
constructor (sdk) {
super();
this.sdk = sdk;
}
async diagnose () {
if (typeof process.env.ANDROID_HOME === 'undefined') {
return nok(`${this.sdk} could not be found because ANDROID_HOME is NOT set!`);
}
let sdkPath = path.resolve(process.env.ANDROID_HOME, path.join("platforms", this.sdk));
return await fs.exists(sdkPath) ? ok(`${this.sdk} was found at: ${sdkPath}`) :
nok(`${this.sdk} could NOT be found at \'${sdkPath}\'!`);
}
fix() {
if (typeof process.env.ANDROID_HOME === "undefined") {
return 'Manually configure ANDROID_HOME.';
}
return `Manually install the ${this.sdk} sdk.`;
}
}
checks.push(new AndroidSdkExists('android-16'));
checks.push(new AndroidSdkExists('android-19'));
export { BinaryIsInPathCheck, AndroidSdkExists };
export default checks;
+150
View File
@@ -0,0 +1,150 @@
import 'colors';
import _ from 'lodash';
import log from './logger';
class FixSkippedError extends Error {
}
class DoctorCheck {
constructor(opts={}) {
this.autofix = !!opts.autofix;
}
diagnose () { throw new Error('Not Implemented!'); }
fix () {
// return string for manual fixes.
throw new Error('Not Implemented!');
}
}
class Doctor {
constructor() {
this.checks = [];
this.toFix = [];
}
register (checks) {
checks = Array.isArray(checks) ? checks : [checks];
this.checks = this.checks.concat(checks);
}
async diagnose() {
log.info('### Diagnostic starting ###');
this.toFix = [];
for (let check of this.checks) {
let res = await check.diagnose();
if (res.ok) {
log.info(` ${'\u2714'.green} ${res.message}`);
} else {
let errorMessage = ` ${'\u2716'.red} ${res.message}`;
log.warn(errorMessage);
this.toFix.push({
error: errorMessage,
check: check
});
}
}
let fixMessage;
switch (this.toFix.length) {
case 0:
fixMessage = 'no fix needed';
break;
case 1:
fixMessage = 'one fix needed';
break;
default:
fixMessage = `${this.toFix.length} fixes needed`;
}
log.info(`### Diagnostic completed, ${fixMessage}. ###`);
log.info('');
}
async reportSuccess () {
if (this.toFix.length === 0) {
log.info('Everything looks good, bye!');
log.info('');
return true;
} else {
return false;
}
}
async reportManualFixes () {
let manualFixes = _.filter(this.toFix, (f) => {return !f.check.autofix;});
if (manualFixes.length >0) {
log.info('### Manual Fixes Needed ###');
log.info('The configuration cannot be automatically fixed, please do the following first:');
// for manual fixes, the fix method always return a string
let fixMessages = [];
for (let f of manualFixes) {
fixMessages.push(await f.check.fix());
}
for (let m of _.uniq(fixMessages)) {
log.warn(`- ${m}`);
}
log.info('###');
log.info('');
log.info('Bye, run appium-doctor again when the all the manual fixes have been applied!');
log.info('');
return true;
} else {
return false;
}
}
async runAutoFix (f) {
log.info(`### Fixing: ${f.error} ###`);
try {
await f.check.fix();
} catch (err) {
if (err instanceof FixSkippedError) {
log.info(`### Skipped fix ###`);
return;
} else {
log.warn(`${err}`.replace(/\n$/g, ''));
log.info(`### Fix did not succeed ###`);
return;
}
}
log.info('Checking if this was fixed:');
let res = await f.check.diagnose();
if (res.ok) {
f.fixed = true;
log.info(` ${'\u2714'.green} ${res.message}`);
log.info(`### Fix was successfully applied ###`);
} else {
log.info(` ${'\u2716'.red} ${res.message}`);
log.info(`### Fix was applied but issue remains ###`);
}
}
async runAutoFixes () {
let autoFixes = _.filter(this.toFix, (f) => {return f.check.autofix;});
for (let f of autoFixes) {
await this.runAutoFix(f);
log.info('');
}
if(_.find(autoFixes, (f) => { return !f.fixed; })) {
// a few issues remain.
log.info('Bye, a few issues remain, fix manually and/or rerun appium-doctor!');
} else {
// nothing left to fix.
log.info('Bye, all issues have been fixed!');
}
log.info('');
}
async run () {
await this.diagnose();
if (await this.reportSuccess()) {
return;
}
if (await this.reportManualFixes()) {
return;
}
await this.runAutoFixes();
}
}
export { Doctor, DoctorCheck, FixSkippedError };
@@ -1,17 +1,16 @@
import _ from 'lodash';
import {Doctor} from './doctor';
import generalChecks from './general';
import { Doctor } from './doctor.js';
import iosChecks from './ios';
import androidChecks from './android';
import devChecks from './dev';
import demoChecks from './demo';
let checks = {generalChecks, iosChecks, androidChecks, devChecks, demoChecks};
let checks = { iosChecks, androidChecks, devChecks, demoChecks };
let newDoctor = (opts) => {
let doctor = new Doctor();
for (let [k, v] of _.toPairs(opts)) {
if (v) {
for (let [k, v] of _.pairs(opts)) {
if(v) {
doctor.register(checks[`${k}Checks`] || []);
}
}
+156
View File
@@ -0,0 +1,156 @@
import { ok, nok, authorize } from './utils';
import { fs, system } from 'appium-support';
import { exec } from 'teen_process';
import { DoctorCheck } from './doctor';
import log from './logger';
import { FixSkippedError } from './doctor';
import NodeDetector from './node-detector';
import { fixIt } from './prompt';
let checks = [];
let fixes = {};
// Check for Xcode.
class XcodeCheck extends DoctorCheck {
async diagnose() {
let xcodePath;
try {
let {stdout} = await exec('xcode-select', ['--print-path']);
xcodePath = stdout.replace("\n", "");
} catch (err) {
return nok('Xcode is NOT installed!');
}
return xcodePath && await fs.exists(xcodePath) ? ok(`Xcode is installed at: ${xcodePath}`) :
nok(`Xcode cannot be found at \'${xcodePath}\'!`);
}
async fix () {
return 'Manually install Xcode.';
}
}
checks.push(new XcodeCheck());
// Check for Xcode Command Line Tools.
class XcodeCmdLineToolsCheck extends DoctorCheck {
constructor() {
super({autofix: true});
}
async diagnose () {
const errMess = 'Xcode Command Line Tools are NOT installed!';
let pkgName = await system.macOsxVersion() === '10.8' ? 'com.apple.pkg.DeveloperToolsCLI' : 'com.apple.pkg.CLTools_Executables';
let stdout;
try {
stdout = (await exec('pkgutil', [`--pkg-info=${pkgName}`])).stdout;
} catch (err) {
log.debug(err);
return nok(errMess);
}
return stdout.match(/install-time/) ? ok('Xcode Command Line Tools are installed.') :
nok(errMess);
}
async fix () {
log.info(`The following command need be executed: xcode-select --install`);
let yesno = await fixIt();
if (yesno === 'yes') {
await exec('xcode-select', ['--install']);
} else {
log.info('Skipping you will need to install Xcode manually.');
throw new FixSkippedError();
}
}
}
checks.push(new XcodeCmdLineToolsCheck());
// Automatically run authorize iOS if requested
fixes.authorizeIosFix = async function () {
log.info(`The authorize iOS script need to be run.`);
let yesno = await fixIt();
if (yesno === 'yes') {
await authorize();
} else {
log.info('Skipping you will need to run the authorize iOS manually.');
throw new FixSkippedError();
}
};
// Dev Tools Security
class DevToolsSecurityCheck extends DoctorCheck {
constructor() {
super({autofix: true});
}
async diagnose () {
const errMess = 'DevToolsSecurity is NOT enabled!';
let stdout;
try {
stdout = (await exec('DevToolsSecurity', [])).stdout;
} catch (err) {
log.debug(err);
return nok(errMess);
}
return stdout && stdout.match(/enabled/) ? ok('DevToolsSecurity is enabled.')
: nok(errMess);
}
async fix () {
return await fixes.authorizeIosFix();
}
}
checks.push(new DevToolsSecurityCheck());
// Authorization DB
class AuthorizationDbCheck extends DoctorCheck {
constructor() {
super({autofix: true});
}
async diagnose () {
const successMess = 'The Authorization DB is set up properly.';
const errMess = 'The Authorization DB is NOT set up properly.';
let stdout;
try {
stdout = (await exec('security', ['authorizationdb', 'read', 'system.privilege.taskport'])).stdout;
} catch (err) {
if (await system.macOsxVersion() === '10.8') {
let data;
try {
data = await fs.readFile('/etc/authorization', 'utf8');
} catch (err) {
log.debug(err);
return nok(errMess);
}
let rg =/<key>system.privilege.taskport<\/key>\s*\n\s*<dict>\n\s*<key>allow-root<\/key>\n\s*(<true\/>)/;
return data && data.match(rg) ? ok(successMess) : nok(errMess);
} else {
log.debug(err);
return nok(errMess);
}
}
return stdout && (stdout.match(/is-developer/) || stdout.match(/allow/)) ?
ok(successMess) : nok(errMess);
}
async fix () {
return await fixes.authorizeIosFix();
}
}
checks.push(new AuthorizationDbCheck());
// Node Binary
class NodeBinaryCheck extends DoctorCheck {
async diagnose () {
let nodePath = await NodeDetector.detect();
return nodePath ? ok(`The Node.js binary was found at: ${nodePath}`) :
nok('The Node.js binary was NOT found!');
}
fix() {
return `Manually setup Node.js.`;
}
}
checks.push(new NodeBinaryCheck());
export { fixes, XcodeCheck, XcodeCmdLineToolsCheck, DevToolsSecurityCheck,
AuthorizationDbCheck, NodeBinaryCheck };
export default checks;
+5
View File
@@ -0,0 +1,5 @@
import { getLogger } from 'appium-logger';
const logger = getLogger('AppiumDoctor');
export default logger;
+98
View File
@@ -0,0 +1,98 @@
import { fs } from 'appium-support';
import { exec } from 'teen_process';
import log from './logger';
import path from 'path';
const NODE_COMMON_PATHS = [
process.env.NODE_BIN,
'/usr/local/bin/node',
'/opt/local/bin/node',
];
// Look for node
class NodeDetector {
static async retrieveInCommonPlaces () {
for (let p of NODE_COMMON_PATHS) {
if (p && await fs.exists(p)) {
log.debug(`Node binary found at common place: ${p}`);
return p;
}
}
log.debug('Node binary wasn\'t found at common places.');
return null;
}
static async retrieveUsingWhichCommand () {
let stdout;
try {
stdout = (await exec('which', ['node'])).stdout;
} catch (ign) {}
let nodePath = stdout.replace("\n", "");
if (await fs.exists(nodePath)) {
log.debug("Node binary found using which command at: " + nodePath);
return nodePath;
} else {
log.debug('Node binary not found using the which command.');
return null;
}
}
static async retrieveUsingAppleScript () {
var appScript = [
'try'
, ' set appiumIsRunning to false'
, ' tell application "System Events"'
, ' set appiumIsRunning to name of every process contains "Appium"'
, ' end tell'
, ' if appiumIsRunning then'
, ' tell application "Appium" to return node path'
, ' end if'
, 'end try'
, 'return "NULL"'
].join("\n");
let stdout;
try {
stdout = (await exec('osascript', ['-e', appScript ])).stdout;
} catch(ign) {}
let nodePath = stdout.replace("\n", "");
if (await fs.exists(nodePath)) {
log.debug(`Node binary found using AppleScript at: ${nodePath}`);
return nodePath;
} else {
log.debug('Node binary not found using AppleScript.');
return null;
}
}
static async retrieveUsingAppiumConfigFile () {
let jsonobj;
try {
var appiumConfigPath = path.resolve(__dirname, '../..', '.appiumconfig.json');
if (await fs.exists(appiumConfigPath)) {
jsonobj = JSON.parse(await fs.readFile(appiumConfigPath, 'utf8'));
}
} catch (ign) {}
if (jsonobj && jsonobj.node_bin && await fs.exists(jsonobj.node_bin) ) {
log.debug(`Node binary found using .appiumconfig.json at: ${jsonobj.node_bin}`);
return jsonobj.node_bin;
} else {
log.debug('Node binary not found in the .appiumconfig.json file.');
return null;
}
}
static async detect () {
let nodePath = await this.retrieveInCommonPlaces() ||
await NodeDetector.retrieveUsingWhichCommand() ||
await NodeDetector.retrieveUsingAppleScript() ||
await NodeDetector.retrieveUsingAppiumConfigFile();
if (nodePath) {
return nodePath;
} else {
log.warn('The node binary could not be found.');
return null;
}
}
}
export default NodeDetector;
@@ -1,4 +1,4 @@
import {inquirer} from './utils';
import { inquirer } from './utils';
let persistentResponse;
@@ -6,26 +6,24 @@ const fixItQuestion = {
type: 'list',
name: 'confirmation',
message: 'Fix it:',
choices: ['yes', 'no', 'always', 'never'],
filter(val) {
return val.toLowerCase();
},
choices: [ 'yes', 'no', 'always', 'never'],
filter: function ( val ) { return val.toLowerCase(); }
};
function configure(opts) {
if (opts.yes) {
function configure (opts) {
if(opts.yes) {
persistentResponse = 'yes';
}
if (opts.no) {
if(opts.no) {
persistentResponse = 'no';
}
}
function clear() {
function clear () {
persistentResponse = undefined;
}
async function fixIt() {
async function fixIt () {
if (persistentResponse) {
return persistentResponse;
}
@@ -35,4 +33,4 @@ async function fixIt() {
return persistentResponse || resp.confirmation;
}
export {configure, fixIt, clear};
export { configure, fixIt, clear };
+27
View File
@@ -0,0 +1,27 @@
import B from 'bluebird';
import path from 'path';
import _inquirer from 'inquirer';
import log from '../lib/logger';
import authorize from 'authorize-ios';
let pkgRoot = process.env.NO_PRECOMPILE ?
path.resolve(__dirname, '..') : path.resolve(__dirname, '..', '..');
let ok = (message) => { return {ok: true, message: message}; };
let nok = (message) => { return {ok: false, message: message}; };
let inquirer = {
prompt: B.promisify(function (question, cb) {
_inquirer.prompt(question, function (resp) { cb(null, resp); });
})
};
function configureBinaryLog (opts) {
log.unwrap().log = function (level) {
let l = this.levels[level];
if (l < this.levels[this.level]) return;
};
log.level = opts.debug ? 'debug' : 'info';
}
export { pkgRoot, ok, nok, inquirer, configureBinaryLog, authorize };
-44832
View File
File diff suppressed because it is too large Load Diff
+38 -160
View File
@@ -1,174 +1,52 @@
{
"name": "appium-monorepo",
"version": "0.0.0",
"private": true,
"description": "Automation for Apps.",
"name": "appium-doctor",
"description": "Description goes here.",
"keywords": [
"automation",
"javascript",
"selenium",
"webdriver",
"ios",
"android",
"firefoxos",
"testing"
"appium"
],
"homepage": "https://appium.io",
"bugs": {
"url": "https://github.com/appium/appium/issues"
},
"version": "1.0.1",
"author": "appium",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/appium/appium.git"
"url": "https://github.com/appium/appium-doctor.git"
},
"license": "Apache-2.0",
"author": "https://github.com/appium",
"scripts": {
"build": "run-s build:distfiles build:types",
"build:distfiles": "lerna run --parallel --prefix --concurrency=8 build",
"build:types": "tsc -b",
"clean": "run-s clean:artifacts clean:packages clean:monorepo",
"clean:artifacts": "run-s clean:distfiles clean:types && npx rimraf \"packages/*/build\"",
"clean:distfiles": "npx rimraf \"packages/*/build/**/*.js\"",
"clean:monorepo": "npx rimraf node_modules",
"clean:packages": "lerna clean -y && npx rimraf \"packages/*/package-lock.json\"",
"clean:types": "tsc -b --clean",
"dev": "run-p dev:*",
"dev:distfiles": "lerna run --parallel --prefix --concurrency=8 dev",
"dev:types": "tsc -b --watch",
"doctor": "node ./packages/doctor",
"generate-docs": "lerna run --scope=appium generate-docs",
"prepare": "npm run build:types || true",
"lint": "eslint .",
"lint:fix": "npm run lint -- --fix",
"precommit-lint": "lint-staged",
"precommit-msg": "echo 'Pre-commit checks...'",
"prepublishOnly": "run-s clean:artifacts build",
"reinstall": "run-p clean:artifacts clean:packages && npm ci",
"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:keywords": "sync-monorepo-packages --field=keywords --packages=\"packages/*\" --packages=\"!packages/eslint-config-appium\" --packages=\"!packages/types\"",
"sync-pkgs:license": "sync-monorepo-packages --force --no-package-json LICENSE",
"test": "run-s build test:unit lint",
"test:ci": "run-s test:smoke test:unit test:ci:e2e",
"test:ci:e2e": "lerna run test:e2e",
"test:e2e": "lerna run --parallel --max-buffer=128 test:e2e",
"test:smoke": "smoker --all test:smoke",
"test:unit": "lerna run test",
"uninstall-fake-driver": "npm start -- driver uninstall fake",
"upload": "gulp github-upload",
"preversion": "run-s clean:artifacts build sync-pkgs && git add -A packages/appium/README.md packages/*/package.json",
"zip": "zip -qr ./appium.zip ./packages/appium",
"zip-and-upload": "run-s zip upload"
"bugs": {
"url": "https://github.com/appium/appium-doctor/issues"
},
"pre-commit": [
"precommit-msg",
"precommit-lint"
"engines": [
"node"
],
"lint-staged": {
"*.js": [
"eslint --fix",
"prettier --write"
],
"*.ts*": [
"prettier --write"
]
"main": "./build/index.js",
"bin": {
"appium-doctor": "./appium-doctor.js"
},
"prettier": {
"bracketSpacing": false,
"printWidth": 100,
"singleQuote": true
"directories": {
"lib": "lib"
},
"dependencies": {
"@appium/base-driver": "file:packages/base-driver",
"@appium/base-plugin": "file:packages/base-plugin",
"@appium/doctor": "file:packages/doctor",
"@appium/docutils": "file:packages/docutils",
"@appium/driver-test-support": "file:packages/driver-test-support",
"@appium/eslint-config-appium": "file:packages/eslint-config-appium",
"@appium/execute-driver-plugin": "file:packages/execute-driver-plugin",
"@appium/fake-driver": "file:packages/fake-driver",
"@appium/fake-plugin": "file:packages/fake-plugin",
"@appium/gulp-plugins": "file:packages/gulp-plugins",
"@appium/images-plugin": "file:packages/images-plugin",
"@appium/opencv": "file:packages/opencv",
"@appium/plugin-test-support": "file:packages/plugin-test-support",
"@appium/relaxed-caps-plugin": "file:packages/relaxed-caps-plugin",
"@appium/schema": "file:packages/schema",
"@appium/support": "file:packages/support",
"@appium/test-support": "file:packages/test-support",
"@appium/types": "file:packages/types",
"@appium/universal-xml-plugin": "file:packages/universal-xml-plugin",
"appium": "file:packages/appium",
"glob": "8.0.3"
"appium-logger": "^2.0.0",
"appium-support": "^2.0.4",
"authorize-ios": "^1.0.3",
"babel-runtime": "=5.8.24",
"bluebird": "^2.10.2",
"colors": "^1.1.2",
"inquirer": "^0.10.1",
"lodash": "^3.10.1",
"source-map-support": "^0.3.2",
"teen_process": "^1.3.1",
"yargs": "^3.27.0"
},
"scripts": {
"prepublish": "./node_modules/.bin/gulp prepublish",
"test": "./node_modules/.bin/gulp once",
"watch": "./node_modules/.bin/gulp"
},
"devDependencies": {
"@appium/fake-plugin": "1.3.1",
"@babel/cli": "7.19.3",
"@babel/core": "7.19.3",
"@babel/preset-env": "7.19.4",
"@babel/register": "7.18.9",
"@colors/colors": "1.5.0",
"@types/chai": "4.3.3",
"@types/chai-as-promised": "7.1.5",
"@types/mocha": "10.0.0",
"@types/node": "16.11.64",
"@types/semver": "7.3.12",
"@types/sinon": "10.0.13",
"@types/sinon-chai": "3.2.8",
"@types/teen_process": "1.16.1",
"@types/ws": "8.5.3",
"asyncbox": "2.9.2",
"babel-plugin-istanbul": "6.1.1",
"babel-plugin-source-map-support": "2.2.0",
"chai": "4.3.6",
"chai-as-promised": "7.1.1",
"chai-webdriverio-async": "2.7.0",
"eslint": "8.25.0",
"eslint-config-prettier": "8.5.0",
"eslint-find-rules": "4.1.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-mocha": "10.1.0",
"eslint-plugin-promise": "6.1.0",
"fancy-log": "2.0.0",
"finalhandler": "1.2.0",
"get-port": "5.1.1",
"gulp": "4.0.2",
"handlebars": "4.7.7",
"json-schema-to-typescript": "10.1.5",
"lerna": "4.0.0",
"lint-staged": "13.0.3",
"log-symbols": "4.1.0",
"midnight-smoker": "1.1.1",
"mjpeg-consumer": "2.0.0",
"mjpeg-server": "0.3.1",
"mocha": "10.0.0",
"npm-run-all": "4.1.5",
"pre-commit": "1.2.2",
"prettier": "2.7.1",
"rewiremock": "3.14.3",
"rimraf": "3.0.2",
"serve-static": "1.15.0",
"sinon": "14.0.1",
"sinon-chai": "3.7.0",
"sync-monorepo-packages": "0.3.5",
"through2": "4.0.2",
"typescript": "4.7.4",
"validate.js": "0.13.1",
"webdriverio": "7.25.1",
"ws": "8.9.0",
"yaml-js": "0.3.1"
},
"engines": {
"node": ">=14",
"npm": ">=8"
},
"publishConfig": {
"access": "public"
},
"workspaces": [
"packages/*"
]
"appium-gulp-plugins": "^1.3.11",
"appium-test-support": "^0.0.5",
"chai": "^3.3.0",
"chai-as-promised": "^5.1.0",
"gulp": "^3.9.0"
}
}
-445
View File
@@ -1,445 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.46](https://github.com/appium/appium/compare/appium@2.0.0-beta.45...appium@2.0.0-beta.46) (2022-10-14)
**Note:** Version bump only for package appium
# [2.0.0-beta.45](https://github.com/appium/appium/compare/appium@2.0.0-beta.44...appium@2.0.0-beta.45) (2022-10-13)
### Features
* **appium,support:** enable detection of local extensions for improved DX ([b186928](https://github.com/appium/appium/commit/b186928e60493e7603dc3b27725dad8ee20d3750))
# [2.0.0-beta.44](https://github.com/appium/appium/compare/appium@2.0.0-beta.43...appium@2.0.0-beta.44) (2022-09-07)
### Bug Fixes
* **appium:** do not throw ENAMETOOLONG on long cli arg ([cfdf898](https://github.com/appium/appium/commit/cfdf898e04e94032e3dd48b595caa4b6f0828289))
* **appium:** eat update info errors ([7d7bb7a](https://github.com/appium/appium/commit/7d7bb7abc3173d29b843b3b238465d9914eaf091)), closes [#17357](https://github.com/appium/appium/issues/17357)
### chore
* **appium:** remove test export ([6820f5e](https://github.com/appium/appium/commit/6820f5ec4e62fbb5e91ce739d8aadb7f7b7a7a74)), closes [#17398](https://github.com/appium/appium/issues/17398)
### Features
* **appium:** Adjust NODE_PATH so NPM could properly resolve component peer dependencies ([#17325](https://github.com/appium/appium/issues/17325)) ([39d5cee](https://github.com/appium/appium/commit/39d5cee1b71f611e810900d3faed8e0fed6e1ce0))
* **support:** Move module root detection utility into support package ([#17427](https://github.com/appium/appium/issues/17427)) ([5ab7829](https://github.com/appium/appium/commit/5ab78297e172bc6a5751c636f81b3b202fbe2743))
### BREAKING CHANGES
* **appium:** This removes the `test` export from `appium`. `import * from 'appium/test'` is no longer supported.
Use `@appium/test-support`, `@appium/driver-test-support` or `@appium/plugin-test-support` instead.
# [2.0.0-beta.43](https://github.com/appium/appium/compare/appium@2.0.0-beta.42...appium@2.0.0-beta.43) (2022-08-10)
### Bug Fixes
* **appium:** fix busted config file normalization algorithm ([dc4835f](https://github.com/appium/appium/commit/dc4835f293f371c36873801a0060bb22eead2cc0))
### Features
* **appium,base-driver,fake-driver,fake-plugin,test-support,types:** updateServer receives cliArgs param ([d4b9833](https://github.com/appium/appium/commit/d4b983328af21d1e5c27a91e438e7934eb152ab1)), closes [#17304](https://github.com/appium/appium/issues/17304)
* **base-driver,fake-driver,appium:** add convenience methods for defining execute script overloads ([#17321](https://github.com/appium/appium/issues/17321)) ([337ec3e](https://github.com/appium/appium/commit/337ec3e7ba216dd6f8cdc88143ecaa4c75f5d266))
# [2.0.0-beta.42](https://github.com/appium/appium/compare/appium@2.0.0-beta.41...appium@2.0.0-beta.42) (2022-08-03)
### Bug Fixes
* **appium,base-driver,base-plugin,doctor,docutils,eslint-config-appium,execute-driver-plugin,fake-driver,fake-plugin,gulp-plugins,images-plugin,opencv,relaxed-caps-plugin,schema,support,test-support,types,universal-xml-plugin:** update engines ([d8d2382](https://github.com/appium/appium/commit/d8d2382327ba7b7db8a4d1cad987c0e60184c92d))
* **appium:** add npm version check ([27ac2fa](https://github.com/appium/appium/commit/27ac2fa125bbfbe2e2ad5a3e7bf31d518510aa2d))
* **appium:** partially revert 2a6a056187ce925d5776b7acc4954b10ecf9221b ([b7e905e](https://github.com/appium/appium/commit/b7e905eaf188f0f23f279620d8ce7dfba60f0b25))
### Features
* **appium:** pass unknown args to extension scripts ([faff3ce](https://github.com/appium/appium/commit/faff3ce3471abaea24d2cb4c3e3b75b1af5ac3a1)), closes [#17250](https://github.com/appium/appium/issues/17250)
# [2.0.0-beta.41](https://github.com/appium/appium/compare/appium@2.0.0-beta.40...appium@2.0.0-beta.41) (2022-07-28)
### Bug Fixes
* **appium,support:** fix installation problems ([2a6a056](https://github.com/appium/appium/commit/2a6a056187ce925d5776b7acc4954b10ecf9221b)), closes [#17073](https://github.com/appium/appium/issues/17073)
* **appium,types:** include @appium/types in appium ([a0a6166](https://github.com/appium/appium/commit/a0a6166738f3db32f2512681914c4c5410cd4b28))
* **appium:** fix incorrect count of errors and warnings ([1e42c23](https://github.com/appium/appium/commit/1e42c2378cb762d5f327139c027e2071918b5c17))
* **appium:** postinstall: never assume local appium if it is being installed globally ([965752f](https://github.com/appium/appium/commit/965752f288ba5d74ab24f41d780c46cc8ff14984)), closes [#17054](https://github.com/appium/appium/issues/17054)
* **appium:** remove references to js in typescript code ([d3f90d5](https://github.com/appium/appium/commit/d3f90d5ed6e887feffcabfc8aabd012e43c37e63))
* moved type packages to deps of specific packages ([f9129df](https://github.com/appium/appium/commit/f9129dfee32fcc3f89ffcfa69fb83b7c2419c24f))
* Update the way build info is fetched from GitHub ([#17078](https://github.com/appium/appium/issues/17078)) ([d2a3adc](https://github.com/appium/appium/commit/d2a3adc2e361d5f0cff11094e8884e3270f5c94c))
### Features
* **appium,base-driver,base-plugin,test-support,types:** move test fixtures into test-support ([70d88cb](https://github.com/appium/appium/commit/70d88cb86f28354efe313cc6be6a0afef20b38b3))
# [2.0.0-beta.40](https://github.com/appium/appium/compare/appium@2.0.0-beta.39...appium@2.0.0-beta.40) (2022-06-04)
**Note:** Version bump only for package appium
# [2.0.0-beta.39](https://github.com/appium/appium/compare/appium@2.0.0-beta.38...appium@2.0.0-beta.39) (2022-06-03)
**Note:** Version bump only for package appium
# [2.0.0-beta.38](https://github.com/appium/appium/compare/appium@2.0.0-beta.37...appium@2.0.0-beta.38) (2022-06-01)
**Note:** Version bump only for package appium
# [2.0.0-beta.37](https://github.com/appium/appium/compare/appium@2.0.0-beta.36...appium@2.0.0-beta.37) (2022-05-31)
**Note:** Version bump only for package appium
# [2.0.0-beta.36](https://github.com/appium/appium/compare/appium@2.0.0-beta.35...appium@2.0.0-beta.36) (2022-05-31)
### Bug Fixes
* **appium:** fix extension autoinstall postinstall script ([3e2c05d](https://github.com/appium/appium/commit/3e2c05d8a290072484afde34fe5fd968618f6359)), closes [#16924](https://github.com/appium/appium/issues/16924)
### Features
* **appium,support:** extension check improvements ([6b224f5](https://github.com/appium/appium/commit/6b224f545f44b8e6ad9d587c7157bc67d7d11439))
* **appium:** appium now expects extensions to use peer dependencies ([48f1d99](https://github.com/appium/appium/commit/48f1d990871dbcd4ab3042c19dc4f43ca89bf80f))
# [2.0.0-beta.35](https://github.com/appium/appium/compare/appium@2.0.0-beta.34...appium@2.0.0-beta.35) (2022-05-03)
**Note:** Version bump only for package appium
# [2.0.0-beta.34](https://github.com/appium/appium/compare/appium@2.0.0-beta.33...appium@2.0.0-beta.34) (2022-05-02)
**Note:** Version bump only for package appium
# [2.0.0-beta.33](https://github.com/appium/appium/compare/appium@2.0.0-beta.32...appium@2.0.0-beta.33) (2022-04-20)
**Note:** Version bump only for package appium
# [2.0.0-beta.32](https://github.com/appium/appium/compare/appium@2.0.0-beta.31...appium@2.0.0-beta.32) (2022-04-20)
**Note:** Version bump only for package appium
# [2.0.0-beta.31](https://github.com/appium/appium/compare/appium@2.0.0-beta.30...appium@2.0.0-beta.31) (2022-04-20)
### Bug Fixes
* **appium,types:** avoid call to assignServer() ([cd08daf](https://github.com/appium/appium/commit/cd08dafabcc16e718a5bdc6b96d5a7bcbfe6e1be))
* **appium:** fix some argument-related types ([37cb3bd](https://github.com/appium/appium/commit/37cb3bd80c76f003940e680b7925b5c3bdc5144c))
* **appium:** make types actually consumable ([8b814c9](https://github.com/appium/appium/commit/8b814c9243a7b51ecd0bc619146063aa5b0ccb76))
# [2.0.0-beta.30](https://github.com/appium/appium/compare/appium@2.0.0-beta.29...appium@2.0.0-beta.30) (2022-04-12)
**Note:** Version bump only for package appium
# [2.0.0-beta.29](https://github.com/appium/appium/compare/appium@2.0.0-beta.28...appium@2.0.0-beta.29) (2022-04-12)
### Bug Fixes
* **appium:** Properly detect if a command is a session command ([#16737](https://github.com/appium/appium/issues/16737)) ([f8a5144](https://github.com/appium/appium/commit/f8a51443e490d9a373778499bfc440e8464ca2ed))
# [2.0.0-beta.28](https://github.com/appium/appium/compare/appium@2.0.0-beta.27...appium@2.0.0-beta.28) (2022-04-07)
### Bug Fixes
* **appium:** allow multiple drivers to be installed ([0bbec13](https://github.com/appium/appium/commit/0bbec13d1e386b2fdf3f9cdcb43da78d6834f28f)), closes [#16674](https://github.com/appium/appium/issues/16674)
### Features
* **appium:** generate declaration files ([#16597](https://github.com/appium/appium/issues/16597)) ([06a6054](https://github.com/appium/appium/commit/06a605420d761a830be267f0f96e12f4caa2c534))
# [2.0.0-beta.27](https://github.com/appium/appium/compare/appium@2.0.0-beta.26...appium@2.0.0-beta.27) (2022-03-23)
### Bug Fixes
* **base-driver:** Use WeakRef to reference the driver instance in the log prefix generator ([#16636](https://github.com/appium/appium/issues/16636)) ([bbfc7ef](https://github.com/appium/appium/commit/bbfc7ef51d8a5c7e99072ee599ce2a6265017ea4))
# [2.0.0-beta.26](https://github.com/appium/appium/compare/appium@2.0.0-beta.25...appium@2.0.0-beta.26) (2022-03-22)
### Bug Fixes
* **appium:** Increase the default limit of process listeners ([#16471](https://github.com/appium/appium/issues/16471)) ([a8315f3](https://github.com/appium/appium/commit/a8315f3f87862b3deeae90b4e21b133e9e3e78d5))
* **appium:** make sure logsink init happens first since it patches npmlog globally (fix [#16519](https://github.com/appium/appium/issues/16519)) ([5abf852](https://github.com/appium/appium/commit/5abf85204614b47d2363097a5356f4bddf697352))
* **appium:** remove bad log ([1dbeee2](https://github.com/appium/appium/commit/1dbeee200677a9c0452bb8c24d78da1e2b5e181c))
### Features
* **appium:** allow installation of extensions via `npm` ([d89fb9b](https://github.com/appium/appium/commit/d89fb9b354b274f2ba410527d25d73af6743d76c))
* **support:** move npm module into support ([2fbd49f](https://github.com/appium/appium/commit/2fbd49fed4cdf10fe1f4b374b5b44ae327ab3f85))
# [2.0.0-beta.25](https://github.com/appium/appium/compare/appium@2.0.0-beta.24...appium@2.0.0-beta.25) (2022-01-21)
### Bug Fixes
* **appium:** make show-config more right ([7470ed0](https://github.com/appium/appium/commit/7470ed00b2a8a8ebc39d62184a6ba5819b22f264)), closes [#16340](https://github.com/appium/appium/issues/16340)
# [2.0.0-beta.24](https://github.com/appium/appium/compare/appium@2.0.0-beta.23...appium@2.0.0-beta.24) (2022-01-11)
### Bug Fixes
* **appium:** correctly apply extension defaults ([20d95e4](https://github.com/appium/appium/commit/20d95e45313fc6aac30a2cf7b8f7bef156a17851))
* **appium:** disallow unsupported schemas ([e074fee](https://github.com/appium/appium/commit/e074fee89f90a654407d01d3f3aea6b839bbf24f))
* **appium:** fix behavior of ReadonlyMap to be compatible with Map ([88e351f](https://github.com/appium/appium/commit/88e351fc2da682bb4c8607259e001ed7e0f5d964))
* **appium:** fix incorrect handling of delete session with regard to plugin driver assignment ([7b3893a](https://github.com/appium/appium/commit/7b3893a36202018de7c2124c2028bfbbd8a9d7fd))
* **appium:** make object dumps less weird ([74a5911](https://github.com/appium/appium/commit/74a5911515f6c50f71fe6f18ddaa4f4fd2ed6d43))
* Switch colors package to a non-compomised repository ([#16317](https://github.com/appium/appium/issues/16317)) ([40a6f05](https://github.com/appium/appium/commit/40a6f054dca3d94fc88773af9c6336ba12ebfb81))
### Features
* **appium:** add --show-config ([#16207](https://github.com/appium/appium/issues/16207)) ([af96879](https://github.com/appium/appium/commit/af96879cfdbbe40773182c29a49fbf2f3cf7e233)), closes [#15672](https://github.com/appium/appium/issues/15672)
# [2.0.0-beta.23](https://github.com/appium/appium/compare/appium@2.0.0-beta.22...appium@2.0.0-beta.23) (2021-11-23)
### Features
* **appium:** make server host/port information available to drivers and thereby plugins ([221a3ec](https://github.com/appium/appium/commit/221a3ecd5211fadcd375fe6d6c9df11f1af201a2))
# [2.0.0-beta.22](https://github.com/appium/appium/compare/appium@2.0.0-beta.21...appium@2.0.0-beta.22) (2021-11-19)
### Bug Fixes
* **appium:** create cjs wrapper ([24596d6](https://github.com/appium/appium/commit/24596d67b04590acb568322098c88efc190f6318))
* **appium:** enable --relaxed-security ([46a2041](https://github.com/appium/appium/commit/46a2041fbdc80b6210d0214a4d9fb71312d57e1b)), closes [/github.com/appium/appium/discussions/16103#discussioncomment-1655985](https://github.com//github.com/appium/appium/discussions/16103/issues/discussioncomment-1655985)
### Features
* **appium:** support for deprecated arguments ([aa69388](https://github.com/appium/appium/commit/aa69388c7a296d4d1e39a1ba0fbe23035a5ae8c5))
# [2.0.0-beta.21](https://github.com/appium/appium/compare/appium@2.0.0-beta.20...appium@2.0.0-beta.21) (2021-11-16)
### Bug Fixes
* **appium:** resolve-from is a dependency ([5443b57](https://github.com/appium/appium/commit/5443b570adf41042c4735410b1425d248adfd0a9))
# [2.0.0-beta.20](https://github.com/appium/appium/compare/appium@2.0.0-beta.19...appium@2.0.0-beta.20) (2021-11-15)
### Bug Fixes
* **appium:** add missing support for schema-as-object ([e951010](https://github.com/appium/appium/commit/e951010055118f6be1614abe40f5701daacb441c))
* **appium:** add types for parsed argument object ([95dfe24](https://github.com/appium/appium/commit/95dfe24176bb7ff6957b7942164280a3a2fbd155))
* **appium:** avoid deprecation warning from argparse ([fc56662](https://github.com/appium/appium/commit/fc566628f599e8a529f30344d291f2351665c5f7))
* **appium:** bad type name ([a7fa66b](https://github.com/appium/appium/commit/a7fa66bb7dfb321cf2bf7c90e5e739841a8753e9))
* **appium:** fix interaction of plugins with proxying ([7091008](https://github.com/appium/appium/commit/70910087d11100fe47627754ade379a2d3a7ff5d))
* **appium:** if a sessionless plugin is used for createSession, promote it to a session plugin ([3f1bb4c](https://github.com/appium/appium/commit/3f1bb4c9c38046699e6d8be3dcd257bc53345eb9))
* **appium:** properly validates config files containing extension config ([b7c230c](https://github.com/appium/appium/commit/b7c230c1e9da9206ea050387bc72c5dda3b31620))
* **appium:** remove extra logging from config-file ([7381a13](https://github.com/appium/appium/commit/7381a13da3e76f7051639d3ab2ba376fbb625e80))
* **appium:** restore missing call to validate extensions ([1a860ca](https://github.com/appium/appium/commit/1a860cade2fd3eac151c81c4efcd11364ee35479))
* **appium:** stop calling plugins 'sessionless' since the name is immutable ([ead3e07](https://github.com/appium/appium/commit/ead3e0723f912a2c7e825d397fe2d4272ce3d6d0))
### Features
* **appium:** allow plugins to react to unexpected session shutdowns ([fff6b2e](https://github.com/appium/appium/commit/fff6b2eb004166fc147251c513086b72be857fbd))
* **appium:** configuration file and schema support ([d52c36e](https://github.com/appium/appium/commit/d52c36e1eaaccc8b47de514bdeeef55ac348ecb8))
# [2.0.0-beta.19](https://github.com/appium/appium/compare/appium@2.0.0-beta.18...appium@2.0.0-beta.19) (2021-11-09)
**Note:** Version bump only for package appium
# [2.0.0-beta.18](https://github.com/appium/appium/compare/appium@2.0.0-beta.17...appium@2.0.0-beta.18) (2021-09-16)
**Note:** Version bump only for package appium
# [2.0.0-beta.17](https://github.com/appium/appium/compare/appium@2.0.0-beta.16...appium@2.0.0-beta.17) (2021-09-16)
**Note:** Version bump only for package appium
# [2.0.0-beta.16](https://github.com/appium/appium/compare/appium@2.0.0-beta.15...appium@2.0.0-beta.16) (2021-09-15)
### Features
* **appium:** add env var to trigger reloading of extensions ([ff3bb4f](https://github.com/appium/appium/commit/ff3bb4f4b538ee5136fdc6356ca00e09fcdc5533))
# [2.0.0-beta.15](https://github.com/appium/appium/compare/appium@2.0.0-beta.14...appium@2.0.0-beta.15) (2021-09-14)
**Note:** Version bump only for package appium
# [2.0.0-beta.14](https://github.com/appium/appium/compare/appium@2.0.0-beta.13...appium@2.0.0-beta.14) (2021-09-14)
### Features
* **appium:** support plugin-specific args via --plugin-args ([c8f12d1](https://github.com/appium/appium/commit/c8f12d1e95b84e225def500a05fddf440df8991a))
# [2.0.0-beta.13](https://github.com/appium/appium/compare/appium@2.0.0-beta.12...appium@2.0.0-beta.13) (2021-08-16)
# 2.0.0-beta (2021-08-13)
### Bug Fixes
* **appium:** load plugins before main server to allow plugin monkeypatching ([#15441](https://github.com/appium/appium/issues/15441)) ([52f4fc6](https://github.com/appium/appium/commit/52f4fc6a2cbdb612888ab2a23a704be32594a006))
* **appium:** update references to @appium/support ([9295d0c](https://github.com/appium/appium/commit/9295d0c68284443ecd73add1f8fe0ff7910a7d7d))
* **appium:** use proper base driver package & random ports ([e14d4fb](https://github.com/appium/appium/commit/e14d4fbd0fce16f208569b0cb9149b6307f78a5f))
* **appium:** when updating extensions, make sure to actually remove the previous one first to avoid npm reinstall issues ([4839419](https://github.com/appium/appium/commit/483941974881bf2ad362c6e6cc35883743abcd2a))
* **appium:** when updating extensions, package fields should also be updated in extensions.yaml ([756688b](https://github.com/appium/appium/commit/756688bddb624a6e9a5b5b6403db76eac65774f3))
* do not assume git root and package.json have the same parent dir ([3c5fba7](https://github.com/appium/appium/commit/3c5fba7b38e02f4216d3a26340948d070f7ea9d9))
* doc generation ([9e33c7a](https://github.com/appium/appium/commit/9e33c7ac1135306c6f0d1ff83b8076aecb54c554))
* e2e-tests ([2499b49](https://github.com/appium/appium/commit/2499b49936660280eefaeb26cb3e4e9f82e36c20))
* use random test port ([935b1f8](https://github.com/appium/appium/commit/935b1f80a47e89ccdf81781f35be5123bf8673d5))
### Features
* add "run" command to the client interface in order to allow running driver-defined scripts ([#15356](https://github.com/appium/appium/issues/15356)) ([a265476](https://github.com/appium/appium/commit/a2654762b6a9156380bcdf53df4cb0a8deb061fa))
* **appium:** Add driver and plugin server arg injection feature ([#15388](https://github.com/appium/appium/issues/15388)) ([d3c11e3](https://github.com/appium/appium/commit/d3c11e364dffff87ac38ac8dc3ad65a1e4534a9a))
-120
View File
@@ -1,120 +0,0 @@
## Appium
[![NPM version](https://badge.fury.io/js/appium.svg)](https://npmjs.org/package/appium)
[![Node.js CI](https://github.com/appium/appium/actions/workflows/node.js.yml/badge.svg?branch=2.0)](https://github.com/appium/appium/actions/workflows/node.js.yml)
[![Monthly Downloads](https://img.shields.io/npm/dm/appium.svg)](https://npmjs.org/package/appium)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
Appium is an open-source, cross-platform test automation tool for native,
hybrid, and mobile web and desktop apps. We support simulators (iOS), emulators
(Android), and real devices (iOS, Android, Windows, Mac).
Want to skip straight to the action? Check out our [getting
started](/docs/en/about-appium/getting-started.md) doc.
### Supported Platforms
Appium supports app automation across a variety of platforms, like iOS,
Android, and Windows. Each platform is supported by one or more "drivers",
which know how to automate that particular platform. Choose a driver below for
specific information about how that driver works and how to set it up:
* iOS
* The [XCUITest Driver](/docs/en/drivers/ios-xcuitest.md)
* (DEPRECATED) The [UIAutomation Driver](/docs/en/drivers/ios-uiautomation.md)
* Android
* The [Espresso Driver](/docs/en/drivers/android-espresso.md)
* The [UiAutomator2 Driver](/docs/en/drivers/android-uiautomator2.md)
* (DEPRECATED) The [UiAutomator Driver](/docs/en/drivers/android-uiautomator.md)
* The [Windows Driver](/docs/en/drivers/windows.md) (for Windows Desktop apps)
* The [Mac Driver](/docs/en/drivers/mac.md) (for Mac Desktop apps)
### Why Appium?
1. You don't have to recompile your app or modify it in any way, due
to the use of standard automation APIs on all platforms.
2. You can write tests with your favorite dev tools using any
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html)-compatible
language such as Java, Objective-C, JavaScript (Node), PHP, Python, Ruby,
C#, Clojure, or Perl with the Selenium WebDriver API and [language-specific
client libraries](/docs/en/about-appium/appium-clients.md).
3. You can use any testing framework.
4. Appium has built-in mobile web and hybrid app support. Within the same
script, you can switch seamlessly between native app automation and webview
automation, all using the WebDriver model that's already the standard for
web automation.
Investing in the
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means
you are betting on a single, free, and open protocol for testing that has become
a web standard. Don't lock yourself into a proprietary stack.
For example, if you use Apple's XCUITest library without Appium you can only
write tests using Obj-C/Swift, and you can only run tests through Xcode.
Similarly, with Google's UiAutomator or Espresso, you can only write tests in
Java/Kotlin. Appium opens up the possibility of true cross-platform native app
automation, for mobile and beyond. Finally!
If you're new to Appium or want a more comprehensive description of what this is all
about, please read our [Introduction to Appium
Concepts](/docs/en/about-appium/intro.md).
### Requirements
Your environment needs to be set up for the particular platforms that you want
to run tests on. Each of the drivers above documents the requirements for their
particular brand of automation. At a minimum, you will need to be able to run
Node.js 10+.
### Get Started
Check out our [Getting Started](/docs/en/about-appium/getting-started.md) guide
to get going with Appium.
There is also a sample code that contains [many examples of tests in a variety
of different languages](https://github.com/appium/appium/tree/master/sample-code)!
### Documentation
For prettily-rendered docs, please visit [appium.io](http://appium.io). You can
always find the full list of Appium doc pages at [Appium's GitHub
Repo](https://github.com/appium/appium/tree/master/docs/en/) as well.
[update-appium-io.yml](https://github.com/appium/appium/blob/master/ci-jobs/update-appium-io.yml) creates a PR
by [CI job](https://dev.azure.com/AppiumCI/Appium%20CI/_build?definitionId=37).
in the appium.io repository with the documentation update.
Once the PR has been merged, the latest documentation will be in [appium.io](http://appium.io)
### Contributing
Please take a look at our [contribution documentation](CONTRIBUTING.md)
for instructions on how to build, test, and run Appium from the source.
### Roadmap
Interested in where Appium is heading in the future? Check out the [Roadmap](ROADMAP.md)
### Project History, Credits & Inspiration
* [History](http://appium.io/history)
* [Credits](/docs/en/contributing-to-appium/credits.md)
### User Forums
Announcements and debates often take place on the [Discussion
Group](https://discuss.appium.io), be sure to sign up!
### Troubleshooting
We put together a [troubleshooting
guide](/docs/en/writing-running-appium/other/troubleshooting.md). Please have a look
here first if you run into any problems. It contains instructions for checking
a lot of common errors and how to get in touch with the community if you're
stumped.
### License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)
-4
View File
@@ -1,4 +0,0 @@
en/assets
ja/assets
zh/assets
site
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

@@ -1,6 +0,0 @@
.md-source__fact--version {
display: none;
}
.md-source__fact:nth-child(1n + 2):before {
margin-left: 0 !important;
}
-32
View File
@@ -1,32 +0,0 @@
INHERIT: ../../docutils/base-mkdocs.yml
site_name: Appium Documentation
repo_url: https://github.com/appium/appium
repo_name: appium/appium
copyright: Copyright &copy; 2012 - 2022 OpenJS Foundation
theme:
logo: assets/images/appium-logo-white.png
favicon: assets/images/appium-logo.png
features:
- navigation.sections
extra_css:
- assets/stylesheets/extra.css
extra:
homepage: /
version:
provider: mike
social:
- icon: fontawesome/brands/twitter
link: https://twitter.com/AppiumDevs
alternate:
- name: English
link: /docs/en/
lang: en
- name: 日本
link: /docs/ja/
lang: ja
- name: 中文简体
link: /docs/zh/
lang: zh
-55
View File
@@ -1,55 +0,0 @@
---
title: Server CLI Args
---
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. (You could run different subcommands, like `appium driver` or `appium
plugin`: see the [Extensions CLI](./extensions.md) for more info).
The invocation of `appium` (or `appium server`) takes 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.
<!-- WARNING: anything between the AUTOGEN-START and AUTOGEN-STOP tags will get replaced by
automatic docs generation tooling! Do not edit by hand! -->
<!-- AUTOGEN-START -->
|Argument&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|Description|Type|Default|Aliases|
|--|--|--|--|--|
|`--address`|IP address to listen on|string|`0.0.0.0`|`-a`|
|`--allow-cors`|Whether the Appium server should allow web browser connections from any host|boolean|`false`||
|`--allow-insecure`|Set which insecure features 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`|
|`--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|||
|`--keep-alive-timeout`|Number of seconds the Appium server should apply as both the keep-alive timeout and the connection timeout for all requests. A value of 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<string>|||
|`--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-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`|Do not check that needed files are readable and/or writable|boolean|`false`||
|`--nodeconfig`|Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself|object|||
|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object|||
|`--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`||
|`--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. Defaults to C:\Windows\Temp on Windows and /tmp otherwise.|string|||
|`--trace-dir`|Absolute path to directory Appium can use to save iOS instrument traces; defaults to <tmp>/appium-instruments|string|||
|`--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`|
<!-- AUTOGEN-STOP -->
-197
View File
@@ -1,197 +0,0 @@
---
title: The Extension CLI
---
Appium allows for the flexible installation and management of _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.
!!! 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.
### `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
### `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
```
### `update`
Update one or more extensions that have been installed via NPM. By default, Appium will not
automatically update any extension that has a revision in its major version, 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 passed 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
### `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
```
-5
View File
@@ -1,5 +0,0 @@
---
title: CLI Intro
---
TODO
@@ -1,451 +0,0 @@
---
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.0 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`.
@@ -1,23 +0,0 @@
---
title: Contributing to Appium
---
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
TODO
## The Appium Development Process
TODO
@@ -1,5 +0,0 @@
---
title: Building Docs for Appium Extensions
---
TODO
@@ -1,748 +0,0 @@
---
title: Building Appium Drivers
---
Appium wants to make it easy for anyone to develop their own automation drivers as part of the
Appium ecosystem. This guide will explain what's involved and how you can accomplish various driver
development tasks using the tools Appium provides. This guide assumes you (1) are a competent user of
Appium, (2) are a competent Node.js developer, and (3) that you have read and understood the
[Driver Intro](../intro/drivers.md).
If that describes you, great! This guide will get you started.
## Before you create your driver
Before you get to work implementing your driver, it's important to have a few things sorted out.
For example, you need to know what your driver will do. Which platform is it trying to expose
WebDriver automation for?
Appium doesn't magically give you the power to automate any platform. All it does is give you a set
of convenient tools for implementing the WebDriver Protocol. So if you want to create, for example,
a driver for a new app platform, you'll need to know how to automate apps on that platform *without Appium*.
This usually means that you need to be very familiar with app development for a given platform. And
it usually means that you will rely on tools or SDKs provided by the platform vendor.
Basically, if you can't answer the question **"how would I launch, remotely trigger behaviours, and
read state from an app on this platform?" then you're not quite ready to write an Appium driver**.
Make sure you do the research to feel comfortable that there *is* a path forward. Once there is,
coding it up and making it available as an Appium driver should be the easy part!
## Other drivers to reference
One of the greatest things about building an Appium driver is that there are already a number of
open source Appium drivers which you can look at for reference. There is
a [fake-driver](https://github.com/appium/appium/tree/2.0/packages/fake-driver) sample driver which
does basically nothing other than showcase some of the things described in this guide.
And of course, all of Appium's official drivers are open source and available in repositories at
the project's GitHub organization. So if you ever find yourself asking, "how does a driver do X?",
read the code for these drivers! Also don't be afraid to ask questions of the Appium developers if
you get stuck; we're always happy to help make sure the driver development experience is a good
one!
## Basic requirements for Appium drivers
These are the things your driver *must* do (or be), if you want it to be a valid Appium driver.
### Node.js package with Appium extension metadata
All Appium drivers are fundamentally Node.js packages, and therefore must have a valid
`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in Node.js so it can be loaded by Appium.
Your `package.json` must include `appium` as a `peerDependency`. The requirements for the
dependency versions should be as loose as possible (unless you happen to know your driver will only
work with certain versions of Appium). For Appium 2.0, for example, this would look something like
`^2.0.0`, declaring that your driver works with any version of Appium that starts with 2.x.
Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension
metadata'):
```json
{
...,
"appium": {
"driverName": "fake",
"automationName": "Fake",
"platformNames": [
"Fake"
],
"mainClass": "FakeDriver"
},
...
}
```
The required subfields are:
* `driverName`: this should be a short name for your driver.
* `automationName`: this should be the string users will use for their `appium:automationName`
capability to tell Appium to use *your* driver.
* `platformNames`: this is an array of one or more platform names considered valid for your driver.
When a user sends in the `platformName` capability to start a session, it must be included in
this list for your driver to handle the session. Known platform name strings include: `iOS`,
`tvOS`, `macOS`, `Windows`, `Android`.
* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
class which extends Appium's `BaseDriver` (see below).
### Extend Appium's `BaseDriver` class
Ultimately, your driver is much easier to write because most of the hard work of implementing the
WebDriver protocol and handling certain common logic is taken care of already by Appium. This is
all encoded up as a class which Appium exports for you to use, called `BaseDriver`. It is exported
from `appium/driver`, so you can use one of these styles to import it and create your *own* class
that extends it:
```js
import {BaseDriver} from 'appium/driver';
// or: const {BaseDriver} = require('appium/driver');
export class MyDriver extends BaseDriver {
}
```
### Make your driver available
That's basically it! With a Node.js package exporting a driver class and with correct Appium
extension metadata, you've got yourself an Appium driver! Now it doesn't *do* anything, but you can
load it up in Appium, start and stop sessions with it, etc...
To make it available to users, you could publish it via NPM. When you do so, your driver will be
installable via the Appium CLI:
```
appium driver install --source=npm <driver-package-on-npm>
```
It's a good idea to test your driver first, of course. One way to see how it works within Appium is
to install it locally first:
```
appium driver install --source=local /path/to/your/driver
```
### Developing your driver
How you develop your driver is up to you. It is convenient, however, to run it from within Appium
without having to do lots of publishing and installing. The most straightforward way to do this is
to include the most recent version of Appium as a `devDependency`, and then also your own driver,
like this:
```json
{
"devDependencies": {
...,
"appium": "^2.0.0",
"your-driver": "file:.",
...
}
}
```
Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your driver is
listed as a dependency alongside it, it will be automatically "installed" and available. You can
design your e2e tests this way, or if you're writing them in Node.js, you can simply import
Appium's start server methods to handle starting and stopping the Appium server in Node. (TODO:
reference an implementation of this in one of the open source drivers when ready).
Another way to do local development with an existing Appium server install is to simply install
your driver locally:
```
appium driver install --source=local /path/to/your/driver/dev/dir
```
## Standard driver implementation ideas
These are things you will probably find yourself wanting to do when creating a driver.
### Set up state in a constructor
If you define your own constructor, you'll need to call `super` to make sure all the standard state
is set up correctly:
```js
constructor(args) {
super(args);
// now do your own thing
}
```
The `args` parameter here is the object containing all the CLI args used to start the Appium
server.
### Define and validate accepted capabilities
You can define your own capabilities and basic validation for them. Users will always be able to
send in capabilities that you don't define, but if they send in capabilities you have explicitly
defined, then Appium will validate that they are of the correct type (and will check for the
presence of required capabilities).
If you want to turn capability validation off entirely, set `this.shouldValidateCaps` to `false` in
your constructor.
To give Appium your validation constraints, set `this.desiredCapConstraints` to a validation object
in your constructor. Validation objects can be somewhat complex. Here's an example from the
UiAutomator2 driver:
```js
{
app: {
presence: true,
isString: true
},
automationName: {
isString: true
},
browserName: {
isString: true
},
launchTimeout: {
isNumber: true
},
}
```
### Start a session and read capabilities
Appium's `BaseDriver` already implements the `createSession` command, so you don't have to. However
it's very common to need to perform your own startup actions (launching an app, running some
platform code, or doing different things based on capabilities you have defined for your driver).
So you'll probably end up overriding `createSession`. You can do so by defining the method in your
driver:
```js
async createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) {
const [sessionId, caps] = super.createSession(w3cCaps);
// do your own stuff here
return [sessionId, caps];
}
```
For legacy reasons, your function will receive old-style JSON Wire Protocol desired and required
caps as the first two arguments. Given that the old protocol isn't supported anymore and clients
have all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion
about what `otherDriverData` is about, see the section below on concurrent drivers).
You'll want to make sure to call `super.createSession` in order to get the session ID as well as
the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`
locally here would have no effect other than changing what the user sees in the create session
response).
So that's it! You can fill out the middle section with whatever startup logic your driver requires.
### End a session
If your driver requires any cleanup or shutdown logic, it's best to do it as part of overriding the
implementation of `deleteSession`:
```js
async deleteSession() {
// do your own cleanup here
// don't forget to call super!
await super.deleteSession();
}
```
It's very important not to throw any errors here if possible so that all parts of session cleanup
can succeed!
### Access capabilities and CLI args
You'll often want to read parameters the user has set for the session, whether as CLI args or as
capabilities. The easiest way to do this is to access `this.opts`, which is a merge of all options,
from the CLI or from capabilities. So for example to access the `appium:app` capability, you could
simply get the value of `this.opts.app`.
If you care about knowing whether something was sent in as a CLI arg *or* a capability, you can
access the `this.cliArgs` and `this.caps` objects explicitly.
In all cases, the `appium:` capability prefix will have been stripped away by the time you are
accessing values here, for convenience.
### Implement WebDriver commands
You handle WebDriver commands by implementing functions in your driver class. Each member of the
WebDriver Protocol, plus the various Appium extensions, has a corresponding function that you
implement if you want to support that command in your driver. The best way to see which commands
Appium supports and which method you need to implement for each command is to look at Appium's
[routes.js](https://github.com/appium/appium/blob/2.0/packages/base-driver/lib/protocol/routes.js).
Each route object in this file tells you the command name as well as the parameters you'd expect to
receive for that command.
Let's take this block for example:
```js
'/session/:sessionId/url': {
GET: {command: 'getUrl'},
POST: {command: 'setUrl', payloadParams: {required: ['url']}},
}
```
Here we see that the route `/session/:sessionId/url` is mapped to two commands, one for a `GET`
request and one for a `POST` request. If we want to allow our driver to change the "url" (or
whatever that might mean for our driver), we can therefore implement the `setUrl` command, knowing
it will take the `url` parameter:
```js
async setUrl(url) {
// your implementation here
}
```
A few notes:
- all command methods should be `async` functions or otherwise return a `Promise`
- you don't need to worry about protocol encoding/decoding. You will get JS objects as params, and
can return JSON-serializable objects in response. Appium will take care of wrapping it up in the
WebDriver protocol response format, turning it into JSON, etc...
- all session-based commands receive the `sessionId` parameter as the last parameter
- all element-based commands receive the `elementId` parameter as the second-to-last parameter
- if your driver doesn't implement a command, users can still try to access the command, and will
get a `501 Not Yet Implemented` response error.
### Implement element finding
Element finding is a special command implementation case. You don't actually want to override
`findElement` or `findElements`, even though those are what are listed in `routes.js`. Appium does
a lot of work for you if instead you implement this function:
```js
async findElOrEls(strategy, selector, mult, context) {
// find your element here
}
```
Here's what gets passed in:
- `strategy` - a string, the locator strategy being used
- `selector` - a string, the selector
- `mult` - boolean, whether the user has requested one element or all elements matching the
selector
- `context` - (optional) if defined, will be a W3C Element (i.e., a JS object with the W3C element
identifier as the key and the element ID as the value)
And you need to return one of the following:
- a single W3C element (an object as described above)
- an array of W3C elements
Note that you can import that W3C web element identifier from `appium/support`:
```js
import {util} from 'appium/support';
const { W3C_WEB_ELEMENT_IDENTIFIER } = util;
```
What you do with elements is up to you! Usually you end up keeping a cache map of IDs to actual
element "objects" or whatever the equivalent is for your platform.
### Define valid locator strategies
Your driver might only support a subset of the standard WebDriver locator strategies, or it might
add its own custom locator strategies. To tell Appium which strategies are considered valid for
your driver, create an array of strategies and assign it to `this.locatorStrategies`:
```js
this.locatorStrategies = ['xpath', 'custom-strategy'];
```
Appium will throw an error if the user attempts to use any strategies other than the allowed ones,
which enables you to keep your element finding code clean and deal with only the strategies you
know about.
By default, the list of valid strategies is empty, so if your driver isn't simply proxying to
another WebDriver endpoint, you'll need to define some. The protocol-standard locator strategies
are defined [here](https://www.w3.org/TR/webdriver/#locator-strategies).
### Throw WebDriver-specific errors
The WebDriver spec defines a [set of error
codes](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`:
```
import {errors} from 'appium/driver';
throw new errors.NoSuchElementError();
```
### Log messages to the Appium log
You can always use `console.log`, of course, but Appium provides a nice logger for you as
`this.log` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log
levels). If you want to create an Appium logger outside of a driver context (say in a script or
helper file), you can always construct your own too:
```js
import {logging} from 'appium/support';
const log = logging.getLogger('MyDriver');
```
## Further possibilities for Appium drivers
These are things your driver *can* do to take advantage of extra driver features or do its job more
conveniently.
### Add a schema for custom command line arguments
You can add custom CLI args if you want your driver to receive data from the command line when the
Appium server is started (for example, ports that a server administrator should set that should not
be passed in as capabilities.
To define CLI arguments (or configuration properties) for the Appium server, your extension must provide a _schema_. In
the `appium` property of your extension's `package.json`, add a `schema` property. This will either
a) be a schema itself, or b) be a path to a schema file.
The rules for these schemas:
- Schemas must conform to [JSON Schema Draft-07](https://ajv.js.org/json-schema.html#draft-07).
- If the `schema` property is a path to a schema file, the file must be in JSON or JS (CommonJS) format.
- Custom `$id` values are unsupported. To use `$ref`, provide a value relative to the schema root, e.g., `/properties/foo`.
- Known values of the `format` keyword are likely supported, but various other keywords may be unsupported. If you find a keyword that is unsupported which you need to use, please [ask for support](https://github.com/appium/appium/issues/new) or send a PR!
- The schema must be of type `object` (`{"type": "object"}`), containing the arguments in a `properties` keyword. Nested properties are unsupported.
Example:
```json
{
"type": "object",
"properties": {
"test-web-server-port": {
"type": "integer",
"minimum": 1,
"maximum": 65535,
"description": "The port to use for the test web server"
},
"test-web-server-host": {
"type": "string",
"description": "The host to use for the test web server",
"default": "sillyhost"
}
}
}
```
The above schema defines two properties which can be set via CLI argument or configuration file. If
this extension is a _driver_ and its name is "horace", the CLI args would be
`--driver-horace-test-web-server-port` and `--driver-horace-test-web-server-host`, respectively.
Alternatively, a user could provide a configuration file containing:
```json
{
"server": {
"driver": {
"horace": {
"test-web-server-port": 1234,
"test-web-server-host": "localhorse"
}
}
}
}
```
### Add driver scripts
Sometimes you might want users of your driver to be able to run scripts outside the context of
a session (for example, to run a script that pre-builds aspects of your driver). To support this,
you can add a map of script names and JS files to the `scripts` field within your Appium extension
metadata. So let's say you've created a script in your project that lives in a `scripts` directory
in your project, named `driver-prebuild.js`. Then you could add a `scripts` field like this:
```json
{
"scripts": {
"prebuild": "./scripts/driver-prebuild.js"
}
}
```
Now, assuming your driver is named `mydriver`, users of your driver can run `appium driver run
mydriver prebuild`, and your script will execute.
### Proxy commands to another WebDriver implementation
A very common design architecture for Appium drivers is to have some kind of platform-specific
WebDriver implementation that the Appium driver interfaces with. For example, the Appium
UiAutomator2 driver interfaces with a special (Java-based) server running on the Android device. In
webview mode, it also interfaces with Chromedriver.
If you find yourself in this situation, it is extremely easy to tell Appium that your driver is
just going to be proxying WebDriver commands straight to another endpoint.
First, let Appium know that your driver *can* proxy by implementing the `canProxy` method:
```js
canProxy() {
return true;
}
```
Next, tell Appium which WebDriver routes it should *not* attempt to proxy (there often end up being
certain routes that you don't want to forward on):
```js
getProxyAvoidList() {
return [
['POST', new RegExp('^/session/[^/]+/appium')]
];
}
```
The proxy avoidance list should be an array of arrays, where each inner array has an HTTP method as
its first member, and a regular expression as its second. If the regular expression matches the
route, then the route will not be proxied and instead will be handled by your driver. In this
example, we are avoiding proxying all `POST` routes that have the `appium` prefix.
Next, we have to set up the proxying itself. The way to do this is to use a special class from
Appium called `JWProxy`. (The name means "JSON Wire Proxy" and is related to a legacy
implementation of the protocol). You'll want to create a `JWProxy` object using the details required to
connect to the remote server:
```js
// import {JWProxy} from 'appium/driver';
const proxy = new JWProxy({
server: 'remote.server',
port: 1234,
base: '/',
});
this.proxyReqRes = proxy.proxyReqRes.bind(proxy);
this.proxyCommand = proxy.command.bind(proxy);
```
Here we are creating a proxy object and assigning some of its methods to `this` under the names
`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget
this step! The `JWProxy` has a variety of other options which you can check out in the source code,
as well. (TODO: publish options as API docs and link here).
Finally, we need a way to tell Appium when the proxy is active. For your driver it might always
be active, or it might only be active when in a certain context. You can define the logic as an
implementation of `proxyActive`:
```js
proxyActive() {
return true; // or use custom logic
}
```
With those pieces in play, you won't have to reimplement anything that's already implemented by the
remote endpoint you're proxying to. Appium will take care of all the proxying for you.
### Extend the existing protocol with new commands
You may find that the existing commands don't cut it for your driver. If you want to expose
behaviours that don't map to any of the existing commands, you can create new commands in one of
two ways:
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
1. Overloading the Execute Script command by defining "Execute Methods"
If you want to follow the first path, you can direct Appium to recognize new methods and add them
to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`
static variable in your driver class to an object of the same form as Appium's `routes.js` object.
For example, here is the `newMethodMap` for the `FakeDriver` example driver:
```js
static newMethodMap = {
'/session/:sessionId/fakedriver': {
GET: {command: 'getFakeThing'},
POST: {command: 'setFakeThing', payloadParams: {required: ['thing']}},
},
'/session/:sessionId/fakedriverargs': {
GET: {command: 'getFakeDriverArgs'},
},
};
```
In this example we're adding a few new routes and a total of 3 new commands. For more examples of
how to define commands in this way, it's best to have a look through `routes.js`. Now all you need
to do is implement the command handlers in the same way you'd implement any other Appium command.
The downside of this way of adding new commands is that people using the standard Appium clients
won't have nice client-side functions designed to target these endpoints. So you would need to
create and release client-side plugins for each language you want to support (directions or
examples can be found at the relevant client docs).
An alternative to this way of doing things is to overload a command which all WebDriver clients
have access to already: Execute Script. Appium provides some a convenient tool for making this
easy. Let's say you are building a driver for stereo system called `soundz`, and you wanted to
create a command for playing a song by name. You could expose this to your users in such a way that
they call something like:
```js
// webdriverio example. Calling webdriverio's `executeScript` command is what trigger's Appium's
// Execute Script command handler
driver.executeScript('soundz: playSong', [{song: 'Stairway to Heaven', artist: 'Led Zeppelin'}]);
```
Then in your driver code you can define the static property `executeMethodMap` as a mapping of
script names to methods on your driver. It has the same basic form as `newMethodMap`, described
above. Once `executeMethodMap` is defined, you'll also need to implement the Execute Script command
handler, which according to Appium's routes mapping is called `execute`. The implementation can
call a single helper function, `this.executeMethod`, which takes care of looking at the script and
arguments the user sent in and routing it to the correct custom handler you've defined. Here's an
example:
```js
static executeMethodMap = {
'soundz: playSong', {
command: 'soundzPlaySong',
params: {required: ['song', 'artist'], optional: []},
}
}
async soundzPlaySong(song, artist) {
// play the song based on song and artist details
}
async execute(script, args) {
return await this.executeMethod(script, args);
}
```
A couple notes about this system:
1. The arguments array sent via the call to Execute Script must contain only zero or one element(s). The
first item in the list is considered to be the parameters object for your method. These parameters
will be parsed, validated, and then applied to your overload method in the order specified in
`executeMethodMap` (the order specified in the `required` parameters list, followed by the
`optional` parameters list). I.e., this framework assumes only a single actual argument sent in via
Execute Script (and this argument should be an object with keys/values representing the
parameters your execute method expects).
1. Appium does not automatically implement `execute` (the Execute Script handler) for you. You may
wish, for example, to only call the `executeMethod` helper function when you're not in proxy
mode!
1. The `executeMethod` helper will reject with an error if a script name doesn't match one of the
script names defined as a command in `executeMethodMap`, or if there are missing parameters.
### Implement handling of Appium settings
Appium users can send parameters to your driver via CLI args as well as via capabilities. But these
cannot change during the course of a test, and sometimes users want to adjust parameters mid-test.
Appium has a [Settings](../guides/settings.md) API for this purpose.
To support settings in your own driver, first of all define `this.settings` to be an instance of
the appropriate class, in your constructor:
```js
// import {DeviceSettings} from 'appium/driver';
this.settings = new DeviceSettings();
```
Now, you can read user settings any time simply by calling `this.settings.getSettings()`. This will
return a JS object where the settings names are keys and have their corresponding values.
If you want to assign some default settings, or run some code on your end whenever settings are
updated, you can do both of these things as well.
```js
constructor() {
const defaults = {setting1: 'value1'};
this.settings = new DeviceSettings(defaults, this.onSettingsUpdate.bind(this));
}
async onSettingsUpdate(key, value) {
// do anything you want here with key and value
}
```
### Make itself aware of resources other concurrent drivers are using
Let's say your driver uses up some system resources, like ports. There are a few ways to make sure
that multiple simultaneous sessions don't use the same resources:
1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc)
1. Just always use free resources (find a new random port for each session)
1. Have each driver express what resources it is using, then examine currently-used resources from
other drivers when a new session begins.
To support this third strategy, you can implement `get driverData` in your driver to return what
sorts of resources your driver is currently using, for example:
```js
get driverData() {
return {specialPort: 1234, specialFile: /path/to/file}
}
```
Now, when a new session is started on your driver, the `driverData` response from any other
simultaneously running drivers (of the same type) will also be included, as the last parameter of
the `createSession` method:
```js
async createSession(jwpCaps, reqCaps, w3cCaps, driverData)
```
You can dig into this `driverData` array to see what resources other drivers are using to help
determine which ones you want to use for this particular session.
!!! warning
Be careful here, since `driverData` is only passed between sessions of a single running Appium
server. There's nothing to stop a user from running multiple Appium servers and requesting your
driver simultaneously on each of them. In this case, you won't be able to ensure independence
of resources via `driverData`, so you might consider using file-based locking mechanisms or
something similar.
!!! warning
It's also important to note you will only receive `driverData` for other instances of *your*
driver. So unrelated drivers also running may still be using some system resources. In general
Appium doesn't provide any features for ensuring unrelated drivers don't interfere with one
another, so it's up to the drivers to allow users to specify resource locations or addresses to
avoid clashes.
### Log events to the Appium event timeline
Appium has an [Event Timing API](../guides/event-timing.md) which allows users to get timestamps
for certain server-side events (like commands, startup milestones, etc...) and display them on
a timeline. The feature basically exists to allow introspection of timing for internal events to
help with debugging or running analysis on Appium driver internals. You can add your own events to
the event log:
```js
this.logEvent(name);
```
Simply provide a name for the event and it will be added at the current time, and made accessible
as part of the event log for users.
### Hide behaviour behind security flags
Appium has a feature-flag based [security model](../guides/security.md) that allows driver authors
to hide certain features behind security flags. What this means is that if you have a feature you
deem insecure and want to require server admins to opt in to it, you can require that they enable
the feature by adding it to the `--allow-insecure` list or turning off server security entirely.
To support the check within your own driver, you can call `this.isFeatureEnabled(featureName)` to
determine whether a feature of the given name has been enabled. Or, if you want to simply
short-circuit and throw an error if the feature isn't enabled, you can call
`this.assertFeatureEnabled(featureName)`.
### Use a temp dir for files
If you want to use a temporary directory for files your driver creates that are not important to
keep around between computer or server restarts, you can simply read from `this.opts.tmpDir`. This
reads the temporary directory location from `@appium/support`, potentially overridden by a CLI
flag. I.e., it's safer than writing to your own temporary directory because the location here plays
nicely with possible user configuration. `this.opts.tmpDir` is a string, the path to the dir.
### Deal with unexpected shutdowns or crashes
Your driver might run into a situation where it can't continue operating normally. For example, it
might detect that some external service has crashed and nothing will work anymore. In this case, it
can call `this.startUnexpectedShutdown(err)` with an error object including any details, and Appium
will attempt to gracefully handle any remaining requests before shutting down the session.
If you want to perform some of your own cleanup logic when you encounter this condition, you can
either do so immediately before calling `this.startUnexpectedShutdown`, or you can attach a handler
to the unexpected shutdown event and run your cleanup logic "out of band" so to speak:
```js
this.onUnexpectedShutdown(handler)
```
`handler` should be a function which receives an error object (representing the reason for the
unexpected shutdown).
@@ -1,5 +0,0 @@
---
title: Building Appium Plugins
---
TODO
@@ -1,60 +0,0 @@
---
title: The Appium Ecosystem
---
Appium has an ecosystem of related software and tools. In this guide we'll discuss important
officially-supported and community-supported projects.
## Appium Inspector
Appium has a graphical client which can be used to manually perform Appium commands, inspect app
hierarchies, view screenshots, and more. It's very useful for Appium test development. You can
learn more about the inspector here: [Appium Inspector](https://github.com/appium/appium-inspector)
## Drivers
You can't use Appium without at least one driver! Here are the drivers that are officially
recognized by Appium. Click on the link for each driver to see the specific installation
instructions and documentation for that driver.
To learn more about what drivers are and how they work, check out the [Driver
Intro](../intro/drivers.md)
|Driver|Installation Key|Platform(s)|Mode(s)|Support|
|-|-|-|-|-|
|[XCUITest](https://github.com/appium/appium-xcuitest-driver)|`xcuitest`|iOS|Native, Hybrid, Web|Appium Team|
|[UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)|`uiautomator2`|Android|Native, Hybrid, Web|Appium Team|
|[Espresso](https://github.com/appium/appium-espresso-driver)|`espresso`|Android|Native|Appium Team|
|[Mac2](https://github.com/appium/appium-mac2-driver)|`mac2`|macOS|Native|Appium Team|
|[Safari](https://github.com/appium/appium-safari-driver)|`safari`|macOS, iOS|Web|Appium Team|
|[Gecko](https://github.com/appium/appium-geckodriver)|`safari`|macOS, Windows, Linux, Android|Web|Appium Team|
|[Windows](https://github.com/appium/appium-windows-driver)|`windows`|Windows|Native|Community / Microsoft|
|[Flutter](https://github.com/appium-userland/appium-flutter-driver)|`flutter`|iOS, Android|Native|Community|
|[Tizen](https://github.com/Samsung/appium-tizen-driver)|`tizen`|Android|Native|Community / Samsung|
|[Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver)|`youiengine`|iOS, Android, macOS, Linux, tvOS|Native|Community / You.i|
And of course, you can install any other drivers you find out there by using the Appium driver CLI.
## Clients
You need a clients to write and run Appium scripts. To learn more about clients, read our [Client
Intro](../intro/clients.md). Here is the list of known Appium clients. You'll want to become very
familiar with your client documentation (as well as the documentation of any Selenium client that
the Appium client depends on) since that is what you will use as your primary interface to Appium.
|Client|Language|Support|
|-|-|-|
|[Appium Java client](https://github.com/appium/java-client)|Java|Appium Team|
|[Appium Python client](https://github.com/appium/python-client)|Python|Appium Team|
|[Appium Ruby client](https://github.com/appium/ruby_lib)|Ruby|Appium Team|
|[WebDriverIO](https://webdriver.io)|Node.js|Community|
|[Appium .NET client](https://github.com/appium/appium-dotnet-driver)|C#|Appium Team*|
|[RobotFramework](https://github.com/serhatbolsu/robotframework-appiumlibrary)|DSL|Community|
!!! warning
Currently, the .NET client has a low level of maintenance/support. Expect bugs and
incompatibility. We're looking for help here, so please reach out if you know .NET!
In general, any W3C WebDriver spec-compatible client will also integrate well with Appium, though
some Appium-specific commands may not be implemented in other clients.
-139
View File
@@ -1,139 +0,0 @@
---
title: Capabilities
---
TODO
## Special Notes for Cloud Providers
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 makes the following recommendations in terms of the *capabilities* service
providers support, for consistency across the industry._ This is a recommendation only, and not
a standard, but adopting it will help users to navigate the increased complexity that working with
Appium 2.0 in a cloud environment may bring.
### Suggested capabilities
In addition to the standard `platformName`, `appium:deviceName`, `appium:automationName`, and
`appium:platformVersion`, we recommend adopting the capability `$cloud:appiumOptions`, where the
label `$cloud` is not meant to be interpreted literally but instead should be replaced by your
vendor prefix (so for HeadSpin it would be `headspin`, Sauce Labs it would be `sauce`, and
BrowserStack it would be `browserstack`, to name just a few examples). The `$cloud:appiumOptions`
capability would itself be a JSON object, with the following internal keys:
| Capability | Used for | Example |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `version` | Designating which version of the Appium server is used to host and manage drivers. If ommitted, behavior left up to the provider, but the recommendation would be to provide the latest official version. | `2.0.0` |
| `automationVersion` | Designating which version of the specified driver should be used. | `1.55.2` |
| `automation` | Designating 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` | Designating the list of plugins (and potentially versions of plugins) to 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": {
"appiumVersion": "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": {
"appiumVersion": "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.0 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. 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 Appium itself would provide to the end user if they were running
Appium on their own.
-95
View File
@@ -1,95 +0,0 @@
---
title: The Appium Config File
---
Instead of passing arguments on the command line to Appium, you may add them to a special config
file. Appium will read values from this config file when it runs. (Please note that CLI arguments
have _precedence_ over configuration files; if a value is set in a config file _and_ via CLI
argument, the CLI argument is preferred.)
## Supported Config File Formats
You can store your config data in the following kinds of files:
- JSON
- YAML
- JS (a JavaScript file exporting a JS object)
- CJS (the same as above; the extension is for common JS)
!!! warning
Note: Configuration files in ESM format are not currently supported.
## Supported Config File Locations
Configuration files can be named anything, but the following filenames will be automatically
discovered and loaded by Appium:
- `.appiumrc.json` (recommended)
- `.appiumrc.yaml`
- `.appiumrc.yml`
- `.appiumrc.js`
- `.appiumrc.cjs`
- `appium.config.js`
- `appium.config.cjs`
- `.appiumrc` (which is considered to be JSON)
Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium` property in your `package.json` and it will be automatically discovered.
### Config File Search
Appium will search _up_ the directory tree from the current working directory for one of these
files. If it reaches the current user's home directory or filesystem root, it will stop looking.
To specify a _custom_ location for your config file, use `appium --config-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 +0,0 @@
---
title: The Context API
---
TODO
@@ -1,71 +0,0 @@
---
title: The Event Timing API
---
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.
@@ -1,5 +0,0 @@
---
title: Execute Script Overloads
---
TODO
-5
View File
@@ -1,5 +0,0 @@
---
title: Appium and Selenium Grid
---
TODO
@@ -1,5 +0,0 @@
---
title: Log Filtering
---
TODO
@@ -1,5 +0,0 @@
---
title: Managing Appium Drivers and Plugins
---
TODO
@@ -1,217 +0,0 @@
---
title: Migrating from Appium 1.x to Appium 2.x
---
This document is a guide for those who are using Appium 1.x and wish to migrate to Appium 2.x. It contains a list of breaking changes and how to migrate your environments or test suites to ensure compatibility with Appium 2.0.
## Overview of Appium 2.0
Appium 2.0 is the most major new release of Appium in over 5 years. The changes in Appium 2.0 are _not_ primarily related to changes in automation behaviors for specific platforms. Instead, Appium 2.0 reenvisions Appium as a _platform_ where "drivers" (code projects that introduce support for automation of a given platform) and "plugins" (code projects that allow for overriding, altering, extending, or adding behaviors to Appium) can be easily created and shared.
At the same time, the Appium project is taking the opportunity to remove many old and deprecated bits of functionality.
Together these do introduce a few breaking changes to how Appium is installed, how drivers and various features are managed, and protocol support. These are detailed below.
## Breaking Changes
Have a look at the [Appium 2.0 release notes](https://github.com/appium/appium/releases) for the most comprehensive lists of changes. Here we call out the breaking changes and what you need to do do account for them.
### :bangbang: Installing drivers during setup
When you installed Appium 1.x, all available drivers would be installed at the same time as the main Appium server. This is no longer the case. Simply installing Appium 2.0 (e.g., by `npm install -g appium@next`), will install the Appium server only, but no drivers. To install drivers, you must instead use the new [Appium extension CLI](../cli/extensions.md). For example, to install the latest versions of the XCUITest and UiAutomator2 drivers, after installing Appium you would run the following commands:
```
appium driver install xcuitest
appium driver install uiautomator2
```
At this point, your drivers are installed and ready. There's a lot more you can do with this CLI so be sure to check out the docs on it.
If you're running in a CI environment or want to install Appium along with some drivers all in one step, you can do so using some special flags during install, for example:
```
npm install --global appium --drivers=xcuitest,uiautomator2
```
This will install Appium and the two drivers for you in one go.
### :bangbang: Chromedriver installation flags
In Appium 1.x it was possible to customize the way Chromedriver was installed (as part of the UiAutomator2 driver for example), using the following command line flags:
* `--chromedriver-skip-install`
* `--chromedriver-version`
* `--chromedriver-cdnurl`
Because Appium 2.0 now installs drivers for you, and because these flags were implemented as NPM config flags, they will no longer work. Instead, use the following environment variables during driver installation:
* `APPIUM_SKIP_CHROMEDRIVER_INSTALL`
* `CHROMEDRIVER_VERSION`
* `CHROMEDRIVER_CDNURL`
For example:
```
APPIUM_SKIP_CHROMEDRIVER_INSTALL=1 appium driver install uiautomator2
```
### :bangbang: Driver-specific command line options
With Appium 1.x, command-line options specific to particular drivers were all hosted on the main Appium server. So, for example, `--chromedriver-executable` was a CLI parameter you could use with Appium to set the location of a specific Chromedriver version for use with, say, the UiAutomator2 driver.
With Appium 2.x, all driver- and platform-specific CLI params have been moved to the drivers themselves. To access them, you'll now need to prepend the argument with the extension type (either `driver` or `plugin`) and the name of the extension. For example, `--chromedriver-executable` becomes `--driver-uiautomator2-chromedriver-executable`.
### :bangbang: Driver-specific automation commands
The definition of certain commands that pertain only to specific drivers has been moved to those
drivers' implementations. For example, `pressKeyCode` is specific to the UiAutomator2 driver and is
now understood only by that driver. In practice, the only breaking change here is the kind of error
you would encounter if the appropriate driver is not installed. Previously, you would get a `501
Not Yet Implemented` error if using a driver that didn't implement the command. Now, you will get
a `404 Not Found` error because if a driver that doesn't know about the command is not active, the
main Appium server will not define the route corresponding to the command.
### :bangbang: Driver updates
In the past, to get updates to your iOS or Android drivers, you'd simply wait for those updates to be rolled into a new release of Appium, and then update your Appium version. With Appium 2.x, the Appium server and the Appium drivers are versioned and released separately. This means that drivers can be on their own release cadence and that you can get driver updates as they happen, rather than waiting for a new Appium server release. The way to check for driver updates is with the CLI:
```bash
appium driver list --updates
```
If any updates are available, you can then run the `update` command for any given driver:
```bash
appium driver update xcuitest
```
(For a complete description of the update command, check out the [Extension
CLI](../cli/extensions.md) doc)
To update the Appium server itself, you do the same thing as in the past: `npm install -g appium`. Now, installing new versions of the Appium server will leave your drivers intact, so the whole process will be much more quick.
### :bangbang: Protocol changes
Appium's API is based on the [W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/), and it has supported this protocol for years. Before the W3C WebDriver Protocol was designed as a web standard, several other protocols were used for both Selenium and Appium. These protocols were the "JSONWP" (JSON Wire Protocol) and "MJSONWP" (Mobile JSON Wire Protocol). The W3C Protocol differs from the (M)JSONWP protocols in a few small ways.
Up until Appium 2.0, Appium supported both protocols, so that older Selenium/Appium clients could still communicate with newer Appium servers. Moving forward, support for older protocols will be removed.
### :bangbang: _Capabilities_
One significant difference between old and new protocols is in the format of capabilities. Previously called "desired capabilities", and now called simply "capabilities", there is now a requirement for a so-called "vendor prefix" on any non-standard capabilities. The list of standard capabilities is given in the [WebDriver Protocol spec](https://www.w3.org/TR/webdriver/#capabilities), and includes a few commonly used capabilities such as `browserName` and `platformName`.
These standard capabilities continue to be used as-is. All other capabilities must include a "vendor prefix" in their name. A vendor prefix is a string followed by a colon, such as `appium:`. Most of Appium's capabilities go beyond the standard W3C capabilities and must therefore include vendor prefixes (we recommend that you use `appium:` unless directed otherwise by documentation). For example:
- `appium:app`
- `appium:noReset`
- `appium:deviceName`
This requirement may or may not be a breaking change for your test suites when targeting Appium 2.0. If you're using an updated Appium client, the client will add the `appium:` prefix for you on all necessary capabilities. New versions of the Appium Inspector tool will also do this. Cloud-based Appium providers may also do this. So simply be aware that if you get any messages to the effect that your capabilities lack a vendor prefix, this is how you solve that problem.
On a related note, it will no longer be possible to start Appium sessions using WebDriver clients that don't support the W3C protocol (see below for a comment to this effect for the WD library).
To make everyone's lives a bit easier, we've also introduced the option of wrapping up all Appium-related capabilities into one object capability, `appium:options`. You can bundle together anything that you would normally put an `appium:` prefix on into this one capability. Here's an example (in raw JSON) of how you might start an iOS session on the Safari browser using `appium:options`:
```json
{
"platformName": "iOS",
"browserName": "Safari",
"appium:options": {
"platformVersion": "14.4",
"deviceName": "iPhone 11",
"automationName": "XCUITest"
}
}
```
(Of course, each client will have a different way of creating structured capabilities like `appium:options` or other ones that you might have seen such as `goog:chromeOptions`). NB: capabilities that show up in `appium:options` will overwrite capabilities of the same name that show up at the top level of the object.
For more information on capabilities, have a look at the [Capabilities Guide](caps.md).
### :bangbang: _Removed Commands_
In addition to commands which have been moved to driver implementations, commands which were a part of the old JSON Wire Protocol and not a part of the W3C Protocol are no longer available:
- TODO (these commands are being identified and removed and will be updated here when complete)
If you use a modern Appium or Selenium client, you should no longer have access to these anyway, so any breaking changes should appear on the client side first and foremost.
### :bangbang: Image analysis features moved to plugin
One of the design goals for Appium 2.0 is to migrate non-core features into special extensions called [plugins](../ecosystem/index.md). This allows people to opt into features which require extra time to download or extra system setup. The various image-related features of Appium (image comparison, finding elements by image, etc...) have been moved into an officially supported plugin called [images](https://github.com/appium/appium/tree/master/packages/images-plugin).
If you use these image-related methods, to continue accessing them you will need to do two things.
1. Install the plugin: `appium plugin install images`
2. Ensure you start the Appium server with access to run the plugin by including it in the list of plugins designated on the command line, e.g., `appium --use-plugins=images`
Image-related commands will also be removed on the client side of things, which means you will need to follow the instructions on the plugin README for installing client-side plugins to access these features.
### :bangbang: Execute Driver Script command moved to plugin
If you use the advanced Execute Driver Script feature (which allows you to send in a WebdriverIO script to have it executed completely on the server instead of command-by-command from the client), this functionality has been moved to a plugin. Here's what to do to keep using it:
1. Install the plugin: `appium plugin install execute-driver`
2. Ensure you start the Appium server with access to run the plugin by including it in the list of plugins designated on the command line, e.g., `appium --use-plugins=execute-driver`
### :bangbang: External Files No Longer Supported for `--nodeconfig`, `--default-capabilities`, `--allow-insecure` and `--deny-insecure`
These options can be provided as strings on the command line (a JSON string for `--nodeconfig` and a comma-separated list of strings for `--allow-insecure` and `--deny-insecure`). Arguments provided on the command line will likely need to be quoted or escaped.
The recommended method to provide these options is now via a [configuration file](#tada-configuration-files).
In summary, if you are using a JSON Appium config file, you can simply cut-and-paste the contents of your "nodeconfig" JSON file into the value of the `server.nodeconfig` property. Any CSV-like files you had previously provided for `--allow-insecure` and `--deny-insecure` become the values of the `server.allow-insecure` and `server.deny-insecure` properties in the Appium config files (respectively); both are arrays of strings.
### :bangbang: Old drivers removed
The old iOS and Android (UiAutomator 1) drivers and related tools (e.g., `authorize-ios`) have been removed. They haven't been relevant for many years anyway.
### :warning: Internal packages renamed
Some Appium-internal NPM packages have been renamed (for example, `appium-base-driver` is now `@appium/base-driver`). This is not a breaking change for Appium users, only for people who have built software that directly incorporates Appium's code.
### :warning: "WD" JavaScript client library no longer supported
For many years, some of Appium's authors maintained the [WD](https://github.com/admc/wd) client library. This library has been deprecated and has not been updated for use with the W3C WebDriver protocol. As such, if you're using this library you'll need to move to a more modern one. We recommend [WebdriverIO](https://webdriver.io).
### :warning: Appium Inspector split out from Appium Desktop
The inspecting portion of Appium Desktop has been moved to its own app, Appium Inspector: [github.com/appium/appium-inspector](https://github.com/appium/appium-inspector). It's fully compatible with Appium 2.0 servers. Simply download it and run it on its own. You no longer need the GUI Appium Desktop server to inspect apps. The Appium Desktop server will continue to be supported at its original site: [github.com/appium/appium-desktop](https://github.com/appium/appium-desktop). It will simply no longer bundle the Inspector with it.
You can also now use the Appium Inspector without downloading anything, by visiting the [web version of Appium Inspector](https://inspector.appiumpro.com). Note that to test against local servers, you'll need to start the server with `--allow-cors` so that the browser-based version of Appium Inspector can access your Appium server to start sessions.
## Major New Features
Apart from the breaking changes mentioned above, in this section is a list of some of the major new features you may wish to take advantage of with Appium 2.0.
### Plugins
#### :tada: _Server Plugins_
Appium extension authors can now develop their own server plugins, which can intercept and modify
any Appium command, or even adjust the way the underlying Appium HTTP server itself works. To learn
more about plugins, read the new [Appium Introduction](../intro/index.md). Interested in building
a plugin? Check out the [Building Plugins](../ecosystem/build-plugins.md) guide.
#### :tada: _Client Plugins_
TODO
### :tada: Install drivers and plugins from anywhere
You're no longer limited to the drivers that come with Appium, or that the Appium team even knows
about! Appium extension authors can now develop custom drivers, which can be downloaded or
installed via Appium's [Extension CLI](../cli/extensions.md) from NPM, Git, GitHub, or even the
local filesystem. Interested in building a driver? Check out the [Building
Drivers](../ecosystem/build-drivers.md) guide.
### :tada: Configuration Files
Appium now supports _configuration files_ in addition to command-line arguments. In a nutshell, nearly all arguments which Appium 1.x required to be provided on the CLI are now able to be expressed via a configuration file. Configuration files may be in JSON, JS, or YAML format. See the [Config Guide](config.md) for a full explanation.
## Special Notes for Cloud Providers
The rest of this document has applied to Appium generally, but some of the architectural changes in Appium 2.0 will constitute breaking changes for Appium-related service providers, whether a cloud-based Appium host or an internal service. At the end of the day, the maintainer of the Appium server is responsible for installing and making available the various Appium drivers and plugins that end users may wish to use.
We encourage cloud providers to thoroughly read and understand our [recommendation for cloud
provider capabilities](caps.md#special-notes-for-cloud-providers) in order to support user needs in
an industry-compatible way!
@@ -1,5 +0,0 @@
---
title: Appium Server Security
---
TODO
@@ -1,5 +0,0 @@
---
title: The Settings API
---
TODO
-61
View File
@@ -1,61 +0,0 @@
---
title: Appium Documentation
---
# Appium Documentation
<div style="text-align: center">
<img src="assets/images/appium-logo-horiz.png" style="max-width: 400px;" />
</div>
Welcome to the Appium documentation! Appium is an open-source project and ecosystem of related
software, designed to facilitate UI automation of many app platforms, including mobile (iOS,
Android, Tizen), browser (Chrome, Firefox, Safari), desktop (macOS, Windows), TV (Roku, tvOS,
Android TV, Samsung), and more.
If you're new to Appium, it's recommended that you start off with the [Introduction](intro/), then
move on to the [Quickstart](quickstart/). And you can always find Appium's code on GitHub at
[appium/appium](https://github.com/appium/appium).
## What is Appium for?
Appium is used mostly in the field of software test automation, to help determine whether the
functionality of a given app is working as expected. In contrast to other types of software
testing, UI automation allows testers to write code that walks through user scenarios in the actual
UI of an application, mimicking as closely as possible what happens in the real world while
enabling the various benefits of automation, including speed, scale, and consistency.
Appium aims to provide a set of tools that support this kind of automation in a standard way across
any number of platforms. Most platforms come with tools that allow UI automation at some level, but
these are usually platform-specific and require specialized knowledge and specific programming
language experience and toolchains. Appium tries to unify all these automation technology under
a single stable interface, accessible via most popular programming languages (you can write Appium
scripts in Java, Python, Ruby, JS, and more).
To learn more about how Appium accomplishes this goal, and the various components involved, have
a read through our [Introduction](intro/).
## Learning Appium
This documentation is a great way to learn more about Appium:
- Check out the [Introduction](intro/) first to make sure you understand all the concepts involved in Appium.
- Go through the [Quickstart](quickstart/) to get set up and run a basic Android test.
- Have a look at the various guides and references.
- Using Appium for a real project means using an Appium driver for a specific platform, so you'll want to have a look at the [Ecosystem](ecosystem/) page where we keep links to the drivers and plugins you might want to use; you can refer to those projects for specific information about using Appium for a given platform.
You can also check out a list of third-party [Resources](resources.md) to explore Appium around the
web.
## 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. To
learn more about contributing, check out our GitHub repo at
[appium/appium](https://github.com/appium/appium) and read through our
[Contributing](contributing/) guides.
-124
View File
@@ -1,124 +0,0 @@
---
title: Intro to Appium Clients
---
For all the reasons discussed in the [main intro](./index.md), Appium is based on the [W3C
WebDriver specification](https://w3c.github.io/webdriver/webdriver-spec.html). This means that
Appium implements a client-server architecture. The server (consisting of Appium itself along with
any drivers or plugins you are using for automation) is connected to the devices under test, and
is actually responsible for making automation happen on those devices. The client (driven by *you*,
the Appium test author) is responsible for sending commands to the server over the network, and
receiving responses from the server as a result. These responses can be used to tell whether
automation commands are successful, or might contain information that you queried about the state
of the application. This document is a conceptual introduction to the client side of this equation.
!!! info
For more about the server side of the equation (i.e., how does Appium actually control
devices?), check out our [Intro to Appium Drivers](./drivers.md). To skip to a list of links to
Appium client libraries, check out the [Ecosystem](../ecosystem/index.md) documentation.
What sorts of automation commands are available? That is up to the particular driver and plugins
that you are using in any given session. A standard set of commands would include, for example, the
following:
- Find Element
- Click Element
- Get Page Source
- Take Screenshot
If you look at these commands in the WebDriver specification, you'll notice that they are not
defined in terms of any particular programming language. They are not Java commands, or JavaScript
commands, or Python commands. Instead, they form part of an HTTP API which can be accessed from
within *any* programming language (or none! you could just use cURL if you want).
So, for example, the `Find Element` command corresponds to an HTTP `POST` request sent to the HTTP
endpoint `/session/:sessionid/element` (where in this case, `:sessionid` is a placeholder for the
unique session ID generated by the server in a previous call to `Create Session`).
This information is primarily useful for people developing technology that works with the WebDriver
spec. It's not particularly useful for people trying to write Appium or Selenium tests. When you
write an Appium test, you want to use a programming language you're familiar with. Luckily, there
exist a set of [Appium client libraries](../ecosystem/index.md)[^1] that take care of the
responsibility of speaking HTTP to the Appium server. Instead, they expose a set of "native"
commands for a particular programming language, so that, to the test author, it just feels like
you're writing Python, or JavaScript, or Java.
As an example, here's the same simple set of Appium commands in five different programming
languages, using the recommended Appium client binding for each language (note that this is not
working sample code including all appropriate imports; see each client library's instructions for
setup and command reference):
=== "JavaScript (Webdriver.io)"
```js
const element = await driver.$('//*[@text="Foo"]');
await element.click();
console.log(await element.getText())
console.log(await driver.getPageSource())
```
=== "Java"
```java
WebElement element = driver.findElement(By.Xpath("//*[@text='Foo']"))
element.click()
System.out.println(element.getText())
System.out.println(driver.getPageSource())
```
=== "Python"
```py
element = driver.find_element(by=By.XPATH, value='//*[@text="Foo"]')
element.click()
print(element.text)
print(driver.page_source)
```
=== "Ruby"
```rb
element = driver.find_element :xpath, '//*[@text="Foo"]'
element.click
puts element.text
puts driver.page_source
```
=== "C#"
```dotnet
AppiumElement element = driver.FindElement(MobileBy.AccessibilityId("Views"));
element.click();
System.Console.WriteLine(element.Text);
System.Console.WriteLine(driver.PageSource);
```
Each of these scripts, despite being in different languages, does the same thing under the hood:
1. Call `Find Element` with a `using` parameter of `xpath` and a `value` parameter expressing the
XPath query used to find an element. (If you're confused about these terms, you might find an
introduction to Appium or Selenium useful)
2. Call `Click Element` with the ID of the element found in the previous call.
3. Call `Get Element Text` with the ID of the same element, and print it to the console.
4. Call `Get Page Source` to retrieve the page/app source and print it to the console.
The only other thing to keep in mind before choosing or using a client is that each client is
independently maintained. Just because a feature is available in one client, it doesn't mean it's
available in another client (though all clients support at least the standard W3C protocol plus any
common appium extensions). Just because one client has a nice set of helper functions, doesn't mean
another will. Some clients are kept very frequently up to date, and others are not! So when
thinking about choosing a library, the first consideration is the language you want to use, and the
second consideration is how full-featured and well-maintained the library is!
To learn how to use an Appium client, visit that client's homepage to learn more. In many cases,
the Appium client for a given language is built *on top of* the *Selenium* client for that
language, and so certain Appium clients may only document the features which the Appium client
added on top of the Selenium client. All that to say, for a full reference, you may need to visit
both the Appium client documentation as well as the Selenium client documentation.
That's all you need to know about Appium clients! Head over to the
[Ecosystem](../ecosystem/index.md) page to check out the current list of clients.
[^1]: These libraries are alternately called "clients", "client libraries", or "client bindings".
They all mean the same thing!
-188
View File
@@ -1,188 +0,0 @@
---
title: Intro to Appium Drivers
---
As the [main Overview](index.md) makes clear, "drivers" are basically Appium's answer to the
question, "how do we support automation of multiple, unrelated platforms?" In this doc we'll get
into a little more detail about how drivers work. The specific details of how drivers work probably
don't matter too much for you, unless you're planning on writing your own driver or contributing to
an existing driver (things we hope you do!).
The main benefit in understanding a bit more of how drivers work is that being aware of the typical
complexity or the typical driver architecture will inform your debugging process when you
inevitably run into an issue in one of your tests.
## Interface Implementations
At the most basic level, drivers are simply Node.js classes that extend a special class included in
Appium, called `BaseDriver`. You could have something very close to a "working" driver, with these
very simple lines of code:
```js
import BaseDriver from '@appium/base-driver'
class MyNewDriver extends BaseDriver {
}
```
This empty driver doesn't *do* anything, but you could wrap it up in a Node.js module, add a few
Appium-related fields to the module's manifest (`package.json`), and then install it using `appium
driver install`.
So, from a technical perspective, an Appium driver is just a bit of code that inherits from some
other Appium code. That's it! Now, inheriting from `BaseDriver` actually gives us a lot, because
`BaseDriver` is essentially an encapsulation of the entire WebDriver protocol. So all a driver
needs to do to do something useful is to *implement* Node.js methods with names corresponding to
their WebDriver protocol equivalents.
So let's say I wanted to do something with this empty driver; first I have to decide which
WebDriver command I want to implement. For our example, let's take the [Navigate
To](https://www.w3.org/TR/webdriver1/#navigate-to) WebDriver command. Leave aside for the moment
what I want to have the driver *do* when this command is executed. To tell Appium the driver can
handle the command, all we have to do is define a method like this in our driver class:[^1]
```js
async setUrl(url) {
// do whatever we want here
}
```
[^1]: You might notice that `setUrl` doesn't look anything like `Navigate To`, so how did we know
to use it rather than some other random string? Well, Appium's WebDriver-protocol-to-method-name
mapping is defined in a special file within the `@appium/base-driver` package called
[routes.js](https://github.com/appium/appium/blob/2.0/packages/base-driver/lib/protocol/routes.js).
So if you're writing a driver, this is where you would go to figure out what method names to use
and what parameters to expect. Or you could look at the source for any of the main Appium
drivers!
That's it! How we actually implement the command is totally up to us, and depends on the
platform(s) we want to support. Here are some different example implementations of this command for
different platforms:
- Browsers: execute some JavaScript to set `window.location.href`
- iOS apps: launch an app using a deep link
- Android apps: launch an app using a deep link
- React apps: load a specific route
- Unity: go to a named scene
So you can see there can be a lot of differences between how drivers implement the same WebDriver
command across platforms.[^2] What is the *same*, though, is how they express that they can handle
a protocol command.
[^2]: Of course, we want to keep the semantics as similar as possible, but in the world of iOS, for
example, launching an app via a deep link (a URL with a special app-specific scheme) is about as
close as we are going to get to navigating to a web URL.
We're going into this great amount of detail (which you don't need to remember, by the way),
because it's important to stress the point that an Appium driver is not inherently anything in
particular, other than a bit of JS code that can handle WebDriver protocol commands. Where you go
from there is up to you, the driver author!
## Automation mapping
But *typically* what driver authors want to do is to provide automation behaviours for a given
platform(s) that are semantically very similar to the the WebDriver spec implementations for
browsers. When you want to find an element, you should get a reference to a UI element. When you
want to click or tap that element, the resulting behaviour should be the same as if a person were
to click or tap on the element. And so on.
So the real challenge for driver authors is not how to work with the WebDriver protocol (because
`BaseDriver` encapsulates all that for you), but how to make the actual automation happen on the
target platform. Every driver relies on its own set of underlying technologies here. As mentioned
in the [Overview](index.md), the iOS driver uses an Apple technology called
[XCUITest](https://developer.apple.com/documentation/xctest/xcuielement). These underlying
automation technologies usually have proprietary or idiosyncratic APIs of their own. Writing
a driver becomes the task of mapping the WebDriver protocol to this underlying API (or sometimes
a set of different underlying APIs--for example, the UiAutomator2 driver relies not only on the
[UiAutomator2](https://developer.android.com/training/testing/other-components/ui-automator)
technology from Google, but also functions only available through
[ADB](https://developer.android.com/studio/command-line/adb), as well as functions only available
via the Android SDK inside a helper app). Tying it all together into a single, usable, WebDriver
interface is the incredibly useful (but incredibly challenging) art of driver development!
## Multi-level architecture
In practice, this often results in a pretty complex architecture. Let's take iOS for example again.
The XCUITest framework (the one used by the Appium driver) expects code that calls it to be written
in Objective-C or Swift. Furthermore, XCUITest code can only be run in a special mode triggered by
Xcode (and directly or indirectly, the Xcode command line tools). In other words, there's no
straightforward way to go from a Node.js function implementation (like `setUrl()` above) to
XCUITest API calls.
What the XCUITest driver authors have done is instead to split the driver into two parts: one part
written in Node.js (the part which is incorporated into Appium and which initially handles the
WebDriver commands), and the other part written in Objective-C (the part which actually gets run on
an iOS device and makes XCUITest API calls). This makes interfacing with XCUITest possible, but
introduces the new problem of coordination between the two parts.
The driver authors could have chosen any of a number of very different strategies to model the
communication between the Node.js side and the Objective-C side, but at the end of the day decided
to use ... the WebDriver protocol! That's right, the Objective-C side of the XCUITest driver is
itself a WebDriver implementation, called
[WebDriverAgent](https://github.com/appium/webdriveragent).[^3]
[^3]: You could in theory, therefore, point your WebDriver client straight to WebDriverAgent and
bypass Appium entirely. This is usually not convenient, however, for a few reasons:
- The Appium XCUITest driver builds and manages WebDriverAgent for you, which can be a pain and
involves the use of Xcode.
- The XCUITest driver does lots more than what can be done by WebDriverAgent, for example working
with simulators or devices, installing apps, and the like.
The moral of the story is that driver architectures can become quite complicated and multilayered,
due to the nature of the problem we're trying to solve. It also means it can be difficult sometimes
to tell where in this chain of technologies something has gone wrong, if you run into a problem
with a particular test. With the XCUITest world again, we have something like the following set of
technologies all in play at the same time:
- Your test code (in its programming language) - owned by you
- The Appium client library - owned by Appium
- The Selenium client library - owned by Selenium
- The network (local or Internet)
- The Appium server - owned by Appium
- The Appium XCUITest driver - owned by Appium
- WebDriverAgent - owned by Appium
- Xcode - owned by Apple
- XCUITest - owned by Apple
- iOS itself - owned by Apple
- macOS (where Xcode and iOS simulators run) - owned by Apple
It's a pretty deep stack!
## Proxy mode
There's one other important architectural aspect of drivers to understand. It can be exemplified
again by the XCUITest driver. Recall that we just discussed how the two "halves" of the XCUITest
driver both speak the WebDriver protocol---the Node.js half clicks right into Appium's WebDriver
server, and the Objective-c half (WebDriverAgent) is its own WebDriver implementation.
This opens up the possibility of Appium taking a shortcut in certain cases. Let's imagine that the
XCUITest driver needs to implement the `Click Element` command. The internal code of this
implementation would look something like taking the appropriate parameters and constructing an HTTP
request to the WebDriverAgent server. In this case, we're basically just reconstructing the
client's original call to the Appium server![^4] So there's really no need to even write a function
implementing the `Click Element` command. Instead, the XCUITest driver can just let Appium know
that this command should be proxied directly to some other WebDriver server.
[^4]: It's not *exactly* the same call, because the Appium server and the WebDriverAgent server
will generate different session IDs, but these differences will be handled transparently.
If you're not familiar with the concept of "proxying," in this case it just means that the XCUITest
driver will not be involved at all in handling the command. Instead it will merely be repackaged
and forwarded to WebDriverAgent at the protocol level, and WebDriverAgent's response will likewise
be passed back directly to the client, without any XCUITest driver code seeing it or modifying it.
This architectural pattern provides a nice bonus for driver authors who choose to deal with the
WebDriver protocol everywhere, rather than constructing bespoke protocols. It also means that
Appium can create wrapper drivers for any other existing WebDriver implementation very easily. If
you look at the [Appium Safari driver](https://github.com/appium/appium-safari-driver) code, for
example, you'll see that it implements basically no standard commands, because all of these are
proxied directly to an underlying SafariDriver process.
It's important to understand that this proxying business is sometimes happening under the hood,
because if you're ever diving into some open source driver code trying to figure out where
a command is implemented, you might be surprised to find no implementation at all in the Node.js
driver code itself! In that case, you'll need to figure out where commands are being proxied to so
you can look there for the appropriate implementation.
OK, that's enough for this very detailed introduction to drivers!
-182
View File
@@ -1,182 +0,0 @@
---
title: Appium Project History
---
Appium has been around in one form or another since 2012. It's been under the
direction of various individuals and organizations, and it's even been
implemented in 3 different programming languages! Welcome to more than you ever
wanted to know about how Appium got to be what is it today...
## Early Inspiration
[Dan Cuellar](https://twitter.com/thedancuellar) was the Test Manager at Zoosk
in 2011, when he encountered a problem. The length of the test passes on the
iOS product was getting out of hand. Less testing was an option, but would come
with additional risk, especially with it taking several days to get patches
through the iOS App Store Review process. He thought back to his days working
on websites and realized automation was the answer.
Dan surveyed the existing landscape of tools, only to find that all of them
hand major drawbacks. The tool supplied by Apple, UIAutomation, required tests
to be written in JavaScript, and did not allow for real-time debugging or
interpretation. It also had to be executed inside the Xcode profiling tool,
Instruments. Other 3rd-party tools used private APIs and required SDKs and HTTP
Servers to be embedded into the application. This seemed highly undesirable.
Unsatisfied with the existing options, Dan asked his manager for some
additional time to see if he could find a better way. He spent 2 weeks poking
and prodding around to see if there was a way to use approved Apple
technologies to automate an iOS application. The first implementation he tried
used AppleScript to send messages to Mac UI elements using the OS
X accessibility APIs. This worked to some degree, but would never work on real
devices, not to mention other drawbacks.
So he thought, what if I could get the UIAutomation framework to run in real
time like an interpreter? He looked into it and he determined that all he would
need to do is find a way to receive, execute, and reply to commands from within
a UIAutomation javascript program. Using the utility Apple provided for
executing shell commands he was able to `cat` sequentially ordered text files
to receive commands, `eval()` the output to execute them, and write them back
to disk with `python`. He then prepared code in C# that implemented the
Selenium-style syntax to write the sequentially ordered javascript commands.
iOSAuto is born.
## Selenium Conference 2012
Dan was selected to speak at Selenium Conference 2012 in London about an
entirely different topic. As part of his presentation, he showed off iOS
Automation using Selenium syntax to demonstrate writing platform-agnostic tests
that use separate platform-specific page objects with a common interface. To
his surprise, the cool test architecture would take a backseat to the spectacle
of iOS tests running like WebDriver tests. Several people suggested that he
give a lightning talk later in the conference to explain exactly how it worked.
On the second day of the conference, Dan stepped up on stage to give the
lightning talk. Jason Huggins, co-creator of Selenium, moderated the lightning
talks. Dan experienced technical difficulties getting his presentation to
load, and Jason nearly had to move on to the next lightning talk. At the last
moment, the screen turned on and Dan jumped into his presentation. He explained
the details of his implementation and how it worked, begged for contributors,
and in five minutes it was over. The crowd applauded politely, and he left the
stage.
## The Phone Rings
Four months after the Selenium Conference, Jason called Dan. Jason had been
working on iOS testing support for a client at Sauce Labs. Jason remembered
Dan's lightning talk and thought the project might be useful to Jason's work,
but Dan's source code was not public. Jason asked Dan to meet up. Later that
week, Dan met Jason in a bar in San Francisco and showed him the source code
for iOS Auto.
A long-time open source advocate, Jason encouraged Dan to release his code
under an open source license. In August, Dan [released the source
code](https://github.com/penguinho/appium-old/commit/3ab56d3a5601897b2790b5256351f9b5af3f9e90)
on GitHub in C#. Jason encouraged Dan to change the language to make the
project more appealing to potential contributors. Dan [uploaded a new version
in
Python](https://github.com/penguinho/appium-old/commit/9b891207be0957bf209a77242750da17d3eb8eda).
In September, Jason added a web server and [began to implement the WebDriver
wire
protocol](https://github.com/hugs/appium-old/commit/ae8fe4578640d9af9137d0546190fa29317d1499)
over HTTP, making iOS Auto scriptable from any Selenium WebDriver client
library in any language.
## The Mobile Testing Summit
Jason decided that the project should be presented at the [Mobile Testing
Summit](https://twitter.com/mobtestsummit) in November, but suggested that the
project get a new name first. Many ideas were thrown out and they settled on
AppleCart. A day later, while he was perusing some of Apple's guidance on
copyright and trademarks, Jason noticed that under the section of examples for
names Apple would defend its trademarks against, the first example was
"AppleCart". He called Dan and informed him of the situation, and they
brainstormed for a bit before Jason hit the jackpot. Appium... Selenium for
Apps.
## Sauce Labs and Node.js
In January 2013, not long after the Mobile Testing Summit, Sauce Labs decided
to fully back Appium and provide more developer power. A task force was created
to evaluate the current state and how best to move forward with the project.
The team, which included Jonathan Lipps (the current project lead), decided
that Appium needed a rebirth, and ultimately settled on Node.js as the
framework to use. Node is well-known as a fast and efficient web server
backend, and at the end of the day, Appium is just a highly-specialized web
server. It was also decided that JavaScript as a language was accessible enough
that Appium would be able to grow into a larger community of open-source
developers with JavaScript than the other options on the table.
In just a few days, the team leveraged the existing work on Appium and had
a new version of Appium with as much functionality as the previous Python
version. The foundation had been laid for Appium's basic architecture, and we
have been successfully building on it since. A few weeks into this sprint,
Jonathan Lipps was formally designated project lead and he began to strategize
how to get more people from the community involved with Appium's development.
## Appium Around the World
Ultimately, Jonathan decided that getting Appium in front of as many developers
at conferences and meetups was the best way to attract users and contributions.
Appium in its new incarnation was debuted at the [Google Test Automation
Conference 2013](https://www.youtube.com/watch?v=1J0aXDbjiUE). Later in 2013,
Appium was presented at conferences and meetups all around the US, as well as
in England, Poland, Portugal, and Australia. Notably, Jonathan had Appium
[perform as instruments in a band](https://www.youtube.com/watch?v=zsbNVkayYRQ)
and Dan Cuellar put together a fun [Appium video
montage](https://www.youtube.com/watch?v=xkzrEn0v0II) for Selenium Conference.
But during all these presentations and conferences, the project continued to
develop. Early in 2013 we released Android and Selendroid support, making
Appium the first truly cross-platform automation framework. The project also
continued to attract users and contributors, and by the end of 2013, we'd
already had well over 1,000 commits.
## The Road to Appium 1.0
Appium began to grow and mature significantly. In May 2014,
we released Appium 1.0, which stood as a milestone in Appium's development.
Appium was given
[various](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/)
and became the most popular open-source cross-platform mobile automation
framework. Stability improved, bugs were prioritized and fixed, and features
added. Sauce Labs increased the number of developers it donated to working
on Appium, but the entire community stayed involved in guiding the project and
contributing to it, and project governance continued to happen in the open, on
public mailing lists and GitHub's issue tracker.
## The Appium Umbrella Broadens
Eventually, it became clear that the Appium codebase was not optimized for
a large team of distributed, sometime contributors. We took the opportunity as
a committer team to rewrite Appium from the ground up, using a more modern
version of the JavaScript language, and redoing Appium's architecture so that
it was easy for users or third-party developers to build their own Appium
"drivers". We wanted for it to be easier for new contributors to get ramped up
on the Appium codebase, and to see support for new platforms added to Appium by
groups other than the core team. That vision has begun to be fulfilled, with
groups like Microsoft and Youi.tv adding drivers to Appium for Windows desktop
app automation and Youi.tv app automation, respectively. Who knows what
platforms will be added next?
## Appium To The People
In late 2016, Sauce Labs donated Appium as a project to the [JS
Foundation](https://js.foundation), in order to cement for the world Sauce's
commitment that Appium remains open source. The JS Foundation is a non-profit
open source stewardship organization which takes responsibility for holding the
copyright for open source projects, as well as ensuring they have a long and
successful tenure in the community. As a result of our move to a non-profit
foundation, we hope that the door will open even more widely for new
contributors, either as individuals or representing one of the many companies
which now have an interest in seeing Appium move forward.
Eventually, the JS Foundation merged into the [OpenJS Foundation](https://openjsf.org), and Appium
is currently an Impact Project in the foundation.
## Appium 2.0
Appium 2.0 was released in 2022, with a new focus on Appium as an ecosystem rather than a singular
project. Drivers and plugins can be developed and shared by anyone, opening up a world of
possibilities for automation-related development for platforms far beyond iOS and Android.
-202
View File
@@ -1,202 +0,0 @@
---
title: Intro to Appium
---
As mentioned on the main page, Appium is an open-source project and ecosystem of related software,
designed to facilitate UI automation of many app platforms. With the release of Appium 2.0, Appium
has the following primary goals:[^1]
- Make platform-specific automation capabilities available under a cross-platform, standard API
- Allow easy access to this API from any programming language
- Provide tools to enable convenient community development of Appium extensions
[^1]:
To meet these primary goals, we also work with a set of secondary goals or methodology
principles, which we also encourage for Appium extension developers:
- As far as possible, rely on (and contribute to) open source technology
- As far as possible, rely on vendor-provided tools for a given platform
- As far as possible, rely on automation tools that allow automation of unmodified apps (prefer
not to require the user to build in additional SDKs or software that introduce discrepancies
between the test version of the app and the production version)
- As far as possible, rely on existing standards instead of creating new ones
So, take any app platform you know about, like iOS or Android. Appium wants for there to be a way
for developers and testers to write UI automation code for that platform, according to a single,
unified API. Based on Appium's goals, we have a lot of questions to answer to make it all work:
- Which API should that "single, unified" API be?
- How do we map that API to automation behaviour for a specific platform?
- How do we make that API accessible via multiple popular programming languages?
There's another, larger, question lurking in the background here too, given that there are more app
platforms out there than just iOS and Android:
- How do we enable automation for *all* the platforms?
Exploring Appium's answers to these questions may not be the quickest way to learn what Appium is,
but it is certainly a good one! So let's dive in.
## Appium's choice of API
Appium is very fortunate to have been preceded by a technology which has been a long-standing
pioneer in the field of UI automation, namely [Selenium](https://seleniumhq.org). The goal of the
Selenium project has been to support UI automation of web browsers, and in this way we can think of
it as occupying a subset of Appium's goals. Along the way, Selenium (and, after they merged,
another project called WebDriver) developed a relatively stable API for browser automation.
Over the years, Selenium worked with various web browser vendors and the [W3C](https://w3c.org)
standards group to turn its API into an official web browser standard, called the [WebDriver
specification](https://w3c.github.io/webdriver/webdriver-spec.html). All the main browsers now
implement automation capabilities inline with the WebDriver spec, without the Selenium team having
to maintain any software that performs actual automation; standards for the win!
Appium's initial goals were to develop an automation standard for mobile apps (iOS and Android). We
could have made up something new, but in the spirit of joining forces and keeping standards, well,
standard, we decided to adopt the WebDriver spec as Appium's API.[^2] While user interaction on
websites and in mobile native apps are not entirely identical (with even greater differences once
we start to consider, for example, TV platforms controlled by simple remotes), the fact is that
most software UIs are pretty much the same. This means that the WebDriver spec provides automation
API primitives (finding elements, interacting with elements, loading pages or screens, etc...) that
more or less map to any platform.
[^2]: Technically, when Appium was first written, we were dealing with something older than the
WebDriver spec, called the JSON Wire Protocol. Since then, Appium continued to evolve along with
the W3C spec and is fully W3C-compliant.
Of course, Appium wants to support the cases where user interaction *does* differ from web to
mobile or web to TV, and so Appium also makes use of the built-in *extensibility* of the WebDriver
spec. The result is that, no matter what platform you want to automate, when you use Appium, you
will do so using the standard WebDriver spec, with two caveats:
- We might not have any way to support a particular WebDriver API command on a given platform, and
so some commands might be unsupported (for example, getting or setting cookies is not possible in
the world of native mobile app automation).
- We might support automation behaviours that go *beyond* what's available in the WebDriver API
command list, though any such commands will be valid and spec-compliant extensions to the
WebDriver API.
How do you actually *use* the WebDriver API, particularly in the context of Appium? We'll cover
that in the [section below](#universal-programming-language-access) on how Appium provides
universal programming language access. All you need to know for now is that the way Appium
introduces a universal UI automation interface is by implementing the WebDriver protocol.
## Platform automation behaviour
The next question is, how does Appium map this protocol to automation behaviour on a wide range of
platforms? The trick is that, strictly speaking, Appium doesn't! It leaves this responsibility up
to a kind of software module called an Appium *driver*. There's a whole [Driver
Introduction](./drivers.md) which you can read next, so we won't go into huge detail on how they
work for now.
What's important to understand at the moment is that a driver is kind of like a pluggable module
for Appium that gives Appium the power to automate a particular platform (or set of platforms,
depending on the goal of the driver). At the end of the day, a driver's responsibility is to simply
implement an Appium-internal interface representing the WebDriver protocol. How it implements this
interface is totally up to the driver, based on its strategy for making automation happen on
a specific platform. Typically, and with a lot more complexity and difficulty in the details,
a driver does this by relying on platform-specific automation technologies. For example, Apple
maintains an iOS automation technology called
[XCUITest](https://developer.apple.com/documentation/xctest/user_interface_tests). The Appium
driver that supports iOS app automation is called the [XCUITest
Driver](https://github.com/appium/appium-xcuitest-driver) because ultimately what it does is
convert the WebDriver protocol to XCUITest library calls.
One of the reasons that drivers are independent, pluggable modules is that they work completely
differently from one another. The tools and requirements for building and using drivers for
different platforms are completely different. And so Appium lets you use just the drivers that you
need for your automation tasks. Choosing drivers and installing them so that you can use them with
your Appium instance is so important that Appium has its very own [CLI for managing
drivers](../cli/extensions.md).
So, to answer our original question, the way that Appium provides access to automation capabilities
for a given platform is that the Appium team (or anyone else[^3]) writes a *driver* for that
platform, implementing as much or little of the WebDriver protocol as desired. The driver can then
be installed by anyone using Appium.
[^3]: You can build and share your own drivers! Check out [Building
Drivers](../ecosystem/build-drivers.md) to learn more about how to develop drivers in Node.js
that can be used with Appium.
## Universal programming language access
But what does it mean, or look like, to *use* Appium, anyway? Since Appium is ultimately a Node.js
program, it *could* have looked like importing Appium and its drivers as libraries into your own
Node.js programs. But that wouldn't meet Appium's goal of providing automation capabilities to
people using any popular programming language.
Luckily, the fact that Appium rode in on Selenium's coattails meant that we had a solution to this
problem from day one. You see, the WebDriver specification is actually an HTTP-based protocol,
meaning it is designed to be used over a network rather than within the memory of a single program.
One of the main benefits of this "client-server" architecture is that it allows the automation
implementer (the thing doing the automation, in this case the 'server') to be completely distinct
from the automation runner (the thing defining what automation should be done, in what steps,
etc..., in this case the 'client'). Basically, all the "hard stuff" (actually figuring out how to
make automation happen on a given platform) can be handled in one place by the server, and "thin"
client libraries can be written in any programming language which simply encode HTTP requests to
the server in language-appropriate way. It's possible, in other words, to bring basic Appium
/ WebDriver capabilities to a new programming language relatively easily, assuming high-level HTTP
libraries exist, simply by coding up a basic HTTP client in that language.
There are a couple important takeaways here for you, the Appium user:
- Appium is an *HTTP server*. It must run as a process on some computer for as long as you want to
be able to use it for automation. It must be accessible on the network to whichever computer you
want to use to run the automation from (whether that is the same machine or one across the
world).
- Unless you want to write raw HTTP calls or use cURL, using Appium for automation involves the use
of an [Appium Client](clients.md) in the language of your choice. The goal of each of these
clients is to encapsulate the WebDriver protocol so that rather than worrying about the protocol
itself, you can work with objects and methods that feel idiomatic for your language.
- The Appium server and the Appium client do *not* need to be running on the same computer. You
simply need to be able to send HTTP requests from the client to the server over some network.
This greatly facilitates the use of cloud providers for Appium, since they can host the Appium
server and any related drivers and devices, and all you need to do is point your client script to
their secure endpoints.
And of course, none of this is about "testing" per se, purely about the use of Appium and its
client libraries for automation purposes. If you want to do automation for the purpose of
"testing", you'll likely want to enlist the help of test runners, test frameworks, and the like,
none of which need be related to Appium; one of the benefits of Appium's "universal accessibility"
is that it plays well with whatever set of tools you find most beneficial for your situation.
## Appium's huge scope
Appium's vision (automation of everything under a single API) is huge! Certainly, much bigger than
the team of core maintainers for the open source project. So how does Appium hope to achieve this
goal? Basically, by empowering the community to develop functionality on top of Appium as
a *platform*. This is what we call the Appium "ecosystem".
The Appium team does officially maintain a few drivers itself (for example, the XCUITest driver
that we spoke about earlier). But it cannot hope to have the platform-specific expertise or the
capacity to maintain drivers for many different platforms. But what we have done, particularly
beginning with Appium 2.0, is to provide tools to empower the community to join in our vision:
- Anyone can create a driver simply by creating a Node.js module that conforms to the appropriate
conventions and implements any (sub|super)set of the WebDriver protocol. Creating a driver often
involves a minimal amount of code because the WebDriver protocol details are abstracted away, and
many helper libraries are available---the same libraries that power the Appium team's own
drivers.
- Sharing drivers with others is easy using the Appium driver CLI. There is no central authority.
Anyone can share drivers publicly or privately, for free or for sale. Drivers can be open or
closed source (though obviously we appreciate open source!).
Appium's vision of being a platform for development extends beyond the support of automation for
all app platforms. As a popular automation tool, there are many opportunities for integrating
Appium with all kinds of other tools and services. In addition, there are many feature ideas for
Appium, either as a core server or in its incarnation across various drivers, which the core team
will never have time to build. And so, with Appium 2.0, Appium has released a plugin system that
enables anyone to build and share modules that change how Appium works!
In the same way that drivers are easily shareable and consumable via the Appium driver CLI, plugins
can be published and consumed via a parallel [Plugin CLI](../cli/extensions.md). Plugins can do all
sorts of things, for example adding the ability for Appium to find and interact with screen regions
based on a template image (as in the [`images`
plugin](https://github.com/appium/appium/tree/2.0/packages/images-plugin)). There are very few
limitations on what you can do with plugins, so you might also be interested in learning how to
[Build Plugins](../ecosystem/build-plugins.md) in Node.js that can be used with Appium.
So that's Appium: an extensible, universal interface for the UI automation of potentially
everything! Read on into some of the specific intro docs for more details, or check out the various
guides to dive into some more general concepts and features of Appium.
@@ -1,19 +0,0 @@
---
title: Appium Requirements
---
The basic requirements for the Appium server are:
* A macOS, Linux, or Windows operating system
* [Node.js](https://nodejs.org) version >= 14
* [NPM](https://npmjs.com) version >= 8 (NPM is usually bundled with Node.js, but can be upgraded
independently)
By itself, Appium is relatively lightweight and doesn't have significant disk space or RAM
requirements. It can even be run in resource-constrained environments like Raspberry Pi, so long as
Node.js is available.
To use Appium to automate a particular platform, please refer to the documentation of the [Appium
driver(s)](../ecosystem/index.md#drivers) for that platform for additional dependencies. It is
almost universally the case that Appium drivers for a given platform will require the developer
toolchain and SDKs for that platform to be available.
@@ -1,26 +0,0 @@
---
title: Quickstart Intro
---
Let's get up and running with Appium! To successfully use this quickstart, it's recommended that
you first have read the [Introduction](../intro), so that you understand the concepts involved in
running Appium and writing Appium scripts.
The basic plan for this quickstart is as follows:
1. Install Appium
1. Install an Appium driver and its dependencies (we'll be using the [UiAutomator2
driver](https://github.com/appium/appium-uiautomator2-driver) for these examples)
1. Install an Appium client library in your language or choice (this guide contains options for
JavaScript, Python, and Java, though [Appium clients](../ecosystem/index.md#clients) also exist in other language).
1. Write and run a simple Appium automation script using a sample application
### Requirements
Before getting started, make sure your system satisfies the
[requirements](../intro/requirements.md) for running the Appium server. Additional requirements
will be discussed in conjunction with installing the UiAutomator2 driver. The guide also assumes
you're basic command line proficiency on your platform, for example being able to run commands, set
and persist environment variables, etc...
Now you're ready to get started! So head on over to [Installing Appium](./install.md).
@@ -1,30 +0,0 @@
---
title: Install Appium
---
Installing Appium is as easy as running a single NPM command:
```bash
npm i -g appium@next
```
!!! note
Currently, you must use `appium@next` instead of just `appium`. Once Appium 2.0 has been
officially published, you can simply use `appium`.
This command installs Appium globally on your system so that you can access it from the command
line simply by running the `appium` command. Go ahead and run it now:
```
appium
```
You should see some output that starts with a line like this:
```
[Appium] Welcome to Appium v2.0.0
```
That's it! If you get this kind of output, the Appium server is up and running. Go ahead and quit
it (CTRL-C) and move on to the next step, where we'll install a driver for automating Android apps.
@@ -1,19 +0,0 @@
---
title: Next Steps
---
Now that you've successfully set up your system for Android automation and run a simple test,
you'll want to continue exploring this documentation. In particular, these are good guides and
reference materials especially for beginners:
- [Managing Appium Drivers and Plugins](../guides/managing-exts.md)
- [Capabilities](../guides/caps.md)
- The list of available [Drivers and Plugins](../ecosystem/index.md)
You'll also find that the [Appium Inspector](https://github.com/appium/appium-inspector) is an
indispensable tool for use in Appium test-writing, as it enables visual inspection of apps and
helps you to discover element locators for use in your test scripts.
You might also take advantage of one of the many online Appium courses available to you.
Good luck and have fun!
@@ -1,5 +0,0 @@
---
title: Write a Test (Java)
---
TODO
@@ -1,68 +0,0 @@
---
title: Write a Test (JS)
---
To write an Appium test in JavaScript (Node.js), we need to choose an Appium-compatible client
library. The best-maintained library and the one the Appium team recommends using is
[WebdriverIO](https://webdriver.io), so let's use that. Since we already have Appium installed we
know our Node and NPM requirements are already satisfied. So just create a new project directory
somewhere on your computer and then initialize a new Node.js project in it:
```bash
npm init
```
It doesn't really matter what you put in the prompts, just so long as you end up with a valid
`package.json`.
Now, install the `webdriverio` package via NPM:
```bash
npm i --save-dev webdriverio
```
Once this is done, your `package.json` file should include a section like the following:
```json title="package.json"
--8<-- "./sample-code/quickstarts/js/package.json"
```
Now it's time to type up the test itself. Create a new file called `test.js` with the following
contents:
```js title="test.js"
--8<-- "./sample-code/quickstarts/js/test.js"
```
!!! note
It's not within the scope of this guide to give a complete run-down on the WebdriverIO client
library or everything that's happening here, so we'll leave the code itself unexplained in
detail for now. You may want to read up particularly on Appium
[Capabilities](../guides/caps.md) in addition to familiarizing yourself with the excellent
[WebdriverIO documentation](https://webdriver.io/docs/gettingstarted) for a fuller explanation
of the various API commands you see and what their purpose is.
Basically, this code is doing the following:
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
kind of thing you want to automate.
1. Starting an Appium session on the built-in Android settings app.
1. Finding the "Battery" list item and clicking it.
1. Pausing for a moment purely for visual effect.
1. Ending the Appium session.
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
running in another terminal session, otherwise you'll get an error about not being able to connect
to one. Then, you can execute the script:
```bash
node test.js
```
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the
app closes again.
Congratulations, you've started your Appium journey! Read on for some next steps to explore.
@@ -1,51 +0,0 @@
---
title: Write a Test (Python)
---
The [Appium Python Client](https://github.com/appium/python-client) is
an official Appium client in Python, which is available via pypi under the [Appium-Python-Client](https://pypi.org/project/Appium-Python-Client/) package name.
It inherits from the [Selenium Python Binding](https://pypi.org/project/selenium/),
so installing the Appium Python Client includes the selenium binding.
```bash
pip install Appium-Python-Client
```
This example uses Python's built-in `unittest` module, though you can use any Python test framework you want.
The Appium Python client adds the `appium:` vendor prefix automatically.
You usually do not need to worry about the prefix.
```python title="test.py"
--8<-- "./sample-code/quickstarts/py/test.py"
```
!!! note
It's not within the scope of this guide to give a complete run-down on the Python client
library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.
- You may want to read up particularly on Appium [Capabilities](../guides/caps.md).
- [functional test code](https://github.com/appium/python-client/tree/master/test/functional) in Python Client GitHub repository should help to find more working example.
- [Documentation](https://appium.github.io/python-client-sphinx/) also helps to find methods
defined in the Appium Python Client.
Basically, this code is doing the following:
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
kind of thing you want to automate.
1. Starting an Appium session on the built-in Android settings app.
1. Finding the "Battery" list item and clicking it.
1. Pausing for a moment purely for visual effect.
1. Ending the Appium session.
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
running in another terminal session, otherwise you'll get an error about not being able to connect
to one. Then, you can execute the script:
```bash
python test.py
```
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the
app closes again.
Congratulations, you've started your Appium journey! Read on for some next steps to explore.
@@ -1,56 +0,0 @@
---
title: Write a Test (Ruby)
---
The [AppiumLib](https://github.com/appium/ruby_lib) and the [AppiumLibCore](https://github.com/appium/ruby_lib_core) are Appium officcial client libraries in Ruby, which are available via gem under the [appium_lib](https://rubygems.org/gems/appium_lib) and the [appium_lib_core](https://rubygems.org/gems/appium_lib_core) package names. The appium_lib_core inherits from the Selenium Ruby Binding, and the appium_lib inherits from the appium_lib_core, so intalling these libraries include the selenium binding.
```bash
gem install appium_lib
# or
gem install appium_lib_core
```
The `appium_lib_core` is the main part as an Appium client.
`appium_lib` has various helper methods, but the driver instance was ordinally designed to be used as a global variable. It could causes an issue to handle the instance.
`appium_lib_core` does not have such a global variable.
This example is by the `appium_lib_core` with `test-unit` gem module.
Tes code in `appium_lib` should be similar.
```python title="test.py"
--8<-- "./sample-code/quickstarts/rb/test.rb"
```
!!! note
It's not within the scope of this guide to give a complete run-down on the Ruby client
library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.
- You may want to read up particularly on Appium [Capabilities](../guides/caps.md).
- [functional test code](https://github.com/appium/ruby_lib_core/tree/master/test/functional) in the appium_lib_core GitHub repository should help to find more working example.
- Documentation [appium_lib_core](https://www.rubydoc.info/github/appium/ruby_lib_core) and [appium_lib](https://www.rubydoc.info/github/appium/ruby_lib) also helps to find avvailable methods.
Basically, this code is doing the following:
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
kind of thing you want to automate.
1. Starting an Appium session on the built-in Android settings app.
1. Finding the "Battery" list item and clicking it.
1. Pausing for a moment purely for visual effect.
1. Ending the Appium session.
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
running in another terminal session, otherwise you'll get an error about not being able to connect
to one. Then, you can execute the script:
```bash
bundle install
bundle exec ruby test.rb
```
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the
app closes again.
Congratulations, you've started your Appium journey! Read on for some next steps to explore.
@@ -1,99 +0,0 @@
---
title: Install the UiAutomator2 Driver
---
You can't do much with Appium unless you have a [driver](../intro/drivers.md), which is an
interface that allows Appium to automate a particular platform.
!!! info
For this quickstart guide, we're going to be automating an app on the Android platform, because
the system requirements for Android automation via Appium are the same as for Appium itself
(whereas the iOS driver, for example, requires you to be using macOS).
The driver we're going to use is called the [UiAutomator2
Driver](https://github.com/appium/appium-uiautomator2-driver). It's worth visiting that driver's
documentation and bookmarking it, because it will be an invaluable reference down the line.
## Set up Android automation requirements
According to the driver, in addition to a working Appium server, we also need to do the following:
- Download [Android SDK platform tools](https://developer.android.com/studio/releases/platform-tools). You will probably want to download [Android Studio](https://developer.android.com/studio) and manage the SDK tools from within it for the easiest experience.
- Set an environment variable pointing to the directory on disk where the Android tools are
installed. You can usually find the path to this directory in the Android Studio SDK manager. It
will contain the `platform-tools` and other directories. We need to define and persist the
environment variable as `ANDROID_HOME` (or alternatively `ANDROID_SDK_ROOT`).
- Use the Android SDK manager to download whichever Android platform we want to automate (for
example, API level 30)
- Install the Java JDK (for the most recent Android API levels, JDK 9 is required, otherwise JDK
8 is required). It's easiest to use the [OpenJDK packages](https://openjdk.java.net/install/). Make
sure you get the JDK and not the JRE.
- When the JDK is installed, you'll need to find the path to the JDK home directory as it was
installed on your system. This will be the directory that *contains* the `bin`, `include`, and
other directories. The path must be persisted as an environment variable named `JAVA_HOME`, so that
Appium can find the appropriate Java tooling that is required to work with the Android platform.
- Use Android Studio to create and launch an Android Virtual Device (an AVD, otherwise known as an
emulator). You may need to download the system images for the API level of the emulator you want to
create. Using the AVD creation wizard in Android Studio is generally the easiest way to do all of
this.
!!! note
You can also use a physical Android device, so long as it is configured for debugging and
development
- With the emulator or device connected, you can run `adb devices` (via the binary located at
`$ANDROID_HOME/platform-tools/adb`) to verify that your device shows up as connected.
Once your device shows up as connected in ADB, and you've verified that the environment variables
are set up correctly in the terminal context where you are going to run Appium, you should be good
to go! If you ran into problems with any of these steps, refer to the driver documentation, or the
various Android or Java documentation sites as necessary.
Also, congratulations: whether or not you intended to, you now have the Android developer toolchain
set up on your system, so you can get busy making Android apps if you want!
## Install the driver itself
Since the UiAutomator2 driver is maintained by the core Appium team, it has an 'official' driver
name that you can use to install it easily via the [Appium Extension CLI](../cli/extensions.md):
```bash
appium driver install uiautomator2
```
It should produce output that looks something like:
```
Attempting to find and install driver 'uiautomator2'
✔ Installing 'uiautomator2' using NPM install spec 'appium-uiautomator2-driver'
Driver uiautomator2@2.0.5 successfully installed
- automationName: UiAutomator2
- platformNames: ["Android"]
```
Running this command will locate and install the latest version of the UiAutomator2 driver, making
it available for automation. Note that when it is installed it tells you what platforms it is valid
for (in this case, `Android`), and what automation name (the `appium:automationName`
[capability](../guides/caps.md)) must be used to select this driver for use during an Appium
session (in this case, `UiAutomator2`).
!!! note
In this quickstart we have used the Extension CLI to install the UiAutomator2 driver, but if you
are incorporating Appium into a Node.js project, you might prefer to use NPM to manage Appium
and its connected drivers. To learn more about this technique, visit the guide on [managing
Appium extensions](../guides/managing-exts.md).
Now, start the Appium server again (run `appium`), and you should see that the newly-installed
driver is listed as available:
```
[Appium] Available drivers:
[Appium] - uiautomator2@2.0.5 (automationName 'UiAutomator2')
```
With the Android setup complete and the UiAutomator2 driver installed, you're ready to write your
first test! So pick the language you're most comfortable with under the quickstart menu and give it
a shot.
-16
View File
@@ -1,16 +0,0 @@
---
title: Additional Resources
---
Here you can find links to additional Appium resources around the web:
## Websites
- [Appium Pro](https://appiumpro.com) - a blog and newsletter written by one of Appium's
maintainers, Jonathan Lipps, with lots of useful guides
## Online Courses
- [Appium and Selenium Fundamentals](https://ui.headspin.io/university/learn/appium-selenium-fundamentals-2020) - a comprehensive video course on learning Python, Selenium, and Appium by Jonathan Lipps
- [Mobile Test Automation with Appium](https://testautomationu.applitools.com/appium-java-tutorial/) - a video course by Moataz Nabil
- [Advanced Appium](https://www.linkedin.com/learning/advanced-appium) - a video course by Jonathan Lipps
@@ -1,23 +0,0 @@
## Appium サーバーをサポートしているクライアントライブラリの一覧
これらのライブラリは、標準の Selenium クライアントライブラリをラップして、[JSON Wire プロトコル](https://w3c.github.io/webdriver/webdriver-spec.html) によって指定されたすべての通常の Selenium コマンドを提供し、**マルチタッチジェスチャー** や **画面の向き** などのモバイルデバイスの制御に関連した追加コマンドを追加します。
Appium クライアントライブラリは、[Mobile JSON Wire プロトコル](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) (標準プロトコルの公式ドラフト拡張) と、[W3C Webdriver 仕様](https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html) (トランスポートに依存しない自動化仕様。ここでは MultiAction API が定義されています) の要素を実装しています。
Appium サーバー自体が公式プロトコルへのカスタム拡張を定義しており、Appium ユーザーに様々なデバイスの動作 (テストセッションの途中でアプリをインストール/アンインストールするなど) を実現する便利な入り口を提供します。これが、「素」な Selenium クライアントだけでなく、Appium 固有のクライアントが必要な理由です。もちろん、Appium クライアントライブラリは機能を**追加**するだけなので (実際には、標準の Selenium クライアントを拡張するだけです)、通常の Selenium セッションに使用できます。
言語/フレームワーク | Github のリポジトリとインストール手順 |
----- | ----- |
Ruby | [https://github.com/appium/ruby_lib](https://github.com/appium/ruby_lib), [https://github.com/appium/ruby_lib_core](https://github.com/appium/ruby_lib_core)
Python | [https://github.com/appium/python-client](https://github.com/appium/python-client)
Java | [https://github.com/appium/java-client](https://github.com/appium/java-client)
C# (.NET) | [https://github.com/appium/appium-dotnet-driver](https://github.com/appium/appium-dotnet-driver)
### Community based
言語/フレームワーク | Github のリポジトリとインストール手順 |
----- | ----- |
JavaScript (Node.js) | [https://github.com/admc/wd](https://github.com/admc/wd)
JavaScript (Node.js) | [https://github.com/webdriverio/webdriverio](https://github.com/webdriverio/webdriverio)
JavaScript (Browser) | [https://github.com/projectxyzio/web2driver](https://github.com/projectxyzio/web2driver)
RobotFramework | [https://github.com/serhatbolsu/robotframework-appiumlibrary](https://github.com/serhatbolsu/robotframework-appiumlibrary)
@@ -1,274 +0,0 @@
## はじめに
このドキュメントでは、簡単な Appium テストを実施して、
Appium の基本的な考え方をご紹介します。
Appium の概念をより包括的に紹介するためには、[概念的な紹介](/docs/ja/about-appium/intro.md)をご覧ください。
### Appium のインストール
Appium は、[NPM](https://npmjs.com) 経由でインストールするか、
Appium サーバーを起動するためのグラフィカルなデスクトップベースの方法である [Appium Desktop](https://github.com/appium/appium-desktop) をダウンロードする
2つの方法のいずれかでインストールすることができます。
#### NPM 経由でのインストール
`npm install` で Appium を実行したり、Appium でハックしたり、Appium に貢献したりするには、
[Node.js と NPM](http://nodejs.org) が必要です
(Node.js をインストールするには、
[nvm](https://github.com/creationix/nvm)、[n](https://github.com/visionmedia/n)、`brew install node` を使用してください。
`sudo` で Node や Appium をインストールしていないことを確認してください)。
Appium は Node 10+ をサポートしていますが、
最新の安定版を推奨します。
実際のインストールはこんな感じで簡単です。
```
npm install -g appium
```
#### デスクトップアプリのダウンロードからのインストール
[リリースページ](https://github.com/appium/appium-desktop/releases)から
Appium Desktop の最新版をダウンロードするだけです。
### ドライバー固有の設定
iOS や Android アプリケーションのように、
特定のものを自動化するために Appium を使用したいと思うでしょう。
特定のプラットフォームの自動化のサポートは、Appium の「ドライバ」によって提供されます。
さまざまな種類の自動化技術へのアクセスを提供するこのようなドライバは多数あり、
それぞれが各々のセットアップ要件を持っています。
これらの要件のほとんどは、特定のプラットフォームでのアプリ開発と同じ要件です。
例えば、Android ドライバを使用して Android アプリケーションを自動化するには、
お使いのシステム上で設定された Android SDK が必要です。
ある時点で、自動化したいプラットフォームのドライバのドキュメントを確認して、
システムが正しくセットアップされていることを確認してください。
- [XCUITest Driver](/docs/en/drivers/ios-xcuitest.md) (iOS と tvOS アプリ用)
- [Espresso ドライバー](/docs/en/drivers/android-espresso.md) (Android アプリ用)
- [UiAutomator2 ドライバー](/docs/en/drivers/android-uiautomator2.md) (Android アプリ用)
- [Windows ドライバー](/docs/en/drivers/windows.md) (Windows デスクトップアプリ用)
- [Mac ドライバー](/docs/en/drivers/mac.md) (Mac デスクトップアプリ用)
### インストールの確認
Appium の依存関係がすべて満たされていることを確認するには、`appium-doctor` を使うことができます。
`npm install -g appium-doctor` でインストールし、
`appium-doctor` コマンドを実行して `--ios` または `--android` フラグを指定して、
すべての依存関係が正しく設定されていることを確認します。
### Appium クライアント
すべてが呼ばれた時、Appium はただの HTTP サーバーです。
それはその状態でクライアントからの接続を待ち、
クライアントはどのような種類のセッションを開始するか、セッションが開始されるとどのような自動化動作を実行するかを Appium に指示します。
これは、Appium を単独では決して使用しないことを意味します。
常に何らかの種類のクライアントライブラリ (または、冒険的な場合は cURL!) と一緒に使用する必要があります。
幸いなことに、Appium は WebDriver プロトコルと呼ばれる [Selenium](http://www.seleniumhq.org/) と同じプロトコルを話します。
標準の Selenium クライアントの 1 つを使用するだけで、
Appium で多くのことを行うことができます。
あなたのシステムにはすでにこれらのクライアントがあるかもしれません。
特にモバイルプラットフォーム上の Web ブラウザをテストする目的で Appium を使用している場合は、
それだけで十分です。
しかし、モバイルデバイスが Web ブラウザではできないことを行えるように、
Appium は Selenium ではできないことを行えます。
そのため、私たちは様々なプログラミング言語の
Appium クライアントを用意しています。
クライアントのリストとダウンロード手順へのリンクは
[Appium クライアントのリスト](/docs/en/about-appium/appium-clients.md)で見ることができます。
先に進む前に、お好きな言語でクライアントをダウンロードし、
準備ができていることを確認してください。
### Appium の開始
(NPMのインストールが成功したと仮定して)
これで、以下のようにコマンドラインから実行することで、Appium サーバーをキックアップすることができます。
```
appium
```
または、Appium Desktop 内の巨大な Start Server ボタンをクリックしてください。
Appium は、実行している Appium のバージョンとどのポートを待ち受けているかを示す小さなウェルカムメッセージを表示します
(デフォルトは `4723` です)。
このポートで Appium に接続するようにテストクライアントを設定する必要があるので、
このポート情報は重要です。
ポートを変更したい場合は、
Appium を起動する際に `-p` フラグを使用して変更することができます
([サーバーパラメータ](/docs/en/writing-running-appium/server-args.md)の全リストを確認してください)。
### 最初のテストの実行
このセクションでは、基本的な "Hello World" の Android テストを実行します。
Android を選択したのは、すべてのプラットフォームで利用可能だからです。
[UiAutomator2 Driver](/docs/en/drivers/android-uiautomator2.md)を使用しますので、
そのドキュメントを読み、システムを適切に設定してください。
また、言語として JavaScript を使用しますので、
追加の依存関係に対処する必要はありません。
(Android 以外のものを
JavaScript 以外のものを使って自動化したいと思うこともあるでしょう。
その場合は、多くの言語やプラットフォームに対応した
[コードサンプル](https://github.com/appium/appium/tree/master/sample-code)を用意しています。)
#### 前提条件
- あなたが Android 8.0 エミュレータを設定して実行していると仮定します
(例は、バージョン番号を調整することで
より低バージョンで動作します。)
- あなたが[このテスト APK](https://github.com/appium/appium/raw/master/sample-code/apps/ApiDemos-debug.apk) をダウンロードして、
ローカルファイルシステム上で
利用可能であると仮定します
#### Appium クライアントの設定
この例では、Appium クライアントとして [Webdriver.io](http://webdriver.io) を使用します。
この例のディレクトリを作成し、実行します。
```
npm init -y
```
プロジェクトを初期化したら、`webdriverio` をインストールします:
```
npm install webdriverio
```
#### セッションの初期化
ここで `index.js` という名前のテストファイルを作成し、
クライアントオブジェクトを初期化します:
```js
// javascript
const wdio = require("webdriverio");
```
次にやるべきことは、Appium セッションを開始することです。
これを行うには、サーバーオプションと Desired Capabilities のセットを定義し、
それらを使って `wdio.remote()` を呼び出します。
Desired Capabilities は、セッションの初期化中に Appium サーバーに送信されるキーと値の集合で、
どのようなことを自動化したいかを Appium に伝えます。
どのような Appium ドライバでも、以下の項目が必要な capabilities の最小セットになります。
- `platformName`: 自動化するプラットフォームの名前
- `platformVersion`: 自動化するプラットフォームのバージョン
- `deviceName`: 自動化するデバイスの種類
- `app`: 自動化したいアプリへのパス (ただし、Web ブラウザを自動化する場合は代わりに
`browserName` capability を使用します)
- `automationName`: 使用するドライバーの名前
Desired Capabilities の詳細と、
Appium で使用できるすべての機能のリストについては、
[Capabilities doc](/docs/en/writing-running-appium/caps.md)を参照してください。
ここでは、以下のテストファイルでセッションを構築する方法を説明します:
```js
// javascript
const opts = {
path: '/wd/hub',
port: 4723,
capabilities: {
platformName: "Android",
platformVersion: "8",
deviceName: "Android Emulator",
app: "/path/to/the/downloaded/ApiDemos-debug.apk",
appPackage: "io.appium.android.apis",
appActivity: ".view.TextFields",
automationName: "UiAutomator2"
}
};
async function main () {
const client = await wdio.remote(opts);
await client.deleteSession();
}
main();
```
#### テストコマンドの実行
Appium ポートを指定し、要件に一致するように Desired Capabilities を構築したことがわかります
(ただし、パスをあなたのシステムの実際のダウンロードパスに置き換えることを忘れないでください)。
この事実を `webdriverio` に登録して、
Appium サーバーへの接続を表すクライアントオブジェクトができました。
ここから先に進み、セッションを開始し、いくつかのテストコマンドを実行し、セッションを終了することができます。
ここでは、テキストフィールドに入力して、
正しいテキストが入力されたかどうかを確認します:
```js
// javascript
const field = await client.$("android.widget.EditText");
await field.setValue("Hello World!");
const value = await field.getText();
assert.strictEqual(value, "Hello World!");
```
ここで何が起こっているのかというと、セッションを作成してアプリを起動した後、
アプリ階層で要素を見つけて入力するように Appium に指示しています。
次に、同じフィールドにテキストを問い合わせ、
期待通りのテキストであることを主張します。
すべてをまとめると、ファイルは次のようになります:
```js
// javascript
const wdio = require("webdriverio");
const assert = require("assert");
const opts = {
path: '/wd/hub',
port: 4723,
capabilities: {
platformName: "Android",
platformVersion: "8",
deviceName: "Android Emulator",
app: "/path/to/the/downloaded/ApiDemos-debug.apk",
appPackage: "io.appium.android.apis",
appActivity: ".view.TextFields",
automationName: "UiAutomator2"
}
};
async function main () {
const client = await wdio.remote(opts);
const field = await client.$("android.widget.EditText");
await field.setValue("Hello World!");
const value = await field.getText();
assert.strictEqual(value,"Hello World!");
await client.deleteSession();
}
main();
```
このテストを自分で実行してみることができます。
保存して `node` を使って実行するだけです:
```
node index.js
```
すべてが正しく設定されている場合、
Appium がたくさんのログを吐き出し始め、
最終的にはアプリが画面上にポップアップし、見えないユーザーがタップしているかのように動作を開始するのがわかります。
### 次は何をするか
Appium でできることについては、まだ表面上のことに過ぎません。
これらのリソースをチェックして、あなたの旅に役立たせてください:
- Appium [コマンドリファレンス](https://appium.io/docs/en/commands/status/) - どのようなコマンドが利用可能か、特定のクライアントライブラリでの使用方法などについて学びます
- [サンプルコード](https://github.com/appium/appium/tree/master/sample-code) ディレクトリには、他にもたくさんのコードサンプルがあります
- [discuss.appium.io](https://discuss.appium.io) - これは Appium コミュニティのフォーラムです。バグに遭遇したかもしれないと思った場合、または始めるための助けを得るために最初に行くのに最適な場所です
- Appium [不具合トラッカー](https://github.com/appium/appium/issues) - バグを見つけたと思ったら、Appium メンテナに知らせてください
-138
View File
@@ -1,138 +0,0 @@
## Appium 入門
Appium は、iOS モバイル、Android モバイル、Windows デスクトッププラットフォーム上の
ネイティブ、モバイル Web、ハイブリッドアプリケーションを自動化するためのオープンソースツールです。
**ネイティブアプリ**とは、iOS、Android、または Windows SDK を使用して開発されたアプリのことです。
**モバイル Web アプリ**は、モバイルブラウザを使用してアクセスする Web アプリです (Appium は、iOS では Safari、Android では Chrome または標準の Browser アプリをサポートしています)。
**ハイブリッドアプリ**は、Web コンテンツとのインタラクションを可能にする標準的な仕組みである「WebView」のラッパーを持っています。
[Apache Cordova](https://cordova.apache.org) のようなプロジェクトでは、
Web 技術を使用してアプリを簡単に構築することができ、
それをネイティブのラッパーにバンドルしてハイブリッドアプリを作成することができます。
重要なことは、Appium は「クロスプラットフォーム」であるということです。
つまり、同じ API を使用して、複数のプラットフォーム (iOS、Android、Windows) に対してテストを書くことができます。
これにより、iOS、Android、Windows のテストスイート間でコードを再利用することができます。
Appium がそのプラットフォームを「サポート」することの意味、
および自動化の様式についての具体的な情報は、
[プラットフォームサポートドキュメント](/docs/ja/about-appium/platform-support.md)を参照してください。
### Appium の理念
Appium は、次の4つの信条によって概説された理念に従って、
モバイルオートメーションのニーズを満たすように設計されました。
1. アプリを自動化するために、
アプリを再コンパイルしたり、修正したりする必要はありません
2. テストを書いて実行するために、
特定の言語やフレームワークに縛られるべきではありません
3. モバイルオートメーションフレームワークは、
自動化 API に関しては、車輪の再発明をしてはいけません
4. モバイルオートメーションフレームワークは、名前だけでなく、
精神的にも実践的にもオープンソースでなければなりません!
### Appium のデザイン
では、Appium プロジェクトの構造はどのようにしてこの理念を実現しているのでしょうか?
ベンダーが提供する自動化フレームワークを基盤に利用することで、要件 1 を満たしています。
この方法では、Appium 固有のコードやサードパーティのコードやフレームワークをアプリに組み込む必要はありません。
つまり、**出荷するアプリと同じアプリをテストしていることになります**。
使用しているベンダー提供のフレームワークは以下の通りです。
* iOS 9.3 以上: Apple の [XCUITest](https://developer.apple.com/reference/xctest)
* iOS 9.3 以下: Apple の [UIAutomation](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
* Android 4.3 以上: Google の [UiAutomator/UiAutomator2](https://developer.android.com/training/testing/ui-automator)
* Windows: Microsoft の [WinAppDriver](http://github.com/microsoft/winappdriver)
ベンダーが提供するフレームワークを
[WebDriver](http://docs.seleniumhq.org/projects/webdriver/) API という1つの API でラップすることで要件 2 を満たしています。
WebDriver (別名 "Selenium WebDriver") は、([JSON Wire Protocol](https://w3c.github.io/webdriver/webdriver-spec.html) として知られる)
クライアント - サーバープロトコルを指定します。
このクライアント - サーバーアーキテクチャを考えると、任意の言語で書かれたクライアントを使用して、
適切な HTTP リクエストをサーバーに送信することができます。
既に[あらゆる一般的なプログラミング言語で書かれたクライアント](http://appium.io/downloads)
が存在します。
これはまた、好きなテストランナーやテストフレームワークを
自由に使用できることを意味します。
言い換えれば、Appium と WebDriver クライアントは技術的には「テストフレームワーク」ではなく、
「自動化ライブラリ」です。
テスト環境を
好きなように管理することができます。
同様に要件 3 を満たしています。
WebDriver は、Web ブラウザを自動化するためのデファクトスタンダードとなっており、
[W3C のワーキングドラフト](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html)です。
なぜモバイル用に全く違うことをするのでしょうか?
その代わりに、モバイルの自動化に役立つ API メソッドを追加して
[プロトコルを拡張](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)しました。
要件 4 が与えられたものであることは明らかなはずです。
あなたがこれを読んでいるのは、[Appium がオープンソース](https://github.com/appium/appium)だからです。
### Appium の概念
#### **クライアント/サーバー アーキテクチャ**
Appium は、REST API を公開する Web サーバーです。
クライアントからの接続を受信し、コマンドを待ち受け、
モバイル デバイス上でそれらのコマンドを実行し、コマンドの実行結果を表す HTTP レスポンスで応答します。
クライアント/サーバー アーキテクチャがあるという事実は、多くの可能性を開きます。
HTTP クライアントの API を持つどの言語でもテストコードを書くことができますが、
[Appium クライアントライブラリ](http://appium.io/downloads)の 1 つを使用する方が簡単です。
テストが実行されているマシンとは別のマシンにサーバーを置くことができます。
テストコードを書き、コマンドを受信して解釈するために
[Sauce Labs](https://saucelabs.com/products/mobile-app-testing) や [LambdaTest](https://www.lambdatest.com/feature) のようなクラウドサービスに頼ることもできます。
#### **セッション**
オートメーションは常にセッションのコンテキストで実行されます。
クライアントはそれぞれのライブラリに固有の方法でサーバーとのセッションを開始しますが、
最終的にはサーバーに `POST /session` リクエストを送信し、'desired capabilities' オブジェクトと呼ばれる JSON オブジェクトを送信します。
この時点で、サーバーはオートメーションセッションを起動し、
さらにコマンドを送信するために使用されるセッション ID で応答します。
#### **Desired capabilities**
Desired capabilities とは、どのような種類の自動化セッションの起動に興味があるかをサーバーに伝えるために、
Appium サーバーに送られるキーと値のセット (すなわち、マップやハッシュ) です。
また、自動化中にサーバーの動作を変更できる様々な機能があります。
例えば、Android や Windows のセッションではなく、
iOS のセッションが必要であることを Appium に伝えるために、
`platformName` capability を `iOS` に設定することができます。
また、Safari の自動化セッション中に JavaScript を使用して新しいウィンドウを開くことができるようにするために、
`safariAllowPopups` の capability を `true` に設定することもできます。
Appium で利用可能な機能の完全なリストについては、[capabilities のドキュメント](/docs/en/writing-running-appium/caps.md) を参照してください。
#### **Appium サーバー**
Appium は Node.js で書かれたサーバーです。
ソースからビルドしてインストールすることもできますし、
[NPM](https://www.npmjs.com/package/appium) から直接インストールすることもできます。
```
$ npm install -g appium
$ appium
```
Appium の `ベータ版` は `npm install -g appium@beta` で NPM 経由で公開されています。
開発版なので、変更点があるかもしれません。
新しいバージョンをインストールする前に
`appium@beta` をアンインストールしてください (`npm uninstall -g appium@beta`)。
#### **Appium クライアント**
WebDriver プロトコルへの Appium の拡張をサポートする
クライアントライブラリ (Java、Ruby、Python、PHP、JavaScript、および C#) があります。
Appium を使用する場合は、
通常の WebDriver クライアントの代わりにこれらのクライアントライブラリを使用します。
ライブラリの完全なリストは[ここ](/docs/en/about-appium/appium-clients.md)で見ることができます。
#### **[Appium デスクトップ](https://github.com/appium/appium-desktop)**
Appium サーバーの GUI ラッパーがあり、どのプラットフォーム用にもダウンロードできます。
Appium サーバーを実行するために必要なすべてのものがバンドルされているので、
Node について心配する必要はありません。
また、インスペクタが付属しており、アプリの階層をチェックアウトすることができます。
これはテストを書くときに便利です。
### はじめに
おめでとうございます!
これで、Appium の使用を開始するのに十分な知識が身につきました。
より詳細な要件と指示のために、
[始め方のドキュメント](/docs/en/about-appium/getting-started.md) をご覧になってみてはいかがでしょうか?
@@ -1,97 +0,0 @@
## Appium プラットフォームのサポート
Appium は、さまざまなプラットフォームとテストの様式
(ネイティブ、ハイブリッド、Web、リアルデバイス、シミュレータなど) をサポートしています。
このドキュメントは、これらのそれぞれのサポートレベルと要件を明示するように設計されています。
もしくは、それぞれの適切なページへ案内します。
## Appium team support
以下はAppiumの開発チームによりサポートされるドライバーです。
### iOS のサポート
iOS の自動化は2つのドライバーでサポートされています:
* [XCUITest Driver](/docs/en/drivers/ios-xcuitest.md)
* (非推奨) [UIAutomation Driver](/docs/en/drivers/ios-uiautomation.md)
* [safaridriver](/docs/en/drivers/safari.md) は Apple の [safaridriver](https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari?language=objc)
設定方法については、これらのドライバーのドキュメントを参照してください。
* バージョン: 12.2 以上 (原則として、Appium は iOS の最新バージョン2つをサポートしています)
* デバイス: iPhone、iPad、tvOS 用のシミュレータと実機
* ネイティブアプリのサポート: はい、デバッグバージョンの .app (シミュレータ)
または正しく署名された .ipa (実機) を使用しています。
基本的なサポートは、Apple の [XCUITest](https://developer.apple.com/reference/xctest) (古いバージョンでは [UIAutomation](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)) フレームワークによって
提供されています
* モバイル Web のサポート: はい、モバイル Safari の自動化機構を経由できます。
手順については、[モバイル Web ドキュメント](/docs/en/writing-running-appium/web/mobile-web.md)を参照してください
* ハイブリッドサポート: はい。
手順については、[ハイブリッドドキュメント](/docs/en/writing-running-appium/web/hybrid.md)を参照してください
* 1つのセッションで複数のアプリの自動化をサポート: いいえ
* 複数のデバイスの同時自動化のサポート: はい
* ベンダー提供またはサードパーティ製アプリの自動化をサポート: はい。予め端末にインストールされている必要があります。
* カスタムの非標準 UI コントロールの自動化のサポート: 最小限の設定です。
基本的な自動化を可能にするコントロールに
アクセシビリティ情報を設定する必要があります
### Android のサポート
Android の自動化は2つのドライバーでサポートされています:
* [UiAutomator2 Driver](/docs/en/drivers/android-uiautomator2.md)
* [Espresso Driver](/docs/en/drivers/android-espresso.md)
* (非推奨) [UiAutomator Driver](/docs/en/drivers/android-uiautomator.md)
* Firefox や [GeckoView](https://wiki.mozilla.org/Mobile/GeckoView) 向けの [geckodriver](/docs/en/drivers/gecko.md)
設定方法については、これらのドライバーのドキュメントを参照してください。
* バージョン: 4.3 以上
* バージョン 4.3 以降は、Appium の [UiAutomator と UiAutomator2](http://developer.android.com/tools/testing-support-library/index.html#UIAutomator) ライブラリを介してサポートされています。
UiAutomator はデフォルトのドライバーです
* デバイス: Android エミュレータと実機の Android 端末
* ネイティブアプリのサポート: はい
* モバイル Web のサポート: はい。自動化は、バンドルされている [Chromedriver](http://chromedriver.chromium.org) サーバーを
プロキシとして使用して行われます。
4.3 では、公式の Chrome ブラウザまたは Chromium 上でのみ自動化が動作します。
4.4 以上では、自動化は標準の「ブラウザ」アプリでも動作します。
Chrome / Chromium / Browser がテスト対象のデバイスに既にインストールされている必要があります。
手順については、[モバイル Web ドキュメント](/docs/en/writing-running-appium/web/mobile-web.md)を参照してください
* ハイブリッドサポート: はい。[ハイブリッドドキュメント](/docs/en/writing-running-appium/web/hybrid.md)を参照してください
* デフォルトの Appium オートメーションバックエンドを使用した場合: バージョン 4.4 以降
* 1つのセッションで複数のアプリの自動化をサポート: はい
* 複数のデバイスの同時自動化のサポート: はい。
ただし、Appium はサーバーパラメータ `--port`、`--bootstrap-port` や `--chromedriver-port` に対して
異なるポートを使用して起動しなければなりません。
これらのパラメータの詳細については
[サーバー引数のドキュメント](/docs/en/writing-running-appium/server-args.md) を参照してください
* ベンダー提供またはサードパーティ製アプリの自動化をサポート: はい
* カスタムの非標準 UI コントロールの自動化のサポート: いいえ
### macOS サポート
macOS の自動化は以下のドライバーによってサポートされます。
* macOS 10.15 以上 [Mac2Driver](/docs/en/drivers/mac2.md)
* macOS 10.15 未満 (非推奨) [MacDriver](/docs/en/drivers/mac.md)
### Windows デスクトップのサポート
Windows の自動化は以下のドライバーによってサポートされます。
* [WinAppDriver](/docs/en/drivers/windows.md)
* Firefox と [GeckoView](https://wiki.mozilla.org/Mobile/GeckoView) は [geckodriver](/docs/en/drivers/gecko.md)
## ベンダー/コミュニティー
以下はベンダーやコミュニティーによってサポートされるドライバーです。
### You.i Engine Support
* [You.i Engine](https://github.com/YOU-i-Labs/appium-youiengine-driver)
### Flutter Support
* [Flutter Driver](https://github.com/truongsinh/appium-flutter-driver)

Some files were not shown because too many files have changed in this diff Show More