Compare commits

..
Author SHA1 Message Date
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
709 changed files with 1816 additions and 110956 deletions
-9
View File
@@ -1,9 +0,0 @@
**/coverage/**
**/node_modules/**
examples/javascript-wd
**/build/**
**/*.min.js
sample-code
**/*.d.ts
**/build-fixtures/**
**/*.ts
-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`"
}
]
}
}
]
}
-40
View File
@@ -1,40 +0,0 @@
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
# Visit https://fossa.com to learn more
version: 3
project:
id: github.com/appium/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
revision:
branch: 2.0
-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](https://cla.js.foundation/appium/appium)
- [ ] 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
-61
View File
@@ -1,61 +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@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # 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 tests
uses: boneskull/nodejs-production-test-action@v1
with:
script: test:smoke
workspaces: true
quiet: true
- name: Run unit & E2E tests
run: npm run test:ci
lint:
name: Lint & Check Types
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Install dependencies
run: npm install
- 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@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Install dependencies
run: npm install
- 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@2fddd8803e2f5c9604345a0b591c3020ee971a93 # 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
-24
View File
@@ -1,24 +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@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
with:
ref: '2.0'
- name: fossa analyze
run: |
npm install
curl -sS -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash
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'],
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-2013 Appium Committers
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+33 -233
View File
@@ -1,252 +1,52 @@
## Appium
appium-doctor
===================
[![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=sebv-doctor-who)](https://coveralls.io/r/appium/appium-doctor?branch=sebv-doctor-who)
[![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. 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.
### Drivers
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.
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
```
npm install appium-doctor -g
```
#### Drivers Maintained By The Appium Team
### Usage
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.
```
➜ appium-doctor -h
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.
Usage: appium-doctor.js [options, defaults: --ios --android]
#### 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/)
</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
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]
```
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):
## Dev
```bash
appium server --use-plugins=device-farm,images
## Watch
```
npm run watch
```
#### Plugins Maintained By The Appium Team
## Test
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.
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.
</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
```
npm test
```
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.
## Hack Cli
### Why Appium?
Use the `--demo` option to simulate the fix process.
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.
```
appium-doctor --demo
```
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
the recent [LTS](https://nodejs.org/en/about/releases/) Node.js version.
### 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)
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", "@babel/plugin-transform-runtime"],
"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();
Binary file not shown.
-40
View File
@@ -1,40 +0,0 @@
# parameters: # No params yet, but may add later
jobs:
- job: generate_docs
pool:
vmImage: "macOS 10.14"
variables:
CC: gcc
CXX: g++
steps:
- task: NodeTool@0
inputs:
versionSpec: '12.x'
- script: |
# do git stuff
npm install
brew install hub
hub --version
git remote add triager https://triager:$GITHUB_TOKEN@github.com/appium/appium
git checkout -b generate-docs-$BUILD_SOURCEVERSION
git status
displayName: Checkout Generate Docs Branch
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
- script: |
# Generate the docs
npm run generate-docs
git add .
# log the status so we know what is going on, on failure
git status -s
# If docs were generated, make a PR to update the docs
if [[ -n $(git status -s) ]]; then
git commit -a -n -m 'Update generated docs [ci skip]'
git push triager generate-docs-$BUILD_SOURCEVERSION
hub pull-request -b "appium:master" -h "appium:generate-docs-$BUILD_SOURCEVERSION" -m "docs: Update auto-generated docs"
fi
displayName: Generate Docs and Make PR
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
-2
View File
@@ -1,2 +0,0 @@
jobs:
- template: templates/bundle-template.yml
-3
View File
@@ -1,3 +0,0 @@
const semver = require('semver');
const {version} = require('../../package.json');
console.log(semver(version).prerelease[0]); //eslint-disable-line no-console
@@ -1,22 +0,0 @@
const path = require('path');
const {fs, logger} = require('appium-support');
const {asyncify} = require('asyncbox');
const packageJson = require('../../package.json');
const log = new logger.getLogger('Create Release Branch:');
async function setPackageJsonVersion(version = `${process.env.MINOR_BRANCH_NAME}.0-rc.0`) {
packageJson.version = version;
log.info(`Setting version to: ${version}`);
await fs.writeFile(
path.resolve(__dirname, '..', '..', 'package.json'),
JSON.stringify(packageJson, null, 2),
'utf8'
);
}
if (require.main === module) {
asyncify(setPackageJsonVersion);
}
module.exports = setPackageJsonVersion;
-40
View File
@@ -1,40 +0,0 @@
# parameters: # No params yet, but may add later
jobs:
- job: bundle_and_upload_appium_zip
pool:
vmImage: 'macOS 10.14'
variables:
CC: gcc
CXX: g++
steps:
- script: gcc --version
displayName: Print GCC Version
- task: NodeTool@0
inputs:
versionSpec: '12.x'
- script: npm install
displayName: Install NPM Dependencies
- script: npm run build
displayName: npm run build
- script: npm prune --production
displayName: Get rid of dev dependencies
- script: |
curl -o node-darwin.tar.gz https://nodejs.org/dist/v12.16.1/node-v12.16.1-darwin-x64.tar.gz
mkdir node-darwin-unpacked
tar -xzf node-darwin.tar.gz -C node-darwin-unpacked/ --strip-components 1
rm -f node-darwin.tar.gz
cp node-darwin-unpacked/bin/node node-darwin
rm -rf node-darwin-unpacked
displayName: Download NodeJS
- script: npm run zip
displayName: Create the bundle zip
- script: npm install
displayName: Reinstall dev dependencies
- task: PublishPipelineArtifact@0
inputs:
targetPath: appium.zip
artifactName: appium
- script: npm run upload
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
displayName: Upload to appium/appium-build-store Github Releases
-31
View File
@@ -1,31 +0,0 @@
# parameters: # No params yet, but may add later
jobs:
- job: update_appium_io
pool:
vmImage: 'Ubuntu-18.04'
variables:
CC: gcc
CXX: g++
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
- script: |
pip install mkdocs==0.16.3
git config --global user.email "maintainers@appium.io"
git config --global user.name "Appium Triager"
git clone https://triager:$GITHUB_TOKEN@github.com/appium/appium.io.git --branch=gh-pages
pushd appium.io
git remote add triager https://triager:$GITHUB_TOKEN@github.com/appium/appium.io
git checkout -b docs-$BUILD_SOURCEVERSION
bundle install
npm install
npm run build:docs
git add docs
git commit -a -n -m "docs: Update documentation for latest version"
git push triager docs-$BUILD_SOURCEVERSION
hub pull-request -b "appium:gh-pages" -h "appium:docs-$BUILD_SOURCEVERSION" -m "docs: Update documentation for latest version"
popd
displayName: Make branch with Updated Docs and make PR
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
-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"]
}
}
-10
View File
@@ -1,10 +0,0 @@
{
"compilerOptions": {
"paths": {
"appium": ["../packages/appium"]
},
"types": ["webdriverio/async"]
},
"extends": "./tsconfig.base.json",
"references": [{"path": "../packages/appium"}, {"path": "../packages/base-plugin"}, {"path": "../packages/types"}]
}
-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"
}
+65
View File
@@ -0,0 +1,65 @@
import { fs } from './utils';
import { DoctorCheck } from './doctor';
import { ok, nok } from './utils';
import { 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;
+18 -20
View File
@@ -1,35 +1,34 @@
// 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 { fs, ok, nok } from './utils';
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}`;
}
}
}
checks.push(new DirCheck('/tmp/appium-doctor'));
checks.push(new DirCheck('/tmp/appium-doctor/demo'));
@@ -40,12 +39,11 @@ class FileCheck extends DoctorCheck {
}
async diagnose() {
return (await fs.exists(this.path))
? ok(`Found file at: ${this.path}`)
: nok(`Could NOT find file at '${this.path}'!`);
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 +59,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;
+71
View File
@@ -0,0 +1,71 @@
import { fs } from './utils';
import { exec } from 'teen_process';
import { DoctorCheck } from './doctor';
import { ok, nok } from './utils';
import { 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;
+149
View File
@@ -0,0 +1,149 @@
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`] || []);
}
}
+153
View File
@@ -0,0 +1,153 @@
import { fs, macOsxVersion, ok, nok } from './utils';
import authorize from 'authorize-ios';
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 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());
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 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;
+97
View File
@@ -0,0 +1,97 @@
import { fs } from './utils';
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',
];
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;
+13 -14
View File
@@ -1,31 +1,29 @@
import {inquirer} from './utils';
import { inquirer } from './utils';
let persistentResponse;
const fixItQuestion = {
type: 'list',
name: 'confirmation',
message: 'Fix it:',
choices: ['yes', 'no', 'always', 'never'],
filter(val) {
return val.toLowerCase();
},
type: "list",
name: "confirmation",
message: "Fix it:",
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,5 @@ async function fixIt() {
return persistentResponse || resp.confirmation;
}
export {configure, fixIt, clear};
export { configure, fixIt, clear };
+51
View File
@@ -0,0 +1,51 @@
import B from 'bluebird';
import _fs from 'fs';
import path from 'path';
import _inquirer from 'inquirer';
import { exec } from 'teen_process';
import log from '../lib/logger';
let pkgRoot = process.env.NO_PRECOMPILE ?
path.resolve(__dirname, '..') : path.resolve(__dirname, '..', '..');
let fs = {
readFile: B.promisify(_fs.readFile),
exists: B.promisify((f, cb) => {
_fs.exists(f, function (res) { cb(null, res);});
}),
lstat: B.promisify(_fs.lstat)
};
async function macOsxVersion () {
// TODO: move this to appium-support
let stdout;
try {
stdout = (await exec('sw_vers', ['-productVersion'])).stdout;
} catch (err) {
throw new Error("Unknown SW Version Command: " + err);
}
for (let v of ['10.8', '10.9', '10.10', '10.11']) {
if (stdout.indexOf(v) === 0) { return v; }
}
throw new Error("Could not detect Mac OS X Version");
}
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, prefix, message) {
let l = this.levels[level];
if (l < this.levels[this.level]) return;
console.log(message);
};
log.level = opts.debug ? 'debug' : 'info';
}
export { pkgRoot, fs, macOsxVersion, ok, nok, inquirer, configureBinaryLog};
-44779
View File
File diff suppressed because it is too large Load Diff
+41 -157
View File
@@ -1,171 +1,55 @@
{
"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": "0.0.5",
"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",
"install-fake-driver": "npm start -- driver install --source=local ./packages/fake-driver",
"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 install-fake-driver test:unit test:ci:e2e",
"test:ci:e2e": "lerna run test:e2e",
"test:e2e": "lerna run --parallel --max-buffer=128 test:e2e",
"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"
]
"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/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/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": "^1.1.5",
"appium-support": "^1.1.1",
"authorize-ios": "^1.0.0",
"babel-runtime": "=5.6.15",
"bluebird": "^2.9.30",
"colors": "^1.1.2",
"inquirer": "^0.8.5",
"lodash": "^3.9.3",
"source-map-support": "^0.3.1",
"teen_process": "^1.2.2",
"yargs": "^3.14.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.18.9",
"@babel/core": "7.18.9",
"@babel/eslint-parser": "7.18.9",
"@babel/plugin-transform-runtime": "7.18.9",
"@babel/preset-env": "7.18.9",
"@babel/register": "7.18.9",
"@babel/runtime": "7.18.9",
"@colors/colors": "1.5.0",
"@types/chai": "4.3.1",
"@types/chai-as-promised": "7.1.5",
"@types/mocha": "9.1.1",
"@types/node": "16.11.46",
"@types/semver": "7.3.10",
"@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": "7.32.0",
"eslint-config-prettier": "8.5.0",
"eslint-find-rules": "4.1.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-mocha": "9.0.0",
"eslint-plugin-promise": "6.0.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",
"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.0",
"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.20.7",
"ws": "8.8.1",
"yaml-js": "0.3.1"
},
"engines": {
"node": ">=14",
"npm": ">=6"
},
"publishConfig": {
"access": "public"
},
"workspaces": [
"packages/*"
]
"appium-gulp-plugins": "^1.2.12",
"appium-test-support": "0.0.2",
"chai": "^3.0.0",
"chai-as-promised": "^5.1.0",
"gulp": "^3.8.11",
"mochawait": "^2.0.0",
"sinon": "~1.14.1",
"uncolor": "^0.3.0"
}
}
-361
View File
@@ -1,361 +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.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
-5
View File
@@ -1,5 +0,0 @@
---
title: Server CLI Args
---
TODO
@@ -1,5 +0,0 @@
---
title: The Extension CLI
---
TODO
-5
View File
@@ -1,5 +0,0 @@
---
title: CLI Intro
---
TODO
@@ -1,5 +0,0 @@
---
title: Contributing to Appium
---
TODO
@@ -1,5 +0,0 @@
---
title: Building Docs for Appium Extensions
---
TODO
@@ -1,684 +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 do this you define a `schema` field within the `appium` field in `package.json`, pointing to
a JS or JSON file defining an argument schema. (See the schema in `fake-driver`, for example).
Arguments you define there will be available as a `--driver-<name>-<arg-name>` flag on the command
line. If you define `my-arg` in the schema, for example, and if your driver's name is `awesome`,
then users will be able to set your arg via `--driver-awesome-my-arg`.
### 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
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. A common driver pattern is to create a magic prefix which
the driver looks for at the beginning of any Execute Script invocation, and if it's present, to
treat the rest of the script string as the name of a custom command to execute. This works in large
part because for most platforms beyond web browsers, executing arbitrary JavaScript isn't a thing
that makes sense.
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
driver.executeScript('soundz: playSong', [{song: 'Stairway to Heaven', artist: 'Led Zeppelin'}]);
```
Then in your driver code you could simply look for `soundz:` at the beginning of your
`execute` override, and do the appropriate thing:
```js
async execute(script, args) {
if (script === 'soundz: playSong') {
const {song, artist} = args[0];
// play the song based on song and artist details
return;
}
// otherwise do the normal thing, or throw errors.NotYetImplementedError if you have nothing to
// do (see the section on WebDriver errors in this guide)
}
```
### 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.
-5
View File
@@ -1,5 +0,0 @@
---
title: Capabilities
---
TODO
-5
View File
@@ -1,5 +0,0 @@
---
title: The Appium Config File
---
TODO
@@ -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,5 +0,0 @@
---
title: Migrating from Appium 1.x to Appium 2.x
---
TODO
@@ -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.
-5
View File
@@ -1,5 +0,0 @@
---
title: Intro to Appium Clients
---
TODO
-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.

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