mirror of
https://github.com/appium/appium.git
synced 2026-11-11 12:37:21 +08:00
Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
172a739904 | ||
|
|
a781c8f232 | ||
|
|
72c3d02ae2 | ||
|
|
3bef783bc5 | ||
|
|
2b1929768f | ||
|
|
861193e39b | ||
|
|
4a9b23889a | ||
|
|
d30edd49cb | ||
|
|
3afeb76e88 | ||
|
|
925d5998ba | ||
|
|
48882df199 | ||
|
|
d7e0ef76a3 | ||
|
|
b8e78c8449 | ||
|
|
97ed6be4d9 | ||
|
|
3cdfecae7d | ||
|
|
43992824a4 | ||
|
|
db036e9ea8 | ||
|
|
51eee6e4f2 | ||
|
|
7c0b9cf861 | ||
|
|
9137040334 | ||
|
|
9d4606cb21 | ||
|
|
299cc6ce7a | ||
|
|
b8af2e11d1 | ||
|
|
d6e1abdb2a | ||
|
|
486c0e7448 | ||
|
|
ccfb631e21 | ||
|
|
14663fbbd3 | ||
|
|
1f5c6a7010 |
@@ -1,13 +0,0 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -1,11 +0,0 @@
|
||||
**/coverage/**
|
||||
**/node_modules/**
|
||||
examples/javascript-wd
|
||||
**/build/**
|
||||
**/*.min.js
|
||||
sample-code
|
||||
**/*.d.ts
|
||||
**/build-fixtures/**
|
||||
**/*.ts
|
||||
packages/appium/docs/**/assets/**
|
||||
**/*.tsx
|
||||
@@ -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`"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
|
||||
# Visit https://fossa.com to learn more
|
||||
|
||||
version: 3
|
||||
|
||||
project:
|
||||
id: appium
|
||||
name: appium
|
||||
|
||||
paths:
|
||||
exclude:
|
||||
- ./sample-code
|
||||
- '**/fixtures/**'
|
||||
- '**/demo/**'
|
||||
- '**/example/**'
|
||||
- '**/examples/**'
|
||||
|
||||
targets:
|
||||
only:
|
||||
- type: npm
|
||||
path: .
|
||||
- type: npm
|
||||
path: ./packages/appium
|
||||
- type: npm
|
||||
path: ./packages/base-driver
|
||||
- type: npm
|
||||
path: ./packages/doctor
|
||||
- type: npm
|
||||
path: ./packages/eslint-config-appium
|
||||
- type: npm
|
||||
path: ./packages/fake-driver
|
||||
- type: npm
|
||||
path: ./packages/support
|
||||
- type: npm
|
||||
path: ./packages/test-support
|
||||
- type: npm
|
||||
path: ./packages/types
|
||||
- type: npm
|
||||
path: ./packages/schema
|
||||
- type: npm
|
||||
path: ./packages/universal-xmlplugin
|
||||
- type: npm
|
||||
path: ./packages/opencv
|
||||
- type: npm
|
||||
path: ./packages/images-plugin
|
||||
- type: npm
|
||||
path: ./packages/base-plugin
|
||||
- type: npm
|
||||
path: ./packages/relaxed-caps-plugin
|
||||
- type: npm
|
||||
path: ./packages/fake-plugin
|
||||
- type: npm
|
||||
path: ./packages/docutils
|
||||
|
||||
revision:
|
||||
- branch: master
|
||||
@@ -1,4 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
# Handle as a text file but merge as binary.
|
||||
package-lock.json merge=binary
|
||||
@@ -1,80 +0,0 @@
|
||||
name: 🐞 Bug Report
|
||||
description: File a new bug report
|
||||
title: 'bug: <title>'
|
||||
labels: [Bug, Needs Triage]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: ':stop_sign: _For support questions, please visit [http://discuss.appium.io](http://discuss.appium.io) instead._'
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 'Is there an existing issue for this?'
|
||||
description: 'Please [search :mag: the issues](https://github.com/appium/appium/issues) to check if this bug has already been reported.'
|
||||
options:
|
||||
- label: 'I have searched the existing issues'
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Current Behavior'
|
||||
description: 'Describe the problem you are experiencing. **Please do not paste your logs here.** Screenshots are welcome.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Expected Behavior'
|
||||
description: 'Describe what you expect to happen instead.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Minimal Reproducible Example'
|
||||
description: |
|
||||
Please provide a the _smallest, complete code snippet_ that Appium's maintainers can run to reproduce the issue ([read more about what this entails](https://stackoverflow.com/help/minimal-reproducible-example)). Failing this, any sort of reproduction steps are better than nothing!
|
||||
|
||||
An easy way to get started is to copy [sample code](https://github.com/appium/appium/tree/master/packages/appium/sample-code) and modify it accordingly.
|
||||
|
||||
If the result is more than a screenful of text _or_ requires multiple files, please:
|
||||
|
||||
- _Attach_ (do not paste) it to this textarea, _or_
|
||||
- Put it in a [Gist](https://gist.github.com) and paste the link, _or_
|
||||
- Provide a link to a new or existing public repository exhibiting the issue
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Environment'
|
||||
description: 'Please provide the following information about your environment; feel free to remove any items which are not relevant.'
|
||||
value: |
|
||||
- Operating system:
|
||||
- If running via `appium` CLI...
|
||||
- Appium CLI version (output of `appium --version`):
|
||||
- Node.js version (output of `node --version`):
|
||||
- `npm` version (output of `npm --version`):
|
||||
- Last `appium` version which did _not_ exhibit the problem:
|
||||
- If running Appium Desktop, its version:
|
||||
- Appium driver(s) and their version(s):
|
||||
- Appium plugin(s) and their version(s):
|
||||
- Platform and version under test:
|
||||
- Real device or emulator/simulator:
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: 'Link to Appium Logs'
|
||||
description: |
|
||||
Create a [Gist](https://gist.github.com)—which contains your _full_ Appium logs—and link it here. Alternatively, you can attach a logfile to this issue (drag it into the "Further Information" field below).
|
||||
|
||||
:warning: _Remember to redact or remove any sensitive information!_
|
||||
placeholder: 'https://gist.github.com/...'
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Futher Information
|
||||
description: |
|
||||
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||
|
||||
_Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in._
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: ':stop_sign: _For support questions, please visit [http://discuss.appium.io](http://discuss.appium.io) instead._'
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[Feat]:"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -1,28 +0,0 @@
|
||||
## Proposed changes
|
||||
|
||||
Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
|
||||
|
||||
## Types of changes
|
||||
|
||||
What types of changes does your code introduce to Appium?
|
||||
_Put an `x` in the boxes that apply_
|
||||
|
||||
- [ ] Bugfix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Documentation Update (if none of the other choices apply)
|
||||
|
||||
## Checklist
|
||||
|
||||
_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
|
||||
|
||||
- [ ] I have read the [CONTRIBUTING](https://github.com/appium/appium/blob/master/CONTRIBUTING.md) doc
|
||||
- [ ] I have signed the CLA
|
||||
- [ ] Lint and unit tests pass locally with my changes
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] I have added necessary documentation (if appropriate)
|
||||
- [ ] Any dependent changes have been merged and published in downstream modules
|
||||
|
||||
## Further comments
|
||||
|
||||
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
|
||||
@@ -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
|
||||
@@ -1,47 +0,0 @@
|
||||
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@755da8c3cf115ac066823e79a1e1788f8940201b # v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- name: Install latest npm
|
||||
run: npm install -g npm
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@1a235c31658a322a3b024444759650ee6345c26d # tag=v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
install-command: npm ci --foreground-scripts
|
||||
- name: Run smoke, unit & E2E tests
|
||||
run: npm run test:ci
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@1a235c31658a322a3b024444759650ee6345c26d # tag=v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
install-command: npm ci --foreground-scripts
|
||||
- name: ESLint
|
||||
run: npm run lint
|
||||
- name: Validate Renovate Config
|
||||
uses: rinchsan/renovate-config-validator@1ea1e8514f6a33fdd71c40b0a5fa3512b9e7b936 # tag=v0
|
||||
with:
|
||||
pattern: '{.renovaterc.json,renovate/default.json}'
|
||||
@@ -1,58 +0,0 @@
|
||||
name: Appium Deploy
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
# node-version: [14.x, 16.x, 18.x]
|
||||
node-version: [16.x, 18.x]
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
steps:
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Appium
|
||||
run: |
|
||||
if [[ "$GITHUB_REF_TYPE" == tag ]]; then
|
||||
npm i -g $GITHUB_REF_NAME
|
||||
else
|
||||
npm i -g appium@next
|
||||
fi
|
||||
shell: bash
|
||||
- name: Install drivers and plugins
|
||||
run: |
|
||||
if grep -q macos <<< ${{ matrix.os }}; then
|
||||
appium driver install xcuitest
|
||||
fi
|
||||
appium driver install uiautomator2
|
||||
appium plugin install images
|
||||
shell: bash
|
||||
- name: Verify installation
|
||||
run: |
|
||||
installed_drivers=$(appium driver list --installed 2>&1)
|
||||
if grep -q macos <<< ${{ matrix.os }}; then
|
||||
grep -q xcuitest <<< $installed_drivers
|
||||
fi
|
||||
grep -q uiautomator2 <<< $installed_drivers
|
||||
installed_plugins=$(appium plugin list --installed 2>&1)
|
||||
grep -q images <<< $installed_plugins
|
||||
shell: bash
|
||||
- name: Verify Appium could be executed
|
||||
run: |
|
||||
appium --use-plugins=images &
|
||||
pid=$(echo $!)
|
||||
sleep 5
|
||||
ps -p $pid || exit 1
|
||||
kill -2 $pid
|
||||
shell: bash
|
||||
@@ -1,26 +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@755da8c3cf115ac066823e79a1e1788f8940201b # v3
|
||||
with:
|
||||
ref: master
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
|
||||
- name: Install fossa-cli
|
||||
run: ./scripts/install-fossa.sh -d
|
||||
- name: Run FOSSA analysis
|
||||
run: |
|
||||
fossa analyze
|
||||
fossa test
|
||||
env:
|
||||
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
|
||||
+3
-62
@@ -1,65 +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
|
||||
typedoc-docs
|
||||
packages/appium/docs/*/reference
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npm run lint:commit -- --edit ${1}
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npm run lint:staged
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"laxcomma": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"node": true,
|
||||
"eqeqeq": true,
|
||||
"trailing": true,
|
||||
"indent": 2,
|
||||
"esnext": true,
|
||||
"experimental": ["asyncawait"]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
'*.js': ['eslint --fix', 'prettier --write'],
|
||||
'*.ts': ['prettier --write'],
|
||||
'appium-config-schema.js': () => [
|
||||
'npm run --workspace=./packages/schema build',
|
||||
'git add -A packages/schema/lib/appium-config.schema.json',
|
||||
'npm run --workspace=./packages/types build',
|
||||
'git add -A packages/types/lib/appium-config.ts',
|
||||
],
|
||||
'!(package|package-lock)*.json': ['prettier --write'],
|
||||
};
|
||||
-12
@@ -1,12 +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,
|
||||
// increase default timeout for CI since it can be slow
|
||||
timeout: process.env.CI ? '5s' : '2s',
|
||||
};
|
||||
+2
-1
@@ -1 +1,2 @@
|
||||
tsconfig.tsbuildinfo
|
||||
node_modules
|
||||
*.log
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Do not disable package-lock. Disabling package-lock also disables npm-shrinkwrap
|
||||
package-lock=true
|
||||
save-exact=true
|
||||
foreground-scripts=true
|
||||
@@ -1,12 +0,0 @@
|
||||
**/node_modules/**
|
||||
**/build/**
|
||||
**/fixtures/**
|
||||
**/*.min.*
|
||||
**/*.md
|
||||
package-lock.json
|
||||
package.json
|
||||
**/.vscode/**
|
||||
**/*.html
|
||||
**/generated/**
|
||||
# generated
|
||||
packages/types/lib/appium-config.ts
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>appium/appium//renovate/default"],
|
||||
"schedule": ["after 10pm and before 5:00am"],
|
||||
"timezone": "America/Vancouver"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.12"
|
||||
after_success:
|
||||
- gulp coveralls
|
||||
Vendored
-62
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"args": [
|
||||
"--log-level=debug"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {
|
||||
"_FORCE_LOGS": "1"
|
||||
},
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"name": "Run Appium",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/appium",
|
||||
"request": "launch",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"type": "node"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--colors",
|
||||
"--no-timeout",
|
||||
"${file}"
|
||||
],
|
||||
"autoAttachChildProcesses": true,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"name": "Test Current File w/ Mocha",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/mocha",
|
||||
"request": "launch",
|
||||
"runtimeArgs": [
|
||||
"--require",
|
||||
"ts-node/register"
|
||||
],
|
||||
"skipFiles": [
|
||||
"<node_internals>/**",
|
||||
"**/node_modules/mocha/**",
|
||||
"**/node_modules/ts-node/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"type": "node"
|
||||
},
|
||||
{
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"name": "Typedoc",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/typedoc",
|
||||
"request": "launch",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"type": "node"
|
||||
}
|
||||
],
|
||||
"version": "0.2.0"
|
||||
}
|
||||
Vendored
-14
@@ -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
@@ -1,61 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (wallaby) => {
|
||||
return {
|
||||
compilers: {
|
||||
'**/*.js': wallaby.compilers.babel(),
|
||||
},
|
||||
debug: true,
|
||||
env: {
|
||||
type: 'node',
|
||||
},
|
||||
files: [
|
||||
'./packages/**/*.js',
|
||||
'./packages/**/*.json',
|
||||
'!./packages/**/build/**',
|
||||
'!./packages/**/test/**/*-specs.js',
|
||||
'!./packages/**/test/**/*.spec.js',
|
||||
'!./packages/*/node_modules/**',
|
||||
'!./packages/*/gulpfile.js',
|
||||
'!./packages/*/scripts/**',
|
||||
'./packages/*/test/**/fixtures/**/*',
|
||||
'./babel.config.json',
|
||||
// below this are fixtures
|
||||
{
|
||||
binary: true,
|
||||
pattern: './packages/support/test/unit/assets/sample_binary.plist',
|
||||
},
|
||||
{
|
||||
instrument: false,
|
||||
pattern: './packages/support/test/unit/assets/sample_text.plist',
|
||||
},
|
||||
{
|
||||
instrument: false,
|
||||
pattern: './packages/base-driver/static/**/*',
|
||||
},
|
||||
'!**/local_appium_home/**',
|
||||
],
|
||||
testFramework: 'mocha',
|
||||
tests: ['./packages/*/test/unit/**/*.spec.js', '!**/local_appium_home/**'],
|
||||
workers: {
|
||||
restart: true,
|
||||
},
|
||||
setup() {
|
||||
// This copied out of `./test/setup.js`, which uses `@babel/register`.
|
||||
// Wallaby doesn't need `@babel/register` (and it probably makes Wallaby slow),
|
||||
// but we need the other stuff, so here it is.
|
||||
|
||||
const chai = require('chai');
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
const sinonChai = require('sinon-chai');
|
||||
|
||||
// The `chai` global is set if a test needs something special.
|
||||
// Most tests won't need this.
|
||||
global.chai = chai.use(chaiAsPromised).use(sinonChai);
|
||||
|
||||
// `should()` is only necessary when working with some `null` or `undefined` values.
|
||||
global.should = chai.should();
|
||||
},
|
||||
runMode: 'onsave',
|
||||
};
|
||||
};
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
-48
@@ -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).
|
||||
@@ -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
@@ -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.
|
||||
@@ -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,192 +1,4 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright JS Foundation and other contributors, https://js.foundation
|
||||
Copyright 2012-2015 Sauce Labs, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,221 +1,53 @@
|
||||
## Appium
|
||||
appium-doctor
|
||||
===================
|
||||
Attempts to diagnose and fix common Node, iOS and Android configuration issues before starting Appium.
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://travis-ci.org/appium/appium-doctor)
|
||||
[](https://coveralls.io/github/appium/appium-doctor?branch=master)
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
|
||||
### Install
|
||||
|
||||
[](https://github.com/vshymanskyy/StandWithUkraine/)
|
||||
|
||||
[](https://vshymanskyy.github.io/StandWithUkraine/)
|
||||
|
||||
Appium is an open-source, cross-platform test automation tool for native,
|
||||
hybrid, mobile web and desktop apps. Initially created to automate iOS and Android mobile
|
||||
applications Appium has grown to a full-featured platform that provides [WebDriver](https://www.w3.org/TR/webdriver/)-based automation possibilities for the whole set of different mobile and desktop platforms.
|
||||
See [Drivers Maintained By The Appium Team](#drivers-maintained-by-the-appium-team)
|
||||
and [Drivers Provided By Third Parties](#drivers-provided-by-third-parties) sections below for more details.
|
||||
|
||||
:bangbang: Major documentation revision in progress
|
||||
|
||||
:bangbang: Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022. All recent versions of officially supported platform drivers are not compatible to Appium 1.x anymore, and require Appium 2 to run. [Please read the migration guide from 1.x to 2.0](https://github.com/appium/appium/blob/master/packages/appium/docs/en/guides/migrating-1-to-2.md) to manage the Appium server.
|
||||
|
||||
Appium is in the final stages of a major revision (to version 2.0). As such, the documentation
|
||||
found around the web may not be correct. The current Appium 2.0 documentation is very much in
|
||||
progress. Currently, it can be found [here](https://appium.github.io/appium/docs/en/2.0/).
|
||||
|
||||
### Requirements
|
||||
|
||||
- macOS, Linux or Windows operating system
|
||||
- Node.js 14+
|
||||
- NPM (Node Package Manager) 8+
|
||||
|
||||
These are only server requirements. Each driver might have its own requirements. Consider checking the corresponding driver tutorial for more details.
|
||||
|
||||
### Server
|
||||
|
||||
To install Appium 2 server using Node Package Manager (npm) run the following command:
|
||||
|
||||
```bash
|
||||
npm install -g appium@next
|
||||
```
|
||||
npm install appium-doctor -g
|
||||
```
|
||||
|
||||
:bangbang: Running `npm install -g appium` would still install Appium 1 because version 2 is in its late beta stage.
|
||||
### Usage
|
||||
|
||||
### Drivers
|
||||
```
|
||||
➜ appium-doctor -h
|
||||
|
||||
Appium supports app automation across a variety of platforms, like iOS,
|
||||
Android, and Windows. Each platform is supported by one or more "drivers",
|
||||
which know how to automate that particular platform. Since version 2.0
|
||||
all drivers have been isolated from the Appium server app and can
|
||||
be managed independently using the [appium driver](https://appiumpro.com/editions/122-installing-appium-20-and-the-driver-and-plugins-cli) command line interface.
|
||||
Usage: appium-doctor.js [options, defaults: --ios --android]
|
||||
|
||||
In general, the drivers management in Appium 2 is as simple as:
|
||||
|
||||
```bash
|
||||
# To install a new driver from npm
|
||||
appium driver install --source=npm appium-xcuitest-driver[@<version>]
|
||||
# To install a driver from a local folder (useful for developers)
|
||||
appium driver install --source=local /Users/me/sources/appium-xcuitest-driver
|
||||
# To install a new driver from github (hm, maybe it's time to publish it to NPM?)
|
||||
appium driver install --source=github appium/appium-xcuitest-driver
|
||||
|
||||
# To list already installed drivers
|
||||
appium driver list --installed
|
||||
|
||||
# To update a driver (it must be already installed)
|
||||
appium driver update xcuitest
|
||||
|
||||
# To uninstall a driver (it won't last forever, wouldn't it?)
|
||||
appium driver uninstall xcuitest
|
||||
Options:
|
||||
--ios Check iOS setup [boolean]
|
||||
--android Check Android setup [boolean]
|
||||
--dev Check dev setup [boolean]
|
||||
--debug Show debug messages [boolean]
|
||||
--yes Always respond yes [boolean]
|
||||
--no Always respond no [boolean]
|
||||
--demo Run appium-doctor demo (for dev). [boolean]
|
||||
-h, --help Show help [boolean]
|
||||
```
|
||||
|
||||
You can find a full list of
|
||||
[officially-supported](https://appium.github.io/appium/docs/en/latest/ecosystem/#drivers) and
|
||||
[third-party](https://appium.github.io/appium/docs/en/latest/ecosystem/#other-drivers) drivers at
|
||||
the current Appium 2.0 documentation.
|
||||
## Dev
|
||||
|
||||
### Plugins
|
||||
## Watch
|
||||
|
||||
The concept of plugins is something new that has been added exclusively to Appium2. Plugins allow you to extend server functionality without changing the server code. Plugins could be managed similarly to drivers:
|
||||
|
||||
```bash
|
||||
# To install an officially supported plugin
|
||||
appium plugin install images
|
||||
# To install a plugin from a local folder (useful for developers)
|
||||
appium plugin install --source=local /Users/me/sources/images
|
||||
# To install a new plugin from npm
|
||||
appium plugin install --source=npm appium-device-farm
|
||||
|
||||
# To list already installed plugins
|
||||
appium plugin list --installed
|
||||
|
||||
# To update a plugins (it must be already installed)
|
||||
appium plugin update appium-device-farm
|
||||
|
||||
# To uninstall a plugin
|
||||
appium plugin uninstall appium-device-farm
|
||||
```
|
||||
npm run watch
|
||||
```
|
||||
|
||||
The main difference between drivers and plugins is that the latter must be explicitly enabled on server startup after it was installed (drivers are enabled by default after installation):
|
||||
## Test
|
||||
|
||||
```bash
|
||||
appium server --use-plugins=device-farm,images
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
You can find a full list of
|
||||
[officially-supported](https://appium.github.io/appium/docs/en/latest/ecosystem/#plugins) and
|
||||
[third-party](https://appium.github.io/appium/docs/en/latest/ecosystem/#other-plugins) plugins at
|
||||
the current Appium 2.0 documentation.
|
||||
## Hack Cli
|
||||
|
||||
Use the `--demo` option to simulate the fix process.
|
||||
|
||||
### Server Command Line Interface
|
||||
|
||||
In order to start sending commands to Appium over the wire it must be listening
|
||||
on the URL where your client library expects it to listen.
|
||||
Use the following commands to run and configure Appium server:
|
||||
|
||||
```bash
|
||||
# Start the server on the default port and host (e.g. http://0.0.0.0:4723/)
|
||||
appium server
|
||||
# Start the server on the given port, host and use the base path prefix (the default prefix is /)
|
||||
appium server -p 9000 -a 127.0.0.1 -pa /wd/hub
|
||||
|
||||
# Get the list of all supported command line parameters.
|
||||
# This list would also include descriptions of driver-specific
|
||||
# command line arguments for all installed drivers.
|
||||
# Each driver and plugin must have their command line arguments
|
||||
# exposed in a special JSON schema declared as a part of the corresponding
|
||||
# package.json file.
|
||||
appium server --help
|
||||
```
|
||||
appium-doctor --demo
|
||||
```
|
||||
|
||||
Appium supports execution of parallel server processes as well as parallel driver sessions within
|
||||
single server process. Refer the corresponding driver documentations regarding which mode is optimal
|
||||
for the particular driver or whether it supports parallel sessions.
|
||||
|
||||
### Why Appium?
|
||||
|
||||
1. You usually don't have to recompile your app or modify it in any way, due
|
||||
to the use of standard automation APIs on all platforms.
|
||||
2. You can write tests with your favorite dev tools using any
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html)-compatible
|
||||
language such as [Java](https://github.com/appium/java-client),
|
||||
[JavaScript](https://webdriver.io/), [Python](https://github.com/appium/python-client),
|
||||
[Ruby](https://github.com/appium/ruby_lib), [C#](https://github.com/appium/dotnet-client)
|
||||
with the Selenium WebDriver API. There are also various third party
|
||||
client implementations for other languages.
|
||||
3. You can use any testing framework.
|
||||
4. Some drivers, like xcuitest and uiautomator2 ones have built-in mobile web and
|
||||
hybrid app support. Within the same script, you can switch seamlessly between native
|
||||
app automation and webview automation, all using the WebDriver model that's already
|
||||
the standard for web automation.
|
||||
5. You can run your automated tests locally and in a cloud. There are multiple
|
||||
cloud providers that support various Appium drivers (mostly
|
||||
targeting iOS and Android mobile automation).
|
||||
6. [Appium Inspector](https://github.com/appium/appium-inspector) allows
|
||||
visual debugging of automated tests and could be extremely useful for
|
||||
beginners.
|
||||
|
||||
Investing in the
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means
|
||||
you are betting on a single, free, and open protocol for testing that has become
|
||||
a web standard. Don't lock yourself into a proprietary stack.
|
||||
|
||||
For example, if you use Apple's XCUITest library without Appium you can only
|
||||
write tests using Obj-C/Swift, and you can only run tests through Xcode.
|
||||
Similarly, with Google's UiAutomator or Espresso, you can only write tests in
|
||||
Java/Kotlin. Appium opens up the possibility of true cross-platform native app
|
||||
automation, for mobile and beyond. Finally!
|
||||
|
||||
If you're new to Appium or want a more comprehensive description of what this is all
|
||||
about, please read our [Introduction to Appium Concepts](/docs/en/about-appium/intro.md).
|
||||
|
||||
### Get Started
|
||||
|
||||
Check out our [Getting Started](http://appium.io/docs/en/about-appium/getting-started) guide
|
||||
to get going with Appium.
|
||||
|
||||
There is also a sample code that contains [many examples of tests in a variety
|
||||
of different languages](https://github.com/appium/appium/tree/1.x/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) 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
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)
|
||||
|
||||
BIN
Binary file not shown.
-59
@@ -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)|
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('./build/bin/appium-doctor');
|
||||
@@ -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();
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
rules: {
|
||||
'body-leading-blank': [0],
|
||||
'body-max-line-length': [0],
|
||||
'footer-max-line-length': [0],
|
||||
'header-max-length': [0],
|
||||
'subject-case': [0],
|
||||
'subject-full-stop': [0],
|
||||
},
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@tsconfig/node14/tsconfig.json",
|
||||
"ts-node": {
|
||||
"transpileOnly": true
|
||||
},
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"strictNullChecks": true,
|
||||
"sourceMap": true,
|
||||
"removeComments": false,
|
||||
"strict": false,
|
||||
"types": ["node", "mocha", "chai", "sinon-chai", "chai-as-promised"]
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"appium": ["../packages/appium"],
|
||||
"appium/plugin": ["../packages/appium/plugin"],
|
||||
"@appium/plugin-test-support": ["../packages/plugin-test-support"]
|
||||
},
|
||||
"types": ["webdriverio/async"]
|
||||
},
|
||||
"extends": "./tsconfig.base.json",
|
||||
"references": [
|
||||
{"path": "../packages/appium"},
|
||||
{"path": "../packages/base-plugin"},
|
||||
{"path": "../packages/types"},
|
||||
{"path": "../packages/plugin-test-support"}
|
||||
]
|
||||
}
|
||||
@@ -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
@@ -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,
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
import newDoctor from './lib/factory';
|
||||
import { Doctor, DoctorCheck } from './lib/doctor';
|
||||
|
||||
export { newDoctor, Doctor, DoctorCheck };
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"command": {
|
||||
"run": {
|
||||
"concurrency": 8
|
||||
},
|
||||
"version": {
|
||||
"conventionalCommits": true,
|
||||
"createRelease": "github",
|
||||
"version": {
|
||||
"allowBranch": "master"
|
||||
}
|
||||
},
|
||||
"add": {
|
||||
"exact": true
|
||||
}
|
||||
},
|
||||
"ignoreChanges": ["**/test/**", "**/*.md"],
|
||||
"version": "independent",
|
||||
"useWorkspaces": true,
|
||||
"useNx": false
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { DoctorCheck } from './doctor';
|
||||
import { ok, nok } from './utils';
|
||||
import { fs, system } from 'appium-support';
|
||||
import path from 'path';
|
||||
let checks = [];
|
||||
|
||||
// Check env variables
|
||||
class EnvVarAndPathCheck extends DoctorCheck {
|
||||
constructor (varName) {
|
||||
super();
|
||||
this.varName = varName;
|
||||
}
|
||||
|
||||
async diagnose () {
|
||||
let varValue = process.env[this.varName];
|
||||
if (typeof varValue === 'undefined') {
|
||||
return nok(`${this.varName} is NOT set!`);
|
||||
}
|
||||
return await fs.exists(varValue) ? ok(`${this.varName} is set to: ${varValue}`) :
|
||||
nok(`${this.varName} is set to \'${varValue}\' but this is NOT a valid path!`);
|
||||
}
|
||||
|
||||
fix () {
|
||||
return `Manually configure ${this.varName}.`;
|
||||
}
|
||||
}
|
||||
|
||||
checks.push(new EnvVarAndPathCheck('ANDROID_HOME'));
|
||||
checks.push(new EnvVarAndPathCheck('JAVA_HOME'));
|
||||
|
||||
// Check tools
|
||||
class AndroidToolCheck extends DoctorCheck {
|
||||
constructor (toolName, toolPath) {
|
||||
super();
|
||||
this.toolName = toolName;
|
||||
this.toolPath = toolPath;
|
||||
}
|
||||
|
||||
async diagnose () {
|
||||
if (typeof process.env.ANDROID_HOME === 'undefined') {
|
||||
return nok(`${this.toolName} could not be found because ANDROID_HOME is NOT set!`);
|
||||
}
|
||||
let fullPath = path.resolve(process.env.ANDROID_HOME, this.toolPath);
|
||||
return await fs.exists(fullPath) ? ok(`${this.toolName} exists at: ${fullPath}`) :
|
||||
nok(`${this.toolName} could NOT be found at \'${fullPath}\'!`);
|
||||
}
|
||||
|
||||
fix () {
|
||||
if (typeof process.env.ANDROID_HOME === 'undefined') {
|
||||
return 'Manually configure ANDROID_HOME and run appium-doctor again.';
|
||||
}
|
||||
return `Manually install ${this.toolName} and add it to PATH.`;
|
||||
}
|
||||
}
|
||||
checks.push(new AndroidToolCheck('adb',
|
||||
path.join("platform-tools", system.isWindows() ? 'adb.exe' : 'adb')));
|
||||
checks.push(new AndroidToolCheck('android',
|
||||
path.join("tools", system.isWindows() ? 'android.bat' : 'android')));
|
||||
checks.push(new AndroidToolCheck('emulator',
|
||||
path.join("tools", system.isWindows() ? 'emulator.exe' : 'emulator')));
|
||||
|
||||
export { EnvVarAndPathCheck, AndroidToolCheck };
|
||||
export default checks;
|
||||
@@ -1,31 +1,31 @@
|
||||
// demo rule to test the gui
|
||||
|
||||
import {ok, nok} from './utils';
|
||||
import {fs} from '@appium/support';
|
||||
import {exec} from 'teen_process';
|
||||
import {DoctorCheck, FixSkippedError} from './doctor';
|
||||
import { ok, nok } from './utils';
|
||||
import { fs } from 'appium-support';
|
||||
import { exec } from 'teen_process';
|
||||
import { DoctorCheck } from './doctor';
|
||||
import log from './logger';
|
||||
import {fixIt} from './prompt';
|
||||
import { fixIt } from './prompt';
|
||||
import { FixSkippedError } from './doctor';
|
||||
|
||||
let checks = [];
|
||||
|
||||
class DirCheck extends DoctorCheck {
|
||||
constructor(path) {
|
||||
constructor (path) {
|
||||
super({autofix: false});
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
async diagnose() {
|
||||
if (!(await fs.exists(this.path))) {
|
||||
return nok(`Could NOT find directory at '${this.path}'!`);
|
||||
async diagnose () {
|
||||
if(!await fs.exists(this.path)) {
|
||||
return nok(`Could NOT find directory at \'${this.path}\'!`);
|
||||
}
|
||||
let stats = await fs.lstat(this.path);
|
||||
return stats.isDirectory()
|
||||
? ok(`Found directory at: ${this.path}`)
|
||||
: nok(`'${this.path}' is NOT a directory!`);
|
||||
return stats.isDirectory() ?
|
||||
ok(`Found directory at: ${this.path}`) : nok(`\'${this.path}\' is NOT a directory!`);
|
||||
}
|
||||
// eslint-disable-next-line require-await
|
||||
async fix() {
|
||||
|
||||
async fix () {
|
||||
return `Manually create a directory at: ${this.path}`;
|
||||
}
|
||||
}
|
||||
@@ -39,13 +39,12 @@ class FileCheck extends DoctorCheck {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
async diagnose() {
|
||||
return (await fs.exists(this.path))
|
||||
? ok(`Found file at: ${this.path}`)
|
||||
: nok(`Could NOT find file at '${this.path}'!`);
|
||||
async diagnose () {
|
||||
return await fs.exists(this.path) ?
|
||||
ok(`Found file at: ${this.path}`) : nok(`Could NOT find file at \'${this.path}\'!`);
|
||||
}
|
||||
|
||||
async fix() {
|
||||
async fix () {
|
||||
log.info(`The following command need be executed: touch '${this.path}'`);
|
||||
let yesno = await fixIt();
|
||||
if (yesno === 'yes') {
|
||||
@@ -61,5 +60,5 @@ checks.push(new FileCheck('/tmp/appium-doctor/demo/apple.fruit'));
|
||||
checks.push(new FileCheck('/tmp/appium-doctor/demo/pear.fruit'));
|
||||
checks.push(new FileCheck('/tmp/appium-doctor/demo/orange.fruit'));
|
||||
|
||||
export {DirCheck, FileCheck};
|
||||
export { DirCheck, FileCheck };
|
||||
export default checks;
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { exec } from 'teen_process';
|
||||
import { DoctorCheck } from './doctor';
|
||||
import { ok, nok } from './utils';
|
||||
import { fs, system } from 'appium-support';
|
||||
import path from 'path';
|
||||
import { EOL } from 'os';
|
||||
|
||||
let checks = [];
|
||||
|
||||
// Check PATH binaries
|
||||
class BinaryIsInPathCheck extends DoctorCheck {
|
||||
constructor (binary) {
|
||||
super();
|
||||
this.binary = binary;
|
||||
}
|
||||
|
||||
async diagnose () {
|
||||
let resolvedPath;
|
||||
try {
|
||||
let executable = system.isWindows() ? 'where' : 'which';
|
||||
let {stdout} = await exec(executable, [this.binary]);
|
||||
if (stdout.match(/not found/gi)) {
|
||||
throw new Error('Not Found');
|
||||
}
|
||||
resolvedPath = system.isWindows() ? stdout.split(EOL)[0] : stdout.replace(EOL, '');
|
||||
} catch (err) {
|
||||
return nok(`${this.binary} is MISSING in PATH!`);
|
||||
}
|
||||
return await fs.exists(resolvedPath) ? ok(`${this.binary} was found at ${resolvedPath}`) :
|
||||
nok(`${this.binary} was found in PATH at '${resolvedPath}', but this is NOT a valid path!`);
|
||||
}
|
||||
|
||||
fix() {
|
||||
return `Manually install the ${this.binary} binary and add it to PATH.`;
|
||||
}
|
||||
}
|
||||
|
||||
checks.push(new BinaryIsInPathCheck(system.isWindows() ? 'mvn.bat' : 'mvn'));
|
||||
checks.push(new BinaryIsInPathCheck(system.isWindows() ? 'ant.bat' : 'ant'));
|
||||
checks.push(new BinaryIsInPathCheck(system.isWindows() ? 'adb.exe' : 'adb'));
|
||||
|
||||
// Check Android SDKs
|
||||
class AndroidSdkExists extends DoctorCheck {
|
||||
constructor (sdk) {
|
||||
super();
|
||||
this.sdk = sdk;
|
||||
}
|
||||
|
||||
async diagnose () {
|
||||
if (typeof process.env.ANDROID_HOME === 'undefined') {
|
||||
return nok(`${this.sdk} could not be found because ANDROID_HOME is NOT set!`);
|
||||
}
|
||||
let sdkPath = path.resolve(process.env.ANDROID_HOME, path.join("platforms", this.sdk));
|
||||
return await fs.exists(sdkPath) ? ok(`${this.sdk} was found at: ${sdkPath}`) :
|
||||
nok(`${this.sdk} could NOT be found at \'${sdkPath}\'!`);
|
||||
}
|
||||
|
||||
fix() {
|
||||
if (typeof process.env.ANDROID_HOME === "undefined") {
|
||||
return 'Manually configure ANDROID_HOME.';
|
||||
}
|
||||
return `Manually install the ${this.sdk} sdk.`;
|
||||
}
|
||||
}
|
||||
|
||||
checks.push(new AndroidSdkExists('android-16'));
|
||||
checks.push(new AndroidSdkExists('android-19'));
|
||||
|
||||
export { BinaryIsInPathCheck, AndroidSdkExists };
|
||||
export default checks;
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
import 'colors';
|
||||
import _ from 'lodash';
|
||||
import log from './logger';
|
||||
|
||||
class FixSkippedError extends Error {
|
||||
}
|
||||
|
||||
class DoctorCheck {
|
||||
constructor(opts={}) {
|
||||
this.autofix = !!opts.autofix;
|
||||
}
|
||||
|
||||
diagnose () { throw new Error('Not Implemented!'); }
|
||||
|
||||
fix () {
|
||||
// return string for manual fixes.
|
||||
throw new Error('Not Implemented!');
|
||||
}
|
||||
}
|
||||
|
||||
class Doctor {
|
||||
constructor() {
|
||||
this.checks = [];
|
||||
this.toFix = [];
|
||||
}
|
||||
|
||||
register (checks) {
|
||||
checks = Array.isArray(checks) ? checks : [checks];
|
||||
this.checks = this.checks.concat(checks);
|
||||
}
|
||||
|
||||
async diagnose() {
|
||||
log.info('### Diagnostic starting ###');
|
||||
this.toFix = [];
|
||||
for (let check of this.checks) {
|
||||
let res = await check.diagnose();
|
||||
if (res.ok) {
|
||||
log.info(` ${'\u2714'.green} ${res.message}`);
|
||||
} else {
|
||||
let errorMessage = ` ${'\u2716'.red} ${res.message}`;
|
||||
log.warn(errorMessage);
|
||||
this.toFix.push({
|
||||
error: errorMessage,
|
||||
check: check
|
||||
});
|
||||
}
|
||||
}
|
||||
let fixMessage;
|
||||
switch (this.toFix.length) {
|
||||
case 0:
|
||||
fixMessage = 'no fix needed';
|
||||
break;
|
||||
case 1:
|
||||
fixMessage = 'one fix needed';
|
||||
break;
|
||||
default:
|
||||
fixMessage = `${this.toFix.length} fixes needed`;
|
||||
}
|
||||
log.info(`### Diagnostic completed, ${fixMessage}. ###`);
|
||||
log.info('');
|
||||
}
|
||||
|
||||
async reportSuccess () {
|
||||
if (this.toFix.length === 0) {
|
||||
log.info('Everything looks good, bye!');
|
||||
log.info('');
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async reportManualFixes () {
|
||||
let manualFixes = _.filter(this.toFix, (f) => {return !f.check.autofix;});
|
||||
if (manualFixes.length >0) {
|
||||
log.info('### Manual Fixes Needed ###');
|
||||
log.info('The configuration cannot be automatically fixed, please do the following first:');
|
||||
// for manual fixes, the fix method always return a string
|
||||
let fixMessages = [];
|
||||
for (let f of manualFixes) {
|
||||
fixMessages.push(await f.check.fix());
|
||||
}
|
||||
for (let m of _.uniq(fixMessages)) {
|
||||
log.warn(`- ${m}`);
|
||||
}
|
||||
log.info('###');
|
||||
log.info('');
|
||||
log.info('Bye, run appium-doctor again when the all the manual fixes have been applied!');
|
||||
log.info('');
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async runAutoFix (f) {
|
||||
log.info(`### Fixing: ${f.error} ###`);
|
||||
try {
|
||||
await f.check.fix();
|
||||
} catch (err) {
|
||||
if (err instanceof FixSkippedError) {
|
||||
log.info(`### Skipped fix ###`);
|
||||
return;
|
||||
} else {
|
||||
log.warn(`${err}`.replace(/\n$/g, ''));
|
||||
log.info(`### Fix did not succeed ###`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
log.info('Checking if this was fixed:');
|
||||
let res = await f.check.diagnose();
|
||||
if (res.ok) {
|
||||
f.fixed = true;
|
||||
log.info(` ${'\u2714'.green} ${res.message}`);
|
||||
log.info(`### Fix was successfully applied ###`);
|
||||
} else {
|
||||
log.info(` ${'\u2716'.red} ${res.message}`);
|
||||
log.info(`### Fix was applied but issue remains ###`);
|
||||
}
|
||||
}
|
||||
|
||||
async runAutoFixes () {
|
||||
let autoFixes = _.filter(this.toFix, (f) => {return f.check.autofix;});
|
||||
for (let f of autoFixes) {
|
||||
await this.runAutoFix(f);
|
||||
log.info('');
|
||||
}
|
||||
if(_.find(autoFixes, (f) => { return !f.fixed; })) {
|
||||
// a few issues remain.
|
||||
log.info('Bye, a few issues remain, fix manually and/or rerun appium-doctor!');
|
||||
} else {
|
||||
// nothing left to fix.
|
||||
log.info('Bye, all issues have been fixed!');
|
||||
}
|
||||
log.info('');
|
||||
}
|
||||
|
||||
async run () {
|
||||
await this.diagnose();
|
||||
if (await this.reportSuccess()) {
|
||||
return;
|
||||
}
|
||||
if (await this.reportManualFixes()) {
|
||||
return;
|
||||
}
|
||||
await this.runAutoFixes();
|
||||
}
|
||||
}
|
||||
|
||||
export { Doctor, DoctorCheck, FixSkippedError };
|
||||
@@ -1,17 +1,16 @@
|
||||
import _ from 'lodash';
|
||||
import {Doctor} from './doctor';
|
||||
import generalChecks from './general';
|
||||
import { Doctor } from './doctor.js';
|
||||
import iosChecks from './ios';
|
||||
import androidChecks from './android';
|
||||
import devChecks from './dev';
|
||||
import demoChecks from './demo';
|
||||
|
||||
let checks = {generalChecks, iosChecks, androidChecks, devChecks, demoChecks};
|
||||
let checks = { iosChecks, androidChecks, devChecks, demoChecks };
|
||||
|
||||
let newDoctor = (opts) => {
|
||||
let doctor = new Doctor();
|
||||
for (let [k, v] of _.toPairs(opts)) {
|
||||
if (v) {
|
||||
for (let [k, v] of _.pairs(opts)) {
|
||||
if(v) {
|
||||
doctor.register(checks[`${k}Checks`] || []);
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
import { ok, nok, authorize } from './utils';
|
||||
import { fs, system } from 'appium-support';
|
||||
import { exec } from 'teen_process';
|
||||
import { DoctorCheck } from './doctor';
|
||||
import log from './logger';
|
||||
import { FixSkippedError } from './doctor';
|
||||
import NodeDetector from './node-detector';
|
||||
import { fixIt } from './prompt';
|
||||
|
||||
let checks = [];
|
||||
let fixes = {};
|
||||
|
||||
// Check for Xcode.
|
||||
class XcodeCheck extends DoctorCheck {
|
||||
async diagnose() {
|
||||
let xcodePath;
|
||||
try {
|
||||
let {stdout} = await exec('xcode-select', ['--print-path']);
|
||||
xcodePath = stdout.replace("\n", "");
|
||||
} catch (err) {
|
||||
return nok('Xcode is NOT installed!');
|
||||
}
|
||||
return xcodePath && await fs.exists(xcodePath) ? ok(`Xcode is installed at: ${xcodePath}`) :
|
||||
nok(`Xcode cannot be found at \'${xcodePath}\'!`);
|
||||
}
|
||||
|
||||
async fix () {
|
||||
return 'Manually install Xcode.';
|
||||
}
|
||||
}
|
||||
checks.push(new XcodeCheck());
|
||||
|
||||
// Check for Xcode Command Line Tools.
|
||||
class XcodeCmdLineToolsCheck extends DoctorCheck {
|
||||
constructor() {
|
||||
super({autofix: true});
|
||||
}
|
||||
|
||||
async diagnose () {
|
||||
const errMess = 'Xcode Command Line Tools are NOT installed!';
|
||||
let pkgName = await system.macOsxVersion() === '10.8' ? 'com.apple.pkg.DeveloperToolsCLI' : 'com.apple.pkg.CLTools_Executables';
|
||||
let stdout;
|
||||
try {
|
||||
stdout = (await exec('pkgutil', [`--pkg-info=${pkgName}`])).stdout;
|
||||
} catch (err) {
|
||||
log.debug(err);
|
||||
return nok(errMess);
|
||||
}
|
||||
return stdout.match(/install-time/) ? ok('Xcode Command Line Tools are installed.') :
|
||||
nok(errMess);
|
||||
}
|
||||
|
||||
async fix () {
|
||||
log.info(`The following command need be executed: xcode-select --install`);
|
||||
let yesno = await fixIt();
|
||||
if (yesno === 'yes') {
|
||||
await exec('xcode-select', ['--install']);
|
||||
} else {
|
||||
log.info('Skipping you will need to install Xcode manually.');
|
||||
throw new FixSkippedError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checks.push(new XcodeCmdLineToolsCheck());
|
||||
|
||||
// Automatically run authorize iOS if requested
|
||||
fixes.authorizeIosFix = async function () {
|
||||
log.info(`The authorize iOS script need to be run.`);
|
||||
let yesno = await fixIt();
|
||||
if (yesno === 'yes') {
|
||||
await authorize();
|
||||
} else {
|
||||
log.info('Skipping you will need to run the authorize iOS manually.');
|
||||
throw new FixSkippedError();
|
||||
}
|
||||
};
|
||||
|
||||
// Dev Tools Security
|
||||
class DevToolsSecurityCheck extends DoctorCheck {
|
||||
constructor() {
|
||||
super({autofix: true});
|
||||
}
|
||||
|
||||
async diagnose () {
|
||||
const errMess = 'DevToolsSecurity is NOT enabled!';
|
||||
let stdout;
|
||||
try {
|
||||
stdout = (await exec('DevToolsSecurity', [])).stdout;
|
||||
} catch (err) {
|
||||
log.debug(err);
|
||||
return nok(errMess);
|
||||
}
|
||||
return stdout && stdout.match(/enabled/) ? ok('DevToolsSecurity is enabled.')
|
||||
: nok(errMess);
|
||||
}
|
||||
async fix () {
|
||||
return await fixes.authorizeIosFix();
|
||||
}
|
||||
}
|
||||
checks.push(new DevToolsSecurityCheck());
|
||||
|
||||
// Authorization DB
|
||||
class AuthorizationDbCheck extends DoctorCheck {
|
||||
constructor() {
|
||||
super({autofix: true});
|
||||
}
|
||||
|
||||
async diagnose () {
|
||||
const successMess = 'The Authorization DB is set up properly.';
|
||||
const errMess = 'The Authorization DB is NOT set up properly.';
|
||||
let stdout;
|
||||
try {
|
||||
stdout = (await exec('security', ['authorizationdb', 'read', 'system.privilege.taskport'])).stdout;
|
||||
} catch (err) {
|
||||
if (await system.macOsxVersion() === '10.8') {
|
||||
let data;
|
||||
try {
|
||||
data = await fs.readFile('/etc/authorization', 'utf8');
|
||||
} catch (err) {
|
||||
log.debug(err);
|
||||
return nok(errMess);
|
||||
}
|
||||
let rg =/<key>system.privilege.taskport<\/key>\s*\n\s*<dict>\n\s*<key>allow-root<\/key>\n\s*(<true\/>)/;
|
||||
return data && data.match(rg) ? ok(successMess) : nok(errMess);
|
||||
} else {
|
||||
log.debug(err);
|
||||
return nok(errMess);
|
||||
}
|
||||
}
|
||||
return stdout && (stdout.match(/is-developer/) || stdout.match(/allow/)) ?
|
||||
ok(successMess) : nok(errMess);
|
||||
}
|
||||
async fix () {
|
||||
return await fixes.authorizeIosFix();
|
||||
}
|
||||
}
|
||||
checks.push(new AuthorizationDbCheck());
|
||||
|
||||
// Node Binary
|
||||
class NodeBinaryCheck extends DoctorCheck {
|
||||
async diagnose () {
|
||||
let nodePath = await NodeDetector.detect();
|
||||
return nodePath ? ok(`The Node.js binary was found at: ${nodePath}`) :
|
||||
nok('The Node.js binary was NOT found!');
|
||||
}
|
||||
|
||||
fix() {
|
||||
return `Manually setup Node.js.`;
|
||||
}
|
||||
}
|
||||
checks.push(new NodeBinaryCheck());
|
||||
|
||||
export { fixes, XcodeCheck, XcodeCmdLineToolsCheck, DevToolsSecurityCheck,
|
||||
AuthorizationDbCheck, NodeBinaryCheck };
|
||||
export default checks;
|
||||
@@ -0,0 +1,5 @@
|
||||
import { getLogger } from 'appium-logger';
|
||||
|
||||
const logger = getLogger('AppiumDoctor');
|
||||
|
||||
export default logger;
|
||||
@@ -0,0 +1,98 @@
|
||||
import { fs } from 'appium-support';
|
||||
import { exec } from 'teen_process';
|
||||
import log from './logger';
|
||||
import path from 'path';
|
||||
|
||||
const NODE_COMMON_PATHS = [
|
||||
process.env.NODE_BIN,
|
||||
'/usr/local/bin/node',
|
||||
'/opt/local/bin/node',
|
||||
];
|
||||
|
||||
// Look for node
|
||||
class NodeDetector {
|
||||
static async retrieveInCommonPlaces () {
|
||||
for (let p of NODE_COMMON_PATHS) {
|
||||
if (p && await fs.exists(p)) {
|
||||
log.debug(`Node binary found at common place: ${p}`);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
log.debug('Node binary wasn\'t found at common places.');
|
||||
return null;
|
||||
}
|
||||
|
||||
static async retrieveUsingWhichCommand () {
|
||||
let stdout;
|
||||
try {
|
||||
stdout = (await exec('which', ['node'])).stdout;
|
||||
} catch (ign) {}
|
||||
let nodePath = stdout.replace("\n", "");
|
||||
if (await fs.exists(nodePath)) {
|
||||
log.debug("Node binary found using which command at: " + nodePath);
|
||||
return nodePath;
|
||||
} else {
|
||||
log.debug('Node binary not found using the which command.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async retrieveUsingAppleScript () {
|
||||
var appScript = [
|
||||
'try'
|
||||
, ' set appiumIsRunning to false'
|
||||
, ' tell application "System Events"'
|
||||
, ' set appiumIsRunning to name of every process contains "Appium"'
|
||||
, ' end tell'
|
||||
, ' if appiumIsRunning then'
|
||||
, ' tell application "Appium" to return node path'
|
||||
, ' end if'
|
||||
, 'end try'
|
||||
, 'return "NULL"'
|
||||
].join("\n");
|
||||
let stdout;
|
||||
try {
|
||||
stdout = (await exec('osascript', ['-e', appScript ])).stdout;
|
||||
} catch(ign) {}
|
||||
let nodePath = stdout.replace("\n", "");
|
||||
if (await fs.exists(nodePath)) {
|
||||
log.debug(`Node binary found using AppleScript at: ${nodePath}`);
|
||||
return nodePath;
|
||||
} else {
|
||||
log.debug('Node binary not found using AppleScript.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async retrieveUsingAppiumConfigFile () {
|
||||
let jsonobj;
|
||||
try {
|
||||
var appiumConfigPath = path.resolve(__dirname, '../..', '.appiumconfig.json');
|
||||
if (await fs.exists(appiumConfigPath)) {
|
||||
jsonobj = JSON.parse(await fs.readFile(appiumConfigPath, 'utf8'));
|
||||
}
|
||||
} catch (ign) {}
|
||||
if (jsonobj && jsonobj.node_bin && await fs.exists(jsonobj.node_bin) ) {
|
||||
log.debug(`Node binary found using .appiumconfig.json at: ${jsonobj.node_bin}`);
|
||||
return jsonobj.node_bin;
|
||||
} else {
|
||||
log.debug('Node binary not found in the .appiumconfig.json file.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async detect () {
|
||||
let nodePath = await this.retrieveInCommonPlaces() ||
|
||||
await NodeDetector.retrieveUsingWhichCommand() ||
|
||||
await NodeDetector.retrieveUsingAppleScript() ||
|
||||
await NodeDetector.retrieveUsingAppiumConfigFile();
|
||||
if (nodePath) {
|
||||
return nodePath;
|
||||
} else {
|
||||
log.warn('The node binary could not be found.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default NodeDetector;
|
||||
@@ -1,4 +1,4 @@
|
||||
import {inquirer} from './utils';
|
||||
import { inquirer } from './utils';
|
||||
|
||||
let persistentResponse;
|
||||
|
||||
@@ -6,26 +6,24 @@ const fixItQuestion = {
|
||||
type: 'list',
|
||||
name: 'confirmation',
|
||||
message: 'Fix it:',
|
||||
choices: ['yes', 'no', 'always', 'never'],
|
||||
filter(val) {
|
||||
return val.toLowerCase();
|
||||
},
|
||||
choices: [ 'yes', 'no', 'always', 'never'],
|
||||
filter: function ( val ) { return val.toLowerCase(); }
|
||||
};
|
||||
|
||||
function configure(opts) {
|
||||
if (opts.yes) {
|
||||
function configure (opts) {
|
||||
if(opts.yes) {
|
||||
persistentResponse = 'yes';
|
||||
}
|
||||
if (opts.no) {
|
||||
if(opts.no) {
|
||||
persistentResponse = 'no';
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
function clear () {
|
||||
persistentResponse = undefined;
|
||||
}
|
||||
|
||||
async function fixIt() {
|
||||
async function fixIt () {
|
||||
if (persistentResponse) {
|
||||
return persistentResponse;
|
||||
}
|
||||
@@ -35,4 +33,4 @@ async function fixIt() {
|
||||
return persistentResponse || resp.confirmation;
|
||||
}
|
||||
|
||||
export {configure, fixIt, clear};
|
||||
export { configure, fixIt, clear };
|
||||
@@ -0,0 +1,27 @@
|
||||
import B from 'bluebird';
|
||||
import path from 'path';
|
||||
import _inquirer from 'inquirer';
|
||||
import log from '../lib/logger';
|
||||
import authorize from 'authorize-ios';
|
||||
|
||||
let pkgRoot = process.env.NO_PRECOMPILE ?
|
||||
path.resolve(__dirname, '..') : path.resolve(__dirname, '..', '..');
|
||||
|
||||
let ok = (message) => { return {ok: true, message: message}; };
|
||||
let nok = (message) => { return {ok: false, message: message}; };
|
||||
|
||||
let inquirer = {
|
||||
prompt: B.promisify(function (question, cb) {
|
||||
_inquirer.prompt(question, function (resp) { cb(null, resp); });
|
||||
})
|
||||
};
|
||||
|
||||
function configureBinaryLog (opts) {
|
||||
log.unwrap().log = function (level) {
|
||||
let l = this.levels[level];
|
||||
if (l < this.levels[this.level]) return;
|
||||
};
|
||||
log.level = opts.debug ? 'debug' : 'info';
|
||||
}
|
||||
|
||||
export { pkgRoot, ok, nok, inquirer, configureBinaryLog, authorize };
|
||||
Generated
-17450
File diff suppressed because it is too large
Load Diff
+40
-135
@@ -1,147 +1,52 @@
|
||||
{
|
||||
"name": "appium-monorepo",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "Automation for Apps.",
|
||||
"name": "appium-doctor",
|
||||
"description": "Description goes here.",
|
||||
"keywords": [
|
||||
"automation",
|
||||
"javascript",
|
||||
"selenium",
|
||||
"webdriver",
|
||||
"ios",
|
||||
"android",
|
||||
"firefoxos",
|
||||
"testing"
|
||||
"appium"
|
||||
],
|
||||
"homepage": "https://appium.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/appium/appium/issues"
|
||||
},
|
||||
"version": "1.0.1",
|
||||
"author": "appium",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appium/appium.git"
|
||||
"url": "https://github.com/appium/appium-doctor.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": "https://github.com/appium",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
"bugs": {
|
||||
"url": "https://github.com/appium/appium-doctor/issues"
|
||||
},
|
||||
"engines": [
|
||||
"node"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
"build:all": "run-s build build:packages",
|
||||
"build:packages": "lerna run build",
|
||||
"clean": "run-s \"clean:artifacts:*\" clean:workspaces",
|
||||
"clean:artifacts": "run-p \"clean:artifacts:*\"",
|
||||
"clean:artifacts:distfiles": "run-s \"build -- --clean\"",
|
||||
"clean:artifacts:packages": "lerna run clean || true",
|
||||
"clean:workspaces": "lerna clean -y",
|
||||
"ci": "npm ci",
|
||||
"dev": "run-s \"build -- --watch\"",
|
||||
"doctor": "node ./packages/doctor",
|
||||
"husky-install": "husky install",
|
||||
"generate-docs": "npm run --workspace=packages/appium generate-docs",
|
||||
"prepare": "run-p husky-install build:all || true",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "run-s \"lint -- --fix\"",
|
||||
"lint:commit": "commitlint",
|
||||
"lint:staged": "lint-staged",
|
||||
"prepublishOnly": "run-s rebuild",
|
||||
"reinstall": "run-s clean ci",
|
||||
"rebuild": "run-s clean:artifacts build:all",
|
||||
"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",
|
||||
"stage-synced-pkgs": "git add -A packages/appium/README.md \"packages/*/package.json\"",
|
||||
"test": "npm-run-all -p lint build -s test:unit",
|
||||
"test:ci": "run-s test:smoke test:unit test:e2e",
|
||||
"test:e2e": "lerna run --concurrency=2 test:e2e",
|
||||
"test:smoke": "smoker --all test:smoke",
|
||||
"test:unit": "lerna run test",
|
||||
"typedoc": "typedoc --logLevel Verbose",
|
||||
"upload": "gulp github-upload",
|
||||
"preversion": "run-s rebuild sync-pkgs stage-synced-pkgs",
|
||||
"zip": "zip -qr ./appium.zip ./packages/appium",
|
||||
"zip-and-upload": "run-s zip upload"
|
||||
"main": "./build/index.js",
|
||||
"bin": {
|
||||
"appium-doctor": "./appium-doctor.js"
|
||||
},
|
||||
"prettier": {
|
||||
"bracketSpacing": false,
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"appium-logger": "^2.0.0",
|
||||
"appium-support": "^2.0.4",
|
||||
"authorize-ios": "^1.0.3",
|
||||
"babel-runtime": "=5.8.24",
|
||||
"bluebird": "^2.10.2",
|
||||
"colors": "^1.1.2",
|
||||
"inquirer": "^0.10.1",
|
||||
"lodash": "^3.10.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"teen_process": "^1.3.1",
|
||||
"yargs": "^3.27.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "./node_modules/.bin/gulp prepublish",
|
||||
"test": "./node_modules/.bin/gulp once",
|
||||
"watch": "./node_modules/.bin/gulp"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@colors/colors": "1.5.0",
|
||||
"@commitlint/cli": "17.3.0",
|
||||
"@commitlint/config-conventional": "17.3.0",
|
||||
"@tsconfig/node14": "1.0.3",
|
||||
"@types/chai": "4.3.4",
|
||||
"@types/chai-as-promised": "7.1.5",
|
||||
"@types/mocha": "10.0.1",
|
||||
"@types/node": "18.11.17",
|
||||
"@types/semver": "7.3.13",
|
||||
"@types/sinon": "10.0.13",
|
||||
"@types/sinon-chai": "3.2.9",
|
||||
"@types/teen_process": "2.0.0",
|
||||
"@types/ws": "8.5.3",
|
||||
"asyncbox": "2.9.4",
|
||||
"chai": "4.3.7",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"chai-webdriverio-async": "2.7.0",
|
||||
"cpy-cli": "4.2.0",
|
||||
"eslint": "8.30.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-find-rules": "4.1.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"eslint-plugin-mocha": "10.1.0",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"fancy-log": "2.0.0",
|
||||
"finalhandler": "1.2.0",
|
||||
"get-port": "5.1.1",
|
||||
"handlebars": "4.7.7",
|
||||
"husky": "8.0.2",
|
||||
"json-schema-to-typescript": "11.0.2",
|
||||
"lerna": "6.1.0",
|
||||
"lint-staged": "13.1.0",
|
||||
"log-symbols": "4.1.0",
|
||||
"midnight-smoker": "2.0.0",
|
||||
"mjpeg-consumer": "2.0.0",
|
||||
"mjpeg-server": "0.3.1",
|
||||
"mocha": "10.2.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"prettier": "2.8.1",
|
||||
"rewiremock": "3.14.4",
|
||||
"rimraf": "3.0.2",
|
||||
"serve-static": "1.15.0",
|
||||
"sinon": "15.0.1",
|
||||
"sinon-chai": "3.7.0",
|
||||
"sync-monorepo-packages": "1.0.2",
|
||||
"through2": "4.0.2",
|
||||
"ts-node": "10.9.1",
|
||||
"typedoc": "0.23.23",
|
||||
"typedoc-plugin-markdown": "3.14.0",
|
||||
"typedoc-plugin-resolve-crossmodule-references": "0.3.3",
|
||||
"typescript": "4.7.4",
|
||||
"validate.js": "0.13.1",
|
||||
"webdriverio": "7.28.0",
|
||||
"ws": "8.11.0",
|
||||
"yaml-js": "0.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
||||
"npm": ">=8"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"overrides": {
|
||||
"jpeg-js": "0.4.4",
|
||||
"@sidvind/better-ajv-errors": {
|
||||
"ajv": "8.11.2"
|
||||
},
|
||||
"ajv-formats": {
|
||||
"ajv": "8.11.2"
|
||||
}
|
||||
"appium-gulp-plugins": "^1.3.11",
|
||||
"appium-test-support": "^0.0.5",
|
||||
"chai": "^3.3.0",
|
||||
"chai-as-promised": "^5.1.0",
|
||||
"gulp": "^3.9.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,333 +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.48](https://github.com/appium/appium/compare/appium@2.0.0-beta.47...appium@2.0.0-beta.48) (2022-12-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** ensure migration always gets applied ([20667be](https://github.com/appium/appium/commit/20667be9a21e71963ecb7e25e1b8d51864bce011))
|
||||
- **appium:** fix manifest migrations ([df250cc](https://github.com/appium/appium/commit/df250cc1e024f4971abe7e756594f7feee32cba6))
|
||||
- **execute-driver-plugin:** update dependency webdriverio to v7.28.0 ([f81e2e9](https://github.com/appium/appium/commit/f81e2e92eff25c33d36f767209f423227d288218))
|
||||
- **types:** update dependency type-fest to v3.4.0 ([37f71c3](https://github.com/appium/appium/commit/37f71c327a7c1a6d882b5198af6fedc9e8d51496))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** add chromium driver to list of officially supported drivers ([#17939](https://github.com/appium/appium/issues/17939)) ([fe67e4c](https://github.com/appium/appium/commit/fe67e4cb2fca977dd9994f1cfbba4a0edc61ef83))
|
||||
|
||||
# [2.0.0-beta.47](https://github.com/appium/appium/compare/appium@2.0.0-beta.46...appium@2.0.0-beta.47) (2022-12-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** --show-config shouid only show CLI args if any were used ([3de553a](https://github.com/appium/appium/commit/3de553ad3a58313c14c12880d099d59ba03cd559))
|
||||
- **appium,support:** re-enable log-filters ([b3b6427](https://github.com/appium/appium/commit/b3b642778aae6138f246c4fa9ecb32b017c25f7a))
|
||||
- **appium,types:** cliArgs is never undefined ([e66dbb5](https://github.com/appium/appium/commit/e66dbb55cb43ecb4d01e8b9bf1cb8476a9e21639))
|
||||
- **appium:** do not pollute pre-config parsed args with config file & defaults ([5dcd2e2](https://github.com/appium/appium/commit/5dcd2e2d303b905fe96e8566fbf6fa80d8687595))
|
||||
- **appium:** ensure appiumCliDest is recognized by config file normalizer ([1f89d7c](https://github.com/appium/appium/commit/1f89d7c2ffcad823bb0dbac54cb747ac24aa40ef)), closes [#17638](https://github.com/appium/appium/issues/17638)
|
||||
- **appium:** fix problematic ExtManifestWithSchema type ([6d514c5](https://github.com/appium/appium/commit/6d514c54b365197eacc37d01324a78eb508002c5))
|
||||
- **appium:** fixup ([6c61eb8](https://github.com/appium/appium/commit/6c61eb8f4ed0f19edc0fa4affe9e374e6b4e426a))
|
||||
- **appium:** squelch deprecation warning out of argparser ([f4d1b81](https://github.com/appium/appium/commit/f4d1b817a10302b407a84fe644c968bf17ba89a1))
|
||||
- **appium:** store path to installed extension ([10d1438](https://github.com/appium/appium/commit/10d1438af7e5bc2b523cf775c65199abe000e747))
|
||||
- **appium:** update dependency ajv to v8.11.2 ([5a794ce](https://github.com/appium/appium/commit/5a794ce1b61e433e568964551c805aa9c82af3ca))
|
||||
- **execute-driver-plugin:** update dependency webdriverio to v7.27.0 ([edb3251](https://github.com/appium/appium/commit/edb325131b809edae3e73db8d43322dda915b201))
|
||||
- **fake-driver:** update dependency asyncbox to v2.9.4 ([70a9c14](https://github.com/appium/appium/commit/70a9c144fc0bd80c4459223d5c8170a4d541db6c))
|
||||
- **opencv:** update definitelytyped ([32557f4](https://github.com/appium/appium/commit/32557f4bca5acc2f89cfd3a70f369cebeb94c588))
|
||||
- **schema:** add definition for log filters ([09c5901](https://github.com/appium/appium/commit/09c59017193b0fd839e41e44400872ab592d177a))
|
||||
- **support:** Make upgradable versions parsing more permissive ([#17666](https://github.com/appium/appium/issues/17666)) ([32a2616](https://github.com/appium/appium/commit/32a2616c3600e0ba91a29981d9af27fb4fede833))
|
||||
- **support:** update dependency axios to v1.2.0 ([b80b88b](https://github.com/appium/appium/commit/b80b88bd9cf2d6325ea6104449170b8339bf23e0))
|
||||
- **support:** update dependency axios to v1.2.1 ([07d6ef6](https://github.com/appium/appium/commit/07d6ef6b8cc1608da8860f601a80ec0f6a7a7598))
|
||||
- **support:** update dependency npmlog to v7 ([68778ca](https://github.com/appium/appium/commit/68778ca5c5f92ae973fb7055d84030630b31e1e9))
|
||||
- **types:** update dependency type-fest to v3.2.0 ([f5da9f3](https://github.com/appium/appium/commit/f5da9f31a31b62d32b076857891cb027887fdbaf))
|
||||
- **types:** update dependency type-fest to v3.3.0 ([33aef07](https://github.com/appium/appium/commit/33aef07d245627e67823a3b344cdf612e4452551))
|
||||
- **types:** update webdriverio monorepo to v7.26.0 ([2a445ad](https://github.com/appium/appium/commit/2a445addffb5c972c7dcac50a1bf25601efa003d))
|
||||
|
||||
- chore!: set engines to minimum Node.js v14.17.0 ([a1dbe6c](https://github.com/appium/appium/commit/a1dbe6c43efe76604943a607d402f4c8b864d652))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium,support:** use npm link for local installs ([b5be1fe](https://github.com/appium/appium/commit/b5be1fe93bc73953d7da17938d41f1db1b76143d))
|
||||
- **appium:** Add colorized console logs to Appium (2.x) ([#17481](https://github.com/appium/appium/issues/17481)) ([fe4c6d6](https://github.com/appium/appium/commit/fe4c6d68a078cefa6bcdc9258e3f25b311bfe521))
|
||||
- **appium:** add easy access to a few more drivers and plugins ([#17878](https://github.com/appium/appium/issues/17878)) ([5d60c45](https://github.com/appium/appium/commit/5d60c45cce83f664d0cbac256936d5ed0e43aec6))
|
||||
- **appium:** implement schema migrations ([13df5c7](https://github.com/appium/appium/commit/13df5c74e0ef1acae46d2ef821ed01d9118eab05))
|
||||
- experimental support for typedoc generation ([4746080](https://github.com/appium/appium/commit/4746080e54ed8bb494cbc7c6ce83db503bf6bb52))
|
||||
- **schema:** allow root $schema prop ([726a7e1](https://github.com/appium/appium/commit/726a7e10deadcc8150a549fb853fbf5cca033248))
|
||||
- **types:** add declarations for versioned manifest files and their types ([2092360](https://github.com/appium/appium/commit/209236023d5f23e2ccb94be6959babd8702a65bc))
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- Appium now supports version range `^14.17.0 || ^16.13.0 || >=18.0.0`
|
||||
|
||||
# [2.0.0-beta.46](https://github.com/appium/appium/compare/appium@2.0.0-beta.45...appium@2.0.0-beta.46) (2022-10-14)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.45](https://github.com/appium/appium/compare/appium@2.0.0-beta.44...appium@2.0.0-beta.45) (2022-10-13)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium,support:** enable detection of local extensions for improved DX ([b186928](https://github.com/appium/appium/commit/b186928e60493e7603dc3b27725dad8ee20d3750))
|
||||
|
||||
# [2.0.0-beta.44](https://github.com/appium/appium/compare/appium@2.0.0-beta.43...appium@2.0.0-beta.44) (2022-09-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** do not throw ENAMETOOLONG on long cli arg ([cfdf898](https://github.com/appium/appium/commit/cfdf898e04e94032e3dd48b595caa4b6f0828289))
|
||||
- **appium:** eat update info errors ([7d7bb7a](https://github.com/appium/appium/commit/7d7bb7abc3173d29b843b3b238465d9914eaf091)), closes [#17357](https://github.com/appium/appium/issues/17357)
|
||||
|
||||
### chore
|
||||
|
||||
- **appium:** remove test export ([6820f5e](https://github.com/appium/appium/commit/6820f5ec4e62fbb5e91ce739d8aadb7f7b7a7a74)), closes [#17398](https://github.com/appium/appium/issues/17398)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** Adjust NODE_PATH so NPM could properly resolve component peer dependencies ([#17325](https://github.com/appium/appium/issues/17325)) ([39d5cee](https://github.com/appium/appium/commit/39d5cee1b71f611e810900d3faed8e0fed6e1ce0))
|
||||
- **support:** Move module root detection utility into support package ([#17427](https://github.com/appium/appium/issues/17427)) ([5ab7829](https://github.com/appium/appium/commit/5ab78297e172bc6a5751c636f81b3b202fbe2743))
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- **appium:** This removes the `test` export from `appium`. `import * from 'appium/test'` is no longer supported.
|
||||
|
||||
Use `@appium/test-support`, `@appium/driver-test-support` or `@appium/plugin-test-support` instead.
|
||||
|
||||
# [2.0.0-beta.43](https://github.com/appium/appium/compare/appium@2.0.0-beta.42...appium@2.0.0-beta.43) (2022-08-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** fix busted config file normalization algorithm ([dc4835f](https://github.com/appium/appium/commit/dc4835f293f371c36873801a0060bb22eead2cc0))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium,base-driver,fake-driver,fake-plugin,test-support,types:** updateServer receives cliArgs param ([d4b9833](https://github.com/appium/appium/commit/d4b983328af21d1e5c27a91e438e7934eb152ab1)), closes [#17304](https://github.com/appium/appium/issues/17304)
|
||||
- **base-driver,fake-driver,appium:** add convenience methods for defining execute script overloads ([#17321](https://github.com/appium/appium/issues/17321)) ([337ec3e](https://github.com/appium/appium/commit/337ec3e7ba216dd6f8cdc88143ecaa4c75f5d266))
|
||||
|
||||
# [2.0.0-beta.42](https://github.com/appium/appium/compare/appium@2.0.0-beta.41...appium@2.0.0-beta.42) (2022-08-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium,base-driver,base-plugin,doctor,docutils,eslint-config-appium,execute-driver-plugin,fake-driver,fake-plugin,gulp-plugins,images-plugin,opencv,relaxed-caps-plugin,schema,support,test-support,types,universal-xml-plugin:** update engines ([d8d2382](https://github.com/appium/appium/commit/d8d2382327ba7b7db8a4d1cad987c0e60184c92d))
|
||||
- **appium:** add npm version check ([27ac2fa](https://github.com/appium/appium/commit/27ac2fa125bbfbe2e2ad5a3e7bf31d518510aa2d))
|
||||
- **appium:** partially revert 2a6a056187ce925d5776b7acc4954b10ecf9221b ([b7e905e](https://github.com/appium/appium/commit/b7e905eaf188f0f23f279620d8ce7dfba60f0b25))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** pass unknown args to extension scripts ([faff3ce](https://github.com/appium/appium/commit/faff3ce3471abaea24d2cb4c3e3b75b1af5ac3a1)), closes [#17250](https://github.com/appium/appium/issues/17250)
|
||||
|
||||
# [2.0.0-beta.41](https://github.com/appium/appium/compare/appium@2.0.0-beta.40...appium@2.0.0-beta.41) (2022-07-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium,support:** fix installation problems ([2a6a056](https://github.com/appium/appium/commit/2a6a056187ce925d5776b7acc4954b10ecf9221b)), closes [#17073](https://github.com/appium/appium/issues/17073)
|
||||
- **appium,types:** include @appium/types in appium ([a0a6166](https://github.com/appium/appium/commit/a0a6166738f3db32f2512681914c4c5410cd4b28))
|
||||
- **appium:** fix incorrect count of errors and warnings ([1e42c23](https://github.com/appium/appium/commit/1e42c2378cb762d5f327139c027e2071918b5c17))
|
||||
- **appium:** postinstall: never assume local appium if it is being installed globally ([965752f](https://github.com/appium/appium/commit/965752f288ba5d74ab24f41d780c46cc8ff14984)), closes [#17054](https://github.com/appium/appium/issues/17054)
|
||||
- **appium:** remove references to js in typescript code ([d3f90d5](https://github.com/appium/appium/commit/d3f90d5ed6e887feffcabfc8aabd012e43c37e63))
|
||||
- moved type packages to deps of specific packages ([f9129df](https://github.com/appium/appium/commit/f9129dfee32fcc3f89ffcfa69fb83b7c2419c24f))
|
||||
- Update the way build info is fetched from GitHub ([#17078](https://github.com/appium/appium/issues/17078)) ([d2a3adc](https://github.com/appium/appium/commit/d2a3adc2e361d5f0cff11094e8884e3270f5c94c))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium,base-driver,base-plugin,test-support,types:** move test fixtures into test-support ([70d88cb](https://github.com/appium/appium/commit/70d88cb86f28354efe313cc6be6a0afef20b38b3))
|
||||
|
||||
# [2.0.0-beta.40](https://github.com/appium/appium/compare/appium@2.0.0-beta.39...appium@2.0.0-beta.40) (2022-06-04)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.39](https://github.com/appium/appium/compare/appium@2.0.0-beta.38...appium@2.0.0-beta.39) (2022-06-03)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.38](https://github.com/appium/appium/compare/appium@2.0.0-beta.37...appium@2.0.0-beta.38) (2022-06-01)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.37](https://github.com/appium/appium/compare/appium@2.0.0-beta.36...appium@2.0.0-beta.37) (2022-05-31)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.36](https://github.com/appium/appium/compare/appium@2.0.0-beta.35...appium@2.0.0-beta.36) (2022-05-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** fix extension autoinstall postinstall script ([3e2c05d](https://github.com/appium/appium/commit/3e2c05d8a290072484afde34fe5fd968618f6359)), closes [#16924](https://github.com/appium/appium/issues/16924)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium,support:** extension check improvements ([6b224f5](https://github.com/appium/appium/commit/6b224f545f44b8e6ad9d587c7157bc67d7d11439))
|
||||
- **appium:** appium now expects extensions to use peer dependencies ([48f1d99](https://github.com/appium/appium/commit/48f1d990871dbcd4ab3042c19dc4f43ca89bf80f))
|
||||
|
||||
# [2.0.0-beta.35](https://github.com/appium/appium/compare/appium@2.0.0-beta.34...appium@2.0.0-beta.35) (2022-05-03)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.34](https://github.com/appium/appium/compare/appium@2.0.0-beta.33...appium@2.0.0-beta.34) (2022-05-02)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.33](https://github.com/appium/appium/compare/appium@2.0.0-beta.32...appium@2.0.0-beta.33) (2022-04-20)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.32](https://github.com/appium/appium/compare/appium@2.0.0-beta.31...appium@2.0.0-beta.32) (2022-04-20)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.31](https://github.com/appium/appium/compare/appium@2.0.0-beta.30...appium@2.0.0-beta.31) (2022-04-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium,types:** avoid call to assignServer() ([cd08daf](https://github.com/appium/appium/commit/cd08dafabcc16e718a5bdc6b96d5a7bcbfe6e1be))
|
||||
- **appium:** fix some argument-related types ([37cb3bd](https://github.com/appium/appium/commit/37cb3bd80c76f003940e680b7925b5c3bdc5144c))
|
||||
- **appium:** make types actually consumable ([8b814c9](https://github.com/appium/appium/commit/8b814c9243a7b51ecd0bc619146063aa5b0ccb76))
|
||||
|
||||
# [2.0.0-beta.30](https://github.com/appium/appium/compare/appium@2.0.0-beta.29...appium@2.0.0-beta.30) (2022-04-12)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.29](https://github.com/appium/appium/compare/appium@2.0.0-beta.28...appium@2.0.0-beta.29) (2022-04-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** Properly detect if a command is a session command ([#16737](https://github.com/appium/appium/issues/16737)) ([f8a5144](https://github.com/appium/appium/commit/f8a51443e490d9a373778499bfc440e8464ca2ed))
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/appium/appium/compare/appium@2.0.0-beta.27...appium@2.0.0-beta.28) (2022-04-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** allow multiple drivers to be installed ([0bbec13](https://github.com/appium/appium/commit/0bbec13d1e386b2fdf3f9cdcb43da78d6834f28f)), closes [#16674](https://github.com/appium/appium/issues/16674)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** generate declaration files ([#16597](https://github.com/appium/appium/issues/16597)) ([06a6054](https://github.com/appium/appium/commit/06a605420d761a830be267f0f96e12f4caa2c534))
|
||||
|
||||
# [2.0.0-beta.27](https://github.com/appium/appium/compare/appium@2.0.0-beta.26...appium@2.0.0-beta.27) (2022-03-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **base-driver:** Use WeakRef to reference the driver instance in the log prefix generator ([#16636](https://github.com/appium/appium/issues/16636)) ([bbfc7ef](https://github.com/appium/appium/commit/bbfc7ef51d8a5c7e99072ee599ce2a6265017ea4))
|
||||
|
||||
# [2.0.0-beta.26](https://github.com/appium/appium/compare/appium@2.0.0-beta.25...appium@2.0.0-beta.26) (2022-03-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** Increase the default limit of process listeners ([#16471](https://github.com/appium/appium/issues/16471)) ([a8315f3](https://github.com/appium/appium/commit/a8315f3f87862b3deeae90b4e21b133e9e3e78d5))
|
||||
- **appium:** make sure logsink init happens first since it patches npmlog globally (fix [#16519](https://github.com/appium/appium/issues/16519)) ([5abf852](https://github.com/appium/appium/commit/5abf85204614b47d2363097a5356f4bddf697352))
|
||||
- **appium:** remove bad log ([1dbeee2](https://github.com/appium/appium/commit/1dbeee200677a9c0452bb8c24d78da1e2b5e181c))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** allow installation of extensions via `npm` ([d89fb9b](https://github.com/appium/appium/commit/d89fb9b354b274f2ba410527d25d73af6743d76c))
|
||||
- **support:** move npm module into support ([2fbd49f](https://github.com/appium/appium/commit/2fbd49fed4cdf10fe1f4b374b5b44ae327ab3f85))
|
||||
|
||||
# [2.0.0-beta.25](https://github.com/appium/appium/compare/appium@2.0.0-beta.24...appium@2.0.0-beta.25) (2022-01-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** make show-config more right ([7470ed0](https://github.com/appium/appium/commit/7470ed00b2a8a8ebc39d62184a6ba5819b22f264)), closes [#16340](https://github.com/appium/appium/issues/16340)
|
||||
|
||||
# [2.0.0-beta.24](https://github.com/appium/appium/compare/appium@2.0.0-beta.23...appium@2.0.0-beta.24) (2022-01-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** correctly apply extension defaults ([20d95e4](https://github.com/appium/appium/commit/20d95e45313fc6aac30a2cf7b8f7bef156a17851))
|
||||
- **appium:** disallow unsupported schemas ([e074fee](https://github.com/appium/appium/commit/e074fee89f90a654407d01d3f3aea6b839bbf24f))
|
||||
- **appium:** fix behavior of ReadonlyMap to be compatible with Map ([88e351f](https://github.com/appium/appium/commit/88e351fc2da682bb4c8607259e001ed7e0f5d964))
|
||||
- **appium:** fix incorrect handling of delete session with regard to plugin driver assignment ([7b3893a](https://github.com/appium/appium/commit/7b3893a36202018de7c2124c2028bfbbd8a9d7fd))
|
||||
- **appium:** make object dumps less weird ([74a5911](https://github.com/appium/appium/commit/74a5911515f6c50f71fe6f18ddaa4f4fd2ed6d43))
|
||||
- Switch colors package to a non-compomised repository ([#16317](https://github.com/appium/appium/issues/16317)) ([40a6f05](https://github.com/appium/appium/commit/40a6f054dca3d94fc88773af9c6336ba12ebfb81))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** add --show-config ([#16207](https://github.com/appium/appium/issues/16207)) ([af96879](https://github.com/appium/appium/commit/af96879cfdbbe40773182c29a49fbf2f3cf7e233)), closes [#15672](https://github.com/appium/appium/issues/15672)
|
||||
|
||||
# [2.0.0-beta.23](https://github.com/appium/appium/compare/appium@2.0.0-beta.22...appium@2.0.0-beta.23) (2021-11-23)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** make server host/port information available to drivers and thereby plugins ([221a3ec](https://github.com/appium/appium/commit/221a3ecd5211fadcd375fe6d6c9df11f1af201a2))
|
||||
|
||||
# [2.0.0-beta.22](https://github.com/appium/appium/compare/appium@2.0.0-beta.21...appium@2.0.0-beta.22) (2021-11-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** create cjs wrapper ([24596d6](https://github.com/appium/appium/commit/24596d67b04590acb568322098c88efc190f6318))
|
||||
- **appium:** enable --relaxed-security ([46a2041](https://github.com/appium/appium/commit/46a2041fbdc80b6210d0214a4d9fb71312d57e1b)), closes [/github.com/appium/appium/discussions/16103#discussioncomment-1655985](https://github.com//github.com/appium/appium/discussions/16103/issues/discussioncomment-1655985)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** support for deprecated arguments ([aa69388](https://github.com/appium/appium/commit/aa69388c7a296d4d1e39a1ba0fbe23035a5ae8c5))
|
||||
|
||||
# [2.0.0-beta.21](https://github.com/appium/appium/compare/appium@2.0.0-beta.20...appium@2.0.0-beta.21) (2021-11-16)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** resolve-from is a dependency ([5443b57](https://github.com/appium/appium/commit/5443b570adf41042c4735410b1425d248adfd0a9))
|
||||
|
||||
# [2.0.0-beta.20](https://github.com/appium/appium/compare/appium@2.0.0-beta.19...appium@2.0.0-beta.20) (2021-11-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** add missing support for schema-as-object ([e951010](https://github.com/appium/appium/commit/e951010055118f6be1614abe40f5701daacb441c))
|
||||
- **appium:** add types for parsed argument object ([95dfe24](https://github.com/appium/appium/commit/95dfe24176bb7ff6957b7942164280a3a2fbd155))
|
||||
- **appium:** avoid deprecation warning from argparse ([fc56662](https://github.com/appium/appium/commit/fc566628f599e8a529f30344d291f2351665c5f7))
|
||||
- **appium:** bad type name ([a7fa66b](https://github.com/appium/appium/commit/a7fa66bb7dfb321cf2bf7c90e5e739841a8753e9))
|
||||
- **appium:** fix interaction of plugins with proxying ([7091008](https://github.com/appium/appium/commit/70910087d11100fe47627754ade379a2d3a7ff5d))
|
||||
- **appium:** if a sessionless plugin is used for createSession, promote it to a session plugin ([3f1bb4c](https://github.com/appium/appium/commit/3f1bb4c9c38046699e6d8be3dcd257bc53345eb9))
|
||||
- **appium:** properly validates config files containing extension config ([b7c230c](https://github.com/appium/appium/commit/b7c230c1e9da9206ea050387bc72c5dda3b31620))
|
||||
- **appium:** remove extra logging from config-file ([7381a13](https://github.com/appium/appium/commit/7381a13da3e76f7051639d3ab2ba376fbb625e80))
|
||||
- **appium:** restore missing call to validate extensions ([1a860ca](https://github.com/appium/appium/commit/1a860cade2fd3eac151c81c4efcd11364ee35479))
|
||||
- **appium:** stop calling plugins 'sessionless' since the name is immutable ([ead3e07](https://github.com/appium/appium/commit/ead3e0723f912a2c7e825d397fe2d4272ce3d6d0))
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** allow plugins to react to unexpected session shutdowns ([fff6b2e](https://github.com/appium/appium/commit/fff6b2eb004166fc147251c513086b72be857fbd))
|
||||
- **appium:** configuration file and schema support ([d52c36e](https://github.com/appium/appium/commit/d52c36e1eaaccc8b47de514bdeeef55ac348ecb8))
|
||||
|
||||
# [2.0.0-beta.19](https://github.com/appium/appium/compare/appium@2.0.0-beta.18...appium@2.0.0-beta.19) (2021-11-09)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.18](https://github.com/appium/appium/compare/appium@2.0.0-beta.17...appium@2.0.0-beta.18) (2021-09-16)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.17](https://github.com/appium/appium/compare/appium@2.0.0-beta.16...appium@2.0.0-beta.17) (2021-09-16)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.16](https://github.com/appium/appium/compare/appium@2.0.0-beta.15...appium@2.0.0-beta.16) (2021-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** add env var to trigger reloading of extensions ([ff3bb4f](https://github.com/appium/appium/commit/ff3bb4f4b538ee5136fdc6356ca00e09fcdc5533))
|
||||
|
||||
# [2.0.0-beta.15](https://github.com/appium/appium/compare/appium@2.0.0-beta.14...appium@2.0.0-beta.15) (2021-09-14)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
# [2.0.0-beta.14](https://github.com/appium/appium/compare/appium@2.0.0-beta.13...appium@2.0.0-beta.14) (2021-09-14)
|
||||
|
||||
### Features
|
||||
|
||||
- **appium:** support plugin-specific args via --plugin-args ([c8f12d1](https://github.com/appium/appium/commit/c8f12d1e95b84e225def500a05fddf440df8991a))
|
||||
|
||||
# [2.0.0-beta.13](https://github.com/appium/appium/compare/appium@2.0.0-beta.12...appium@2.0.0-beta.13) (2021-08-16)
|
||||
|
||||
# 2.0.0-beta (2021-08-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **appium:** load plugins before main server to allow plugin monkeypatching ([#15441](https://github.com/appium/appium/issues/15441)) ([52f4fc6](https://github.com/appium/appium/commit/52f4fc6a2cbdb612888ab2a23a704be32594a006))
|
||||
- **appium:** update references to @appium/support ([9295d0c](https://github.com/appium/appium/commit/9295d0c68284443ecd73add1f8fe0ff7910a7d7d))
|
||||
- **appium:** use proper base driver package & random ports ([e14d4fb](https://github.com/appium/appium/commit/e14d4fbd0fce16f208569b0cb9149b6307f78a5f))
|
||||
- **appium:** when updating extensions, make sure to actually remove the previous one first to avoid npm reinstall issues ([4839419](https://github.com/appium/appium/commit/483941974881bf2ad362c6e6cc35883743abcd2a))
|
||||
- **appium:** when updating extensions, package fields should also be updated in extensions.yaml ([756688b](https://github.com/appium/appium/commit/756688bddb624a6e9a5b5b6403db76eac65774f3))
|
||||
- do not assume git root and package.json have the same parent dir ([3c5fba7](https://github.com/appium/appium/commit/3c5fba7b38e02f4216d3a26340948d070f7ea9d9))
|
||||
- doc generation ([9e33c7a](https://github.com/appium/appium/commit/9e33c7ac1135306c6f0d1ff83b8076aecb54c554))
|
||||
- e2e-tests ([2499b49](https://github.com/appium/appium/commit/2499b49936660280eefaeb26cb3e4e9f82e36c20))
|
||||
- use random test port ([935b1f8](https://github.com/appium/appium/commit/935b1f80a47e89ccdf81781f35be5123bf8673d5))
|
||||
|
||||
### Features
|
||||
|
||||
- add "run" command to the client interface in order to allow running driver-defined scripts ([#15356](https://github.com/appium/appium/issues/15356)) ([a265476](https://github.com/appium/appium/commit/a2654762b6a9156380bcdf53df4cb0a8deb061fa))
|
||||
- **appium:** Add driver and plugin server arg injection feature ([#15388](https://github.com/appium/appium/issues/15388)) ([d3c11e3](https://github.com/appium/appium/commit/d3c11e364dffff87ac38ac8dc3ad65a1e4534a9a))
|
||||
@@ -1,221 +0,0 @@
|
||||
## Appium
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://npmjs.org/package/appium)
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
|
||||
|
||||
[](https://github.com/vshymanskyy/StandWithUkraine/)
|
||||
|
||||
[](https://vshymanskyy.github.io/StandWithUkraine/)
|
||||
|
||||
Appium is an open-source, cross-platform test automation tool for native,
|
||||
hybrid, mobile web and desktop apps. Initially created to automate iOS and Android mobile
|
||||
applications Appium has grown to a full-featured platform that provides [WebDriver](https://www.w3.org/TR/webdriver/)-based automation possibilities for the whole set of different mobile and desktop platforms.
|
||||
See [Drivers Maintained By The Appium Team](#drivers-maintained-by-the-appium-team)
|
||||
and [Drivers Provided By Third Parties](#drivers-provided-by-third-parties) sections below for more details.
|
||||
|
||||
:bangbang: Major documentation revision in progress
|
||||
|
||||
:bangbang: Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022. All recent versions of officially supported platform drivers are not compatible to Appium 1.x anymore, and require Appium 2 to run. [Please read the migration guide from 1.x to 2.0](https://github.com/appium/appium/blob/master/packages/appium/docs/en/guides/migrating-1-to-2.md) to manage the Appium server.
|
||||
|
||||
Appium is in the final stages of a major revision (to version 2.0). As such, the documentation
|
||||
found around the web may not be correct. The current Appium 2.0 documentation is very much in
|
||||
progress. Currently, it can be found [here](https://appium.github.io/appium/docs/en/2.0/).
|
||||
|
||||
### Requirements
|
||||
|
||||
- macOS, Linux or Windows operating system
|
||||
- Node.js 14+
|
||||
- NPM (Node Package Manager) 8+
|
||||
|
||||
These are only server requirements. Each driver might have its own requirements. Consider checking the corresponding driver tutorial for more details.
|
||||
|
||||
### Server
|
||||
|
||||
To install Appium 2 server using Node Package Manager (npm) run the following command:
|
||||
|
||||
```bash
|
||||
npm install -g appium@next
|
||||
```
|
||||
|
||||
:bangbang: Running `npm install -g appium` would still install Appium 1 because version 2 is in its late beta stage.
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
You can find a full list of
|
||||
[officially-supported](https://appium.github.io/appium/docs/en/latest/ecosystem/#drivers) and
|
||||
[third-party](https://appium.github.io/appium/docs/en/latest/ecosystem/#other-drivers) drivers at
|
||||
the current Appium 2.0 documentation.
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
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):
|
||||
|
||||
```bash
|
||||
appium server --use-plugins=device-farm,images
|
||||
```
|
||||
|
||||
You can find a full list of
|
||||
[officially-supported](https://appium.github.io/appium/docs/en/latest/ecosystem/#plugins) and
|
||||
[third-party](https://appium.github.io/appium/docs/en/latest/ecosystem/#other-plugins) plugins at
|
||||
the current Appium 2.0 documentation.
|
||||
|
||||
|
||||
### Server Command Line Interface
|
||||
|
||||
In order to start sending commands to Appium over the wire it must be listening
|
||||
on the URL where your client library expects it to listen.
|
||||
Use the following commands to run and configure Appium server:
|
||||
|
||||
```bash
|
||||
# Start the server on the default port and host (e.g. http://0.0.0.0:4723/)
|
||||
appium server
|
||||
# Start the server on the given port, host and use the base path prefix (the default prefix is /)
|
||||
appium server -p 9000 -a 127.0.0.1 -pa /wd/hub
|
||||
|
||||
# Get the list of all supported command line parameters.
|
||||
# This list would also include descriptions of driver-specific
|
||||
# command line arguments for all installed drivers.
|
||||
# Each driver and plugin must have their command line arguments
|
||||
# exposed in a special JSON schema declared as a part of the corresponding
|
||||
# package.json file.
|
||||
appium server --help
|
||||
```
|
||||
|
||||
Appium supports execution of parallel server processes as well as parallel driver sessions within
|
||||
single server process. Refer the corresponding driver documentations regarding which mode is optimal
|
||||
for the particular driver or whether it supports parallel sessions.
|
||||
|
||||
### Why Appium?
|
||||
|
||||
1. You usually don't have to recompile your app or modify it in any way, due
|
||||
to the use of standard automation APIs on all platforms.
|
||||
2. You can write tests with your favorite dev tools using any
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html)-compatible
|
||||
language such as [Java](https://github.com/appium/java-client),
|
||||
[JavaScript](https://webdriver.io/), [Python](https://github.com/appium/python-client),
|
||||
[Ruby](https://github.com/appium/ruby_lib), [C#](https://github.com/appium/dotnet-client)
|
||||
with the Selenium WebDriver API. There are also various third party
|
||||
client implementations for other languages.
|
||||
3. You can use any testing framework.
|
||||
4. Some drivers, like xcuitest and uiautomator2 ones have built-in mobile web and
|
||||
hybrid app support. Within the same script, you can switch seamlessly between native
|
||||
app automation and webview automation, all using the WebDriver model that's already
|
||||
the standard for web automation.
|
||||
5. You can run your automated tests locally and in a cloud. There are multiple
|
||||
cloud providers that support various Appium drivers (mostly
|
||||
targeting iOS and Android mobile automation).
|
||||
6. [Appium Inspector](https://github.com/appium/appium-inspector) allows
|
||||
visual debugging of automated tests and could be extremely useful for
|
||||
beginners.
|
||||
|
||||
Investing in the
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means
|
||||
you are betting on a single, free, and open protocol for testing that has become
|
||||
a web standard. Don't lock yourself into a proprietary stack.
|
||||
|
||||
For example, if you use Apple's XCUITest library without Appium you can only
|
||||
write tests using Obj-C/Swift, and you can only run tests through Xcode.
|
||||
Similarly, with Google's UiAutomator or Espresso, you can only write tests in
|
||||
Java/Kotlin. Appium opens up the possibility of true cross-platform native app
|
||||
automation, for mobile and beyond. Finally!
|
||||
|
||||
If you're new to Appium or want a more comprehensive description of what this is all
|
||||
about, please read our [Introduction to Appium Concepts](/docs/en/about-appium/intro.md).
|
||||
|
||||
### Get Started
|
||||
|
||||
Check out our [Getting Started](http://appium.io/docs/en/about-appium/getting-started) guide
|
||||
to get going with Appium.
|
||||
|
||||
There is also a sample code that contains [many examples of tests in a variety
|
||||
of different languages](https://github.com/appium/appium/tree/1.x/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) 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
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 © 2012 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
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
title: Server CLI Args
|
||||
---
|
||||
|
||||
To start the Appium server, you may either run `appium` or `appium server`. The `server` subcommand
|
||||
is considered to be the default, so if you omit it, Appium will interpret this as your request to
|
||||
run the Appium server. (You could run different subcommands, like `appium driver` or `appium
|
||||
plugin`: see the [Extensions CLI](./extensions.md) for more info).
|
||||
|
||||
The invocation of `appium` (or `appium server`) takes a number of arguments, which are detailed
|
||||
below.
|
||||
|
||||
!!! note
|
||||
|
||||
All of these arguments can be set via a [Configuration File](../guides/config.md) instead if
|
||||
you want. Any arguments set on the command line will override any arguments found in
|
||||
a configuration file.
|
||||
|
||||
|
||||
<!-- WARNING: anything between the AUTOGEN-START and AUTOGEN-STOP tags will get replaced by
|
||||
automatic docs generation tooling! Do not edit by hand! -->
|
||||
<!-- AUTOGEN-START -->
|
||||
|Argument |Description|Type|Default|Aliases|
|
||||
|--|--|--|--|--|
|
||||
|`--address`|IP address to listen on|string|`0.0.0.0`|`-a`|
|
||||
|`--allow-cors`|Whether the Appium server should allow web browser connections from any host|boolean|`false`||
|
||||
|`--allow-insecure`|Set which insecure features are allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Note that features defined via "deny-insecure" will be disabled, even if also listed here. If string, a path to a text file containing policy or a comma-delimited list.|array<string>|`[]`||
|
||||
|`--base-path`|Base path to use as the prefix for all webdriver routes running on the server|string|`""`|`-pa`|
|
||||
|`--callback-address`|Callback IP address (default: same as "address")|string||`-ca`|
|
||||
|`--callback-port`|Callback port (default: same as "port") (Value must be between `1` and `65535`)|integer|`4723`|`-cp`|
|
||||
|`--debug-log-spacing`|Add exaggerated spacing in logs to help with visual inspection|boolean|`false`||
|
||||
|`--default-capabilities`|Set the default desired capabilities, which will be set on each session unless overridden by received capabilities. If a string, a path to a JSON file containing the capabilities, or raw JSON.|object||`-dc`|
|
||||
|`--deny-insecure`|Set which insecure features are not allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Features listed here will not be enabled even if also listed in "allow-insecure", and even if "relaxed-security" is enabled. If string, a path to a text file containing policy or a comma-delimited list.|array<string>|`[]`||
|
||||
|`--driver`|Driver-specific configuration. Keys should correspond to driver package names|object|||
|
||||
|`--keep-alive-timeout`|Number of seconds the Appium server should apply as both the keep-alive timeout and the connection timeout for all requests. A value of 0 disables the timeout.|integer|`600`|`-ka`|
|
||||
|`--local-timezone`|Use local timezone for timestamps|boolean|`false`||
|
||||
|`--log`|Also send log output to this file|string||`-g`|
|
||||
|`--log-filters`|One or more log filtering rules|array|||
|
||||
|`--log-level`|Log level (console[:file]) (Value must be one of: `info`, `info:debug`, `info:info`, `info:warn`, `info:error`, `warn`, `warn:debug`, `warn:info`, `warn:warn`, `warn:error`, `error`, `error:debug`, `error:info`, `error:warn`, `error:error`, `debug`, `debug:debug`, `debug:info`, `debug:warn`, `debug:error`)|string|`debug`||
|
||||
|`--log-no-colors`|Do not use color in console output|boolean|`false`||
|
||||
|`--log-timestamp`|Show timestamps in console output|boolean|`false`||
|
||||
|`--long-stacktrace`|Add long stack traces to log entries. Recommended for debugging only.|boolean|`false`||
|
||||
|`--no-perms-check`|Do not check that needed files are readable and/or writable|boolean|`false`||
|
||||
|`--nodeconfig`|Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself|object|||
|
||||
|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object|||
|
||||
|`--port`|Port to listen on (Value must be between `1` and `65535`)|integer|`4723`|`-p`|
|
||||
|`--relaxed-security`|Disable additional security checks, so it is possible to use some advanced features, provided by drivers supporting this option. Only enable it if all the clients are in the trusted network and it's not the case if a client could potentially break out of the session sandbox. Specific features can be overridden by using "deny-insecure"|boolean|`false`||
|
||||
|`--session-override`|Enables session override (clobbering)|boolean|`false`||
|
||||
|`--strict-caps`|Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device|boolean|`false`||
|
||||
|`--tmp`|Absolute path to directory Appium can use to manage temp files. Defaults to C:\Windows\Temp on Windows and /tmp otherwise.|string|||
|
||||
|`--trace-dir`|Absolute path to directory Appium can use to save iOS instrument traces; defaults to <tmp>/appium-instruments|string|||
|
||||
|`--use-drivers`|A list of drivers to activate. By default, all installed drivers will be activated.|array<string>|`[]`||
|
||||
|`--use-plugins`|A list of plugins to activate. To activate all plugins, the value should be an array with a single item "all".|array<string>|`[]`||
|
||||
|`--webhook`|Also send log output to this http listener|string||`-G`|
|
||||
<!-- AUTOGEN-STOP -->
|
||||
@@ -1,197 +0,0 @@
|
||||
---
|
||||
title: The Extension CLI
|
||||
---
|
||||
|
||||
Appium allows for the flexible installation and management of _drivers_ (which provide Appium with
|
||||
the capability to automate a given platform) and *plugins* (which can augment or alter the way
|
||||
individual Appium commands work). For a conceptual understanding of these entities, please review
|
||||
the [Introduction](../intro/index.md). Management of drivers and plugins is handled by Appium's
|
||||
Extension CLI.
|
||||
|
||||
!!! note
|
||||
|
||||
This reference uses placeholders to refer to various options. Anywhere you see one of these
|
||||
placeholders in the reference, ensure you replace it with the correct type of actual content.
|
||||
|
||||
|Placeholder|Meaning|
|
||||
|--|--|
|
||||
|`<ext-type>`|"Extension type". It should be either `driver` or `plugin`. All the Extension CLI commands can be used with either drivers or plugins, so you must specify which type of extension will be used|
|
||||
|`<ext-name>`|"Extension name". This is the short name of the extension found in a call to `appium <ext-type> list`. This is distinct from the NPM package name of the extension or, in general, the "install spec" of the extension.|
|
||||
|`<install-spec>`|"Install specification". This refers to the string used to indicate what extension Appium should install.|
|
||||
|`<install-source>`|This refers to the method that Appium should use to install an extension.|
|
||||
|
||||
## Commands
|
||||
|
||||
All Extension CLI commands begin with `appium <ext-type>`, i.e., either `appium driver` or `appium
|
||||
plugin`.
|
||||
|
||||
All Extension CLI commands can take an optional `--json` argument, which will return the result of
|
||||
the command as a machine-readable JSON string rather than the standard output, which is colourized
|
||||
and tuned for human consumption.
|
||||
|
||||
### `list`
|
||||
|
||||
List installed and available extensions. "Available" extensions include those which are officially
|
||||
recognized by the Appium team, but you are not limited to installing only the extensions displayed
|
||||
in this list.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> list [--installed] [--updates] [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--installed`: show only installed extensions, not installed plus available extensions
|
||||
- `--updates`: for extensions installed via NPM, display a message if there are any updates
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
### `install`
|
||||
|
||||
Install an extension. If successful, respond with the short name of the extension which can be used
|
||||
in other invocations of the Extension CLI. If the extension is a driver, also note which platforms
|
||||
may be used with the driver.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> install <install-spec> [--source=<install-source>] [--package=<package-name>] [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<install-spec>`: this is the name, location, and/or version of the extension you want to
|
||||
install. Its possible values are dependent on the `<install-source>` (see below).
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--source`: this directs Appium where to find your extension. See below for a table of possible
|
||||
source types and corresponding install specification.
|
||||
- `--package`: when `<install-source>` is `git` or `github`, `--package` is required. It should be
|
||||
the Node.js package name of the extension. Without this information, Appium will not be able to
|
||||
find the installed package.
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
|Install source type|Behaviour|
|
||||
|--|--|
|
||||
|None|This is the default behaviour when no `--source` is used. In this case, Appium will look at `<install-spec>` and match it against the name of extensions available when running `appium <ext-type> list`, i.e., against the officially recognized extension names. If found, it will install that extension at the latest version via NPM|
|
||||
|`npm`|Install an extension based on its NPM package name. Here, `<install-spec>` must be the NPM package name with any additional NPM installation modifiers, like version (see below)|
|
||||
|`github`|Install an extension via a GitHub spec of the form `<org>/<repo>`|
|
||||
|`git`|Install an extension via a Git URL (e.g., `git+ssh://git-host.com/repo.git`)|
|
||||
|`local`|Install an extension via a local path. This must be a path to the directory where the Node.js package information for the driver is located.|
|
||||
|
||||
#### NPM-based `<install-spec>`
|
||||
|
||||
When Appium is installing an extension via NPM (as is the case when `--source` is either omitted or
|
||||
set to `npm`), the `<install-spec>` can be complex, and can include any kind of information allowed
|
||||
by `npm install`:
|
||||
|
||||
- `[@scope]/<name>`
|
||||
- `[@scope]/<name>@<version>`
|
||||
- `[@scope]/<name>@<tag>`
|
||||
- `[@scope]/<name>@<version range>`
|
||||
|
||||
#### Examples
|
||||
|
||||
- Install the latest XCUITest driver:
|
||||
|
||||
```
|
||||
appium driver install xcuitest
|
||||
```
|
||||
|
||||
- Install the XCUITest driver at version 4.11.1:
|
||||
|
||||
```
|
||||
appium driver install xcuitest@4.11.1
|
||||
```
|
||||
|
||||
- Install the `beta` version of the `@appium/fake-driver` from NPM:
|
||||
|
||||
```
|
||||
appium driver install --source=npm @appium/fake-driver@beta
|
||||
```
|
||||
|
||||
- Install a locally-developed plugin:
|
||||
|
||||
```
|
||||
appium plugin install --source=local /path/to/my/plugin
|
||||
```
|
||||
|
||||
### `update`
|
||||
|
||||
Update one or more extensions that have been installed via NPM. By default, Appium will not
|
||||
automatically update any extension that has a revision in its major version, so as to prevent
|
||||
unintended breaking changes.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> update <ext-name> [--unsafe] [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<ext-name>`: the name of the extension to update, or the string `installed` (which will update
|
||||
all installed extensions)
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--unsafe`: direct Appium to go ahead and update passed a major version boundary
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
### `uninstall`
|
||||
|
||||
Remove an installed extension.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> uninstall <ext-name> [--json]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<ext-name>`: the name of the extension to uninstall
|
||||
|
||||
Optional arguments:
|
||||
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
### `run`
|
||||
|
||||
Run a script included in an extension package. Extension authors can include runnable scripts that
|
||||
assist with setup or perform other tasks. These scripts are given names (called the `<script-name>`
|
||||
in this reference) by extension authors and will generally be documented in extension
|
||||
documentation.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
appium <ext-type> run <ext-name> [--json] <script-name> [script-args]
|
||||
```
|
||||
|
||||
Required arguments:
|
||||
|
||||
- `<ext-type>`: must be `driver` or `plugin`
|
||||
- `<ext-name>`: the name of the extension whose script you want to run
|
||||
- `<script-name>`: the name of the script the extension has published
|
||||
|
||||
Optional arguments:
|
||||
|
||||
* `script-args`: any arguments that Appium does not interpret as belonging to its own set of
|
||||
arguments will be passed along to the extension script
|
||||
- `--json`: return the result in JSON format
|
||||
|
||||
Example (run the `reset` script included with the UiAutomator2 driver):
|
||||
|
||||
```
|
||||
appium driver run uiautomator2 reset
|
||||
```
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
title: CLI Intro
|
||||
---
|
||||
|
||||
When you install Appium globally via `npm`, an executable shell script named `appium` is placed in
|
||||
your global Node `bin` folder, often also symlinked to places like `/usr/local/bin`. If your `PATH`
|
||||
is set up to look for programs in appropriate directory, then you will be able to run `appium` from
|
||||
the command line of your terminal, like any other executable. The `appium` program has three main
|
||||
subcommands, each of which has its own set of documentation:
|
||||
|
||||
1. The [`server`](./args.md) subcommand starts an Appium server listening for new session requests,
|
||||
and takes a variety of parameters related to the operation of the server and also those consumed
|
||||
by active drivers or plugins.
|
||||
2. The [Extension](./extensions) (`driver` and `plugin`) subcommands assist in managing Appium
|
||||
drivers and plugins.
|
||||
@@ -1,451 +0,0 @@
|
||||
---
|
||||
title: Appium's Config System
|
||||
---
|
||||
|
||||
Appium 2 supports [configuration files](../guides/config.md). A configuration file is intended to
|
||||
have (nearly) 1:1 parity with command-line arguments. An end user can supply Appium 2 with
|
||||
a configuration file, CLI args, or both (the args have precedence over the config file).
|
||||
|
||||
This document will be a technical overview of how the configuration system works. It is intended
|
||||
for Appium contributors, but will also explain the system's fundamental features.
|
||||
|
||||
## Reading a Config File
|
||||
|
||||
A config file is a JSON, JavaScript, or YAML file which can be validated against a schema. By
|
||||
default, this file will be named `.appiumrc.{json,js,yaml,yml}` and should be in the root of the
|
||||
project which depends upon `appium`. Other filenames and locations are supported via the `--config
|
||||
<file>` flag. For obvious reasons, the `config` argument is disallowed within config files.
|
||||
|
||||
In lieu of a separate file, configuration can be embedded in a project's `package.json` using the
|
||||
`appiumConfig` property, e.g.,:
|
||||
|
||||
```json
|
||||
{
|
||||
"appiumConfig": {
|
||||
"server": {
|
||||
"port": 12345
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`
|
||||
will call into `lib/config-file.js` to load and/or search for a configuration file and in
|
||||
`package.json`.
|
||||
|
||||
!!! note
|
||||
|
||||
It is not an error if configuration isn't found!
|
||||
|
||||
The [`lilconfig`](https://npm.im/lilconfig) package provides the search & load functionality; refer
|
||||
to its documentation for more information about the search paths. Additionally, Appium provides
|
||||
support for config files written in YAML via the package [`yaml`](https://npm.im/yaml).
|
||||
|
||||
If a config file is found and successfully [validated](#validation), the result will be merged with
|
||||
a set of defaults and any additionall CLI arguments. CLI arguments have precedence over config
|
||||
files, and config files have precedence over defaults.
|
||||
|
||||
## Validation
|
||||
|
||||
The same system is used for _both_ validation of config files _and_ command-line arguments.
|
||||
|
||||
The package [`ajv`](https://npm.im/ajv) provides validation. Of course, to make `ajv` validate
|
||||
anything, it must be provided a _schema_.
|
||||
|
||||
The _base_ schema is a [JSON Schema
|
||||
Draft-7](https://json-schema.org/draft/2020-12/json-schema-core.html)-compliant object exported by
|
||||
`lib/schema/appium-config-schema.js`. This schema defines configuration _native to Appium_, and
|
||||
only concerns its behavior as a _server_; it does not define configuration for any other
|
||||
functionality (e.g., the `plugin` or `driver` subcommands).
|
||||
|
||||
!!! warning
|
||||
|
||||
Note that this file is the _base_ schema; this will become painfully relevant.
|
||||
|
||||
This file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
|
||||
especially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files.
|
||||
|
||||
It is more straightforward to explain how config files are validated, so we'll start there.
|
||||
|
||||
### Validating Config Files
|
||||
|
||||
When a config file is found (`lib/config-file.js`), it will call the `validate` function exported
|
||||
from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to
|
||||
validate the data against the schema that Appium has provided it.
|
||||
|
||||
If the config file is invalid, errors will be generated to be displayed to the user. Finally, the
|
||||
`init` function will detect these errors, display them, and the process will exit.
|
||||
|
||||
I hope that made sense, because this is the easy part.
|
||||
|
||||
### Validating CLI Arguments
|
||||
|
||||
As mentioned earlier, the same system is used for validating both config files and CLI arguments.
|
||||
|
||||
Totally not judging, but Appium uses [`argparse`](https://npm.im/argparse) for its CLI argument
|
||||
parsing. This package, and others like it, provides an API to define the arguments a command-line
|
||||
Node.js script accepts, and will ultimately return an object representation of the user-supplied
|
||||
arguments.
|
||||
|
||||
Just as the schema defines what's allowed in a config file, it also defines what's allowed on the
|
||||
command-line.
|
||||
|
||||
#### Defining CLI Arguments via Schema
|
||||
|
||||
CLI arguments must be _defined_ before their values can be validated.
|
||||
|
||||
A JSON schema isn't a natural fit for defining CLI args--it needs some grease to make it work--but
|
||||
it's close enough that we can do so with an adapter and some custom metadata.
|
||||
|
||||
In `lib/cli/parser.js`, there's a wrapper around `argparse`'s `ArgumentParser`; it's called (wait
|
||||
for it)... `ArgParser`. The wrapper exists because we're doing some custom things with `argparse`,
|
||||
but is has nothing to do with the schema directly.
|
||||
|
||||
An `ArgParser` instance is created and its `parseArgs()` method is called with the raw CLI
|
||||
arguments. The definition of the accepted arguments comes from `lib/cli/args.js` in part--here, all
|
||||
of the arguments _not_ intended for use with the `server` subcommand are hard-coded (e.g., the
|
||||
`driver` subcommand and _its_ subcommands). `args.js` also contains a function `getServerArgs()`,
|
||||
which in turn calls into `toParserArgs` in `lib/schema/cli-args.js`. `lib/schema/cli-args.js` can
|
||||
be considered the "adapter" layer between `argparse` and the schema.
|
||||
|
||||
`toParserArgs` uses the `flattenSchema` function exported by `lib/schema/schema.js`, which
|
||||
"squashes" the schema into a key/value representation. Then, `toParserArgs` iterates over each
|
||||
key/value pair and "converts" it into a suitable `ArgumentOption` object for final handoff to
|
||||
`ArgParser`.
|
||||
|
||||
This adapter (`cli-args.js`) is where most of the mess is hidden; let's explore this rat's nest
|
||||
a bit further.
|
||||
|
||||
##### CLI & Schema Incongruities
|
||||
|
||||
The conversion algorithm (see function `subSchemaToArgDef` in `lib/schema/cli-args.js`) is mostly
|
||||
just hacks and special cases neatly packed into a function. Things that don't cleanly map from
|
||||
`argparse` to a JSON schema include, but are not limited to:
|
||||
|
||||
- A schema cannot natively express "store the value of `--foo=<value>` in a property called `bar`" in a schema (this corresponds to the `ArgumentOption['dest']` prop).
|
||||
- A schema cannot natively express aliases; e.g., `--verbose` can also be `-v`
|
||||
- A schema `enum` is not restricted to multiple types, but `argparse`'s equivalent `ArgumentOption['choices']` prop _is_
|
||||
- A schema does not know about `argparse`'s concept of "actions" (note that Appium is not currently using custom actions--though it did, and it could again).
|
||||
- `argparse` has no native type for `email`, `hostname`, `ipv4`, `uri` etc., and the schema does
|
||||
- Schema validation only _validates_, it does not perform translation, transformation, or coercion (mostly). `argparse` allows this.
|
||||
- Schemas allow the `null` type, for whatever reason. Ever pass `null` on the CLI?
|
||||
- `argparse` does not understand anything other than primitives; no objects, arrays, etc., and certainly not arrays of a particular type.
|
||||
|
||||
All of the above cases and others are handled by the adapter.
|
||||
|
||||
!!! warning
|
||||
|
||||
Some decisions made in the adapter were arrived at via coin toss. If you are curious about why
|
||||
something is the way it is, it's likely that it had to do _something_.
|
||||
|
||||
Let's look more closely at handling types.
|
||||
|
||||
#### Argument Types via `ajv`
|
||||
|
||||
While `argparse` allows consumers, via its API, to define the _type_ of various arguments (e.g.,
|
||||
a string, number, boolean flag, etc.), Appium mostly avoids these built-in types. _Why is that?_
|
||||
Well:
|
||||
|
||||
1. We already know the type of an argument, because we've defined it in a schema.
|
||||
2. `ajv` provides validation against a schema.
|
||||
3. A schema allows for greater expression of types, allowed values, etc., than `argparse` can provide natively.
|
||||
4. The expressiveness of a schema allows for better error messaging.
|
||||
|
||||
To that end, the adapter eschews `argparse`'s built-in types (see allowed string values of
|
||||
`ArgumentOption['type']`) and instead abuses the ability to provide a _function_ as a `type`. The
|
||||
exception is _boolean_ flags, which do not have a `type`, but rather `action: 'store_true'`. The
|
||||
world may never know why.
|
||||
|
||||
##### Types as Functions
|
||||
|
||||
When a `type` is a function, the function performs both validation _and_ coercion (if necessary).
|
||||
So what are these functions?
|
||||
|
||||
> Note: `type` is _omitted_ (and thus _not_ a function) from the `ArgumentOption` if the property
|
||||
> type is `boolean`, and is instead provided an `action` property of `store_true`. Yes, this is
|
||||
> weird. No, I don't know why.
|
||||
|
||||
Well... it depends upon the schema. But generally speaking, we create a _pipeline_ of functions,
|
||||
each corresponding to a keyword in the schema. Let's take the example of the `port` argument. In
|
||||
lieu of asking the OS which ports the `appium`-running user can bind to, this argument is expected
|
||||
to be an integer between 1 and 65535. This turns out to be two functions which we combine into
|
||||
a pipeline:
|
||||
|
||||
1. Convert the value to an integer, if possible. Because _every value in `process.argv` is a string_, we must coerce if we want a number.
|
||||
2. Use `ajv` to validate the integer against the schema for `port`. A schema lets us define a range via the `minimum` and `maximum` keywords. Read more about how this works in
|
||||
|
||||
Much like the config file validation, if errors are detected, Appium nicely tells the end-user and
|
||||
the process exits w/ some help text.
|
||||
|
||||
For other arguments which are naturally of non-primitive types, things are not so straightforward.
|
||||
|
||||
##### Transformers
|
||||
|
||||
Remember how `argparse` doesn't understand arrays? What if the most ergonomic way to express
|
||||
a value is, in fact, an array?
|
||||
|
||||
Well, Appium can't accept an array on the CLI, even though it can accept one in the config file.
|
||||
But Appium _can_ accept a comma-delimited string (a CSV "line"). Or a string filepath referring to
|
||||
a file which _contains_ a delimited list. Either way: by the time the value gets out of the
|
||||
argument parser, it should be an array.
|
||||
|
||||
And as mentioned above, the native facilities of a JSON schema cannot express this. However, it's
|
||||
possible to define a _custom keyword_ which Appium can then detect and handle accordingly. So
|
||||
that's what Appium does.
|
||||
|
||||
In this case, a custom keyword `appiumCliTransformer` is registered with `ajv`. The value of
|
||||
`appiumCliTransformer` (at the time of this writing) can be `csv` or `json`. In the base schema
|
||||
file, `appium-config-schema.js`, Appium uses `appiumCliTransformer: 'csv'` if this behavior is
|
||||
desired.
|
||||
|
||||
!!! note
|
||||
|
||||
Any property defined in the schema having type `array` will _automatically_ uses the `csv`
|
||||
transformer. Likewise, a property having type `object` will use the `json` transformer. It's
|
||||
conceivable that `array` may want to use the `json` transformer, but otherwise, the presence of
|
||||
the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not stricly
|
||||
necessary.
|
||||
|
||||
The adapter (remember the adapter?) creates a pipeline function including a special "CSV
|
||||
transformer" (transformers are defined in `lib/schema/cli-transformers.js`), and uses this function
|
||||
as the `type` property of the `ArgumentOption` passed into `argparse`. In this case, the `type:
|
||||
'array'` in the schema is ignored.
|
||||
|
||||
!!! note
|
||||
|
||||
The config file doesn't _need_ to perform any complex transformation of values, because it
|
||||
naturally allows Appium to define exactly what it expects. So Appium does no post-processing of
|
||||
config file values.
|
||||
|
||||
Properties that do not need this special treatment use `ajv` directly for validation. How this
|
||||
works requires some explanation, so that's next.
|
||||
|
||||
#### Validation of Individual Arguments via `ajv`
|
||||
|
||||
When we think of a JSON schema, we tend to think, "I have this JSON file and I want to validate it
|
||||
against the schema". That's valid, and in fact Appium does just that with config files! However,
|
||||
Appium does not do this when validating arguments.
|
||||
|
||||
!!! note
|
||||
|
||||
During implementation, I was tempted to mash all of the arguments together into
|
||||
a config-file-like data structure and then validate it all at once. I think that would have
|
||||
been _possible_, but since an object full of CLI arguments is a flat key/value structure and
|
||||
the schema is not, this seemed like trouble.
|
||||
|
||||
Instead, Appium validates a value against a specific property _within_ the schema. To do this, it
|
||||
maintains a mapping between a CLI argument definition and its corresponding property. The mapping
|
||||
itself is a `Map` with a unique identifier for the argument as the key, and an `ArgSpec`
|
||||
(`lib/schema/arg-spec.js`) object as the value.
|
||||
|
||||
An `ArgSpec` object stores the following metadata:
|
||||
|
||||
| Property Name | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------- |
|
||||
| `name` | Canonical name of the argument, corresponding to the property name in the schema. |
|
||||
| `extType?` | `driver` or `plugin`, if appropriate |
|
||||
| `extName?` | Extension name, if appropriate |
|
||||
| `ref` | Computed `$id` of the property in the schema |
|
||||
| `arg` | Argument as accepted on CLI, without leading dashes |
|
||||
| `dest` | Property name in parsed arguments object (as returned by `argparse`'s `parse_args()`) |
|
||||
| `defaultValue?` | Value of the `default` keyword in schema, if appropriate |
|
||||
|
||||
When a schema is [finalized](#schema-finalization), the `Map` is populated with `ArgSpec` objects
|
||||
for all known arguments.
|
||||
|
||||
So when the adapter is creating the pipeline of functions for the argument's `type`, it already has
|
||||
an `ArgSpec` for the argument. It creates a function which calls `validate(value, ref)` (in
|
||||
`lib/schema/schema.js`) where `value` is whatever the user provided, and `ref` is the `ref`
|
||||
property of the `ArgSpec`. The concept is that `ajv` can validate using _any_ `ref` it knows about;
|
||||
each property in a schema can be referenced by this `ref` whether it's defined or not. To help
|
||||
visualize, if a schema is:
|
||||
|
||||
```json
|
||||
{
|
||||
"$id": "my-schema.json",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ref` of `foo` would be `my-schema.json#/properties/foo`. Assuming our `Ajv` instance knows
|
||||
about this `my-schema.json`, then we can call its `getSchema(ref)` method (which has a `schema`
|
||||
property, but is a misnomer nonetheless) to get a validation function; `validate(value, ref)` in
|
||||
`schema.js` calls this validation function.
|
||||
|
||||
!!! note
|
||||
|
||||
The schema spec says a schema author can supply an explicit `$id` keyword to override this;
|
||||
it's unsupported by Appium at this time. If needed, extension authors must carefully use `$ref`
|
||||
without custom `$id`s. It's highly unlikely an extension would have a schema so complicated as
|
||||
to need this, however; Appium itself doesn't even use `$ref` to define its own properties!
|
||||
|
||||
Next, let's take a look at how Appium loads schemas. This actually happens _before_ any argument
|
||||
validation.
|
||||
|
||||
## Schema Loading
|
||||
|
||||
Let's ignore extensions for a moment, and start with the base schema.
|
||||
|
||||
When something first imports the `lib/schema/schema.js` module, an instance of an `AppiumSchema` is
|
||||
created. This is a singleton, and its methods are exported from the module (all of which are bound
|
||||
to the instance).
|
||||
|
||||
The constructor does very little; it instantiates an `Ajv` instance and configures it with Appium's
|
||||
[custom keywords](#custom-keyword-reference) and adds support for the `format` keyword via the
|
||||
[ajv-formats](https://npm.im/ajv-formats) module.
|
||||
|
||||
Otherwise, the `AppiumSchema` instance does not interact with the `Ajv` instance until its
|
||||
`finalize()` method (exported as `finalizeSchema()`) is called. When this method is called, we're
|
||||
saying "we are not going to add any more schemas; go ahead and create `ArgSpec` objects and
|
||||
register schemas with `ajv`".
|
||||
|
||||
When does finalization happen? Well:
|
||||
|
||||
1. When the `appium` executable begins, it _checks for and configures extensions_ (hand-wave) in `APPIUM_HOME`.
|
||||
2. Only then does it start to think about arguments--it instantiates an `ArgParser`, which (as you'll recall) runs the adapter to convert the schema to arguments.
|
||||
3. _Finalization happens here_--when creating the parser. Appium need the schema(s) to be registered with `ajv` in order to create validation functions for arguments.
|
||||
4. Thereafter, Appium parses the arguments with the `ArgParser`.
|
||||
5. Finally, decides what to do with the returned object.
|
||||
|
||||
Without extensions, `finalize()` still knows about the Appium base schema
|
||||
(`appium-config-schema.js`), and just registers that. However, step 1. above is doing a _lot of
|
||||
work_, so let's look at how extensions come into play.
|
||||
|
||||
## Extension Support
|
||||
|
||||
One of the design goals of this system is the following:
|
||||
|
||||
_An extension should be able to register custom CLI arguments with the Appium, and a user should be
|
||||
able to use them like any other argument_.
|
||||
|
||||
Previously, Appium 2.0 accepted arguments in this manner (via `--driverArgs`), but validation was
|
||||
hand-rolled and required extension implementors to use a custom API. It also required the user to
|
||||
awkwardly pass a JSON string as the configuration on the command-line. Further, no contextual help
|
||||
(via `--help`) existed for these arguments.
|
||||
|
||||
Now, by providing a schema for its options, a driver or plugin can register CLI arguments and
|
||||
config file schemas with Appium.
|
||||
|
||||
To register a schema, an extension must provide the `appium.schema` property in its `package.json`.
|
||||
The value may be a schema or a path to a schema. If the latter, the schema should be JSON or
|
||||
a CommonJS module (ESM not supported at this time, nor is YAML).
|
||||
|
||||
For any property in this schema, the property will appear as a CLI argument of the form
|
||||
`--<extension-type>-<extension-name>-<property-name>`. For example, if the `fake` driver provides
|
||||
a property `foo`, the argument will be `--driver-fake-foo`, and will show in `appium server --help`
|
||||
like any other CLI argument.
|
||||
|
||||
The corresponding property in a config file would be
|
||||
`server.<extension-type>.<extension-name>.<property-name>`, e.g.:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"fake": {
|
||||
"foo": "bar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The naming convention described above avoids problems of one extension type having a name conflict
|
||||
with a different extension type.
|
||||
|
||||
!!! note
|
||||
|
||||
While an extension can provide aliases via `appiumCliAliases`, "short" flags are disallowed,
|
||||
since all arguments from extensions are prefixed with `--<extension-type>-<extension-name>-`.
|
||||
The extension name and argument name will be kebab-cased for the CLI, according to [Lodash's
|
||||
rules](https://lodash.com/docs/4.17.15#kebabCase) around kebab-casing.
|
||||
|
||||
The schema object will look much like Appium's base schema, but it will only have top-level
|
||||
properties (nested properties are currently unsupported). Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "my rad schema for the cowabunga driver",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fizz": {
|
||||
"type": "string",
|
||||
"default": "buzz",
|
||||
"$comment": "corresponds to CLI --driver-cowabunga-fizz"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As written in a user's config file, this would be the `server.driver.cowabunga.fizz` property.
|
||||
|
||||
When extensions are loaded, the `schema` property is verified and the schema is registered with the
|
||||
`AppiumSchema` (it is _not_ registered with `Ajv` until `finalize()` is called).
|
||||
|
||||
During finalization, each registered schema is added to the `Ajv` instance. The schema is assigned
|
||||
an `$id` based on the extension type and name (which overrides whatever the extension provides, if
|
||||
anything). Schemas are also forced to disallowed unknown arguments via the `additionalProperties:
|
||||
false` keyword.
|
||||
|
||||
Behind the scenes, the base schema has `driver` and `plugin` properties which are objects. When
|
||||
finalized, a property is added to each--corresponding to an extension name--and the value of this
|
||||
property is a reference to the `$id` of a property in the extension schema. For example, the
|
||||
`server.driver` property will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"driver": {
|
||||
"cowabunga": {
|
||||
"$ref": "driver-cowabunga.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is why we call it the "base" schema--it is _mutated_ when extensions provide schemas. The
|
||||
extension schemas are kept separately, but the _references_ are added to the schema before it's
|
||||
ultimately added to `ajv`. This works because an `Ajv` instance understands references _from_ any
|
||||
schema it knows about _to_ any schema it knows about.
|
||||
|
||||
!!! note
|
||||
|
||||
This makes it impossible to provide a complete static schema for Appium _and_ the installed
|
||||
extensions (as of Nov 5 2021). A static `.json` schema _is_ generated from the base (via a Gulp
|
||||
task), but it does not contain any extension schemas. The static schema also has uses beyond
|
||||
Appium; e.g., IDEs can provide contextual error-checking of config files this way. Let's solve
|
||||
this?
|
||||
|
||||
Just like how we look up the reference ID of a particular argument in the base schema, validation
|
||||
of arguments from extensions happens the exact same way. If the `cowabunga` driver has the schema
|
||||
ID `driver-cowabunga.json`, then the `fizz` property can be referenced from any schema registered
|
||||
with `ajv` via `driver-cowabunga.json#/properties/fizz`. "Base" schema arguments begin with
|
||||
`appium.json#properties/` instead.
|
||||
|
||||
## Development Environment Support
|
||||
|
||||
During the flow of development, a couple extra tasks have been automated to maintain the base
|
||||
schema:
|
||||
|
||||
- As a post-transpilation step, a `lib/appium-config.schema.json` gets generated from
|
||||
- `lib/schema/appium-config-schema.js` (in addition to its CJS counterpart generated by Babel).
|
||||
- This file is under version control. It ends up being _copied_ to
|
||||
- `build/lib/appium-config.schema.json` in this step. A pre-commit hook (see
|
||||
- `scripts/generate-schema-declarations.js` in the root monorepo) generates
|
||||
- a `types/appium-config-schema.d.ts` from the above JSON file. The types in `types/types.d.ts`
|
||||
- depend upon this file. This file is under version control.
|
||||
|
||||
## Custom Keyword Reference
|
||||
|
||||
Keywords are defined in `lib/schema/keywords.js`.
|
||||
|
||||
- `appiumCliAliases`: allows a schema to express aliases (e.g., a CLI argument can be `--verbose` or `-v`). This is an array of strings. Strings shorter than three (3) characters will begin with a single dash (`-`) instead of a double-dash (`--`). Note that any argument provided by an extension will begin with a double-dash, because these are required to have the `--<extension-type>-<extension-name>-` prefix.
|
||||
- `appiumCliDest`: allows a schema to specify a custom property name in the post-`argprase` arguments objects. If not set, this becomes a camelCased string.
|
||||
- `appiumCliDescription`: allows a schema to override the description of the argument when displayed on the command-line. This is useful paired with `appiumCliTransformer` (or `array`/`object`-typed properties), since there's a substantial difference between what a CLI-using user can provide vs. what a config-file-using user can provide.
|
||||
- `appiumCliTransformer`: currently a choice between `csv` and `json`. These are custom functions which post-process a value. They are not used when loading & validating config files, but the idea should be that they result in the same object you'd get if you used whatever the config file wanted (e.g., an array of strings). `csv` is for comma-delimited strings and CSV files; `json` is for raw JSON strings and `.json` files.
|
||||
- `appiumCliIgnore`: If `true`, do not support this property on the CLI.
|
||||
- `appiumDeprecated`: If `true`, the property is considered "deprecated", and will be displayed as such to the user (e.g., in the `--help` output). Note the JSON Schema draft-2019-09 introduces a new keyword `deprecated` which we should use instead if upgrading to this metaschema. When doing so, `appiumDeprecated` should itself be marked as `deprecated`.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: Contributing to Appium
|
||||
---
|
||||
|
||||
This section of Appium's documentation is for those who are interested in contributing to Appium's
|
||||
development. It contains developer overviews, guides, and notes. Use the navigation menu to find
|
||||
a specific topic. All the information in these guides assumes in-depth familiarity with Appium
|
||||
already.
|
||||
|
||||
!!! warning
|
||||
|
||||
Developer information may not be kept up to date as frequently as user-facing information, or
|
||||
it may be most relevant in its current form on the online repository, not in this published
|
||||
version. Always be sure to check the repo or discuss with maintainers. We're always happy to
|
||||
help new contributors get started!
|
||||
|
||||
## Ways to Contribute
|
||||
|
||||
TODO
|
||||
|
||||
## The Appium Development Process
|
||||
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Building Docs for Appium Extensions
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,749 +0,0 @@
|
||||
---
|
||||
title: Building Appium Drivers
|
||||
---
|
||||
|
||||
Appium wants to make it easy for anyone to develop their own automation drivers as part of the
|
||||
Appium ecosystem. This guide will explain what's involved and how you can accomplish various driver
|
||||
development tasks using the tools Appium provides. This guide assumes you (1) are a competent user of
|
||||
Appium, (2) are a competent Node.js developer, and (3) that you have read and understood the
|
||||
[Driver Intro](../intro/drivers.md).
|
||||
|
||||
If that describes you, great! This guide will get you started.
|
||||
|
||||
## Before you create your driver
|
||||
|
||||
Before you get to work implementing your driver, it's important to have a few things sorted out.
|
||||
For example, you need to know what your driver will do. Which platform is it trying to expose
|
||||
WebDriver automation for?
|
||||
|
||||
Appium doesn't magically give you the power to automate any platform. All it does is give you a set
|
||||
of convenient tools for implementing the WebDriver Protocol. So if you want to create, for example,
|
||||
a driver for a new app platform, you'll need to know how to automate apps on that platform *without Appium*.
|
||||
|
||||
This usually means that you need to be very familiar with app development for a given platform. And
|
||||
it usually means that you will rely on tools or SDKs provided by the platform vendor.
|
||||
|
||||
Basically, if you can't answer the question **"how would I launch, remotely trigger behaviours, and
|
||||
read state from an app on this platform?" then you're not quite ready to write an Appium driver**.
|
||||
Make sure you do the research to feel comfortable that there *is* a path forward. Once there is,
|
||||
coding it up and making it available as an Appium driver should be the easy part!
|
||||
|
||||
## Other drivers to reference
|
||||
|
||||
One of the greatest things about building an Appium driver is that there are already a number of
|
||||
open source Appium drivers which you can look at for reference. There is
|
||||
a [fake-driver](https://github.com/appium/appium/tree/2.0/packages/fake-driver) sample driver which
|
||||
does basically nothing other than showcase some of the things described in this guide.
|
||||
|
||||
And of course, all of Appium's official drivers are open source and available in repositories at
|
||||
the project's GitHub organization. So if you ever find yourself asking, "how does a driver do X?",
|
||||
read the code for these drivers! Also don't be afraid to ask questions of the Appium developers if
|
||||
you get stuck; we're always happy to help make sure the driver development experience is a good
|
||||
one!
|
||||
|
||||
## Basic requirements for Appium drivers
|
||||
|
||||
These are the things your driver *must* do (or be), if you want it to be a valid Appium driver.
|
||||
|
||||
### Node.js package with Appium extension metadata
|
||||
|
||||
All Appium drivers are fundamentally Node.js packages, and therefore must have a valid
|
||||
`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in Node.js so it can be loaded by Appium.
|
||||
|
||||
Your `package.json` must include `appium` as a `peerDependency`. The requirements for the
|
||||
dependency versions should be as loose as possible (unless you happen to know your driver will only
|
||||
work with certain versions of Appium). For Appium 2.0, for example, this would look something like
|
||||
`^2.0.0`, declaring that your driver works with any version of Appium that starts with 2.x.
|
||||
|
||||
Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension
|
||||
metadata'):
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"appium": {
|
||||
"driverName": "fake",
|
||||
"automationName": "Fake",
|
||||
"platformNames": [
|
||||
"Fake"
|
||||
],
|
||||
"mainClass": "FakeDriver"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The required subfields are:
|
||||
|
||||
* `driverName`: this should be a short name for your driver.
|
||||
* `automationName`: this should be the string users will use for their `appium:automationName`
|
||||
capability to tell Appium to use *your* driver.
|
||||
* `platformNames`: this is an array of one or more platform names considered valid for your driver.
|
||||
When a user sends in the `platformName` capability to start a session, it must be included in
|
||||
this list for your driver to handle the session. Known platform name strings include: `iOS`,
|
||||
`tvOS`, `macOS`, `Windows`, `Android`.
|
||||
* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
|
||||
class which extends Appium's `BaseDriver` (see below).
|
||||
|
||||
### Extend Appium's `BaseDriver` class
|
||||
|
||||
Ultimately, your driver is much easier to write because most of the hard work of implementing the
|
||||
WebDriver protocol and handling certain common logic is taken care of already by Appium. This is
|
||||
all encoded up as a class which Appium exports for you to use, called `BaseDriver`. It is exported
|
||||
from `appium/driver`, so you can use one of these styles to import it and create your *own* class
|
||||
that extends it:
|
||||
|
||||
```js
|
||||
import {BaseDriver} from 'appium/driver';
|
||||
// or: const {BaseDriver} = require('appium/driver');
|
||||
|
||||
export class MyDriver extends BaseDriver {
|
||||
}
|
||||
```
|
||||
|
||||
### Make your driver available
|
||||
|
||||
That's basically it! With a Node.js package exporting a driver class and with correct Appium
|
||||
extension metadata, you've got yourself an Appium driver! Now it doesn't *do* anything, but you can
|
||||
load it up in Appium, start and stop sessions with it, etc...
|
||||
|
||||
To make it available to users, you could publish it via NPM. When you do so, your driver will be
|
||||
installable via the Appium CLI:
|
||||
|
||||
```
|
||||
appium driver install --source=npm <driver-package-on-npm>
|
||||
```
|
||||
|
||||
It's a good idea to test your driver first, of course. One way to see how it works within Appium is
|
||||
to install it locally first:
|
||||
|
||||
```
|
||||
appium driver install --source=local /path/to/your/driver
|
||||
```
|
||||
|
||||
### Developing your driver
|
||||
|
||||
How you develop your driver is up to you. It is convenient, however, to run it from within Appium
|
||||
without having to do lots of publishing and installing. The most straightforward way to do this is
|
||||
to include the most recent version of Appium as a `devDependency`, and then also your own driver,
|
||||
like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
...,
|
||||
"appium": "^2.0.0",
|
||||
"your-driver": "file:.",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your driver is
|
||||
listed as a dependency alongside it, it will be automatically "installed" and available. You can
|
||||
design your e2e tests this way, or if you're writing them in Node.js, you can simply import
|
||||
Appium's start server methods to handle starting and stopping the Appium server in Node. (TODO:
|
||||
reference an implementation of this in one of the open source drivers when ready).
|
||||
|
||||
Another way to do local development with an existing Appium server install is to simply install
|
||||
your driver locally:
|
||||
|
||||
```
|
||||
appium driver install --source=local /path/to/your/driver/dev/dir
|
||||
```
|
||||
|
||||
## Standard driver implementation ideas
|
||||
|
||||
These are things you will probably find yourself wanting to do when creating a driver.
|
||||
|
||||
### Set up state in a constructor
|
||||
|
||||
If you define your own constructor, you'll need to call `super` to make sure all the standard state
|
||||
is set up correctly:
|
||||
|
||||
```js
|
||||
constructor(args) {
|
||||
super(args);
|
||||
// now do your own thing
|
||||
}
|
||||
```
|
||||
|
||||
The `args` parameter here is the object containing all the CLI args used to start the Appium
|
||||
server.
|
||||
|
||||
### Define and validate accepted capabilities
|
||||
|
||||
You can define your own capabilities and basic validation for them. Users will always be able to
|
||||
send in capabilities that you don't define, but if they send in capabilities you have explicitly
|
||||
defined, then Appium will validate that they are of the correct type (and will check for the
|
||||
presence of required capabilities).
|
||||
|
||||
If you want to turn capability validation off entirely, set `this.shouldValidateCaps` to `false` in
|
||||
your constructor.
|
||||
|
||||
To give Appium your validation constraints, set `this.desiredCapConstraints` to a validation object
|
||||
in your constructor. Validation objects can be somewhat complex. Here's an example from the
|
||||
UiAutomator2 driver:
|
||||
|
||||
```js
|
||||
{
|
||||
app: {
|
||||
presence: true,
|
||||
isString: true
|
||||
},
|
||||
automationName: {
|
||||
isString: true
|
||||
},
|
||||
browserName: {
|
||||
isString: true
|
||||
},
|
||||
launchTimeout: {
|
||||
isNumber: true
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Start a session and read capabilities
|
||||
|
||||
Appium's `BaseDriver` already implements the `createSession` command, so you don't have to. However
|
||||
it's very common to need to perform your own startup actions (launching an app, running some
|
||||
platform code, or doing different things based on capabilities you have defined for your driver).
|
||||
So you'll probably end up overriding `createSession`. You can do so by defining the method in your
|
||||
driver:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) {
|
||||
const [sessionId, caps] = super.createSession(w3cCaps);
|
||||
// do your own stuff here
|
||||
return [sessionId, caps];
|
||||
}
|
||||
```
|
||||
|
||||
For legacy reasons, your function will receive old-style JSON Wire Protocol desired and required
|
||||
caps as the first two arguments. Given that the old protocol isn't supported anymore and clients
|
||||
have all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion
|
||||
about what `otherDriverData` is about, see the section below on concurrent drivers).
|
||||
|
||||
You'll want to make sure to call `super.createSession` in order to get the session ID as well as
|
||||
the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`
|
||||
locally here would have no effect other than changing what the user sees in the create session
|
||||
response).
|
||||
|
||||
So that's it! You can fill out the middle section with whatever startup logic your driver requires.
|
||||
|
||||
### End a session
|
||||
|
||||
If your driver requires any cleanup or shutdown logic, it's best to do it as part of overriding the
|
||||
implementation of `deleteSession`:
|
||||
|
||||
```js
|
||||
async deleteSession() {
|
||||
// do your own cleanup here
|
||||
// don't forget to call super!
|
||||
await super.deleteSession();
|
||||
}
|
||||
```
|
||||
|
||||
It's very important not to throw any errors here if possible so that all parts of session cleanup
|
||||
can succeed!
|
||||
|
||||
### Access capabilities and CLI args
|
||||
|
||||
You'll often want to read parameters the user has set for the session, whether as CLI args or as
|
||||
capabilities. The easiest way to do this is to access `this.opts`, which is a merge of all options,
|
||||
from the CLI or from capabilities. So for example to access the `appium:app` capability, you could
|
||||
simply get the value of `this.opts.app`.
|
||||
|
||||
If you care about knowing whether something was sent in as a CLI arg *or* a capability, you can
|
||||
access the `this.cliArgs` and `this.caps` objects explicitly.
|
||||
|
||||
In all cases, the `appium:` capability prefix will have been stripped away by the time you are
|
||||
accessing values here, for convenience.
|
||||
|
||||
### Implement WebDriver commands
|
||||
|
||||
You handle WebDriver commands by implementing functions in your driver class. Each member of the
|
||||
WebDriver Protocol, plus the various Appium extensions, has a corresponding function that you
|
||||
implement if you want to support that command in your driver. The best way to see which commands
|
||||
Appium supports and which method you need to implement for each command is to look at Appium's
|
||||
[routes.js](https://github.com/appium/appium/blob/2.0/packages/base-driver/lib/protocol/routes.js).
|
||||
Each route object in this file tells you the command name as well as the parameters you'd expect to
|
||||
receive for that command.
|
||||
|
||||
Let's take this block for example:
|
||||
```js
|
||||
'/session/:sessionId/url': {
|
||||
GET: {command: 'getUrl'},
|
||||
POST: {command: 'setUrl', payloadParams: {required: ['url']}},
|
||||
}
|
||||
```
|
||||
|
||||
Here we see that the route `/session/:sessionId/url` is mapped to two commands, one for a `GET`
|
||||
request and one for a `POST` request. If we want to allow our driver to change the "url" (or
|
||||
whatever that might mean for our driver), we can therefore implement the `setUrl` command, knowing
|
||||
it will take the `url` parameter:
|
||||
|
||||
```js
|
||||
async setUrl(url) {
|
||||
// your implementation here
|
||||
}
|
||||
```
|
||||
|
||||
A few notes:
|
||||
- all command methods should be `async` functions or otherwise return a `Promise`
|
||||
- you don't need to worry about protocol encoding/decoding. You will get JS objects as params, and
|
||||
can return JSON-serializable objects in response. Appium will take care of wrapping it up in the
|
||||
WebDriver protocol response format, turning it into JSON, etc...
|
||||
- all session-based commands receive the `sessionId` parameter as the last parameter
|
||||
- all element-based commands receive the `elementId` parameter as the second-to-last parameter
|
||||
- if your driver doesn't implement a command, users can still try to access the command, and will
|
||||
get a `501 Not Yet Implemented` response error.
|
||||
|
||||
### Implement element finding
|
||||
|
||||
Element finding is a special command implementation case. You don't actually want to override
|
||||
`findElement` or `findElements`, even though those are what are listed in `routes.js`. Appium does
|
||||
a lot of work for you if instead you implement this function:
|
||||
|
||||
```js
|
||||
async findElOrEls(strategy, selector, mult, context) {
|
||||
// find your element here
|
||||
}
|
||||
```
|
||||
|
||||
Here's what gets passed in:
|
||||
|
||||
- `strategy` - a string, the locator strategy being used
|
||||
- `selector` - a string, the selector
|
||||
- `mult` - boolean, whether the user has requested one element or all elements matching the
|
||||
selector
|
||||
- `context` - (optional) if defined, will be a W3C Element (i.e., a JS object with the W3C element
|
||||
identifier as the key and the element ID as the value)
|
||||
|
||||
And you need to return one of the following:
|
||||
|
||||
- a single W3C element (an object as described above)
|
||||
- an array of W3C elements
|
||||
|
||||
Note that you can import that W3C web element identifier from `appium/support`:
|
||||
|
||||
```js
|
||||
import {util} from 'appium/support';
|
||||
const { W3C_WEB_ELEMENT_IDENTIFIER } = util;
|
||||
```
|
||||
|
||||
What you do with elements is up to you! Usually you end up keeping a cache map of IDs to actual
|
||||
element "objects" or whatever the equivalent is for your platform.
|
||||
|
||||
### Define valid locator strategies
|
||||
|
||||
Your driver might only support a subset of the standard WebDriver locator strategies, or it might
|
||||
add its own custom locator strategies. To tell Appium which strategies are considered valid for
|
||||
your driver, create an array of strategies and assign it to `this.locatorStrategies`:
|
||||
|
||||
```js
|
||||
this.locatorStrategies = ['xpath', 'custom-strategy'];
|
||||
```
|
||||
|
||||
Appium will throw an error if the user attempts to use any strategies other than the allowed ones,
|
||||
which enables you to keep your element finding code clean and deal with only the strategies you
|
||||
know about.
|
||||
|
||||
By default, the list of valid strategies is empty, so if your driver isn't simply proxying to
|
||||
another WebDriver endpoint, you'll need to define some. The protocol-standard locator strategies
|
||||
are defined [here](https://www.w3.org/TR/webdriver/#locator-strategies).
|
||||
|
||||
### Throw WebDriver-specific errors
|
||||
|
||||
The WebDriver spec defines a [set of error
|
||||
codes](https://github.com/jlipps/simple-wd-spec#error-codes) to accompany command responses if an
|
||||
error occurred. Appium has created error classes for each of these codes, so you can throw the
|
||||
appropriate error from inside a command, and it will do the right thing in terms of the protocol
|
||||
response to the user. To get access to these error classes, import them from `appium/driver`:
|
||||
|
||||
```
|
||||
import {errors} from 'appium/driver';
|
||||
|
||||
throw new errors.NoSuchElementError();
|
||||
```
|
||||
|
||||
### Log messages to the Appium log
|
||||
|
||||
You can always use `console.log`, of course, but Appium provides a nice logger for you as
|
||||
`this.log` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log
|
||||
levels). If you want to create an Appium logger outside of a driver context (say in a script or
|
||||
helper file), you can always construct your own too:
|
||||
|
||||
```js
|
||||
import {logging} from 'appium/support';
|
||||
const log = logging.getLogger('MyDriver');
|
||||
```
|
||||
|
||||
## Further possibilities for Appium drivers
|
||||
|
||||
These are things your driver *can* do to take advantage of extra driver features or do its job more
|
||||
conveniently.
|
||||
|
||||
### Add a schema for custom command line arguments
|
||||
|
||||
You can add custom CLI args if you want your driver to receive data from the command line when the
|
||||
Appium server is started (for example, ports that a server administrator should set that should not
|
||||
be passed in as capabilities.
|
||||
|
||||
To define CLI arguments (or configuration properties) for the Appium server, your extension must provide a _schema_. In
|
||||
the `appium` property of your extension's `package.json`, add a `schema` property. This will either
|
||||
a) be a schema itself, or b) be a path to a schema file.
|
||||
|
||||
The rules for these schemas:
|
||||
|
||||
- Schemas must conform to [JSON Schema Draft-07](https://ajv.js.org/json-schema.html#draft-07).
|
||||
- If the `schema` property is a path to a schema file, the file must be in JSON or JS (CommonJS) format.
|
||||
- Custom `$id` values are unsupported. To use `$ref`, provide a value relative to the schema root, e.g., `/properties/foo`.
|
||||
- Known values of the `format` keyword are likely supported, but various other keywords may be unsupported. If you find a keyword that is unsupported which you need to use, please [ask for support](https://github.com/appium/appium/issues/new) or send a PR!
|
||||
- The schema must be of type `object` (`{"type": "object"}`), containing the arguments in a `properties` keyword. Nested properties are unsupported.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"test-web-server-port": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535,
|
||||
"description": "The port to use for the test web server"
|
||||
},
|
||||
"test-web-server-host": {
|
||||
"type": "string",
|
||||
"description": "The host to use for the test web server",
|
||||
"default": "sillyhost"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above schema defines two properties which can be set via CLI argument or configuration file. If
|
||||
this extension is a _driver_ and its name is "horace", the CLI args would be
|
||||
`--driver-horace-test-web-server-port` and `--driver-horace-test-web-server-host`, respectively.
|
||||
Alternatively, a user could provide a configuration file containing:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"horace": {
|
||||
"test-web-server-port": 1234,
|
||||
"test-web-server-host": "localhorse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Add driver scripts
|
||||
|
||||
Sometimes you might want users of your driver to be able to run scripts outside the context of
|
||||
a session (for example, to run a script that pre-builds aspects of your driver). To support this,
|
||||
you can add a map of script names and JS files to the `scripts` field within your Appium extension
|
||||
metadata. So let's say you've created a script in your project that lives in a `scripts` directory
|
||||
in your project, named `driver-prebuild.js`. Then you could add a `scripts` field like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"prebuild": "./scripts/driver-prebuild.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, assuming your driver is named `mydriver`, users of your driver can run `appium driver run
|
||||
mydriver prebuild`, and your script will execute.
|
||||
|
||||
### Proxy commands to another WebDriver implementation
|
||||
|
||||
A very common design architecture for Appium drivers is to have some kind of platform-specific
|
||||
WebDriver implementation that the Appium driver interfaces with. For example, the Appium
|
||||
UiAutomator2 driver interfaces with a special (Java-based) server running on the Android device. In
|
||||
webview mode, it also interfaces with Chromedriver.
|
||||
|
||||
If you find yourself in this situation, it is extremely easy to tell Appium that your driver is
|
||||
just going to be proxying WebDriver commands straight to another endpoint.
|
||||
|
||||
First, let Appium know that your driver *can* proxy by implementing the `canProxy` method:
|
||||
|
||||
```js
|
||||
canProxy() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Next, tell Appium which WebDriver routes it should *not* attempt to proxy (there often end up being
|
||||
certain routes that you don't want to forward on):
|
||||
|
||||
```js
|
||||
getProxyAvoidList() {
|
||||
return [
|
||||
['POST', new RegExp('^/session/[^/]+/appium')]
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
The proxy avoidance list should be an array of arrays, where each inner array has an HTTP method as
|
||||
its first member, and a regular expression as its second. If the regular expression matches the
|
||||
route, then the route will not be proxied and instead will be handled by your driver. In this
|
||||
example, we are avoiding proxying all `POST` routes that have the `appium` prefix.
|
||||
|
||||
Next, we have to set up the proxying itself. The way to do this is to use a special class from
|
||||
Appium called `JWProxy`. (The name means "JSON Wire Proxy" and is related to a legacy
|
||||
implementation of the protocol). You'll want to create a `JWProxy` object using the details required to
|
||||
connect to the remote server:
|
||||
|
||||
```js
|
||||
// import {JWProxy} from 'appium/driver';
|
||||
|
||||
const proxy = new JWProxy({
|
||||
server: 'remote.server',
|
||||
port: 1234,
|
||||
base: '/',
|
||||
});
|
||||
|
||||
this.proxyReqRes = proxy.proxyReqRes.bind(proxy);
|
||||
this.proxyCommand = proxy.command.bind(proxy);
|
||||
```
|
||||
|
||||
Here we are creating a proxy object and assigning some of its methods to `this` under the names
|
||||
`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget
|
||||
this step! The `JWProxy` has a variety of other options which you can check out in the source code,
|
||||
as well. (TODO: publish options as API docs and link here).
|
||||
|
||||
Finally, we need a way to tell Appium when the proxy is active. For your driver it might always
|
||||
be active, or it might only be active when in a certain context. You can define the logic as an
|
||||
implementation of `proxyActive`:
|
||||
|
||||
```js
|
||||
proxyActive() {
|
||||
return true; // or use custom logic
|
||||
}
|
||||
```
|
||||
|
||||
With those pieces in play, you won't have to reimplement anything that's already implemented by the
|
||||
remote endpoint you're proxying to. Appium will take care of all the proxying for you.
|
||||
|
||||
### Extend the existing protocol with new commands
|
||||
|
||||
You may find that the existing commands don't cut it for your driver. If you want to expose
|
||||
behaviours that don't map to any of the existing commands, you can create new commands in one of
|
||||
two ways:
|
||||
|
||||
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
|
||||
1. Overloading the Execute Script command by defining [Execute
|
||||
Methods](../guides/execute-methods.md)
|
||||
|
||||
If you want to follow the first path, you can direct Appium to recognize new methods and add them
|
||||
to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`
|
||||
static variable in your driver class to an object of the same form as Appium's `routes.js` object.
|
||||
For example, here is the `newMethodMap` for the `FakeDriver` example driver:
|
||||
|
||||
```js
|
||||
static newMethodMap = {
|
||||
'/session/:sessionId/fakedriver': {
|
||||
GET: {command: 'getFakeThing'},
|
||||
POST: {command: 'setFakeThing', payloadParams: {required: ['thing']}},
|
||||
},
|
||||
'/session/:sessionId/fakedriverargs': {
|
||||
GET: {command: 'getFakeDriverArgs'},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
In this example we're adding a few new routes and a total of 3 new commands. For more examples of
|
||||
how to define commands in this way, it's best to have a look through `routes.js`. Now all you need
|
||||
to do is implement the command handlers in the same way you'd implement any other Appium command.
|
||||
|
||||
The downside of this way of adding new commands is that people using the standard Appium clients
|
||||
won't have nice client-side functions designed to target these endpoints. So you would need to
|
||||
create and release client-side plugins for each language you want to support (directions or
|
||||
examples can be found at the relevant client docs).
|
||||
|
||||
An alternative to this way of doing things is to overload a command which all WebDriver clients
|
||||
have access to already: Execute Script. Appium provides some a convenient tool for making this
|
||||
easy. Let's say you are building a driver for stereo system called `soundz`, and you wanted to
|
||||
create a command for playing a song by name. You could expose this to your users in such a way that
|
||||
they call something like:
|
||||
|
||||
```js
|
||||
// webdriverio example. Calling webdriverio's `executeScript` command is what trigger's Appium's
|
||||
// Execute Script command handler
|
||||
driver.executeScript('soundz: playSong', [{song: 'Stairway to Heaven', artist: 'Led Zeppelin'}]);
|
||||
```
|
||||
|
||||
Then in your driver code you can define the static property `executeMethodMap` as a mapping of
|
||||
script names to methods on your driver. It has the same basic form as `newMethodMap`, described
|
||||
above. Once `executeMethodMap` is defined, you'll also need to implement the Execute Script command
|
||||
handler, which according to Appium's routes mapping is called `execute`. The implementation can
|
||||
call a single helper function, `this.executeMethod`, which takes care of looking at the script and
|
||||
arguments the user sent in and routing it to the correct custom handler you've defined. Here's an
|
||||
example:
|
||||
|
||||
```js
|
||||
static executeMethodMap = {
|
||||
'soundz: playSong', {
|
||||
command: 'soundzPlaySong',
|
||||
params: {required: ['song', 'artist'], optional: []},
|
||||
}
|
||||
}
|
||||
|
||||
async soundzPlaySong(song, artist) {
|
||||
// play the song based on song and artist details
|
||||
}
|
||||
|
||||
async execute(script, args) {
|
||||
return await this.executeMethod(script, args);
|
||||
}
|
||||
```
|
||||
|
||||
A couple notes about this system:
|
||||
1. The arguments array sent via the call to Execute Script must contain only zero or one element(s). The
|
||||
first item in the list is considered to be the parameters object for your method. These parameters
|
||||
will be parsed, validated, and then applied to your overload method in the order specified in
|
||||
`executeMethodMap` (the order specified in the `required` parameters list, followed by the
|
||||
`optional` parameters list). I.e., this framework assumes only a single actual argument sent in via
|
||||
Execute Script (and this argument should be an object with keys/values representing the
|
||||
parameters your execute method expects).
|
||||
1. Appium does not automatically implement `execute` (the Execute Script handler) for you. You may
|
||||
wish, for example, to only call the `executeMethod` helper function when you're not in proxy
|
||||
mode!
|
||||
1. The `executeMethod` helper will reject with an error if a script name doesn't match one of the
|
||||
script names defined as a command in `executeMethodMap`, or if there are missing parameters.
|
||||
|
||||
### Implement handling of Appium settings
|
||||
|
||||
Appium users can send parameters to your driver via CLI args as well as via capabilities. But these
|
||||
cannot change during the course of a test, and sometimes users want to adjust parameters mid-test.
|
||||
Appium has a [Settings](../guides/settings.md) API for this purpose.
|
||||
|
||||
To support settings in your own driver, first of all define `this.settings` to be an instance of
|
||||
the appropriate class, in your constructor:
|
||||
|
||||
```js
|
||||
// import {DeviceSettings} from 'appium/driver';
|
||||
|
||||
this.settings = new DeviceSettings();
|
||||
```
|
||||
|
||||
Now, you can read user settings any time simply by calling `this.settings.getSettings()`. This will
|
||||
return a JS object where the settings names are keys and have their corresponding values.
|
||||
|
||||
If you want to assign some default settings, or run some code on your end whenever settings are
|
||||
updated, you can do both of these things as well.
|
||||
|
||||
```js
|
||||
constructor() {
|
||||
const defaults = {setting1: 'value1'};
|
||||
this.settings = new DeviceSettings(defaults, this.onSettingsUpdate.bind(this));
|
||||
}
|
||||
|
||||
async onSettingsUpdate(key, value) {
|
||||
// do anything you want here with key and value
|
||||
}
|
||||
```
|
||||
|
||||
### Make itself aware of resources other concurrent drivers are using
|
||||
|
||||
Let's say your driver uses up some system resources, like ports. There are a few ways to make sure
|
||||
that multiple simultaneous sessions don't use the same resources:
|
||||
|
||||
1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc)
|
||||
1. Just always use free resources (find a new random port for each session)
|
||||
1. Have each driver express what resources it is using, then examine currently-used resources from
|
||||
other drivers when a new session begins.
|
||||
|
||||
To support this third strategy, you can implement `get driverData` in your driver to return what
|
||||
sorts of resources your driver is currently using, for example:
|
||||
|
||||
```js
|
||||
get driverData() {
|
||||
return {specialPort: 1234, specialFile: /path/to/file}
|
||||
}
|
||||
```
|
||||
|
||||
Now, when a new session is started on your driver, the `driverData` response from any other
|
||||
simultaneously running drivers (of the same type) will also be included, as the last parameter of
|
||||
the `createSession` method:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, driverData)
|
||||
```
|
||||
|
||||
You can dig into this `driverData` array to see what resources other drivers are using to help
|
||||
determine which ones you want to use for this particular session.
|
||||
|
||||
!!! warning
|
||||
|
||||
Be careful here, since `driverData` is only passed between sessions of a single running Appium
|
||||
server. There's nothing to stop a user from running multiple Appium servers and requesting your
|
||||
driver simultaneously on each of them. In this case, you won't be able to ensure independence
|
||||
of resources via `driverData`, so you might consider using file-based locking mechanisms or
|
||||
something similar.
|
||||
|
||||
!!! warning
|
||||
|
||||
It's also important to note you will only receive `driverData` for other instances of *your*
|
||||
driver. So unrelated drivers also running may still be using some system resources. In general
|
||||
Appium doesn't provide any features for ensuring unrelated drivers don't interfere with one
|
||||
another, so it's up to the drivers to allow users to specify resource locations or addresses to
|
||||
avoid clashes.
|
||||
|
||||
### Log events to the Appium event timeline
|
||||
|
||||
Appium has an [Event Timing API](../guides/event-timing.md) which allows users to get timestamps
|
||||
for certain server-side events (like commands, startup milestones, etc...) and display them on
|
||||
a timeline. The feature basically exists to allow introspection of timing for internal events to
|
||||
help with debugging or running analysis on Appium driver internals. You can add your own events to
|
||||
the event log:
|
||||
|
||||
```js
|
||||
this.logEvent(name);
|
||||
```
|
||||
|
||||
Simply provide a name for the event and it will be added at the current time, and made accessible
|
||||
as part of the event log for users.
|
||||
|
||||
### Hide behaviour behind security flags
|
||||
|
||||
Appium has a feature-flag based [security model](../guides/security.md) that allows driver authors
|
||||
to hide certain features behind security flags. What this means is that if you have a feature you
|
||||
deem insecure and want to require server admins to opt in to it, you can require that they enable
|
||||
the feature by adding it to the `--allow-insecure` list or turning off server security entirely.
|
||||
|
||||
To support the check within your own driver, you can call `this.isFeatureEnabled(featureName)` to
|
||||
determine whether a feature of the given name has been enabled. Or, if you want to simply
|
||||
short-circuit and throw an error if the feature isn't enabled, you can call
|
||||
`this.assertFeatureEnabled(featureName)`.
|
||||
|
||||
### Use a temp dir for files
|
||||
|
||||
If you want to use a temporary directory for files your driver creates that are not important to
|
||||
keep around between computer or server restarts, you can simply read from `this.opts.tmpDir`. This
|
||||
reads the temporary directory location from `@appium/support`, potentially overridden by a CLI
|
||||
flag. I.e., it's safer than writing to your own temporary directory because the location here plays
|
||||
nicely with possible user configuration. `this.opts.tmpDir` is a string, the path to the dir.
|
||||
|
||||
### Deal with unexpected shutdowns or crashes
|
||||
|
||||
Your driver might run into a situation where it can't continue operating normally. For example, it
|
||||
might detect that some external service has crashed and nothing will work anymore. In this case, it
|
||||
can call `this.startUnexpectedShutdown(err)` with an error object including any details, and Appium
|
||||
will attempt to gracefully handle any remaining requests before shutting down the session.
|
||||
|
||||
If you want to perform some of your own cleanup logic when you encounter this condition, you can
|
||||
either do so immediately before calling `this.startUnexpectedShutdown`, or you can attach a handler
|
||||
to the unexpected shutdown event and run your cleanup logic "out of band" so to speak:
|
||||
|
||||
```js
|
||||
this.onUnexpectedShutdown(handler)
|
||||
```
|
||||
|
||||
`handler` should be a function which receives an error object (representing the reason for the
|
||||
unexpected shutdown).
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Building Appium Plugins
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,99 +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 currently
|
||||
maintained by the Appium team. 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)|
|
||||
|--|--|--|--|
|
||||
|[Chromium](https://github.com/appium/appium-chromium-driver)|`chromium`|macOS, Windows, Linux|Web|
|
||||
|[Espresso](https://github.com/appium/appium-espresso-driver)|`espresso`|Android|Native|
|
||||
|[Gecko](https://github.com/appium/appium-geckodriver)|`gecko`|macOS, Windows, Linux, Android|Web|
|
||||
|[Mac2](https://github.com/appium/appium-mac2-driver)|`mac2`|macOS|Native|
|
||||
|[Safari](https://github.com/appium/appium-safari-driver)|`safari`|macOS, iOS|Web|
|
||||
|[UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)|`uiautomator2`|Android|Native, Hybrid, Web|
|
||||
|[XCUITest](https://github.com/appium/appium-xcuitest-driver)|`xcuitest`|iOS|Native, Hybrid, Web|
|
||||
|
||||
And of course, you can install any other drivers you find out there by using the Appium driver CLI.
|
||||
|
||||
### Other drivers
|
||||
|
||||
These drivers are not maintained by the Appium team and can be used to target additional platforms.
|
||||
|
||||
|Driver|Installation Key|Platform(s)|Mode(s)|Supported By|
|
||||
|--|--|--|--|--|
|
||||
|[Flutter](https://github.com/appium-userland/appium-flutter-driver)|`--source=npm appium-flutter-driver`|iOS, Android|Native|Community|
|
||||
|[LG WebOS](https://github.com/headspinio/appium-lg-webos-driver)|`--source=npm appium-lg-webos-driver`|LG TV|Web|HeadSpin|
|
||||
|[Linux](https://github.com/fantonglang/appium-linux-driver)|`--source=npm @stdspa/appium-linux-driver`|Linux|Native|`@fantonglang`|
|
||||
|[Roku](https://github.com/headspinio/appium-roku-driver)|`--source=npm @headspinio/appium-roku-driver`|Roku|Native|HeadSpin|
|
||||
|[Tizen](https://github.com/Samsung/appium-tizen-driver)|`--source=npm appium-tizen-driver`|Android|Native|Community / Samsung|
|
||||
|[TizenTV](https://github.com/headspinio/appium-tizen-tv-driver)|`--source=npm appium-tizen-tv-driver`|Samsung TV|Web|HeadSpin|
|
||||
|[Windows](https://github.com/appium/appium-windows-driver)|`--source=npm appium-windows-driver`|Windows|Native|Community / Microsoft|
|
||||
|[Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver)|`--source=npm appium-youiengine-driver`|iOS, Android, macOS, Linux, tvOS|Native|Community / You.i|
|
||||
|
||||
!!! note
|
||||
|
||||
If you maintain an Appium driver that you would like to be listed in the Appium docs, feel free
|
||||
to make a PR to add it to this section with a link to the driver documentation.
|
||||
|
||||
## 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|Supported By|
|
||||
|-|-|-|
|
||||
|[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 Core client](https://github.com/appium/ruby_lib_core) (Recommended)<br>[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/dotnet-client)|C#|Appium Team*|
|
||||
|[RobotFramework](https://github.com/serhatbolsu/robotframework-appiumlibrary)|DSL|Community|
|
||||
|
||||
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.
|
||||
|
||||
## Plugins
|
||||
|
||||
Appium Plugins offer ways to extend or modify Appium's behaviour. This is the list of plugins that
|
||||
are currently maintained by the Appium Team:
|
||||
|
||||
|Plugin|Installation Key|Description|Supported By|
|
||||
|---|---|---|---|
|
||||
|[Execute Driver](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin)|`execute-driver`|Run entire batches of commands in a single call to the Appium server|Appium Team|
|
||||
|[Images](https://github.com/appium/appium/tree/master/packages/images-plugin)|`images`|Image matching and comparison features|Appium Team|
|
||||
|[Relaxed Caps](https://github.com/appium/appium/tree/master/packages/relaxed-caps-plugin)|`relaxed-caps`|Relax Appium's requirement for vendor prefixes on capabilities|Appium Team|
|
||||
|[Universal XML](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin)|`universal-xml`|Instead of the standard XML format for iOS and Android, use an XML definition that is the same across both platforms|Appium Team|
|
||||
|
||||
### Other plugins
|
||||
|
||||
|Plugin|Installation Key|Description|Supported By|
|
||||
|---|---|---|---|
|
||||
|[AltUnity](https://github.com/headspinio/appium-altunity-plugin)|`--source=npm appium-altunity-plugin`|Target Unity games and apps for automation with a new context, via the AltUnityTester framework|HeadSpin|
|
||||
|[Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)|`--source=npm appium-device-farm`|Manage and create driver session on connected android devices and iOS Simulators.|`@AppiumTestDistribution`|
|
||||
|[OCR](https://github.com/jlipps/appium-ocr-plugin)|`--source=npm appium-ocr-plugin`|Find elements via OCR text|`@jlipps`|
|
||||
|[Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)|`--source=npm appium-reporter-plugin`|Generates standalone consolidated html report with screenshots. Reports can be fetched from appium server, without worrying about heavy lifting such as screenshot capturing, report generation etc.|`@AppiumTestDistribution`|
|
||||
|
||||
!!! note
|
||||
|
||||
If you maintain an Appium plugin that you would like to be listed in the Appium docs, feel free
|
||||
to make a PR to add it to this section with a link to the documentation for the plugin.
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
---
|
||||
title: Capabilities
|
||||
---
|
||||
|
||||
"Capabilities" is the name given to the set of parameters used to start an Appium session. The
|
||||
information in the set is used to describe what sort of "capabilities" you want your session to
|
||||
have, for example, a certain mobile operating system or a certain version of a device. When you
|
||||
start your Appium session, your Appium client will include the set of capabilities you've defined
|
||||
as an object in the JSON-formatted body of the request. Capabilities are represented as key-value
|
||||
pairs, with values allowed to be any valid JSON type, including other objects. Appium will then
|
||||
examine the capabilities and make sure that it can satisfy them before proceeding to start the
|
||||
session and return an ID representing the session to your client library.
|
||||
|
||||
The W3C WebDriver spec's [section on Capabilities](https://w3c.github.io/webdriver/#capabilities)
|
||||
identifies a small set of 10 standard capabilities, including the following:
|
||||
|
||||
| Capability Name | Type | Description |
|
||||
|------------------|----------|------------------------------------------------|
|
||||
| `browserName` | `string` | The name of the browser to launch and automate |
|
||||
| `browserVersion` | `string` | The specific version of the browser |
|
||||
| `platformName` | `string` | The type of platform hosting the browser |
|
||||
|
||||
## Appium capabilities
|
||||
|
||||
Appium understands these browser-focused capabilities, but introduces a number of additional
|
||||
capabilities. According to the WebDriver spec, any
|
||||
non-standard "extension capabilities" must include a namespace prefix (signifying the vendor
|
||||
introducing the capability), ending in a `:`. Appium's vendor prefix is
|
||||
`appium:`, and so any Appium-specific capabilities must include this prefix. Depending on which
|
||||
client you are using, the prefix may be added automatically or in conjunction with certain
|
||||
interfaces, but it is always a good practice to explicitly include it for clarity.
|
||||
|
||||
Here is a list of all the globally-recognized Appium capabilities. Notes:
|
||||
|
||||
- Individual drivers and plugins can support other capabilities, so refer to their documentation for lists of extension-specific
|
||||
capability names.
|
||||
- Some drivers might not implement support for all of these capabilities
|
||||
- A few Appium extension capabilities are required to start any Appium session; these are noted below as "Required"
|
||||
|
||||
| Capability | Type | Required? | Description |
|
||||
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `platformName` | `string` | Required | The type of platform hosting the app or browser |
|
||||
| `appium:automationName` | `string` | Required | The name of the Appium driver to use |
|
||||
| `browserName` | `string` | | The name of the browser to launch and automate, if the driver supports web browsers as a special case |
|
||||
| `appium:app` | `string` | | The path to an installable application |
|
||||
| `appium:deviceName` | `string` | | The name of a particular device to automate, e.g., `iPhone 14` (currently only actually useful for specifying iOS simulators, since in other situations it's typically recommended to use a specific device id via the `appium:udid` capability). |
|
||||
| `appium:platformVersion` | `string` | | The version of a platform, e.g., for iOS, `16.0` |
|
||||
| `appium:newCommandTimeout` | `number` | | The number of seconds the Appium server should wait for clients to send commands before deciding that the client has gone away and the session should shut down |
|
||||
| `appium:noReset` | `boolean` | | If true, instruct an Appium driver to avoid its usual reset logic during session start and cleanup (default `false`) |
|
||||
| `appium:fullReset` | `boolean` | | If true, instruct an Appium driver to augment its usual reset logic with additional steps to ensure maximum environmental reproducibility (default `false`) |
|
||||
| `appium:eventTimings` | `boolean` | | If true, instruct an Appium driver to collect [Event Timings](./event-timing.md) (default `false`) |
|
||||
| `appium:printPageSourceOnFindFailure` | `boolean` | | If true, collect the page source and print it to the Appium log whenever a request to find an element fails (default `false`) |
|
||||
|
||||
|
||||
Some drivers place more complex constraints on capabilities as a group. For example, while the
|
||||
`appium:app` and `browserName` capabilities are listed above as optional, if you want to launch
|
||||
a session with a specific app, the XCUITest driver requires that at least one of `appium:app`,
|
||||
`browserName`, or `appium:bundleId` are included in the capabilities (otherwise it will not know
|
||||
what app to install and/or launch and will simply open a session on the home screen). Each driver
|
||||
will document how it interprets these capabilities and any other platform-specific requirements.
|
||||
|
||||
!!! note
|
||||
|
||||
Capabilities are like parameters used when starting a session. After the capabilities are sent
|
||||
and the session is started, they cannot be changed. If a driver supports updating aspects of
|
||||
its behaviour in the course of a session, it will provide a [Setting](./settings.md) for this
|
||||
purpose instead of, or in addition to, a capability.
|
||||
|
||||
Each Appium client has its own way of constructing capabilities and starting a session. For
|
||||
examples of doing this in each client library, head to the [Ecosystem](../ecosystem/index.md) page
|
||||
and click through to the appropriate client documentation.
|
||||
|
||||
## `appium:options`
|
||||
|
||||
If you use a lot of `appium:` capabilities in your tests, it can get a little repetitive. You can
|
||||
combine all capabilities as an object value of a single `appium:options` capability instead, in
|
||||
which case you don't need to use prefixes on the capabilities inside the object. For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:options": {
|
||||
"automationName": "XCUITest",
|
||||
"platformVersion": "16.0",
|
||||
"app": "/path/to/your.app",
|
||||
"deviceName": "iPhone 12",
|
||||
"noReset": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that constructing a capability value which is itself an object differs by language; refer to
|
||||
your client documentation for further examples on how to achieve this.
|
||||
|
||||
!!! warning
|
||||
|
||||
If you include the same capabilities both inside and outside of `appium:options`, the values
|
||||
inside of `appium:options` take precedence.
|
||||
|
||||
## Always-match and first-match capabilities
|
||||
|
||||
The W3C spec allows clients to give the Appium server some flexibility in the kind of session it
|
||||
creates in response to a new session request. This is through the concept of "always-match" and
|
||||
"first-match" capabilities:
|
||||
|
||||
- Always-match capabilities consist of a single set of capabilities, every member of which must be satisfied by the server in order for the new session request to proceed.
|
||||
- First-match capabilities consist of an array of capability sets. Each set is merged with the always-match capabilities, and the first set that the server knows how to handle will be the set that is used to start the session.
|
||||
|
||||
!!! note
|
||||
|
||||
Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or
|
||||
a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for
|
||||
a more in-depth description of how capabilities are processed.
|
||||
|
||||
In practice, use of first-match capabilities is not necessary or recommended for use with Appium.
|
||||
Instead, we recommend that you define the explicit set of capabilities you want the Appium
|
||||
server to handle. These will be encoded as the always-match capabilities, and the array of
|
||||
first-match capabilities will be empty.
|
||||
|
||||
That being said, Appium _does_ understand always-match and first-match capabilities as
|
||||
defined in the W3C spec, so if you use these features, Appium will work as expected. The process of
|
||||
defining always-match and first-match capabilities is unique to each client library, so refer to
|
||||
the documentation for your client library to see examples of how it works.
|
||||
|
||||
## Special notes for cloud providers
|
||||
|
||||
!!! warning
|
||||
|
||||
This section is not intended for end-users of Appium; it is intended for developers building
|
||||
Appium-compatible cloud services.
|
||||
|
||||
When managing an Appium cloud, your users may wish to target various independent versions of Appium
|
||||
drivers and plugins. It is of course up to each service provider how they wish to implement the
|
||||
discovery, installation, and availability of any official or third party drivers or plugins. _But
|
||||
the Appium team makes the following recommendations in terms of the *capabilities* service
|
||||
providers support, for consistency across the industry._ This is a recommendation only, and not
|
||||
a standard, but adopting it will help users to navigate the increased complexity that working with
|
||||
Appium 2.0 in a cloud environment may bring.
|
||||
|
||||
### Suggested capabilities
|
||||
|
||||
In addition to the standard `platformName`, `appium:deviceName`, `appium:automationName`, and
|
||||
`appium:platformVersion`, we recommend adopting the capability `$cloud:appiumOptions`, where the
|
||||
label `$cloud` is not meant to be interpreted literally but instead should be replaced by your
|
||||
vendor prefix (so for HeadSpin it would be `headspin`, Sauce Labs it would be `sauce`, and
|
||||
BrowserStack it would be `browserstack`, to name just a few examples). The `$cloud:appiumOptions`
|
||||
capability would itself be a JSON object, with the following internal keys:
|
||||
|
||||
| Capability | Used for | Example |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| `version` | Designating which version of the Appium server is used to host and manage drivers. If ommitted, behavior left up to the provider, but the recommendation would be to provide the latest official version. | `2.0.0` |
|
||||
| `automationVersion` | Designating which version of the specified driver should be used. | `1.55.2` |
|
||||
| `automation` | Designating a custom driver to use (see below for more info). This would override `appium:automationName` and `$cloud:automationVersion` | `{"name": "@org/custom-driver", "source": "github", "package": "custom-driver"}` |
|
||||
| `plugins` | Designating the list of plugins (and potentially versions of plugins) to be activated (see below for more info). | `["images", "universal-xml"]` |
|
||||
|
||||
### Basic example
|
||||
|
||||
Appium extensions (drivers and plugins) have a set of properties that specify where they can be
|
||||
installed from. Cloud providers are obviously under no obligation to provide support for
|
||||
arbitrarily specified extensions, seeing as these may represent untrusted code running in a managed
|
||||
environment. In the case where arbitrary extensions are not supported, the `appium:automationName`,
|
||||
`$cloud:automationVersion`, and `$cloud:appiumPlugins` capabilities should be sufficient. See the
|
||||
following JSON object representing capabilities for a session:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:platformVersion": "14.4",
|
||||
"appium:deviceName": "iPhone 11",
|
||||
"appium:app": "Some-App.app.zip",
|
||||
"appium:automationName": "XCUITest",
|
||||
"$cloud:appiumOptions": {
|
||||
"version": "2.0.0",
|
||||
"automationVersion": "3.52.0",
|
||||
"plugins": ["images"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This set of capabilities requests an Appium 2+ server supporting the XCUITest driver at version
|
||||
`3.52.0`, and the `images` plugin active. This set is easy for a cloud provider to verify. The
|
||||
cloud provider can obviously do anything it wants in response to these capabilities, including
|
||||
downloading Appium and driver and plugin packages on the fly, or erroring out if the versions
|
||||
requested are not in a supported set, or if the plugin is not supported, etc...
|
||||
|
||||
### Basic example with `appium:options`
|
||||
|
||||
The previous example still looks a bit disorganized, so of course we also recommend that cloud
|
||||
providers support the `appium:options` capability as detailed above, which could turn the previous
|
||||
set of capabilities into the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:options": {
|
||||
"platformVersion": "14.4",
|
||||
"deviceName": "iPhone 11",
|
||||
"app": "Some-App.app.zip",
|
||||
"automationName": "XCUITest"
|
||||
},
|
||||
"$cloud:appiumOptions": {
|
||||
"version": "2.0.0",
|
||||
"automationVersion": "3.52.0",
|
||||
"plugins": ["images"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Extension objects
|
||||
|
||||
Some service providers may wish to dynamically allow access to all of the features of the Appium
|
||||
2.0 CLI, including downloading arbitrary drivers and plugins. To represent these extensions, we can
|
||||
define special JSON "extension objects", with the following keys:
|
||||
|
||||
- `name`: the name of the extension. This would be an NPM package name (if downloading from NPM), or a git or GitHub spec (if downloading from a git server or GitHub).
|
||||
- `version`: the version of the extension, e.g., the NPM package version or Git SHA.
|
||||
- (optional) `source`: a denotation of where the extension can be downloaded from. Recommended to support the following values: `appium`, `npm`, `git`, `github`. Here, `appium` means "Appium's own official list", and should be the default value if this key is not included.
|
||||
- (optional) `package`: when downloading extensions from git or github, the NPM package name of the extension must also be provided. This is optional for non-git sources.
|
||||
|
||||
Since each session is handled by a single driver, the `$cloud:appiumOptions`/`$automation`
|
||||
capability could be used with an extension object value to denote this driver, for example:
|
||||
|
||||
```json
|
||||
{
|
||||
"$cloud:appiumOptions": {
|
||||
"automation": {
|
||||
"name": "git+https://some-git-host.com/custom-driver-project.git",
|
||||
"version": "some-git-sha",
|
||||
"source": "git",
|
||||
"package": "driver-npm-package-name"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And since sessions can handle multiple plugins, each value in the list of `$cloud:appiumPlugins`
|
||||
could also be an extension object rather than a string, so that specific versions could be
|
||||
requested:
|
||||
|
||||
```json
|
||||
{
|
||||
"$cloud:appiumOptions": {
|
||||
"plugins": [{
|
||||
"name": "images",
|
||||
"version": "1.1.0"
|
||||
}, {
|
||||
"name": "my-github-org/my-custom-plugin",
|
||||
"version": "a83f2e",
|
||||
"source": "github",
|
||||
"package": "custom-plugin"
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These serve as illustrative examples for the recommendations here. Of course it is up to the
|
||||
service providers to implement the handling of these capabilities at their front end / load
|
||||
balancer, to perform any error checking, or to actually run any of the `appium driver` or `appium
|
||||
plugin` CLI commands that support the end user's request. This section is merely a suggestion as to
|
||||
how service providers might design their user-facing capabilities API in a way which in principle
|
||||
supports all of the capabilities Appium itself would provide to the end user if they were running
|
||||
Appium on their own.
|
||||
@@ -1,95 +0,0 @@
|
||||
---
|
||||
title: The Appium Config File
|
||||
---
|
||||
|
||||
Instead of passing arguments on the command line to Appium, you may add them to a special config
|
||||
file. Appium will read values from this config file when it runs. (Please note that CLI arguments
|
||||
have _precedence_ over configuration files; if a value is set in a config file _and_ via CLI
|
||||
argument, the CLI argument is preferred.)
|
||||
|
||||
## Supported Config File Formats
|
||||
|
||||
You can store your config data in the following kinds of files:
|
||||
|
||||
- JSON
|
||||
- YAML
|
||||
- JS (a JavaScript file exporting a JS object)
|
||||
- CJS (the same as above; the extension is for common JS)
|
||||
|
||||
!!! warning
|
||||
|
||||
Note: Configuration files in ESM format are not currently supported.
|
||||
|
||||
## Supported Config File Locations
|
||||
|
||||
Configuration files can be named anything, but the following filenames will be automatically
|
||||
discovered and loaded by Appium:
|
||||
|
||||
- `.appiumrc.json` (recommended)
|
||||
- `.appiumrc.yaml`
|
||||
- `.appiumrc.yml`
|
||||
- `.appiumrc.js`
|
||||
- `.appiumrc.cjs`
|
||||
- `appium.config.js`
|
||||
- `appium.config.cjs`
|
||||
- `.appiumrc` (which is considered to be JSON)
|
||||
|
||||
Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium` property in your `package.json` and it will be automatically discovered.
|
||||
|
||||
### Config File Search
|
||||
|
||||
Appium will search _up_ the directory tree from the current working directory for one of these
|
||||
files. If it reaches the current user's home directory or filesystem root, it will stop looking.
|
||||
|
||||
To specify a _custom_ location for your config file, use `appium --config-file /path/to/config/file`.
|
||||
|
||||
#### Configuration File Format
|
||||
|
||||
First, you might want to look at some examples:
|
||||
|
||||
- [Appium Configuration - JSON](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.json)
|
||||
- [Appium Configuration - YAML](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.yaml)
|
||||
- [Appium Configuration - JS](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.js)
|
||||
|
||||
A description of the format is available, as well:
|
||||
|
||||
- [Appium Configuration File JSON Schema](https://github.com/appium/appium/blob/master/packages/schema/lib/appium-config.schema.json)
|
||||
- [TypeScript declarations for Appium Configuration](https://github.com/appium/appium/blob/master/packages/types/lib/config.ts)
|
||||
|
||||
To describe in words, the config file will have a root `server` property, and all arguments are
|
||||
child properties. For certain properties which must be supplied on the command-line as comma-delimited lists, JSON strings, and/or external filepaths, these instead will be of their "native" type. For example,
|
||||
`--use-plugins <value>` needs `<value>` to be comma-delimited string or path to a delimited file.
|
||||
However, the config file just wants an array, e.g.,:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"use-plugins": ["my-plugin", "some-other-plugin"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuring extensions (drivers and plugins)
|
||||
|
||||
For `driver`-and-`plugin`-specific configuration, these live under the `server.driver` and
|
||||
`server.plugin` properties, respectively. Each driver or plugin will have its own named property,
|
||||
and the values of any specific configuration it provides are under this. For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"xcuitest": {
|
||||
"webkit-debug-proxy-port": 5400
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
The above configuration corresponds to the `--driver-xcuitest-webkit-debug-proxy-port` CLI argument.
|
||||
|
||||
All properties are case-sensitive and will be in [kebab-case](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Delimiter-separated_words). For example, `callback-port` is
|
||||
allowed, but `callbackPort` is not.
|
||||
@@ -1,41 +0,0 @@
|
||||
---
|
||||
title: The Context API
|
||||
---
|
||||
|
||||
A common feature of many app platforms is the ability for developers to embed web content inside of
|
||||
the platform-native app frame. This allows developers to leverage web technologies or existing web
|
||||
content for some or all of the app functionality. However, the additional complexity of mixing
|
||||
"modes" within a single application can make it difficult for automation tools that are designed to
|
||||
target the "native" elements and behaviours.
|
||||
|
||||
Appium provides a set of APIs for working with different app modes, called "contexts", that Appium
|
||||
drivers can implement if they support automation commands in these different modes. There are three
|
||||
basic commands that Appium has added to the W3C WebDriver spec for this purpose:
|
||||
|
||||
| Command Name | Method/Route | Params | Description | Returns |
|
||||
|-----------------------|-----------------------------|-------------------|-----------------------------------------------|-----------------|
|
||||
| `Get Contexts` | `GET /session/:id/contexts` | | Get a list of the available contexts | `array<string>` |
|
||||
| `Get Current Context` | `GET /session/:id/context` | | Get the name of the active context | `string` |
|
||||
| `Set Context` | `POST /session/:id/context` | `name` (`string)` | Switch into the context with the given `name` | `null` |
|
||||
|
||||
This API is flexible enough to handle a variety of semantic interpretations on the part of the
|
||||
driver. For example, the XCUITest driver includes two kinds of contexts: the native app context and
|
||||
any active webviews, as one context per webview. A call to `Get Contexts` will return the list of
|
||||
names, which you as a test author can sift through and use to switch into the appropriate context.
|
||||
As another example, the [Appium Altunity
|
||||
Plugin](https://github.com/headspinio/appium-altunity-plugin) introduces the concept of a `UNITY`
|
||||
context, which encapsulates all the plugin's specific behaviour to ensure that when outside of the
|
||||
`UNITY` context, the active driver's usual command implementations are used.
|
||||
|
||||
It is important to note that a call to `Get Contexts` will always contain at least one context,
|
||||
conventionally but not necessarily named `NATIVE_APP`. This is the default active context.
|
||||
|
||||
Depending on the type of context you're in, the operation of the driver might change. The XCUITest
|
||||
driver, when targeting a webview context, will not run its typical routines for finding and
|
||||
interacting with elements. Instead, it will run a different set of routines appropriate to web
|
||||
elements. This might have a variety of consequences, like supporting a different set of locator
|
||||
strategies.
|
||||
|
||||
The command names in the table above are generic references to the commands and not code examples.
|
||||
For examples of how to access the Context API in the language-specific client libraries, please
|
||||
visit the documentation for a given library.
|
||||
@@ -1,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,115 +0,0 @@
|
||||
---
|
||||
title: Execute Methods
|
||||
---
|
||||
|
||||
Because the scope of commands implemented in Appium drivers is broader than the scope of commands
|
||||
defined by the W3C WebDriver spec, Appium needs a way for these "extended" commands to be accessible
|
||||
by client libraries. There are two main strategies for this:
|
||||
|
||||
1. Appium drivers define new W3C-compatible API routes, and Appium clients are updated to include
|
||||
support for those new routes.
|
||||
2. Appium drivers define so-called "Execute Methods" which provide new functionality by
|
||||
overloading the existing `Execute Script` command which is already available in any WebDriver-
|
||||
based client library (including all Selenium and Appium clients).
|
||||
|
||||
There are pros and cons for each strategy, but it is ultimately up to the extension author to
|
||||
decide how they wish implement new commands.
|
||||
|
||||
This guide is designed to specifically help you understand the "Execute Method" strategy. This pattern is commonly used in official Appium drivers and other third-party extensions.
|
||||
Here's an example of how the `Execute Script` command is designed to work in the world of WebDriver
|
||||
and browser automation:
|
||||
|
||||
=== "JS (WebDriverIO)"
|
||||
|
||||
```js
|
||||
await driver.executeScript('return arguments[0] + arguments[1]', [3, 4])
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
|
||||
jsDriver.executeScript("return arguments[0] + arguments[1]", 3, 4);
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
driver.execute_script('return arguments[0] + arguments[1]', 3, 4)
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```rb
|
||||
driver.execute_script 'return arguments[0] + arguments[1]', 3, 4
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```dotnet
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0] + arguments[1]", 3, 4);
|
||||
```
|
||||
|
||||
What's happening here is that we are defining a snippet of Javascript (technically,
|
||||
a function body) to be executed within the web browser. The client can send arguments which are serialized, sent over HTTP, and finally provided to the function as parameters. In this example, we are essentially defining
|
||||
an addition function. The return value of the `Execute Script` command is whatever the return value
|
||||
of the Javascript snippet is! In the case of this example, that value would be the number `7` (`3`
|
||||
+ `4`).
|
||||
|
||||
Each client library has its own way of calling the command and providing any arguments to the
|
||||
script function, but the function itself—the snippet—is always a string and is the same across all languages.
|
||||
|
||||
In the world of Appium, we are usually not automating a web browser, which means this command is
|
||||
not particularly useful. But it *is* useful as a way to encode the name of an arbitrary command and
|
||||
to provide parameters. For example, the [XCUITest
|
||||
Driver](https://github.com/appium/appium-xcuitest-driver) has implemented a command that lets a client
|
||||
terminate a running application if you know the ID (the `bundleId`) of the app. The way that the
|
||||
driver makes this command available is via the Execute Method `mobile: terminateApp`. Instead of providing a JavaScript function to the "Execute Script" command, the user provides a _known string_ as defined by the driver. The only other thing a client needs to know is the set of
|
||||
parameters for the method, which are documented by the driver. In this case, we have a parameter
|
||||
named `bundleId`, whose value should be a string encoding the ID of the app to terminate. Here is
|
||||
how this Execute Method would be called:
|
||||
|
||||
=== "JS (WebDriverIO)"
|
||||
|
||||
```js
|
||||
await driver.executeScript('mobile: terminateApp', [{bundleId: 'com.my.app'}])
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
|
||||
jsDriver.executeScript("mobile: terminateApp", ImmutableMap.of("bundleId", "com.my.app"));
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
driver.execute_script('mobile: terminateApp', {'bundleId': 'com.my.app'})
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```rb
|
||||
driver.execute_script 'mobile: terminateApp', { bundleId: 'com.my.app' }
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```dotnet
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: terminateApp",
|
||||
new Dictionary<string, string> { { "bundleId", "com.my.app" } });
|
||||
|
||||
```
|
||||
|
||||
There are two important differences in using Appium Execute Methods from vanilla Selenium
|
||||
Javascript execution:
|
||||
|
||||
1. The script string is just a command name; it will be provided by the driver documentation
|
||||
1. The standard way to provide parameters is as a *single* object with keys representing parameter
|
||||
names and values representing parameter values. So in this case, we had to specify both the
|
||||
parameter name (`bundleId`) as the key of the parameters object, and the parameter value
|
||||
(`com.my.app`) as the value for that key. A driver can define parameters as _required_ or _optional_.
|
||||
|
||||
Of course, always refer to the documentation for the particular Execute Method in case the author
|
||||
has made any alterations to the standard access method.
|
||||
@@ -1,166 +0,0 @@
|
||||
---
|
||||
title: Appium and Selenium Grid
|
||||
---
|
||||
|
||||
## Using Selenium Grid 4+
|
||||
|
||||
The
|
||||
[relay](https://www.selenium.dev/documentation/grid/configuration/toml_options/#relaying-commands-to-a-service-endpoint-that-supports-webdriver)
|
||||
feature in Grid 4 allows you to proxy Appium requests to an Appium server instance. Here is
|
||||
an example walkthrough of how you would connect two different Appium instances to a Selenium Grid.
|
||||
|
||||
### Define the Appium configs
|
||||
|
||||
Each Appium instance should have a config file that can be easily updated. It should contain any
|
||||
information which needs to be unique to that particular server (e.g., ports its drivers should use
|
||||
that others should not). We are going to have 2 Appium servers, so we will need 2 config files:
|
||||
|
||||
```yaml
|
||||
# appium1.yml
|
||||
server:
|
||||
port: 4723
|
||||
use-drivers:
|
||||
- xcuitest
|
||||
default-capabilities:
|
||||
wdaLocalPort: 8100
|
||||
mjpegServerPort: 9100
|
||||
mjpegScreenshotUrl: "http://localhost:9100"
|
||||
```
|
||||
|
||||
In the above YAML config file, we specify the Appium server port, the driver used, and parameters
|
||||
for the driver that will be sent in as default capabilities. Our goal is to ensure that any other
|
||||
drivers running on this host will not compete with system ports or other resources. The second
|
||||
config file could look like the following, where we simply adjust a few ports to prevent clashes:
|
||||
|
||||
```yaml
|
||||
# appium2.yml
|
||||
server:
|
||||
port: 4733
|
||||
use-drivers:
|
||||
- xcuitest
|
||||
default-capabilities:
|
||||
wdaLocalPort: 8110
|
||||
mjpegServerPort: 9110
|
||||
mjpegScreenshotUrl: "http://localhost:9110"
|
||||
```
|
||||
|
||||
### Define the Grid node configs
|
||||
|
||||
We will be launching one Grid "node" per Appium server, to manage relaying commands and determining
|
||||
capacity and online status, etc... So we should have one config file per Grid node as well. Each
|
||||
node config should include the address of the Appium server it will target, as well as a list of
|
||||
capability "configs" it should accept to relay a session request to Appium. Here is what the config
|
||||
could look like for the two nodes:
|
||||
|
||||
```toml
|
||||
# node1.toml
|
||||
[server]
|
||||
port = 5555
|
||||
|
||||
[node]
|
||||
detect-drivers = false
|
||||
|
||||
[relay]
|
||||
url = "http://localhost:4723"
|
||||
status-endpoint = "/status"
|
||||
configs = [
|
||||
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 13\", \"appium:automationName\": \"XCUITest\"}"
|
||||
]
|
||||
```
|
||||
|
||||
```toml
|
||||
# node2.toml
|
||||
[server]
|
||||
port = 5565
|
||||
|
||||
[node]
|
||||
detect-drivers = false
|
||||
|
||||
[relay]
|
||||
url = "http://localhost:4733"
|
||||
status-endpoint = "/status"
|
||||
configs = [
|
||||
"1", "{\"platformName\": \"iOS\", \"appium:platformVersion\": \"15.5\", \"appium:deviceName\": \"iPhone 12\", \"appium:automationName\": \"XCUITest\"}"
|
||||
]
|
||||
```
|
||||
|
||||
Note that each node config also specifies a different port itself for the node to run on.
|
||||
|
||||
### Putting it together
|
||||
|
||||
The Grid nodes aren't enough--you'll also want a Grid "hub" that acts as a load balancer and
|
||||
manager for all the nodes. So in the end we'll have 5 processes running at once: 2 Appium servers,
|
||||
2 Grid nodes, and 1 Grid hub. It's best to run each of these in a separate terminal window to avoid
|
||||
confusion of logs. Here is how you'd start each process:
|
||||
|
||||
0. `appium --config appium1.yml`
|
||||
0. `appium --config appium2.yml`
|
||||
0. `java -jar /path/to/selenium.jar node --config node1.toml`
|
||||
0. `java -jar /path/to/selenium.jar node --config node2.toml`
|
||||
0. `java -jar /path/to/selenium.jar hub`
|
||||
|
||||
Once you wait a few moments for the nodes to detect their Appium servers, and to register with the
|
||||
hub, you'll be able to send all your Appium traffic via the single hub endpoint (defaulting to
|
||||
`http://localhost:4444`).
|
||||
|
||||
And of course, you're able to link up Appium servers and nodes running on different machines in
|
||||
your network to form a larger grid.
|
||||
|
||||
## Using Selenium Grid 3
|
||||
|
||||
It is possible to register your Appium server with a local [Selenium Grid 3](https://www.selenium.dev/documentation/legacy/selenium_3/grid_3/)
|
||||
([setup docs](https://www.selenium.dev/documentation/legacy/grid_3/setting_up_your_own_grid/)) instance by using the
|
||||
`--nodeconfig` server argument.
|
||||
|
||||
```bash
|
||||
appium server --nodeconfig /path/to/nodeconfig.json --base-path=/wd/hub
|
||||
```
|
||||
|
||||
In the referenced config file you have to define the `browserName`, `version` and `platform`
|
||||
capabilities and based on these parameters the grid will re-direct your test to the right device.
|
||||
You will also need to configure your host details and the Selenium Grid details. For a full list of
|
||||
all parameters and descriptions see
|
||||
[here](https://www.selenium.dev/documentation/legacy/selenium_3/grid_setup/).
|
||||
|
||||
Once you start the Appium server it will register with the grid, and you will see your device on
|
||||
the grid console page:
|
||||
|
||||
`http://**\<grid-ip-adress\>**:**\<grid-port\>**/grid/console`
|
||||
|
||||
### Example Grid Node Configuration JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities":
|
||||
[
|
||||
{
|
||||
"browserName": "<e.g._iPhone5_or_iPad4>",
|
||||
"version":"<version_of_iOS_e.g._7.1>",
|
||||
"maxInstances": 1,
|
||||
"platform":"<platform_e.g._MAC_or_ANDROID>"
|
||||
}
|
||||
],
|
||||
"configuration":
|
||||
{
|
||||
"cleanUpCycle":2000,
|
||||
"timeout":30000,
|
||||
"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
|
||||
"url":"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub",
|
||||
"host": "<host_name_appium_server_or_ip-address_appium_server>",
|
||||
"port": <appium_port>,
|
||||
"maxSession": 1,
|
||||
"register": true,
|
||||
"registerCycle": 5000,
|
||||
"hubPort": <grid_port>,
|
||||
"hubHost": "<Grid_host_name_or_grid_ip-address>",
|
||||
"hubProtocol": "<Protocol_of_Grid_defaults_to_http>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If `url`, `host`, and `port` are not given, the config will be auto updated to point to
|
||||
`localhost:<appium-port>`.
|
||||
|
||||
If your Appium server is running on a different machine to your Selenium Grid server, make sure you
|
||||
use an external name/IP address in your `host` and `url` configuration; `localhost` and `127.0.0.1`
|
||||
will prevent Selenium Grid from connecting correctly.
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
title: Log Filtering
|
||||
---
|
||||
|
||||
Sometimes it might be necessary to hide sensitive information, like passwords, device identifiers,
|
||||
hashes, etc..., from the server log. Appium makes it possible to ensure such information is
|
||||
redacted in logs via the `--log-filters` command line argument. This argument allows you to provide
|
||||
the path to a special config file, containing one or more log obfuscation rules.
|
||||
|
||||
## Config Format
|
||||
|
||||
The filtering config must be one of:
|
||||
|
||||
- a path to a valid JSON file containing an array of filtering rules
|
||||
- a `log-filters` entry in an [Appium Config](./config.md) file, with the rules array inline
|
||||
|
||||
Each rule is an object with a set of predefined properties. The following rule properties are
|
||||
supported:
|
||||
|
||||
- `pattern`: A valid Javascript RegExp pattern to replace. Must be a valid non-empty pattern.
|
||||
- `text`: A simple non-empty exact text match to replace. Either this property or the above one must be provided. `pattern` has priority over `text` if both are provided.
|
||||
- `flags`: Regular expression flags for the given pattern. Supported flags are the same as for the standard JavaScript [RegExp constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2). Note that the `g` (global matching) flag is always enabled.
|
||||
- `replacer`: The replacer value to use. By default it is `**SECURE**`. Empty values are allowed.
|
||||
|
||||
### Config Examples
|
||||
|
||||
Replace all occurrences of `my.magic.app` string with the default replacer:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"text": "my.magic.app"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Replace all occurrences of `my.magic.<any char>` string with a custom replacer (case insensitive):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"pattern": "my\\.magic\\.\\w",
|
||||
"flags": "i",
|
||||
"replacer": "***"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Replace all occurrences of `my.magic.<any chars>` and/or `your.magic` strings with a custom
|
||||
replacer (case insensitive):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"pattern": "my\\.magic\\.\\w+",
|
||||
"flags": "i",
|
||||
"replacer": "***"
|
||||
},
|
||||
{
|
||||
"pattern": "your\\.magic",
|
||||
"flags": "i",
|
||||
"replacer": "***"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Truncate all log lines to max 15 chars (advanced):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"pattern": "(.{1,15}).*",
|
||||
"flags": "s",
|
||||
"replacer": "$1"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Config Errors Handling
|
||||
|
||||
If any of the config rules contains invalid items (such as empty/invalid pattern, empty rule, etc.)
|
||||
then Appium will print the detailed report about collected errors and will fail to start until
|
||||
these errors are addressed.
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
title: Managing Appium Drivers and Plugins
|
||||
---
|
||||
|
||||
To do anything useful with Appium, you need to have at least one [Driver](../intro/drivers.md)
|
||||
installed, otherwise Appium won't know how to automate anything. There is an entire
|
||||
[Ecosystem](../ecosystem/index.md) of drivers and plugins out there!
|
||||
|
||||
This guide helps explain how to manage these drivers and plugins. There are
|
||||
two basic strategies: using Appium's extension CLI interface, or managing extensions yourself in an
|
||||
npm-based project.
|
||||
|
||||
> Note: Alternative package managers are not supported by Appium at the time of this writing.
|
||||
|
||||
## Using Appium's Extension CLI
|
||||
|
||||
With Appium's [Extension CLI](../cli/extensions.md), you let Appium manage drivers and plugins for
|
||||
you. You will use CLI commands to tell Appium which extensions you would like to install, update,
|
||||
or remove. Here's an example of how you might install a driver using the CLI:
|
||||
|
||||
```bash
|
||||
appium driver install xcuitest
|
||||
```
|
||||
|
||||
This command will install the latest version of the [XCUITest Driver](https://github.com/appium/appium-xcuitest-driver). The Extension CLI comes with a variety
|
||||
of commands and parameters; see the documentation for that command for all the specifics.
|
||||
|
||||
The all-important question when Appium is managing your extensions for you is: where are they installed?
|
||||
Appium manages extensions in a directory specified by the `APPIUM_HOME` environment variable. You
|
||||
can set that variable to anything you like, and Appium will manage its extensions there. You can
|
||||
therefore also use the `APPIUM_HOME` environment variable to manage different sets of extensions,
|
||||
for example if you want to have the same driver installed at conflicting versions:
|
||||
|
||||
```bash
|
||||
APPIUM_HOME=/path/to/home1 appium driver install xcuitest@4.11.1
|
||||
APPIUM_HOME=/path/to/home2 appium driver install xcuitest@4.11.2
|
||||
```
|
||||
|
||||
Running these commands will result in two separate `APPIUM_HOME` directories being created and
|
||||
populated with the corresponding version of the XCUITest driver. You can then use the same
|
||||
environment variables to direct Appium which version to use on launch:
|
||||
|
||||
```bash
|
||||
APPIUM_HOME=/path/to/home1 appium # use xcuitest driver 4.11.1
|
||||
APPIUM_HOME=/path/to/home2 appium # use xcuitest driver 4.11.2
|
||||
```
|
||||
|
||||
You don't need to set `APPIUM_HOME` if you don't want to! By default, Appium will set `APPIUM_HOME`
|
||||
to the directory `.appium` in your user home directory.
|
||||
|
||||
These installed packages will be managed by `extensions.yaml` in `$APPIUM_HOME/node_modules/.cache/appium/extensions.yaml`.
|
||||
|
||||
## Do-It-Yourself with `npm`
|
||||
|
||||
Because Appium and Appium drivers are Node.js programs, if you are integrating your Appium scripts
|
||||
into your own Node.js project, there is an alternative way to manage drivers and plugins: via `npm`, like any other dependency.
|
||||
Basically, whenever you run Appium, if you have not explicitly set `APPIUM_HOME`, it will:
|
||||
|
||||
1. Try to determine whether the _current directory_ is inside an `npm` package.
|
||||
1. If so, it will check whether `appium` is a dependency (dev, prod, or peer) in the project's
|
||||
`package.json`
|
||||
1. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will ignore load drivers and plugins defined in that
|
||||
`package.json` file instead.
|
||||
|
||||
This means you are freely able to add Appium drivers and plugins as regular package dependencies or dev dependencies. For
|
||||
example, if your project has a `package.json` which includes the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
"appium": "^2.0.0",
|
||||
"appium-xcuitest-driver": "^4.11.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then, if you run `npx appium` inside your project, Appium will detect that it is a dependency of
|
||||
the project, and will load the XCUITest driver which is also listed as a dev dependency for the
|
||||
project.
|
||||
|
||||
This strategy is *only* recommended if you are already using `npm` for your project.
|
||||
Otherwise, it is recommended that you use Appium's Extension CLI and, if necessary, adjust
|
||||
`APPIUM_HOME` to change the location of stored extensions.
|
||||
@@ -1,233 +0,0 @@
|
||||
---
|
||||
title: Migrating from Appium 1.x to Appium 2.x
|
||||
---
|
||||
|
||||
This document is a guide for those who are using Appium 1.x and wish to migrate to Appium 2.x. It contains a list of breaking changes and how to migrate your environments or test suites to ensure compatibility with Appium 2.0.
|
||||
|
||||
## Overview of Appium 2.0
|
||||
|
||||
Appium 2.0 is the most major new release of Appium in over 5 years. The changes in Appium 2.0 are _not_ primarily related to changes in automation behaviors for specific platforms. Instead, Appium 2.0 reenvisions Appium as a _platform_ where "drivers" (code projects that introduce support for automation of a given platform) and "plugins" (code projects that allow for overriding, altering, extending, or adding behaviors to Appium) can be easily created and shared.
|
||||
|
||||
At the same time, the Appium project is taking the opportunity to remove many old and deprecated bits of functionality.
|
||||
|
||||
Together these do introduce a few breaking changes to how Appium is installed, how drivers and various features are managed, and protocol support. These are detailed below.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
Have a look at the [Appium 2.0 release notes](https://github.com/appium/appium/releases) for the most comprehensive lists of changes. Here we call out the breaking changes and what you need to do do account for them.
|
||||
|
||||
### :bangbang: Installing drivers during setup
|
||||
|
||||
When you installed Appium 1.x, all available drivers would be installed at the same time as the main Appium server. This is no longer the case. Simply installing Appium 2.0 (e.g., by `npm install -g appium@next`), will install the Appium server only, but no drivers. To install drivers, you must instead use the new [Appium extension CLI](../cli/extensions.md). For example, to install the latest versions of the XCUITest and UiAutomator2 drivers, after installing Appium you would run the following commands:
|
||||
|
||||
```bash
|
||||
appium driver install uiautomator2 # installs the latest driver version
|
||||
appium driver install xcuitest@4.12.2 # installs a specific driver version
|
||||
```
|
||||
|
||||
At this point, your drivers are installed and ready. There's a lot more you can do with this CLI so be sure to check out the docs on it.
|
||||
If you're running in a CI environment or want to install Appium along with some drivers all in one step, you can do so using some special flags during install, for example:
|
||||
|
||||
```bash
|
||||
npm install --global appium --drivers=xcuitest,uiautomator2
|
||||
```
|
||||
|
||||
This will install Appium and the two drivers for you in one go.
|
||||
|
||||
### :bangbang: Drivers installation path
|
||||
|
||||
When you installed Appium 1.x, all available drivers would be installed at the same time as the main Appium server.
|
||||
The path was `/path/to/appium/node_modules`.
|
||||
For example, `appium-webdriveragent` to build WebDriverAgent manually was `/path/to/appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`.
|
||||
|
||||
Appium 2.0 installs such dependencies in `APPIUM_HOME` environment variable. The default path is `~/.appium`.
|
||||
So, the path to `appium-webdriveragent` could be `$APPIUM_HOME/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent` after installing the XCUITest driver package.
|
||||
|
||||
### :bangbang: Chromedriver installation flags
|
||||
|
||||
In Appium 1.x it was possible to customize the way Chromedriver was installed (as part of the UiAutomator2 driver for example), using the following command line flags:
|
||||
|
||||
* `--chromedriver-skip-install`
|
||||
* `--chromedriver-version`
|
||||
* `--chromedriver-cdnurl`
|
||||
|
||||
Because Appium 2.0 now installs drivers for you, and because these flags were implemented as NPM config flags, they will no longer work. Instead, use the following environment variables during driver installation:
|
||||
|
||||
* `APPIUM_SKIP_CHROMEDRIVER_INSTALL`
|
||||
* `CHROMEDRIVER_VERSION`
|
||||
* `CHROMEDRIVER_CDNURL`
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
APPIUM_SKIP_CHROMEDRIVER_INSTALL=1 appium driver install uiautomator2
|
||||
```
|
||||
|
||||
### :bangbang: Driver-specific command line options
|
||||
|
||||
With Appium 1.x, command-line options specific to particular drivers were all hosted on the main Appium server. So, for example, `--chromedriver-executable` was a CLI parameter you could use with Appium to set the location of a specific Chromedriver version for use with, say, the UiAutomator2 driver.
|
||||
|
||||
With Appium 2.x, all driver- and platform-specific CLI params have been moved to the drivers themselves. To access them, you'll now need to prepend the argument with the extension type (either `driver` or `plugin`) and the name of the extension. For example, `--chromedriver-executable` becomes `--driver-uiautomator2-chromedriver-executable`.
|
||||
|
||||
### :bangbang: Driver-specific automation commands
|
||||
|
||||
The definition of certain commands that pertain only to specific drivers has been moved to those
|
||||
drivers' implementations. For example, `pressKeyCode` is specific to the UiAutomator2 driver and is
|
||||
now understood only by that driver. In practice, the only breaking change here is the kind of error
|
||||
you would encounter if the appropriate driver is not installed. Previously, you would get a `501
|
||||
Not Yet Implemented` error if using a driver that didn't implement the command. Now, you will get
|
||||
a `404 Not Found` error because if a driver that doesn't know about the command is not active, the
|
||||
main Appium server will not define the route corresponding to the command.
|
||||
|
||||
### :bangbang: Driver updates
|
||||
|
||||
In the past, to get updates to your iOS or Android drivers, you'd simply wait for those updates to be rolled into a new release of Appium, and then update your Appium version. With Appium 2.x, the Appium server and the Appium drivers are versioned and released separately. This means that drivers can be on their own release cadence and that you can get driver updates as they happen, rather than waiting for a new Appium server release. The way to check for driver updates is with the CLI:
|
||||
|
||||
```bash
|
||||
appium driver list --updates
|
||||
```
|
||||
|
||||
If any updates are available, you can then run the `update` command for any given driver:
|
||||
|
||||
```bash
|
||||
appium driver update xcuitest
|
||||
```
|
||||
|
||||
(For a complete description of the update command, check out the [Extension
|
||||
CLI](../cli/extensions.md) doc)
|
||||
|
||||
To update the Appium server itself, you do the same thing as in the past: `npm install -g appium`. Now, installing new versions of the Appium server will leave your drivers intact, so the whole process will be much more quick.
|
||||
|
||||
If you would like to update to a specific version, not the latest, please uninstall the driver and install the desired version using the `install` subcommand instead of `update`.
|
||||
|
||||
```bash
|
||||
appium driver uninstall xcuitest
|
||||
appium driver install xcuitest@4.11.1
|
||||
```
|
||||
|
||||
### :bangbang: Protocol changes
|
||||
|
||||
Appium's API is based on the [W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/), and it has supported this protocol for years. Before the W3C WebDriver Protocol was designed as a web standard, several other protocols were used for both Selenium and Appium. These protocols were the "JSONWP" (JSON Wire Protocol) and "MJSONWP" (Mobile JSON Wire Protocol). The W3C Protocol differs from the (M)JSONWP protocols in a few small ways.
|
||||
|
||||
Up until Appium 2.0, Appium supported both protocols, so that older Selenium/Appium clients could still communicate with newer Appium servers. Moving forward, support for older protocols will be removed.
|
||||
|
||||
### :bangbang: _Capabilities_
|
||||
|
||||
One significant difference between old and new protocols is in the format of capabilities. Previously called "desired capabilities", and now called simply "capabilities", there is now a requirement for a so-called "vendor prefix" on any non-standard capabilities. The list of standard capabilities is given in the [WebDriver Protocol spec](https://www.w3.org/TR/webdriver/#capabilities), and includes a few commonly used capabilities such as `browserName` and `platformName`.
|
||||
|
||||
These standard capabilities continue to be used as-is. All other capabilities must include a "vendor prefix" in their name. A vendor prefix is a string followed by a colon, such as `appium:`. Most of Appium's capabilities go beyond the standard W3C capabilities and must therefore include vendor prefixes (we recommend that you use `appium:` unless directed otherwise by documentation). For example:
|
||||
|
||||
- `appium:app`
|
||||
- `appium:noReset`
|
||||
- `appium:deviceName`
|
||||
|
||||
This requirement may or may not be a breaking change for your test suites when targeting Appium 2.0. If you're using an updated Appium client (at least one maintained by the Appium team), the client will add the `appium:` prefix for you on all necessary capabilities automatically. New versions of [Appium Inspector](https://github.com/appium/appium-inspector) will also do this. Cloud-based Appium providers may also do this. So simply be aware that if you get any messages to the effect that your capabilities lack a vendor prefix, this is how you solve that problem.
|
||||
|
||||
On a related note, it will no longer be possible to start Appium sessions using WebDriver clients that don't support the W3C protocol (see below for a comment to this effect for the WD library).
|
||||
|
||||
To make everyone's lives a bit easier, we've also introduced the option of wrapping up all Appium-related capabilities into one object capability, `appium:options`. You can bundle together anything that you would normally put an `appium:` prefix on into this one capability. Here's an example (in raw JSON) of how you might start an iOS session on the Safari browser using `appium:options`:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"browserName": "Safari",
|
||||
"appium:options": {
|
||||
"platformVersion": "14.4",
|
||||
"deviceName": "iPhone 11",
|
||||
"automationName": "XCUITest"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(Of course, each client will have a different way of creating structured capabilities like `appium:options` or other ones that you might have seen such as `goog:chromeOptions`). NB: capabilities that show up in `appium:options` will overwrite capabilities of the same name that show up at the top level of the object. (The new `appium:options` syntax support by cloud providers may vary.)
|
||||
|
||||
For more information on capabilities, have a look at the [Capabilities Guide](caps.md).
|
||||
|
||||
### :bangbang: _Removed Commands_
|
||||
|
||||
In addition to commands which have been moved to driver implementations, commands which were a part of the old JSON Wire Protocol and not a part of the W3C Protocol are no longer available:
|
||||
|
||||
- TODO (these commands are being identified and removed and will be updated here when complete)
|
||||
|
||||
If you use a modern Appium or Selenium client, you should no longer have access to these anyway, so any breaking changes should appear on the client side first and foremost.
|
||||
|
||||
### :bangbang: Image analysis features moved to plugin
|
||||
|
||||
One of the design goals for Appium 2.0 is to migrate non-core features into special extensions called [plugins](../ecosystem/index.md). This allows people to opt into features which require extra time to download or extra system setup. The various image-related features of Appium (image comparison, finding elements by image, etc...) have been moved into an officially supported plugin called [images](https://github.com/appium/appium/tree/master/packages/images-plugin).
|
||||
|
||||
If you use these image-related methods, to continue accessing them you will need to do two things.
|
||||
|
||||
1. Install the plugin: `appium plugin install images`
|
||||
2. Ensure you start the Appium server with access to run the plugin by including it in the list of plugins designated on the command line, e.g., `appium --use-plugins=images`
|
||||
|
||||
Image-related commands will also be removed on the client side of things, which means you will need to follow the instructions on the plugin README for installing client-side plugins to access these features.
|
||||
|
||||
### :bangbang: Execute Driver Script command moved to plugin
|
||||
|
||||
If you use the advanced Execute Driver Script feature (which allows you to send in a WebdriverIO script to have it executed completely on the server instead of command-by-command from the client), this functionality has been moved to a plugin. Here's what to do to keep using it:
|
||||
|
||||
1. Install the plugin: `appium plugin install execute-driver`
|
||||
2. Ensure you start the Appium server with access to run the plugin by including it in the list of plugins designated on the command line, e.g., `appium --use-plugins=execute-driver`
|
||||
|
||||
### :bangbang: External Files No Longer Supported for `--nodeconfig`, `--default-capabilities`, `--allow-insecure` and `--deny-insecure`
|
||||
|
||||
These options can be provided as strings on the command line (a JSON string for `--nodeconfig` and a comma-separated list of strings for `--allow-insecure` and `--deny-insecure`). Arguments provided on the command line will likely need to be quoted or escaped.
|
||||
|
||||
The recommended method to provide these options is now via a [configuration file](#tada-configuration-files).
|
||||
|
||||
In summary, if you are using a JSON Appium config file, you can simply cut-and-paste the contents of your "nodeconfig" JSON file into the value of the `server.nodeconfig` property. Any CSV-like files you had previously provided for `--allow-insecure` and `--deny-insecure` become the values of the `server.allow-insecure` and `server.deny-insecure` properties in the Appium config files (respectively); both are arrays of strings.
|
||||
|
||||
### :bangbang: Old drivers removed
|
||||
|
||||
The old iOS and Android (UiAutomator 1) drivers and related tools (e.g., `authorize-ios`) have been removed. They haven't been relevant for many years anyway.
|
||||
|
||||
### :warning: Internal packages renamed
|
||||
|
||||
Some Appium-internal NPM packages have been renamed (for example, `appium-base-driver` is now `@appium/base-driver`). This is not a breaking change for Appium users, only for people who have built software that directly incorporates Appium's code.
|
||||
|
||||
### :warning: "WD" JavaScript client library no longer supported
|
||||
|
||||
For many years, some of Appium's authors maintained the [WD](https://github.com/admc/wd) client library. This library has been deprecated and has not been updated for use with the W3C WebDriver protocol. As such, if you're using this library you'll need to move to a more modern one. We recommend [WebdriverIO](https://webdriver.io).
|
||||
|
||||
### :warning: Appium Inspector split out from Appium Desktop
|
||||
|
||||
The inspecting portion of Appium Desktop has been moved to its own app, Appium Inspector: [github.com/appium/appium-inspector](https://github.com/appium/appium-inspector). It's fully compatible with Appium 2.0 servers. Simply download it and run it on its own. You no longer need the GUI Appium Desktop server to inspect apps. The Appium Desktop server will continue to be supported at its original site: [github.com/appium/appium-desktop](https://github.com/appium/appium-desktop). It will simply no longer bundle the Inspector with it. Note that Appium Desktop 1.21 and lower versions depend on the deprecated [WD](https://github.com/admc/wd) client, and are not compatible with Appium 2.0. There is currently no Appium 2.0 support for Appium Desktop planned, now that the Inspector is a standalone app.
|
||||
|
||||
You can also now use the Appium Inspector without downloading anything, by visiting the [web version of Appium Inspector](https://inspector.appiumpro.com). Note that to test against local servers, you'll need to start the server with `--allow-cors` so that the browser-based version of Appium Inspector can access your Appium server to start sessions.
|
||||
|
||||
## Major New Features
|
||||
|
||||
Apart from the breaking changes mentioned above, in this section is a list of some of the major new features you may wish to take advantage of with Appium 2.0.
|
||||
|
||||
### Plugins
|
||||
|
||||
#### :tada: _Server Plugins_
|
||||
|
||||
Appium extension authors can now develop their own server plugins, which can intercept and modify
|
||||
any Appium command, or even adjust the way the underlying Appium HTTP server itself works. To learn
|
||||
more about plugins, read the new [Appium Introduction](../intro/index.md). Interested in building
|
||||
a plugin? Check out the [Building Plugins](../ecosystem/build-plugins.md) guide.
|
||||
|
||||
#### :tada: _Client Plugins_
|
||||
|
||||
TODO
|
||||
|
||||
### :tada: Install drivers and plugins from anywhere
|
||||
|
||||
You're no longer limited to the drivers that come with Appium, or that the Appium team even knows
|
||||
about! Appium extension authors can now develop custom drivers, which can be downloaded or
|
||||
installed via Appium's [Extension CLI](../cli/extensions.md) from NPM, Git, GitHub, or even the
|
||||
local filesystem. Interested in building a driver? Check out the [Building
|
||||
Drivers](../ecosystem/build-drivers.md) guide.
|
||||
|
||||
### :tada: Configuration Files
|
||||
|
||||
Appium now supports _configuration files_ in addition to command-line arguments. In a nutshell, nearly all arguments which Appium 1.x required to be provided on the CLI are now able to be expressed via a configuration file. Configuration files may be in JSON, JS, or YAML format. See the [Config Guide](config.md) for a full explanation.
|
||||
|
||||
## Special Notes for Cloud Providers
|
||||
|
||||
The rest of this document has applied to Appium generally, but some of the architectural changes in Appium 2.0 will constitute breaking changes for Appium-related service providers, whether a cloud-based Appium host or an internal service. At the end of the day, the maintainer of the Appium server is responsible for installing and making available the various Appium drivers and plugins that end users may wish to use.
|
||||
|
||||
We encourage cloud providers to thoroughly read and understand our [recommendation for cloud
|
||||
provider capabilities](caps.md#special-notes-for-cloud-providers) in order to support user needs in
|
||||
an industry-compatible way!
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
title: Appium Server Security
|
||||
---
|
||||
|
||||
The Appium team makes every effort to ensure the security of the Appium server. This is especially
|
||||
important when Appium is run in a multitenant environment, or when multiple users are running
|
||||
sessions on the same Appium server. In general, you can only safely enable all Appium's features if
|
||||
all the following are true:
|
||||
|
||||
- You're running your own Appium server locally or within a protected internal network
|
||||
- You're not sharing it with any untrusted parties
|
||||
- You don't expose Appium's port(s) to the wider internet
|
||||
|
||||
But because many Appium users might not be able to guarantee such a safe environment, the Appium
|
||||
team puts many features behind a security protection mechanism which forces system admins (the
|
||||
people that are in charge of starting the Appium server) to _explicitly opt-in_ to these features.
|
||||
(Third-party driver and plugin authors can also [hide behaviour behind security
|
||||
flags](../ecosystem/build-drivers.md).)
|
||||
|
||||
For security reasons, Appium client sessions can _not_ request feature enablement via capabilities;
|
||||
this is the responsibility of the server admin who configures and launches the Appium server.
|
||||
|
||||
## Security Server Args
|
||||
|
||||
The [Server CLI Args](../cli/args.md) doc outlines three relevant arguments which may be passed to
|
||||
Appium when starting it from the command line:
|
||||
|
||||
|Parameter|Description|
|
||||
|----|----|
|
||||
|`--relaxed-security`|Setting this flag turns on _all_ insecure features (unless blocked by `--deny-insecure`; see below)|
|
||||
|`--allow-insecure`|Setting this flag to a comma-separated list of feature names or a path to a file containing a feature list (each name on a separate line) will allow _only_ the features listed. For example, `--allow-insecure=adb_shell` will cause _only_ the ADB shell execution feature to be enabled. This is true _unless_ `--relaxed-security` is also used, in which case all features will still be enabled. It makes no sense to combine this flag with `--relaxed-security`.|
|
||||
|`--deny-insecure`|This flag can likewise be set to a comma-separated list of feature names, or a path to a feature file. Any features listed here will be _disabled_, regardless of whether `--relaxed-security` is set and regardless of whether the names are also listed with `--allow-insecure`.|
|
||||
|
||||
## Insecure Features
|
||||
|
||||
Each Appium driver is responsible for its own security, and can create its own feature names. Thus
|
||||
you should read through the documentation for a particular driver to know which feature names it
|
||||
might use. Here is an incomplete list of examples from some of Appium's official drivers:
|
||||
|
||||
|Feature Name|Description|Supported Extension(s)|
|
||||
|------------|-----------|-------|
|
||||
|`get_server_logs`|Allows retrieving of Appium server logs via the Webdriver log interface|IOS, XCUITest, Android, UiAutomator2, Espresso|
|
||||
|`adb_shell`|Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command|Android, UiAutomator2, Espresso|
|
||||
|`record_audio`|Allow recording of host machine audio inputs|XCUITest|
|
||||
|`execute_driver_script`| Allows to send a request which has multiple Appium commands.|Execute Driver Plugin|
|
||||
|
||||
## Examples
|
||||
|
||||
To turn on the `get_server_logs` feature for my Appium server, I could start it like this:
|
||||
|
||||
```bash
|
||||
appium --allow-insecure=get_server_logs
|
||||
```
|
||||
|
||||
To turn on multiple features:
|
||||
|
||||
```bash
|
||||
appium --allow-insecure=get_server_logs,record_audio
|
||||
```
|
||||
|
||||
To allow all features except one:
|
||||
|
||||
```bash
|
||||
appium --relaxed-security --deny-insecure=adb_shell
|
||||
```
|
||||
@@ -1,46 +0,0 @@
|
||||
---
|
||||
title: The Settings API
|
||||
---
|
||||
|
||||
Appium has introduced a set of extension APIs that allow you to adjust parameters for a given
|
||||
session during session execution. Called "Settings", these parameters mirror the role of
|
||||
[Capabilities](./caps.md), but Capabilities cannot be adjusted once a session has started. Settings
|
||||
can be adjusted any number of times during the course of a session.
|
||||
|
||||
There are 3 important points to the concept of Settings:
|
||||
- Settings are mutable; they can be changed during a session using the Settings API
|
||||
- Settings are only relevant during the session in which they are set. They are typically reset for each new session, though depending on the driver, some settings may persist between sessions.
|
||||
- Settings adjust the way the appium server behaves during test automation. They don't refer to settings for the device or app under test
|
||||
|
||||
An example of a setting would be the `ignoreUnimportantViews` setting recognized by the
|
||||
UiAutomator2 driver. The driver can be instructed to ignore lements in the view hierarchy which it
|
||||
deems irrelevant. Adjusting this setting to have a value of `true` can cause tests to run faster.
|
||||
But if you *want* to access elements which would be ignored under this setting, you could always
|
||||
reset it to `false` later in the session.
|
||||
|
||||
Settings are implemented via the following API endpoints:
|
||||
|
||||
| Command | Method/Route | Params | Description | Returns |
|
||||
|-------------------|-------------------------------------|------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------|
|
||||
| `Update Settings` | `POST /session/:id/appium/settings` | `settings` (`Record<string, any>`) | Update setting values. The `settings` object needs to be a set of keys and values, where keys are the name of the settings and values are whatever value is documented as appropriate for that setting. | `null` |
|
||||
| `Get Settings` | `GET /session/:id/appium/settings` | | Return the current settings. | `Record<string, any>` |
|
||||
|
||||
Which settings are available depends on the driver you are using. Refer to the driver's
|
||||
documentation for a list of supported settings.
|
||||
|
||||
## Initializing Settings via Capabilities
|
||||
|
||||
When you want to start an Appium session with a setting in a certain state, you can do so by
|
||||
including a capability of the form `appium:settings[<name>]` with the appropriate value. So to turn
|
||||
on the `ignoreUnimportantViews` setting mentioned above from the very beginning of a session, you
|
||||
would construct a set of capabilities that includes the following in its JSON representation:
|
||||
|
||||
```json
|
||||
{
|
||||
"appium:settings[ignoreUnimportantViews]": true
|
||||
}
|
||||
```
|
||||
|
||||
Of course, initializing a setting via capabilities doesn't prevent you from changing it later on
|
||||
via the Settings API. To learn more about how to use the Settings API in the context of your
|
||||
specific client library, visit the documentation for that library.
|
||||
@@ -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.
|
||||
@@ -1,124 +0,0 @@
|
||||
---
|
||||
title: Intro to Appium Clients
|
||||
---
|
||||
|
||||
For all the reasons discussed in the [main intro](./index.md), Appium is based on the [W3C
|
||||
WebDriver specification](https://w3c.github.io/webdriver/webdriver-spec.html). This means that
|
||||
Appium implements a client-server architecture. The server (consisting of Appium itself along with
|
||||
any drivers or plugins you are using for automation) is connected to the devices under test, and
|
||||
is actually responsible for making automation happen on those devices. The client (driven by *you*,
|
||||
the Appium test author) is responsible for sending commands to the server over the network, and
|
||||
receiving responses from the server as a result. These responses can be used to tell whether
|
||||
automation commands are successful, or might contain information that you queried about the state
|
||||
of the application. This document is a conceptual introduction to the client side of this equation.
|
||||
|
||||
!!! info
|
||||
|
||||
For more about the server side of the equation (i.e., how does Appium actually control
|
||||
devices?), check out our [Intro to Appium Drivers](./drivers.md). To skip to a list of links to
|
||||
Appium client libraries, check out the [Ecosystem](../ecosystem/index.md) documentation.
|
||||
|
||||
What sorts of automation commands are available? That is up to the particular driver and plugins
|
||||
that you are using in any given session. A standard set of commands would include, for example, the
|
||||
following:
|
||||
|
||||
- Find Element
|
||||
- Click Element
|
||||
- Get Page Source
|
||||
- Take Screenshot
|
||||
|
||||
If you look at these commands in the WebDriver specification, you'll notice that they are not
|
||||
defined in terms of any particular programming language. They are not Java commands, or JavaScript
|
||||
commands, or Python commands. Instead, they form part of an HTTP API which can be accessed from
|
||||
within *any* programming language (or none! you could just use cURL if you want).
|
||||
|
||||
So, for example, the `Find Element` command corresponds to an HTTP `POST` request sent to the HTTP
|
||||
endpoint `/session/:sessionid/element` (where in this case, `:sessionid` is a placeholder for the
|
||||
unique session ID generated by the server in a previous call to `Create Session`).
|
||||
|
||||
This information is primarily useful for people developing technology that works with the WebDriver
|
||||
spec. It's not particularly useful for people trying to write Appium or Selenium tests. When you
|
||||
write an Appium test, you want to use a programming language you're familiar with. Luckily, there
|
||||
exist a set of [Appium client libraries](../ecosystem/index.md)[^1] that take care of the
|
||||
responsibility of speaking HTTP to the Appium server. Instead, they expose a set of "native"
|
||||
commands for a particular programming language, so that, to the test author, it just feels like
|
||||
you're writing Python, or JavaScript, or Java.
|
||||
|
||||
As an example, here's the same simple set of Appium commands in five different programming
|
||||
languages, using the recommended Appium client binding for each language (note that this is not
|
||||
working sample code including all appropriate imports; see each client library's instructions for
|
||||
setup and command reference):
|
||||
|
||||
=== "JavaScript (Webdriver.io)"
|
||||
|
||||
```js
|
||||
const element = await driver.$('//*[@text="Foo"]');
|
||||
await element.click();
|
||||
console.log(await element.getText())
|
||||
console.log(await driver.getPageSource())
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
WebElement element = driver.findElement(By.Xpath("//*[@text='Foo']"))
|
||||
element.click()
|
||||
System.out.println(element.getText())
|
||||
System.out.println(driver.getPageSource())
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
element = driver.find_element(by=By.XPATH, value='//*[@text="Foo"]')
|
||||
element.click()
|
||||
print(element.text)
|
||||
print(driver.page_source)
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```rb
|
||||
element = driver.find_element :xpath, '//*[@text="Foo"]'
|
||||
element.click
|
||||
puts element.text
|
||||
puts driver.page_source
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```dotnet
|
||||
AppiumElement element = driver.FindElement(MobileBy.AccessibilityId("Views"));
|
||||
element.click();
|
||||
System.Console.WriteLine(element.Text);
|
||||
System.Console.WriteLine(driver.PageSource);
|
||||
```
|
||||
|
||||
Each of these scripts, despite being in different languages, does the same thing under the hood:
|
||||
|
||||
1. Call `Find Element` with a `using` parameter of `xpath` and a `value` parameter expressing the
|
||||
XPath query used to find an element. (If you're confused about these terms, you might find an
|
||||
introduction to Appium or Selenium useful)
|
||||
2. Call `Click Element` with the ID of the element found in the previous call.
|
||||
3. Call `Get Element Text` with the ID of the same element, and print it to the console.
|
||||
4. Call `Get Page Source` to retrieve the page/app source and print it to the console.
|
||||
|
||||
The only other thing to keep in mind before choosing or using a client is that each client is
|
||||
independently maintained. Just because a feature is available in one client, it doesn't mean it's
|
||||
available in another client (though all clients support at least the standard W3C protocol plus any
|
||||
common appium extensions). Just because one client has a nice set of helper functions, doesn't mean
|
||||
another will. Some clients are kept very frequently up to date, and others are not! So when
|
||||
thinking about choosing a library, the first consideration is the language you want to use, and the
|
||||
second consideration is how full-featured and well-maintained the library is!
|
||||
|
||||
To learn how to use an Appium client, visit that client's homepage to learn more. In many cases,
|
||||
the Appium client for a given language is built *on top of* the *Selenium* client for that
|
||||
language, and so certain Appium clients may only document the features which the Appium client
|
||||
added on top of the Selenium client. All that to say, for a full reference, you may need to visit
|
||||
both the Appium client documentation as well as the Selenium client documentation.
|
||||
|
||||
That's all you need to know about Appium clients! Head over to the
|
||||
[Ecosystem](../ecosystem/index.md) page to check out the current list of clients.
|
||||
|
||||
[^1]: These libraries are alternately called "clients", "client libraries", or "client bindings".
|
||||
They all mean the same thing!
|
||||
@@ -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!
|
||||
@@ -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.
|
||||
@@ -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 in the [SemVer](https://semver.org) range `^14.17.0 || ^16.13.0 || >=18.0.0`
|
||||
* [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) (**recommended**) are official Appium 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 installing these libraries include the selenium binding. We recommend `appium_lib_core` if you need a less complex client-side solution. The `appium_lib` has some useful methods the core does not have, but for the cost of greater complexity.
|
||||
|
||||
```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 ordinary 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 available 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
Reference in New Issue
Block a user