mirror of
https://github.com/appium/appium.git
synced 2026-11-11 04:23:55 +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,10 +0,0 @@
|
||||
**/coverage/**
|
||||
**/node_modules/**
|
||||
examples/javascript-wd
|
||||
**/build/**
|
||||
**/*.min.js
|
||||
sample-code
|
||||
**/*.d.ts
|
||||
**/build-fixtures/**
|
||||
**/*.ts
|
||||
packages/appium/docs/**/assets/**
|
||||
@@ -1,53 +0,0 @@
|
||||
{
|
||||
"extends": "@appium/eslint-config-appium",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "packages/fake-driver/**/*",
|
||||
"rules": {"require-await": "off"}
|
||||
},
|
||||
{"files": "packages/support/**/*", "globals": {"BigInt": "readonly"}},
|
||||
{
|
||||
"files": "packages/*/test/**/*",
|
||||
"rules": {"func-names": "off"}
|
||||
},
|
||||
{
|
||||
"files": ["packages/*/index.js", "packages/*/scripts/**/*.js", "test/*.js"],
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"packages/appium/support.js",
|
||||
"packages/appium/driver.js",
|
||||
"packages/appium/plugin.js"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "./packages/*/test/**/*.js",
|
||||
"rules": {
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
{
|
||||
"object": "sinon",
|
||||
"property": "spy",
|
||||
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.spy()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
|
||||
},
|
||||
{
|
||||
"object": "sinon",
|
||||
"property": "stub",
|
||||
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.stub()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
|
||||
},
|
||||
{
|
||||
"object": "sinon",
|
||||
"property": "mock",
|
||||
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.mock()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
|
||||
# Visit https://fossa.com to learn more
|
||||
|
||||
version: 3
|
||||
|
||||
project:
|
||||
id: appium
|
||||
name: appium
|
||||
|
||||
paths:
|
||||
exclude:
|
||||
- ./sample-code
|
||||
- '**/fixtures/**'
|
||||
- '**/demo/**'
|
||||
- '**/example/**'
|
||||
- '**/examples/**'
|
||||
|
||||
targets:
|
||||
only:
|
||||
- type: npm
|
||||
path: .
|
||||
- type: npm
|
||||
path: ./packages/appium
|
||||
- type: npm
|
||||
path: ./packages/base-driver
|
||||
- type: npm
|
||||
path: ./packages/doctor
|
||||
- type: npm
|
||||
path: ./packages/eslint-config-appium
|
||||
- type: npm
|
||||
path: ./packages/fake-driver
|
||||
- type: npm
|
||||
path: ./packages/gulp-plugins
|
||||
- type: npm
|
||||
path: ./packages/support
|
||||
- type: npm
|
||||
path: ./packages/test-support
|
||||
- type: npm
|
||||
path: ./packages/types
|
||||
- type: npm
|
||||
path: ./packages/schema
|
||||
- type: npm
|
||||
path: ./packages/universal-xmlplugin
|
||||
- type: npm
|
||||
path: ./packages/opencv
|
||||
- type: npm
|
||||
path: ./packages/images-plugin
|
||||
- type: npm
|
||||
path: ./packages/base-plugin
|
||||
- type: npm
|
||||
path: ./packages/relaxed-caps-plugin
|
||||
- type: npm
|
||||
path: ./packages/fake-plugin
|
||||
- type: npm
|
||||
path: ./packages/docutils
|
||||
|
||||
|
||||
|
||||
revision:
|
||||
branch: master
|
||||
@@ -1 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
@@ -1,33 +0,0 @@
|
||||
## The problem
|
||||
|
||||
Briefly describe the issue you are experiencing (or the feature you want to see added to Appium). Tell us what you were trying to do and what happened instead. Remember, this is _not_ a place to ask questions. For that, go to http://discuss.appium.io!
|
||||
|
||||
## Environment
|
||||
|
||||
* Appium version (or git revision) that exhibits the issue:
|
||||
* Last Appium version that did not exhibit the issue (if applicable):
|
||||
* Desktop OS/version used to run Appium:
|
||||
* Node.js version (unless using Appium.app|exe):
|
||||
* Npm or Yarn package manager:
|
||||
* Mobile platform/version under test:
|
||||
* Real device or emulator/simulator:
|
||||
* Appium CLI or Appium.app|exe:
|
||||
|
||||
## Details
|
||||
|
||||
If necessary, describe the problem you have been experiencing in more detail.
|
||||
|
||||
## Link to Appium logs
|
||||
|
||||
Create a [GIST](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here.
|
||||
Do _NOT_ paste your full Appium logs here, as it will make this issue very long and hard to read!
|
||||
If you are reporting a bug, _always_ include Appium logs!
|
||||
|
||||
|
||||
## Code To Reproduce Issue [ Good To Have ]
|
||||
|
||||
Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it.
|
||||
|
||||
Please git clone https://github.com/appium/appium and from the `examples` directory, use one of your favourite languages and sample apps to reproduce the issue.
|
||||
|
||||
In case a similar scenario is missing in examples, please submit a PR with one of the sample apps provided.
|
||||
@@ -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,59 +0,0 @@
|
||||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||
|
||||
name: Appium Build
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x, 18.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- name: Install latest npm
|
||||
run: npm install -g npm
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
- name: Run smoke, unit & E2E tests
|
||||
run: npm run test:ci
|
||||
|
||||
lint:
|
||||
name: Lint & Check Types
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
- name: ESLint
|
||||
run: npm run lint
|
||||
- name: Check types
|
||||
run: npm run build:types
|
||||
|
||||
docs:
|
||||
name: Build Command Documentation
|
||||
needs: [test]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
- name: Generate docs
|
||||
run: npm run generate-docs
|
||||
@@ -1,60 +0,0 @@
|
||||
name: Appium Deploy
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- appium@2*
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
# node-version: [14.x, 16.x, 18.x]
|
||||
node-version: [16.x, 18.x]
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
steps:
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Appium
|
||||
run: |
|
||||
if [[ "$GITHUB_REF_TYPE" == tag ]]; then
|
||||
npm i -g $GITHUB_REF_NAME
|
||||
else
|
||||
npm i -g appium@next
|
||||
fi
|
||||
shell: bash
|
||||
- name: Install drivers and plugins
|
||||
run: |
|
||||
if grep -q macos <<< ${{ matrix.os }}; then
|
||||
appium driver install xcuitest
|
||||
fi
|
||||
appium driver install uiautomator2
|
||||
appium plugin install images
|
||||
shell: bash
|
||||
- name: Verify installation
|
||||
run: |
|
||||
installed_drivers=$(appium driver list --installed 2>&1)
|
||||
if grep -q macos <<< ${{ matrix.os }}; then
|
||||
grep -q xcuitest <<< $installed_drivers
|
||||
fi
|
||||
grep -q uiautomator2 <<< $installed_drivers
|
||||
installed_plugins=$(appium plugin list --installed 2>&1)
|
||||
grep -q images <<< $installed_plugins
|
||||
shell: bash
|
||||
- name: Verify Appium could be executed
|
||||
run: |
|
||||
appium --use-plugins=images &
|
||||
pid=$(echo $!)
|
||||
sleep 5
|
||||
ps -p $pid || exit 1
|
||||
kill -2 $pid
|
||||
shell: bash
|
||||
@@ -1,25 +0,0 @@
|
||||
name: License Checks
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
fossa-check:
|
||||
name: Run FOSSA Analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
with:
|
||||
ref: master
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
|
||||
- name: Install fossa-cli
|
||||
run: ./scripts/install-fossa.sh -d
|
||||
- name: Run FOSSA analysis
|
||||
fossa analyze
|
||||
fossa test
|
||||
env:
|
||||
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
|
||||
+3
-60
@@ -1,63 +1,6 @@
|
||||
.irb-history
|
||||
*.swp
|
||||
.DS_Store
|
||||
node_modules
|
||||
*.trace
|
||||
xcuserdata
|
||||
*.sublime-*
|
||||
test/functional/_joined
|
||||
*.iml
|
||||
!examples/java/*.iml
|
||||
*.autosave
|
||||
.idea/
|
||||
!examples/java/.idea/
|
||||
build
|
||||
*.log
|
||||
*.t
|
||||
artifacts
|
||||
input
|
||||
output
|
||||
lib/devices/android/bootstrap/bin/*
|
||||
lib/devices/android/bootstrap/local.properties
|
||||
lib/devices/android/bootstrap/project.properties
|
||||
lib/devices/android/bootstrap/.classpath
|
||||
lib/devices/android/bootstrap/target/
|
||||
.*~
|
||||
*~
|
||||
org.eclipse.ltk.core.refactoring.prefs
|
||||
.appiumconfig*
|
||||
build/
|
||||
.idea
|
||||
*DerivedData
|
||||
__pycache__
|
||||
|
||||
# csharp
|
||||
*.pyc
|
||||
*.pdb
|
||||
.vs
|
||||
|
||||
old
|
||||
.tern-project
|
||||
working
|
||||
.DS_Store
|
||||
coverage
|
||||
docs/mkdocs.yml
|
||||
examples/javascript-wd/node_modules
|
||||
examples/php/vendor
|
||||
examples/php/composer.lock
|
||||
examples/java/out/
|
||||
examples/ruby/Gemfile.lock
|
||||
examples/python/test/results/
|
||||
examples/python/test/input
|
||||
examples/python/.pytest_cache/
|
||||
examples/csharp/test/bin
|
||||
examples/csharp/test/obj
|
||||
examples/csharp/test/bin
|
||||
examples/csharp/packages
|
||||
appium.zip
|
||||
.vscode/settings.json
|
||||
.nyc_output
|
||||
*.lerna_backup
|
||||
**/build-fixtures/**
|
||||
*.tsbuildinfo
|
||||
packages/*/LICENSE
|
||||
local_appium_home
|
||||
jsdoc-out
|
||||
*.tgz
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
require: [require.resolve('./test/setup.js')],
|
||||
// forbids use of .only() in CI
|
||||
forbidOnly: Boolean(process.env.CI),
|
||||
color: true,
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
**/node_modules/**
|
||||
**/build/**
|
||||
**/fixtures/**
|
||||
**/*.min.*
|
||||
**/*.md
|
||||
**/*.yml
|
||||
**/*.json
|
||||
**/.vscode/**
|
||||
**/*.html
|
||||
**/generated/**
|
||||
# generated
|
||||
packages/types/lib/appium-config.ts
|
||||
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.12"
|
||||
after_success:
|
||||
- gulp coveralls
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"args": ["--colors", "--timeout", "0", "${file}"],
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"name": "Test - Current File",
|
||||
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
|
||||
"runtimeArgs": ["--require", "@babel/register"],
|
||||
"request": "launch",
|
||||
"skipFiles": ["<node_internals>/**", "**/node_modules/mocha/**"],
|
||||
"type": "pwa-node",
|
||||
"sourceMaps": true,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"outfiles": [],
|
||||
"env": {
|
||||
"NODE_ENV": "test",
|
||||
"BABEL_ENV": "test"
|
||||
},
|
||||
"autoAttachChildProcesses": true,
|
||||
}
|
||||
]
|
||||
}
|
||||
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,273 +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.
|
||||
|
||||
Appium is in the final stages of a major revision (to version 2.0). As such, the documentation
|
||||
found around the web may not be correct. The current Appium 2.0 documentation is very much in
|
||||
progress. Currently, it can be found [here](https://appium.github.io/appium/docs/en/2.0/).
|
||||
|
||||
### Requirements
|
||||
|
||||
- macOS, Linux or Windows operating system
|
||||
- Node.js 14+
|
||||
- NPM (Node Package Manager) 8+
|
||||
|
||||
These are only server requirements. Each driver might have its own requirements. Consider checking the corresponding driver tutorial for more details.
|
||||
|
||||
### Server
|
||||
|
||||
To install Appium 2 server using Node Package Manager (npm) run the following command:
|
||||
|
||||
```bash
|
||||
npm install -g appium@next
|
||||
```
|
||||
npm install appium-doctor -g
|
||||
```
|
||||
|
||||
:bangbang: Running `npm install -g appium` would still install Appium 1 because version 2 is in its late beta stage.
|
||||
### Usage
|
||||
|
||||
### Drivers
|
||||
```
|
||||
➜ appium-doctor -h
|
||||
|
||||
Appium supports app automation across a variety of platforms, like iOS,
|
||||
Android, and Windows. Each platform is supported by one or more "drivers",
|
||||
which know how to automate that particular platform. Since version 2.0
|
||||
all drivers have been isolated from the Appium server app and can
|
||||
be managed independently using the [appium driver](https://appiumpro.com/editions/122-installing-appium-20-and-the-driver-and-plugins-cli) command line interface.
|
||||
Usage: appium-doctor.js [options, defaults: --ios --android]
|
||||
|
||||
In general, the drivers management in Appium 2 is as simple as:
|
||||
|
||||
```bash
|
||||
# To install a new driver from npm
|
||||
appium driver install --source=npm appium-xcuitest-driver[@<version>]
|
||||
# To install a driver from a local folder (useful for developers)
|
||||
appium driver install --source=local /Users/me/sources/appium-xcuitest-driver
|
||||
# To install a new driver from github (hm, maybe it's time to publish it to NPM?)
|
||||
appium driver install --source=github appium/appium-xcuitest-driver
|
||||
|
||||
# To list already installed drivers
|
||||
appium driver list --installed
|
||||
|
||||
# To update a driver (it must be already installed)
|
||||
appium driver update xcuitest
|
||||
|
||||
# To uninstall a driver (it won't last forever, wouldn't it?)
|
||||
appium driver uninstall xcuitest
|
||||
Options:
|
||||
--ios Check iOS setup [boolean]
|
||||
--android Check Android setup [boolean]
|
||||
--dev Check dev setup [boolean]
|
||||
--debug Show debug messages [boolean]
|
||||
--yes Always respond yes [boolean]
|
||||
--no Always respond no [boolean]
|
||||
--demo Run appium-doctor demo (for dev). [boolean]
|
||||
-h, --help Show help [boolean]
|
||||
```
|
||||
|
||||
#### Drivers Maintained By The Appium Team
|
||||
## Dev
|
||||
|
||||
These drivers are supported by Appium core members. Please report any issues
|
||||
or suggestions regarding them to the corresponding GitHub issue tracker.
|
||||
Refer to the corresponding driver Readme to know more on how to use it and its requirements.
|
||||
## Watch
|
||||
|
||||
Name | Description
|
||||
--- | ---
|
||||
[appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver) | Allows automation of iOS native and web apps (via hybrid mode). Also supports tvOS. This driver is based on Apple's [XCTest framework](https://developer.apple.com/documentation/xctest) and can only use macOS as the host system.
|
||||
[appium-uiautomator2-driver](https://github.com/appium/appium-uiautomator2-driver) | Allows automation of Android native and web apps (via hybrid mode). The driver is based on Google's [UiAutomator](https://developer.android.com/training/testing/other-components/ui-automator) framework.
|
||||
[appium-espresso-driver](https://github.com/appium/appium-espresso-driver) | Allows automation of Android native apps. The driver is based on Google's [Espresso](https://developer.android.com/training/testing/espresso) framework.
|
||||
[appium-mac2-driver](https://github.com/appium/appium-mac2-driver) | Allows automation of macOS native apps. Also supports tvOS. This driver is based on Apple [XCTest framework](https://developer.apple.com/documentation/xctest) and can only use macOS as the host system.
|
||||
[appium-windows-driver](https://github.com/appium/appium-windows-driver) | Allows automation of Windows native and UWP apps. This driver is based on Microsoft's [WinAppDriver](https://github.com/microsoft/WinAppDriver) implementation and can only use Windows 10 as the host system.
|
||||
[appium-gecko-driver](https://github.com/appium/appium-geckodriver) | Allows automation of Gecko-engine-based browsers, like Firefox on mobile and desktop platforms. Uses [geckodriver](https://github.com/mozilla/geckodriver/releases) command line tool provided by Mozilla for various platforms.
|
||||
[appium-safari-driver](https://github.com/appium/appium-safari-driver) | Allows automation of Safari browser on mobile and desktop platforms . Uses the [safaridriver](https://www.manpagez.com/man/1/safaridriver/) command line tool provided by Apple as part of macOS.
|
||||
|
||||
#### Drivers Provided By Third Parties
|
||||
|
||||
These drivers are supported by different companies or communities.
|
||||
Please report any issues related to their functionality to their
|
||||
respective maintainers. If you are a developer yourself and have created a new useful
|
||||
Appium2-compatible driver then don't hesitate to create a PR and add a link to
|
||||
your driver into the below list.
|
||||
|
||||
<details>
|
||||
<summary>Drivers List</summary>
|
||||
|
||||
Name | Description
|
||||
--- | ---
|
||||
[appium-youiengine-driver](https://github.com/YOU-i-Labs/appium-youiengine-driver) | Appium You.i Engine Driver is a test automation tool for devices of various platforms running applications built with [You.i Engine](http://www.youi.tv/youi-engine/)
|
||||
[appium-flutter-driver](https://github.com/appium-userland/appium-flutter-driver) | Allows automation of apps built using [Flutter](https://flutter.dev/) framework
|
||||
[appium-tizen-driver](https://github.com/Samsung/appium-tizen-driver) | Allows automation of apps built for devices running [Tizen OS](https://www.tizen.org/)
|
||||
[appium-linux-driver](https://github.com/fantonglang/appium-linux-driver) | Allows automation of Linux applications using [AtSpi2](https://www.freedesktop.org/wiki/Accessibility/AT-SPI2/) framework
|
||||
</details>
|
||||
|
||||
### Plugins
|
||||
|
||||
The concept of plugins is something new that has been added exclusively to Appium2. Plugins allow you to extend server functionality without changing the server code. Plugins could be managed similarly to drivers:
|
||||
|
||||
```bash
|
||||
# To install an officially supported plugin
|
||||
appium plugin install images
|
||||
# To install a plugin from a local folder (useful for developers)
|
||||
appium plugin install --source=local /Users/me/sources/images
|
||||
# To install a new plugin from npm
|
||||
appium plugin install --source=npm appium-device-farm
|
||||
|
||||
# To list already installed plugins
|
||||
appium plugin list --installed
|
||||
|
||||
# To update a plugins (it must be already installed)
|
||||
appium plugin update appium-device-farm
|
||||
|
||||
# To uninstall a plugin
|
||||
appium plugin uninstall appium-device-farm
|
||||
```
|
||||
npm run watch
|
||||
```
|
||||
|
||||
The main difference between drivers and plugins is that the latter must be explicitly enabled on server startup after it was installed (drivers are enabled by default after installation):
|
||||
## Test
|
||||
|
||||
```bash
|
||||
appium server --use-plugins=device-farm,images
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
#### Plugins Maintained By The Appium Team
|
||||
## Hack Cli
|
||||
|
||||
These plugins are supported by Appium core members. Please report any issues
|
||||
or suggestions regarding them to the corresponding GitHub issue tracker.
|
||||
Refer to the corresponding plugin Readme to know more on how to use it.
|
||||
Use the `--demo` option to simulate the fix process.
|
||||
|
||||
Name | Description
|
||||
--- | ---
|
||||
[images](https://github.com/appium/appium/tree/master/packages/images-plugin) | This is an official Appium plugin designed to facilitate image comparison, visual testing, and image-based functional testing.
|
||||
[relaxed-caps](https://github.com/appium/appium/tree/master/packages/relaxed-caps-plugin) | With the advent of Appium 2.0, the Appium server begins to require that all capabilities conform to the W3C requirements for capabilities. Among these requirements is one that restricts capabilities to those found in a predetermined set. Appium supports many additional capabilities as extension capabilities, and these must be accessed with the prefix appium: in front of the capability name. There are a lot of test scripts out there that don't conform to the requirement, and so this plugin is designed to make it easy to keep running these scripts even with the new stricter capabilities requirements beginning with Appium 2.0. Basically, it inserts the appium: prefix for you!
|
||||
[universal-xml](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin) | This is an official Appium plugin designed to make XML source retrieved from iOS and Android use the same node and attribute names, to facilitate cross-platform test writing.
|
||||
|
||||
#### Plugins Provided By Third Parties
|
||||
|
||||
These plugins are supported by different companies or communities.
|
||||
Please report any issues related to their functionality to their
|
||||
respective maintainers. If you are a developer yourself and have created a new useful
|
||||
plugin then don't hesitate to create a PR and add a link to your plugin into the below list.
|
||||
|
||||
<details>
|
||||
<summary>Plugins List</summary>
|
||||
|
||||
Name | Description
|
||||
--- | ---
|
||||
[appium-device-farm](https://github.com/AppiumTestDistribution/appium-device-farm) | This is an Appium plugin designed to manage and create driver session on connected android devices and iOS Simulators.
|
||||
[appium-reporter-plugin](https://github.com/AppiumTestDistribution/appium-reporter-plugin) | This Plugin generates standalone consolidated html report with screenshots. Report can be fetched from appium server, without worrying about heavy lifting such as screenshot capturing, report generation etc.
|
||||
</details>
|
||||
|
||||
### Server Command Line Interface
|
||||
|
||||
In order to start sending commands to Appium over the wire it must be listening
|
||||
on the URL where your client library expects it to listen.
|
||||
Use the following commands to run and configure Appium server:
|
||||
|
||||
```bash
|
||||
# Start the server on the default port and host (e.g. http://0.0.0.0:4723/)
|
||||
appium server
|
||||
# Start the server on the given port, host and use the base path prefix (the default prefix is /)
|
||||
appium server -p 9000 -a 127.0.0.1 -pa /wd/hub
|
||||
|
||||
# Get the list of all supported command line parameters.
|
||||
# This list would also include descriptions of driver-specific
|
||||
# command line arguments for all installed drivers.
|
||||
# Each driver and plugin must have their command line arguments
|
||||
# exposed in a special JSON schema declared as a part of the corresponding
|
||||
# package.json file.
|
||||
appium server --help
|
||||
```
|
||||
appium-doctor --demo
|
||||
```
|
||||
|
||||
Appium supports execution of parallel server processes as well as parallel driver sessions within
|
||||
single server process. Refer the corresponding driver documentations regarding which mode is optimal
|
||||
for the particular driver or whether it supports parallel sessions.
|
||||
|
||||
### Why Appium?
|
||||
|
||||
1. You usually don't have to recompile your app or modify it in any way, due
|
||||
to the use of standard automation APIs on all platforms.
|
||||
2. You can write tests with your favorite dev tools using any
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html)-compatible
|
||||
language such as [Java](https://github.com/appium/java-client),
|
||||
[JavaScript](https://webdriver.io/), [Python](https://github.com/appium/python-client),
|
||||
[Ruby](https://github.com/appium/ruby_lib), [C#](https://github.com/appium/appium-dotnet-driver)
|
||||
with the Selenium WebDriver API. There are also various third party
|
||||
client implementations for other languages.
|
||||
3. You can use any testing framework.
|
||||
4. Some drivers, like xcuitest and uiautomator2 ones have built-in mobile web and
|
||||
hybrid app support. Within the same script, you can switch seamlessly between native
|
||||
app automation and webview automation, all using the WebDriver model that's already
|
||||
the standard for web automation.
|
||||
5. You can run your automated tests locally and in a cloud. There are multiple
|
||||
cloud providers that support various Appium drivers (mostly
|
||||
targeting iOS and Android mobile automation).
|
||||
6. [Appium Inspector](https://github.com/appium/appium-inspector) allows
|
||||
visual debugging of automated tests and could be extremely useful for
|
||||
beginners.
|
||||
|
||||
Investing in the
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means
|
||||
you are betting on a single, free, and open protocol for testing that has become
|
||||
a web standard. Don't lock yourself into a proprietary stack.
|
||||
|
||||
For example, if you use Apple's XCUITest library without Appium you can only
|
||||
write tests using Obj-C/Swift, and you can only run tests through Xcode.
|
||||
Similarly, with Google's UiAutomator or Espresso, you can only write tests in
|
||||
Java/Kotlin. Appium opens up the possibility of true cross-platform native app
|
||||
automation, for mobile and beyond. Finally!
|
||||
|
||||
If you're new to Appium or want a more comprehensive description of what this is all
|
||||
about, please read our [Introduction to Appium Concepts](/docs/en/about-appium/intro.md).
|
||||
|
||||
### Get Started
|
||||
|
||||
Check out our [Getting Started](http://appium.io/docs/en/about-appium/getting-started) guide
|
||||
to get going with Appium.
|
||||
|
||||
There is also a sample code that contains [many examples of tests in a variety
|
||||
of different languages](https://github.com/appium/appium/tree/master/sample-code)!
|
||||
|
||||
### Documentation
|
||||
|
||||
For prettily-rendered docs, please visit [appium.io](http://appium.io). You can
|
||||
always find the full list of Appium doc pages at [Appium's GitHub
|
||||
Repo](https://github.com/appium/appium/tree/master/docs/en/) as well.
|
||||
|
||||
[update-appium-io.yml](https://github.com/appium/appium/blob/master/ci-jobs/update-appium-io.yml) creates a PR
|
||||
by [CI job](https://dev.azure.com/AppiumCI/Appium%20CI/_build?definitionId=37).
|
||||
in the appium.io repository with the documentation update.
|
||||
|
||||
Once the PR has been merged, the latest documentation will be in [appium.io](http://appium.io)
|
||||
|
||||
### Contributing
|
||||
|
||||
Please take a look at our [contribution documentation](CONTRIBUTING.md)
|
||||
for instructions on how to build, test, and run Appium from the source.
|
||||
|
||||
### Roadmap
|
||||
|
||||
Interested in where Appium is heading in the future? Check out the [Roadmap](ROADMAP.md)
|
||||
|
||||
### Project History, Credits & Inspiration
|
||||
|
||||
* [History](http://appium.io/history)
|
||||
* [Credits](/docs/en/contributing-to-appium/credits.md)
|
||||
|
||||
### User Forums
|
||||
|
||||
Announcements and debates often take place on the [Discussion Group](https://discuss.appium.io),
|
||||
be sure to sign up!
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
We put together a [troubleshooting guide](/docs/en/writing-running-appium/other/troubleshooting.md).
|
||||
Please have a look here first if you run into any problems. It contains instructions for checking
|
||||
a lot of common errors and how to get in touch with the community if you're
|
||||
stumped.
|
||||
|
||||
### License
|
||||
|
||||
[](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,32 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "14"
|
||||
},
|
||||
"shippedProposals": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": ["source-map-support"],
|
||||
"comments": false,
|
||||
"sourceMaps": "both",
|
||||
"env": {
|
||||
"coverage": {
|
||||
"plugins": [
|
||||
[
|
||||
"istanbul",
|
||||
{
|
||||
"exclude": ["test", "build"]
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"retainLines": true,
|
||||
"comments": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
// transpile:main
|
||||
|
||||
import yargs from 'yargs';
|
||||
//import _ from 'lodash';
|
||||
import newDoctor from '../lib/factory';
|
||||
import {configureBinaryLog} from '../lib/utils';
|
||||
import {configure as configurePrompt} from '../lib/prompt';
|
||||
import {system} from '@appium/support';
|
||||
import { configureBinaryLog } from '../lib/utils';
|
||||
import { configure as configurePrompt } from '../lib/prompt';
|
||||
|
||||
yargs
|
||||
.strict()
|
||||
@@ -25,27 +25,15 @@ yargs
|
||||
.describe('demo', 'Run appium-doctor demo (for dev).')
|
||||
.help('h')
|
||||
.alias('h', 'help')
|
||||
.check(function (argv) {
|
||||
if (!argv.ios && !argv.android && !argv.demo) {
|
||||
argv.ios = system.isMac();
|
||||
.check(function(argv) {
|
||||
if(!argv.ios && !argv.android && !argv.demo) {
|
||||
argv.ios = true;
|
||||
argv.android = true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// make sure we use the general checks for every test
|
||||
let opts = Object.assign(
|
||||
{
|
||||
general: true,
|
||||
},
|
||||
yargs.argv
|
||||
);
|
||||
let opts = yargs.argv;
|
||||
|
||||
configurePrompt(opts);
|
||||
configureBinaryLog(opts);
|
||||
newDoctor(opts)
|
||||
.run()
|
||||
.catch(function (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
process.exit(1);
|
||||
});
|
||||
newDoctor(opts).run();
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"strictNullChecks": true,
|
||||
"removeComments": false,
|
||||
"target": "es2015",
|
||||
"types": ["node", "mocha", "chai", "sinon-chai", "chai-as-promised"]
|
||||
}
|
||||
}
|
||||
@@ -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 };
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"command": {
|
||||
"exec": {
|
||||
"ignore": ["@appium/eslint-config-appium", "appium"]
|
||||
},
|
||||
"run": {
|
||||
"prefix": false,
|
||||
"concurrency": 1,
|
||||
"stream": true
|
||||
},
|
||||
"version": {
|
||||
"conventionalCommits": true,
|
||||
"createRelease": "github"
|
||||
},
|
||||
"add": {
|
||||
"exact": true
|
||||
}
|
||||
},
|
||||
"ignoreChanges": [
|
||||
"**/test/**",
|
||||
"**/*.md"
|
||||
],
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "independent"
|
||||
}
|
||||
@@ -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
-44832
File diff suppressed because it is too large
Load Diff
+38
-160
@@ -1,174 +1,52 @@
|
||||
{
|
||||
"name": "appium-monorepo",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "Automation for Apps.",
|
||||
"name": "appium-doctor",
|
||||
"description": "Description goes here.",
|
||||
"keywords": [
|
||||
"automation",
|
||||
"javascript",
|
||||
"selenium",
|
||||
"webdriver",
|
||||
"ios",
|
||||
"android",
|
||||
"firefoxos",
|
||||
"testing"
|
||||
"appium"
|
||||
],
|
||||
"homepage": "https://appium.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/appium/appium/issues"
|
||||
},
|
||||
"version": "1.0.1",
|
||||
"author": "appium",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appium/appium.git"
|
||||
"url": "https://github.com/appium/appium-doctor.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": "https://github.com/appium",
|
||||
"scripts": {
|
||||
"build": "run-s build:distfiles build:types",
|
||||
"build:distfiles": "lerna run --parallel --prefix --concurrency=8 build",
|
||||
"build:types": "tsc -b",
|
||||
"clean": "run-s clean:artifacts clean:packages clean:monorepo",
|
||||
"clean:artifacts": "run-s clean:distfiles clean:types && npx rimraf \"packages/*/build\"",
|
||||
"clean:distfiles": "npx rimraf \"packages/*/build/**/*.js\"",
|
||||
"clean:monorepo": "npx rimraf node_modules",
|
||||
"clean:packages": "lerna clean -y && npx rimraf \"packages/*/package-lock.json\"",
|
||||
"clean:types": "tsc -b --clean",
|
||||
"dev": "run-p dev:*",
|
||||
"dev:distfiles": "lerna run --parallel --prefix --concurrency=8 dev",
|
||||
"dev:types": "tsc -b --watch",
|
||||
"doctor": "node ./packages/doctor",
|
||||
"generate-docs": "lerna run --scope=appium generate-docs",
|
||||
"prepare": "npm run build:types || true",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"precommit-lint": "lint-staged",
|
||||
"precommit-msg": "echo 'Pre-commit checks...'",
|
||||
"prepublishOnly": "run-s clean:artifacts build",
|
||||
"reinstall": "run-p clean:artifacts clean:packages && npm ci",
|
||||
"start": "appium",
|
||||
"sync-pkgs": "run-p sync-pkgs:*",
|
||||
"sync-pkgs:appium-readme": "sync-monorepo-packages --force --no-package-json --packages=packages/appium README.md",
|
||||
"sync-pkgs:common-fields": "sync-monorepo-packages --fields=author,license,bugs,homepage,engines",
|
||||
"sync-pkgs:keywords": "sync-monorepo-packages --field=keywords --packages=\"packages/*\" --packages=\"!packages/eslint-config-appium\" --packages=\"!packages/types\"",
|
||||
"sync-pkgs:license": "sync-monorepo-packages --force --no-package-json LICENSE",
|
||||
"test": "run-s build test:unit lint",
|
||||
"test:ci": "run-s test:smoke test:unit test:ci:e2e",
|
||||
"test:ci:e2e": "lerna run test:e2e",
|
||||
"test:e2e": "lerna run --parallel --max-buffer=128 test:e2e",
|
||||
"test:smoke": "smoker --all test:smoke",
|
||||
"test:unit": "lerna run test",
|
||||
"uninstall-fake-driver": "npm start -- driver uninstall fake",
|
||||
"upload": "gulp github-upload",
|
||||
"preversion": "run-s clean:artifacts build sync-pkgs && git add -A packages/appium/README.md packages/*/package.json",
|
||||
"zip": "zip -qr ./appium.zip ./packages/appium",
|
||||
"zip-and-upload": "run-s zip upload"
|
||||
"bugs": {
|
||||
"url": "https://github.com/appium/appium-doctor/issues"
|
||||
},
|
||||
"pre-commit": [
|
||||
"precommit-msg",
|
||||
"precommit-lint"
|
||||
"engines": [
|
||||
"node"
|
||||
],
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"eslint --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
"*.ts*": [
|
||||
"prettier --write"
|
||||
]
|
||||
"main": "./build/index.js",
|
||||
"bin": {
|
||||
"appium-doctor": "./appium-doctor.js"
|
||||
},
|
||||
"prettier": {
|
||||
"bracketSpacing": false,
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appium/base-driver": "file:packages/base-driver",
|
||||
"@appium/base-plugin": "file:packages/base-plugin",
|
||||
"@appium/doctor": "file:packages/doctor",
|
||||
"@appium/docutils": "file:packages/docutils",
|
||||
"@appium/driver-test-support": "file:packages/driver-test-support",
|
||||
"@appium/eslint-config-appium": "file:packages/eslint-config-appium",
|
||||
"@appium/execute-driver-plugin": "file:packages/execute-driver-plugin",
|
||||
"@appium/fake-driver": "file:packages/fake-driver",
|
||||
"@appium/fake-plugin": "file:packages/fake-plugin",
|
||||
"@appium/gulp-plugins": "file:packages/gulp-plugins",
|
||||
"@appium/images-plugin": "file:packages/images-plugin",
|
||||
"@appium/opencv": "file:packages/opencv",
|
||||
"@appium/plugin-test-support": "file:packages/plugin-test-support",
|
||||
"@appium/relaxed-caps-plugin": "file:packages/relaxed-caps-plugin",
|
||||
"@appium/schema": "file:packages/schema",
|
||||
"@appium/support": "file:packages/support",
|
||||
"@appium/test-support": "file:packages/test-support",
|
||||
"@appium/types": "file:packages/types",
|
||||
"@appium/universal-xml-plugin": "file:packages/universal-xml-plugin",
|
||||
"appium": "file:packages/appium",
|
||||
"glob": "8.0.3"
|
||||
"appium-logger": "^2.0.0",
|
||||
"appium-support": "^2.0.4",
|
||||
"authorize-ios": "^1.0.3",
|
||||
"babel-runtime": "=5.8.24",
|
||||
"bluebird": "^2.10.2",
|
||||
"colors": "^1.1.2",
|
||||
"inquirer": "^0.10.1",
|
||||
"lodash": "^3.10.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"teen_process": "^1.3.1",
|
||||
"yargs": "^3.27.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "./node_modules/.bin/gulp prepublish",
|
||||
"test": "./node_modules/.bin/gulp once",
|
||||
"watch": "./node_modules/.bin/gulp"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@appium/fake-plugin": "1.3.1",
|
||||
"@babel/cli": "7.19.3",
|
||||
"@babel/core": "7.19.3",
|
||||
"@babel/preset-env": "7.19.4",
|
||||
"@babel/register": "7.18.9",
|
||||
"@colors/colors": "1.5.0",
|
||||
"@types/chai": "4.3.3",
|
||||
"@types/chai-as-promised": "7.1.5",
|
||||
"@types/mocha": "10.0.0",
|
||||
"@types/node": "16.11.64",
|
||||
"@types/semver": "7.3.12",
|
||||
"@types/sinon": "10.0.13",
|
||||
"@types/sinon-chai": "3.2.8",
|
||||
"@types/teen_process": "1.16.1",
|
||||
"@types/ws": "8.5.3",
|
||||
"asyncbox": "2.9.2",
|
||||
"babel-plugin-istanbul": "6.1.1",
|
||||
"babel-plugin-source-map-support": "2.2.0",
|
||||
"chai": "4.3.6",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"chai-webdriverio-async": "2.7.0",
|
||||
"eslint": "8.25.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-find-rules": "4.1.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"eslint-plugin-mocha": "10.1.0",
|
||||
"eslint-plugin-promise": "6.1.0",
|
||||
"fancy-log": "2.0.0",
|
||||
"finalhandler": "1.2.0",
|
||||
"get-port": "5.1.1",
|
||||
"gulp": "4.0.2",
|
||||
"handlebars": "4.7.7",
|
||||
"json-schema-to-typescript": "10.1.5",
|
||||
"lerna": "4.0.0",
|
||||
"lint-staged": "13.0.3",
|
||||
"log-symbols": "4.1.0",
|
||||
"midnight-smoker": "1.1.1",
|
||||
"mjpeg-consumer": "2.0.0",
|
||||
"mjpeg-server": "0.3.1",
|
||||
"mocha": "10.0.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"pre-commit": "1.2.2",
|
||||
"prettier": "2.7.1",
|
||||
"rewiremock": "3.14.3",
|
||||
"rimraf": "3.0.2",
|
||||
"serve-static": "1.15.0",
|
||||
"sinon": "14.0.1",
|
||||
"sinon-chai": "3.7.0",
|
||||
"sync-monorepo-packages": "0.3.5",
|
||||
"through2": "4.0.2",
|
||||
"typescript": "4.7.4",
|
||||
"validate.js": "0.13.1",
|
||||
"webdriverio": "7.25.1",
|
||||
"ws": "8.9.0",
|
||||
"yaml-js": "0.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=8"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
]
|
||||
"appium-gulp-plugins": "^1.3.11",
|
||||
"appium-test-support": "^0.0.5",
|
||||
"chai": "^3.3.0",
|
||||
"chai-as-promised": "^5.1.0",
|
||||
"gulp": "^3.9.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,445 +0,0 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [2.0.0-beta.46](https://github.com/appium/appium/compare/appium@2.0.0-beta.45...appium@2.0.0-beta.46) (2022-10-14)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.45](https://github.com/appium/appium/compare/appium@2.0.0-beta.44...appium@2.0.0-beta.45) (2022-10-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,support:** enable detection of local extensions for improved DX ([b186928](https://github.com/appium/appium/commit/b186928e60493e7603dc3b27725dad8ee20d3750))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.44](https://github.com/appium/appium/compare/appium@2.0.0-beta.43...appium@2.0.0-beta.44) (2022-09-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** do not throw ENAMETOOLONG on long cli arg ([cfdf898](https://github.com/appium/appium/commit/cfdf898e04e94032e3dd48b595caa4b6f0828289))
|
||||
* **appium:** eat update info errors ([7d7bb7a](https://github.com/appium/appium/commit/7d7bb7abc3173d29b843b3b238465d9914eaf091)), closes [#17357](https://github.com/appium/appium/issues/17357)
|
||||
|
||||
|
||||
### chore
|
||||
|
||||
* **appium:** remove test export ([6820f5e](https://github.com/appium/appium/commit/6820f5ec4e62fbb5e91ce739d8aadb7f7b7a7a74)), closes [#17398](https://github.com/appium/appium/issues/17398)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** Adjust NODE_PATH so NPM could properly resolve component peer dependencies ([#17325](https://github.com/appium/appium/issues/17325)) ([39d5cee](https://github.com/appium/appium/commit/39d5cee1b71f611e810900d3faed8e0fed6e1ce0))
|
||||
* **support:** Move module root detection utility into support package ([#17427](https://github.com/appium/appium/issues/17427)) ([5ab7829](https://github.com/appium/appium/commit/5ab78297e172bc6a5751c636f81b3b202fbe2743))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **appium:** This removes the `test` export from `appium`. `import * from 'appium/test'` is no longer supported.
|
||||
|
||||
Use `@appium/test-support`, `@appium/driver-test-support` or `@appium/plugin-test-support` instead.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.43](https://github.com/appium/appium/compare/appium@2.0.0-beta.42...appium@2.0.0-beta.43) (2022-08-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** fix busted config file normalization algorithm ([dc4835f](https://github.com/appium/appium/commit/dc4835f293f371c36873801a0060bb22eead2cc0))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,fake-driver,fake-plugin,test-support,types:** updateServer receives cliArgs param ([d4b9833](https://github.com/appium/appium/commit/d4b983328af21d1e5c27a91e438e7934eb152ab1)), closes [#17304](https://github.com/appium/appium/issues/17304)
|
||||
* **base-driver,fake-driver,appium:** add convenience methods for defining execute script overloads ([#17321](https://github.com/appium/appium/issues/17321)) ([337ec3e](https://github.com/appium/appium/commit/337ec3e7ba216dd6f8cdc88143ecaa4c75f5d266))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.42](https://github.com/appium/appium/compare/appium@2.0.0-beta.41...appium@2.0.0-beta.42) (2022-08-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium,base-driver,base-plugin,doctor,docutils,eslint-config-appium,execute-driver-plugin,fake-driver,fake-plugin,gulp-plugins,images-plugin,opencv,relaxed-caps-plugin,schema,support,test-support,types,universal-xml-plugin:** update engines ([d8d2382](https://github.com/appium/appium/commit/d8d2382327ba7b7db8a4d1cad987c0e60184c92d))
|
||||
* **appium:** add npm version check ([27ac2fa](https://github.com/appium/appium/commit/27ac2fa125bbfbe2e2ad5a3e7bf31d518510aa2d))
|
||||
* **appium:** partially revert 2a6a056187ce925d5776b7acc4954b10ecf9221b ([b7e905e](https://github.com/appium/appium/commit/b7e905eaf188f0f23f279620d8ce7dfba60f0b25))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** pass unknown args to extension scripts ([faff3ce](https://github.com/appium/appium/commit/faff3ce3471abaea24d2cb4c3e3b75b1af5ac3a1)), closes [#17250](https://github.com/appium/appium/issues/17250)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.41](https://github.com/appium/appium/compare/appium@2.0.0-beta.40...appium@2.0.0-beta.41) (2022-07-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium,support:** fix installation problems ([2a6a056](https://github.com/appium/appium/commit/2a6a056187ce925d5776b7acc4954b10ecf9221b)), closes [#17073](https://github.com/appium/appium/issues/17073)
|
||||
* **appium,types:** include @appium/types in appium ([a0a6166](https://github.com/appium/appium/commit/a0a6166738f3db32f2512681914c4c5410cd4b28))
|
||||
* **appium:** fix incorrect count of errors and warnings ([1e42c23](https://github.com/appium/appium/commit/1e42c2378cb762d5f327139c027e2071918b5c17))
|
||||
* **appium:** postinstall: never assume local appium if it is being installed globally ([965752f](https://github.com/appium/appium/commit/965752f288ba5d74ab24f41d780c46cc8ff14984)), closes [#17054](https://github.com/appium/appium/issues/17054)
|
||||
* **appium:** remove references to js in typescript code ([d3f90d5](https://github.com/appium/appium/commit/d3f90d5ed6e887feffcabfc8aabd012e43c37e63))
|
||||
* moved type packages to deps of specific packages ([f9129df](https://github.com/appium/appium/commit/f9129dfee32fcc3f89ffcfa69fb83b7c2419c24f))
|
||||
* Update the way build info is fetched from GitHub ([#17078](https://github.com/appium/appium/issues/17078)) ([d2a3adc](https://github.com/appium/appium/commit/d2a3adc2e361d5f0cff11094e8884e3270f5c94c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,base-driver,base-plugin,test-support,types:** move test fixtures into test-support ([70d88cb](https://github.com/appium/appium/commit/70d88cb86f28354efe313cc6be6a0afef20b38b3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.40](https://github.com/appium/appium/compare/appium@2.0.0-beta.39...appium@2.0.0-beta.40) (2022-06-04)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.39](https://github.com/appium/appium/compare/appium@2.0.0-beta.38...appium@2.0.0-beta.39) (2022-06-03)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.38](https://github.com/appium/appium/compare/appium@2.0.0-beta.37...appium@2.0.0-beta.38) (2022-06-01)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.37](https://github.com/appium/appium/compare/appium@2.0.0-beta.36...appium@2.0.0-beta.37) (2022-05-31)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.36](https://github.com/appium/appium/compare/appium@2.0.0-beta.35...appium@2.0.0-beta.36) (2022-05-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** fix extension autoinstall postinstall script ([3e2c05d](https://github.com/appium/appium/commit/3e2c05d8a290072484afde34fe5fd968618f6359)), closes [#16924](https://github.com/appium/appium/issues/16924)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium,support:** extension check improvements ([6b224f5](https://github.com/appium/appium/commit/6b224f545f44b8e6ad9d587c7157bc67d7d11439))
|
||||
* **appium:** appium now expects extensions to use peer dependencies ([48f1d99](https://github.com/appium/appium/commit/48f1d990871dbcd4ab3042c19dc4f43ca89bf80f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.35](https://github.com/appium/appium/compare/appium@2.0.0-beta.34...appium@2.0.0-beta.35) (2022-05-03)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.34](https://github.com/appium/appium/compare/appium@2.0.0-beta.33...appium@2.0.0-beta.34) (2022-05-02)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.33](https://github.com/appium/appium/compare/appium@2.0.0-beta.32...appium@2.0.0-beta.33) (2022-04-20)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.32](https://github.com/appium/appium/compare/appium@2.0.0-beta.31...appium@2.0.0-beta.32) (2022-04-20)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.31](https://github.com/appium/appium/compare/appium@2.0.0-beta.30...appium@2.0.0-beta.31) (2022-04-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium,types:** avoid call to assignServer() ([cd08daf](https://github.com/appium/appium/commit/cd08dafabcc16e718a5bdc6b96d5a7bcbfe6e1be))
|
||||
* **appium:** fix some argument-related types ([37cb3bd](https://github.com/appium/appium/commit/37cb3bd80c76f003940e680b7925b5c3bdc5144c))
|
||||
* **appium:** make types actually consumable ([8b814c9](https://github.com/appium/appium/commit/8b814c9243a7b51ecd0bc619146063aa5b0ccb76))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.30](https://github.com/appium/appium/compare/appium@2.0.0-beta.29...appium@2.0.0-beta.30) (2022-04-12)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.29](https://github.com/appium/appium/compare/appium@2.0.0-beta.28...appium@2.0.0-beta.29) (2022-04-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Properly detect if a command is a session command ([#16737](https://github.com/appium/appium/issues/16737)) ([f8a5144](https://github.com/appium/appium/commit/f8a51443e490d9a373778499bfc440e8464ca2ed))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/appium/appium/compare/appium@2.0.0-beta.27...appium@2.0.0-beta.28) (2022-04-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** allow multiple drivers to be installed ([0bbec13](https://github.com/appium/appium/commit/0bbec13d1e386b2fdf3f9cdcb43da78d6834f28f)), closes [#16674](https://github.com/appium/appium/issues/16674)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** generate declaration files ([#16597](https://github.com/appium/appium/issues/16597)) ([06a6054](https://github.com/appium/appium/commit/06a605420d761a830be267f0f96e12f4caa2c534))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.27](https://github.com/appium/appium/compare/appium@2.0.0-beta.26...appium@2.0.0-beta.27) (2022-03-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **base-driver:** Use WeakRef to reference the driver instance in the log prefix generator ([#16636](https://github.com/appium/appium/issues/16636)) ([bbfc7ef](https://github.com/appium/appium/commit/bbfc7ef51d8a5c7e99072ee599ce2a6265017ea4))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.26](https://github.com/appium/appium/compare/appium@2.0.0-beta.25...appium@2.0.0-beta.26) (2022-03-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** Increase the default limit of process listeners ([#16471](https://github.com/appium/appium/issues/16471)) ([a8315f3](https://github.com/appium/appium/commit/a8315f3f87862b3deeae90b4e21b133e9e3e78d5))
|
||||
* **appium:** make sure logsink init happens first since it patches npmlog globally (fix [#16519](https://github.com/appium/appium/issues/16519)) ([5abf852](https://github.com/appium/appium/commit/5abf85204614b47d2363097a5356f4bddf697352))
|
||||
* **appium:** remove bad log ([1dbeee2](https://github.com/appium/appium/commit/1dbeee200677a9c0452bb8c24d78da1e2b5e181c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** allow installation of extensions via `npm` ([d89fb9b](https://github.com/appium/appium/commit/d89fb9b354b274f2ba410527d25d73af6743d76c))
|
||||
* **support:** move npm module into support ([2fbd49f](https://github.com/appium/appium/commit/2fbd49fed4cdf10fe1f4b374b5b44ae327ab3f85))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.25](https://github.com/appium/appium/compare/appium@2.0.0-beta.24...appium@2.0.0-beta.25) (2022-01-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** make show-config more right ([7470ed0](https://github.com/appium/appium/commit/7470ed00b2a8a8ebc39d62184a6ba5819b22f264)), closes [#16340](https://github.com/appium/appium/issues/16340)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.24](https://github.com/appium/appium/compare/appium@2.0.0-beta.23...appium@2.0.0-beta.24) (2022-01-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** correctly apply extension defaults ([20d95e4](https://github.com/appium/appium/commit/20d95e45313fc6aac30a2cf7b8f7bef156a17851))
|
||||
* **appium:** disallow unsupported schemas ([e074fee](https://github.com/appium/appium/commit/e074fee89f90a654407d01d3f3aea6b839bbf24f))
|
||||
* **appium:** fix behavior of ReadonlyMap to be compatible with Map ([88e351f](https://github.com/appium/appium/commit/88e351fc2da682bb4c8607259e001ed7e0f5d964))
|
||||
* **appium:** fix incorrect handling of delete session with regard to plugin driver assignment ([7b3893a](https://github.com/appium/appium/commit/7b3893a36202018de7c2124c2028bfbbd8a9d7fd))
|
||||
* **appium:** make object dumps less weird ([74a5911](https://github.com/appium/appium/commit/74a5911515f6c50f71fe6f18ddaa4f4fd2ed6d43))
|
||||
* Switch colors package to a non-compomised repository ([#16317](https://github.com/appium/appium/issues/16317)) ([40a6f05](https://github.com/appium/appium/commit/40a6f054dca3d94fc88773af9c6336ba12ebfb81))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** add --show-config ([#16207](https://github.com/appium/appium/issues/16207)) ([af96879](https://github.com/appium/appium/commit/af96879cfdbbe40773182c29a49fbf2f3cf7e233)), closes [#15672](https://github.com/appium/appium/issues/15672)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.23](https://github.com/appium/appium/compare/appium@2.0.0-beta.22...appium@2.0.0-beta.23) (2021-11-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** make server host/port information available to drivers and thereby plugins ([221a3ec](https://github.com/appium/appium/commit/221a3ecd5211fadcd375fe6d6c9df11f1af201a2))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.22](https://github.com/appium/appium/compare/appium@2.0.0-beta.21...appium@2.0.0-beta.22) (2021-11-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** create cjs wrapper ([24596d6](https://github.com/appium/appium/commit/24596d67b04590acb568322098c88efc190f6318))
|
||||
* **appium:** enable --relaxed-security ([46a2041](https://github.com/appium/appium/commit/46a2041fbdc80b6210d0214a4d9fb71312d57e1b)), closes [/github.com/appium/appium/discussions/16103#discussioncomment-1655985](https://github.com//github.com/appium/appium/discussions/16103/issues/discussioncomment-1655985)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** support for deprecated arguments ([aa69388](https://github.com/appium/appium/commit/aa69388c7a296d4d1e39a1ba0fbe23035a5ae8c5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.21](https://github.com/appium/appium/compare/appium@2.0.0-beta.20...appium@2.0.0-beta.21) (2021-11-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** resolve-from is a dependency ([5443b57](https://github.com/appium/appium/commit/5443b570adf41042c4735410b1425d248adfd0a9))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.20](https://github.com/appium/appium/compare/appium@2.0.0-beta.19...appium@2.0.0-beta.20) (2021-11-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** add missing support for schema-as-object ([e951010](https://github.com/appium/appium/commit/e951010055118f6be1614abe40f5701daacb441c))
|
||||
* **appium:** add types for parsed argument object ([95dfe24](https://github.com/appium/appium/commit/95dfe24176bb7ff6957b7942164280a3a2fbd155))
|
||||
* **appium:** avoid deprecation warning from argparse ([fc56662](https://github.com/appium/appium/commit/fc566628f599e8a529f30344d291f2351665c5f7))
|
||||
* **appium:** bad type name ([a7fa66b](https://github.com/appium/appium/commit/a7fa66bb7dfb321cf2bf7c90e5e739841a8753e9))
|
||||
* **appium:** fix interaction of plugins with proxying ([7091008](https://github.com/appium/appium/commit/70910087d11100fe47627754ade379a2d3a7ff5d))
|
||||
* **appium:** if a sessionless plugin is used for createSession, promote it to a session plugin ([3f1bb4c](https://github.com/appium/appium/commit/3f1bb4c9c38046699e6d8be3dcd257bc53345eb9))
|
||||
* **appium:** properly validates config files containing extension config ([b7c230c](https://github.com/appium/appium/commit/b7c230c1e9da9206ea050387bc72c5dda3b31620))
|
||||
* **appium:** remove extra logging from config-file ([7381a13](https://github.com/appium/appium/commit/7381a13da3e76f7051639d3ab2ba376fbb625e80))
|
||||
* **appium:** restore missing call to validate extensions ([1a860ca](https://github.com/appium/appium/commit/1a860cade2fd3eac151c81c4efcd11364ee35479))
|
||||
* **appium:** stop calling plugins 'sessionless' since the name is immutable ([ead3e07](https://github.com/appium/appium/commit/ead3e0723f912a2c7e825d397fe2d4272ce3d6d0))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** allow plugins to react to unexpected session shutdowns ([fff6b2e](https://github.com/appium/appium/commit/fff6b2eb004166fc147251c513086b72be857fbd))
|
||||
* **appium:** configuration file and schema support ([d52c36e](https://github.com/appium/appium/commit/d52c36e1eaaccc8b47de514bdeeef55ac348ecb8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.19](https://github.com/appium/appium/compare/appium@2.0.0-beta.18...appium@2.0.0-beta.19) (2021-11-09)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.18](https://github.com/appium/appium/compare/appium@2.0.0-beta.17...appium@2.0.0-beta.18) (2021-09-16)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.17](https://github.com/appium/appium/compare/appium@2.0.0-beta.16...appium@2.0.0-beta.17) (2021-09-16)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.16](https://github.com/appium/appium/compare/appium@2.0.0-beta.15...appium@2.0.0-beta.16) (2021-09-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** add env var to trigger reloading of extensions ([ff3bb4f](https://github.com/appium/appium/commit/ff3bb4f4b538ee5136fdc6356ca00e09fcdc5533))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.15](https://github.com/appium/appium/compare/appium@2.0.0-beta.14...appium@2.0.0-beta.15) (2021-09-14)
|
||||
|
||||
**Note:** Version bump only for package appium
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.14](https://github.com/appium/appium/compare/appium@2.0.0-beta.13...appium@2.0.0-beta.14) (2021-09-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **appium:** support plugin-specific args via --plugin-args ([c8f12d1](https://github.com/appium/appium/commit/c8f12d1e95b84e225def500a05fddf440df8991a))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.13](https://github.com/appium/appium/compare/appium@2.0.0-beta.12...appium@2.0.0-beta.13) (2021-08-16)
|
||||
|
||||
|
||||
|
||||
# 2.0.0-beta (2021-08-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **appium:** load plugins before main server to allow plugin monkeypatching ([#15441](https://github.com/appium/appium/issues/15441)) ([52f4fc6](https://github.com/appium/appium/commit/52f4fc6a2cbdb612888ab2a23a704be32594a006))
|
||||
* **appium:** update references to @appium/support ([9295d0c](https://github.com/appium/appium/commit/9295d0c68284443ecd73add1f8fe0ff7910a7d7d))
|
||||
* **appium:** use proper base driver package & random ports ([e14d4fb](https://github.com/appium/appium/commit/e14d4fbd0fce16f208569b0cb9149b6307f78a5f))
|
||||
* **appium:** when updating extensions, make sure to actually remove the previous one first to avoid npm reinstall issues ([4839419](https://github.com/appium/appium/commit/483941974881bf2ad362c6e6cc35883743abcd2a))
|
||||
* **appium:** when updating extensions, package fields should also be updated in extensions.yaml ([756688b](https://github.com/appium/appium/commit/756688bddb624a6e9a5b5b6403db76eac65774f3))
|
||||
* do not assume git root and package.json have the same parent dir ([3c5fba7](https://github.com/appium/appium/commit/3c5fba7b38e02f4216d3a26340948d070f7ea9d9))
|
||||
* doc generation ([9e33c7a](https://github.com/appium/appium/commit/9e33c7ac1135306c6f0d1ff83b8076aecb54c554))
|
||||
* e2e-tests ([2499b49](https://github.com/appium/appium/commit/2499b49936660280eefaeb26cb3e4e9f82e36c20))
|
||||
* use random test port ([935b1f8](https://github.com/appium/appium/commit/935b1f80a47e89ccdf81781f35be5123bf8673d5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add "run" command to the client interface in order to allow running driver-defined scripts ([#15356](https://github.com/appium/appium/issues/15356)) ([a265476](https://github.com/appium/appium/commit/a2654762b6a9156380bcdf53df4cb0a8deb061fa))
|
||||
* **appium:** Add driver and plugin server arg injection feature ([#15388](https://github.com/appium/appium/issues/15388)) ([d3c11e3](https://github.com/appium/appium/commit/d3c11e364dffff87ac38ac8dc3ad65a1e4534a9a))
|
||||
@@ -1,120 +0,0 @@
|
||||
## Appium
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://github.com/appium/appium/actions/workflows/node.js.yml)
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
|
||||
|
||||
Appium is an open-source, cross-platform test automation tool for native,
|
||||
hybrid, and mobile web and desktop apps. We support simulators (iOS), emulators
|
||||
(Android), and real devices (iOS, Android, Windows, Mac).
|
||||
|
||||
Want to skip straight to the action? Check out our [getting
|
||||
started](/docs/en/about-appium/getting-started.md) doc.
|
||||
|
||||
### Supported Platforms
|
||||
|
||||
Appium supports app automation across a variety of platforms, like iOS,
|
||||
Android, and Windows. Each platform is supported by one or more "drivers",
|
||||
which know how to automate that particular platform. Choose a driver below for
|
||||
specific information about how that driver works and how to set it up:
|
||||
|
||||
* iOS
|
||||
* The [XCUITest Driver](/docs/en/drivers/ios-xcuitest.md)
|
||||
* (DEPRECATED) The [UIAutomation Driver](/docs/en/drivers/ios-uiautomation.md)
|
||||
* Android
|
||||
* The [Espresso Driver](/docs/en/drivers/android-espresso.md)
|
||||
* The [UiAutomator2 Driver](/docs/en/drivers/android-uiautomator2.md)
|
||||
* (DEPRECATED) The [UiAutomator Driver](/docs/en/drivers/android-uiautomator.md)
|
||||
* The [Windows Driver](/docs/en/drivers/windows.md) (for Windows Desktop apps)
|
||||
* The [Mac Driver](/docs/en/drivers/mac.md) (for Mac Desktop apps)
|
||||
|
||||
### Why Appium?
|
||||
|
||||
1. You don't have to recompile your app or modify it in any way, due
|
||||
to the use of standard automation APIs on all platforms.
|
||||
2. You can write tests with your favorite dev tools using any
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html)-compatible
|
||||
language such as Java, Objective-C, JavaScript (Node), PHP, Python, Ruby,
|
||||
C#, Clojure, or Perl with the Selenium WebDriver API and [language-specific
|
||||
client libraries](/docs/en/about-appium/appium-clients.md).
|
||||
3. You can use any testing framework.
|
||||
4. Appium has built-in mobile web and hybrid app support. Within the same
|
||||
script, you can switch seamlessly between native app automation and webview
|
||||
automation, all using the WebDriver model that's already the standard for
|
||||
web automation.
|
||||
|
||||
Investing in the
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means
|
||||
you are betting on a single, free, and open protocol for testing that has become
|
||||
a web standard. Don't lock yourself into a proprietary stack.
|
||||
|
||||
For example, if you use Apple's XCUITest library without Appium you can only
|
||||
write tests using Obj-C/Swift, and you can only run tests through Xcode.
|
||||
Similarly, with Google's UiAutomator or Espresso, you can only write tests in
|
||||
Java/Kotlin. Appium opens up the possibility of true cross-platform native app
|
||||
automation, for mobile and beyond. Finally!
|
||||
|
||||
If you're new to Appium or want a more comprehensive description of what this is all
|
||||
about, please read our [Introduction to Appium
|
||||
Concepts](/docs/en/about-appium/intro.md).
|
||||
|
||||
### Requirements
|
||||
|
||||
Your environment needs to be set up for the particular platforms that you want
|
||||
to run tests on. Each of the drivers above documents the requirements for their
|
||||
particular brand of automation. At a minimum, you will need to be able to run
|
||||
Node.js 10+.
|
||||
|
||||
### Get Started
|
||||
|
||||
Check out our [Getting Started](/docs/en/about-appium/getting-started.md) guide
|
||||
to get going with Appium.
|
||||
|
||||
There is also a sample code that contains [many examples of tests in a variety
|
||||
of different languages](https://github.com/appium/appium/tree/master/sample-code)!
|
||||
|
||||
### Documentation
|
||||
|
||||
For prettily-rendered docs, please visit [appium.io](http://appium.io). You can
|
||||
always find the full list of Appium doc pages at [Appium's GitHub
|
||||
Repo](https://github.com/appium/appium/tree/master/docs/en/) as well.
|
||||
|
||||
[update-appium-io.yml](https://github.com/appium/appium/blob/master/ci-jobs/update-appium-io.yml) creates a PR
|
||||
by [CI job](https://dev.azure.com/AppiumCI/Appium%20CI/_build?definitionId=37).
|
||||
in the appium.io repository with the documentation update.
|
||||
|
||||
Once the PR has been merged, the latest documentation will be in [appium.io](http://appium.io)
|
||||
|
||||
### Contributing
|
||||
|
||||
Please take a look at our [contribution documentation](CONTRIBUTING.md)
|
||||
for instructions on how to build, test, and run Appium from the source.
|
||||
|
||||
### Roadmap
|
||||
|
||||
Interested in where Appium is heading in the future? Check out the [Roadmap](ROADMAP.md)
|
||||
|
||||
### Project History, Credits & Inspiration
|
||||
|
||||
* [History](http://appium.io/history)
|
||||
* [Credits](/docs/en/contributing-to-appium/credits.md)
|
||||
|
||||
### User Forums
|
||||
|
||||
Announcements and debates often take place on the [Discussion
|
||||
Group](https://discuss.appium.io), be sure to sign up!
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
We put together a [troubleshooting
|
||||
guide](/docs/en/writing-running-appium/other/troubleshooting.md). Please have a look
|
||||
here first if you run into any problems. It contains instructions for checking
|
||||
a lot of common errors and how to get in touch with the community if you're
|
||||
stumped.
|
||||
|
||||
### License
|
||||
|
||||
[](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 - 2022 OpenJS Foundation
|
||||
|
||||
theme:
|
||||
logo: assets/images/appium-logo-white.png
|
||||
favicon: assets/images/appium-logo.png
|
||||
features:
|
||||
- navigation.sections
|
||||
|
||||
extra_css:
|
||||
- assets/stylesheets/extra.css
|
||||
|
||||
extra:
|
||||
homepage: /
|
||||
version:
|
||||
provider: mike
|
||||
social:
|
||||
- icon: fontawesome/brands/twitter
|
||||
link: https://twitter.com/AppiumDevs
|
||||
alternate:
|
||||
- name: English
|
||||
link: /docs/en/
|
||||
lang: en
|
||||
- name: 日本
|
||||
link: /docs/ja/
|
||||
lang: ja
|
||||
- name: 中文简体
|
||||
link: /docs/zh/
|
||||
lang: zh
|
||||
@@ -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<string>|||
|
||||
|`--log-level`|Log level (console[:file]) (Value must be one of: `info`, `info:debug`, `info:info`, `info:warn`, `info:error`, `warn`, `warn:debug`, `warn:info`, `warn:warn`, `warn:error`, `error`, `error:debug`, `error:info`, `error:warn`, `error:error`, `debug`, `debug:debug`, `debug:info`, `debug:warn`, `debug:error`)|string|`debug`||
|
||||
|`--log-no-colors`|Do not use color in console output|boolean|`false`||
|
||||
|`--log-timestamp`|Show timestamps in console output|boolean|`false`||
|
||||
|`--long-stacktrace`|Add long stack traces to log entries. Recommended for debugging only.|boolean|`false`||
|
||||
|`--no-perms-check`|Do not check that needed files are readable and/or writable|boolean|`false`||
|
||||
|`--nodeconfig`|Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself|object|||
|
||||
|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object|||
|
||||
|`--port`|Port to listen on (Value must be between `1` and `65535`)|integer|`4723`|`-p`|
|
||||
|`--relaxed-security`|Disable additional security checks, so it is possible to use some advanced features, provided by drivers supporting this option. Only enable it if all the clients are in the trusted network and it's not the case if a client could potentially break out of the session sandbox. Specific features can be overridden by using "deny-insecure"|boolean|`false`||
|
||||
|`--session-override`|Enables session override (clobbering)|boolean|`false`||
|
||||
|`--strict-caps`|Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device|boolean|`false`||
|
||||
|`--tmp`|Absolute path to directory Appium can use to manage temp files. Defaults to C:\Windows\Temp on Windows and /tmp otherwise.|string|||
|
||||
|`--trace-dir`|Absolute path to directory Appium can use to save iOS instrument traces; defaults to <tmp>/appium-instruments|string|||
|
||||
|`--use-drivers`|A list of drivers to activate. By default, all installed drivers will be activated.|array<string>|`[]`||
|
||||
|`--use-plugins`|A list of plugins to activate. To activate all plugins, the value should be an array with a single item "all".|array<string>|`[]`||
|
||||
|`--webhook`|Also send log output to this http listener|string||`-G`|
|
||||
<!-- AUTOGEN-STOP -->
|
||||
@@ -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,5 +0,0 @@
|
||||
---
|
||||
title: CLI Intro
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,451 +0,0 @@
|
||||
---
|
||||
title: Appium's Config System
|
||||
---
|
||||
|
||||
Appium 2 supports [configuration files](../guides/config.md). A configuration file is intended to
|
||||
have (nearly) 1:1 parity with command-line arguments. An end user can supply Appium 2 with
|
||||
a configuration file, CLI args, or both (the args have precedence over the config file).
|
||||
|
||||
This document will be a technical overview of how the configuration system works. It is intended
|
||||
for Appium contributors, but will also explain the system's fundamental features.
|
||||
|
||||
## Reading a Config File
|
||||
|
||||
A config file is a JSON, JavaScript, or YAML file which can be validated against a schema. By
|
||||
default, this file will be named `.appiumrc.{json,js,yaml,yml}` and should be in the root of the
|
||||
project which depends upon `appium`. Other filenames and locations are supported via the `--config
|
||||
<file>` flag. For obvious reasons, the `config` argument is disallowed within config files.
|
||||
|
||||
In lieu of a separate file, configuration can be embedded in a project's `package.json` using the
|
||||
`appiumConfig` property, e.g.,:
|
||||
|
||||
```json
|
||||
{
|
||||
"appiumConfig": {
|
||||
"server": {
|
||||
"port": 12345
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`
|
||||
will call into `lib/config-file.js` to load and/or search for a configuration file and in
|
||||
`package.json`.
|
||||
|
||||
!!! note
|
||||
|
||||
It is not an error if configuration isn't found!
|
||||
|
||||
The [`lilconfig`](https://npm.im/lilconfig) package provides the search & load functionality; refer
|
||||
to its documentation for more information about the search paths. Additionally, Appium provides
|
||||
support for config files written in YAML via the package [`yaml`](https://npm.im/yaml).
|
||||
|
||||
If a config file is found and successfully [validated](#validation), the result will be merged with
|
||||
a set of defaults and any additionall CLI arguments. CLI arguments have precedence over config
|
||||
files, and config files have precedence over defaults.
|
||||
|
||||
## Validation
|
||||
|
||||
The same system is used for _both_ validation of config files _and_ command-line arguments.
|
||||
|
||||
The package [`ajv`](https://npm.im/ajv) provides validation. Of course, to make `ajv` validate
|
||||
anything, it must be provided a _schema_.
|
||||
|
||||
The _base_ schema is a [JSON Schema
|
||||
Draft-7](https://json-schema.org/draft/2020-12/json-schema-core.html)-compliant object exported by
|
||||
`lib/schema/appium-config-schema.js`. This schema defines configuration _native to Appium_, and
|
||||
only concerns its behavior as a _server_; it does not define configuration for any other
|
||||
functionality (e.g., the `plugin` or `driver` subcommands).
|
||||
|
||||
!!! warning
|
||||
|
||||
Note that this file is the _base_ schema; this will become painfully relevant.
|
||||
|
||||
This file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is
|
||||
especially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files.
|
||||
|
||||
It is more straightforward to explain how config files are validated, so we'll start there.
|
||||
|
||||
### Validating Config Files
|
||||
|
||||
When a config file is found (`lib/config-file.js`), it will call the `validate` function exported
|
||||
from `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to
|
||||
validate the data against the schema that Appium has provided it.
|
||||
|
||||
If the config file is invalid, errors will be generated to be displayed to the user. Finally, the
|
||||
`init` function will detect these errors, display them, and the process will exit.
|
||||
|
||||
I hope that made sense, because this is the easy part.
|
||||
|
||||
### Validating CLI Arguments
|
||||
|
||||
As mentioned earlier, the same system is used for validating both config files and CLI arguments.
|
||||
|
||||
Totally not judging, but Appium uses [`argparse`](https://npm.im/argparse) for its CLI argument
|
||||
parsing. This package, and others like it, provides an API to define the arguments a command-line
|
||||
Node.js script accepts, and will ultimately return an object representation of the user-supplied
|
||||
arguments.
|
||||
|
||||
Just as the schema defines what's allowed in a config file, it also defines what's allowed on the
|
||||
command-line.
|
||||
|
||||
#### Defining CLI Arguments via Schema
|
||||
|
||||
CLI arguments must be _defined_ before their values can be validated.
|
||||
|
||||
A JSON schema isn't a natural fit for defining CLI args--it needs some grease to make it work--but
|
||||
it's close enough that we can do so with an adapter and some custom metadata.
|
||||
|
||||
In `lib/cli/parser.js`, there's a wrapper around `argparse`'s `ArgumentParser`; it's called (wait
|
||||
for it)... `ArgParser`. The wrapper exists because we're doing some custom things with `argparse`,
|
||||
but is has nothing to do with the schema directly.
|
||||
|
||||
An `ArgParser` instance is created and its `parseArgs()` method is called with the raw CLI
|
||||
arguments. The definition of the accepted arguments comes from `lib/cli/args.js` in part--here, all
|
||||
of the arguments _not_ intended for use with the `server` subcommand are hard-coded (e.g., the
|
||||
`driver` subcommand and _its_ subcommands). `args.js` also contains a function `getServerArgs()`,
|
||||
which in turn calls into `toParserArgs` in `lib/schema/cli-args.js`. `lib/schema/cli-args.js` can
|
||||
be considered the "adapter" layer between `argparse` and the schema.
|
||||
|
||||
`toParserArgs` uses the `flattenSchema` function exported by `lib/schema/schema.js`, which
|
||||
"squashes" the schema into a key/value representation. Then, `toParserArgs` iterates over each
|
||||
key/value pair and "converts" it into a suitable `ArgumentOption` object for final handoff to
|
||||
`ArgParser`.
|
||||
|
||||
This adapter (`cli-args.js`) is where most of the mess is hidden; let's explore this rat's nest
|
||||
a bit further.
|
||||
|
||||
##### CLI & Schema Incongruities
|
||||
|
||||
The conversion algorithm (see function `subSchemaToArgDef` in `lib/schema/cli-args.js`) is mostly
|
||||
just hacks and special cases neatly packed into a function. Things that don't cleanly map from
|
||||
`argparse` to a JSON schema include, but are not limited to:
|
||||
|
||||
- A schema cannot natively express "store the value of `--foo=<value>` in a property called `bar`" in a schema (this corresponds to the `ArgumentOption['dest']` prop).
|
||||
- A schema cannot natively express aliases; e.g., `--verbose` can also be `-v`
|
||||
- A schema `enum` is not restricted to multiple types, but `argparse`'s equivalent `ArgumentOption['choices']` prop _is_
|
||||
- A schema does not know about `argparse`'s concept of "actions" (note that Appium is not currently using custom actions--though it did, and it could again).
|
||||
- `argparse` has no native type for `email`, `hostname`, `ipv4`, `uri` etc., and the schema does
|
||||
- Schema validation only _validates_, it does not perform translation, transformation, or coercion (mostly). `argparse` allows this.
|
||||
- Schemas allow the `null` type, for whatever reason. Ever pass `null` on the CLI?
|
||||
- `argparse` does not understand anything other than primitives; no objects, arrays, etc., and certainly not arrays of a particular type.
|
||||
|
||||
All of the above cases and others are handled by the adapter.
|
||||
|
||||
!!! warning
|
||||
|
||||
Some decisions made in the adapter were arrived at via coin toss. If you are curious about why
|
||||
something is the way it is, it's likely that it had to do _something_.
|
||||
|
||||
Let's look more closely at handling types.
|
||||
|
||||
#### Argument Types via `ajv`
|
||||
|
||||
While `argparse` allows consumers, via its API, to define the _type_ of various arguments (e.g.,
|
||||
a string, number, boolean flag, etc.), Appium mostly avoids these built-in types. _Why is that?_
|
||||
Well:
|
||||
|
||||
1. We already know the type of an argument, because we've defined it in a schema.
|
||||
2. `ajv` provides validation against a schema.
|
||||
3. A schema allows for greater expression of types, allowed values, etc., than `argparse` can provide natively.
|
||||
4. The expressiveness of a schema allows for better error messaging.
|
||||
|
||||
To that end, the adapter eschews `argparse`'s built-in types (see allowed string values of
|
||||
`ArgumentOption['type']`) and instead abuses the ability to provide a _function_ as a `type`. The
|
||||
exception is _boolean_ flags, which do not have a `type`, but rather `action: 'store_true'`. The
|
||||
world may never know why.
|
||||
|
||||
##### Types as Functions
|
||||
|
||||
When a `type` is a function, the function performs both validation _and_ coercion (if necessary).
|
||||
So what are these functions?
|
||||
|
||||
> Note: `type` is _omitted_ (and thus _not_ a function) from the `ArgumentOption` if the property
|
||||
> type is `boolean`, and is instead provided an `action` property of `store_true`. Yes, this is
|
||||
> weird. No, I don't know why.
|
||||
|
||||
Well... it depends upon the schema. But generally speaking, we create a _pipeline_ of functions,
|
||||
each corresponding to a keyword in the schema. Let's take the example of the `port` argument. In
|
||||
lieu of asking the OS which ports the `appium`-running user can bind to, this argument is expected
|
||||
to be an integer between 1 and 65535. This turns out to be two functions which we combine into
|
||||
a pipeline:
|
||||
|
||||
1. Convert the value to an integer, if possible. Because _every value in `process.argv` is a string_, we must coerce if we want a number.
|
||||
2. Use `ajv` to validate the integer against the schema for `port`. A schema lets us define a range via the `minimum` and `maximum` keywords. Read more about how this works in
|
||||
|
||||
Much like the config file validation, if errors are detected, Appium nicely tells the end-user and
|
||||
the process exits w/ some help text.
|
||||
|
||||
For other arguments which are naturally of non-primitive types, things are not so straightforward.
|
||||
|
||||
##### Transformers
|
||||
|
||||
Remember how `argparse` doesn't understand arrays? What if the most ergonomic way to express
|
||||
a value is, in fact, an array?
|
||||
|
||||
Well, Appium can't accept an array on the CLI, even though it can accept one in the config file.
|
||||
But Appium _can_ accept a comma-delimited string (a CSV "line"). Or a string filepath referring to
|
||||
a file which _contains_ a delimited list. Either way: by the time the value gets out of the
|
||||
argument parser, it should be an array.
|
||||
|
||||
And as mentioned above, the native facilities of a JSON schema cannot express this. However, it's
|
||||
possible to define a _custom keyword_ which Appium can then detect and handle accordingly. So
|
||||
that's what Appium does.
|
||||
|
||||
In this case, a custom keyword `appiumCliTransformer` is registered with `ajv`. The value of
|
||||
`appiumCliTransformer` (at the time of this writing) can be `csv` or `json`. In the base schema
|
||||
file, `appium-config-schema.js`, Appium uses `appiumCliTransformer: 'csv'` if this behavior is
|
||||
desired.
|
||||
|
||||
!!! note
|
||||
|
||||
Any property defined in the schema having type `array` will _automatically_ uses the `csv`
|
||||
transformer. Likewise, a property having type `object` will use the `json` transformer. It's
|
||||
conceivable that `array` may want to use the `json` transformer, but otherwise, the presence of
|
||||
the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not stricly
|
||||
necessary.
|
||||
|
||||
The adapter (remember the adapter?) creates a pipeline function including a special "CSV
|
||||
transformer" (transformers are defined in `lib/schema/cli-transformers.js`), and uses this function
|
||||
as the `type` property of the `ArgumentOption` passed into `argparse`. In this case, the `type:
|
||||
'array'` in the schema is ignored.
|
||||
|
||||
!!! note
|
||||
|
||||
The config file doesn't _need_ to perform any complex transformation of values, because it
|
||||
naturally allows Appium to define exactly what it expects. So Appium does no post-processing of
|
||||
config file values.
|
||||
|
||||
Properties that do not need this special treatment use `ajv` directly for validation. How this
|
||||
works requires some explanation, so that's next.
|
||||
|
||||
#### Validation of Individual Arguments via `ajv`
|
||||
|
||||
When we think of a JSON schema, we tend to think, "I have this JSON file and I want to validate it
|
||||
against the schema". That's valid, and in fact Appium does just that with config files! However,
|
||||
Appium does not do this when validating arguments.
|
||||
|
||||
!!! note
|
||||
|
||||
During implementation, I was tempted to mash all of the arguments together into
|
||||
a config-file-like data structure and then validate it all at once. I think that would have
|
||||
been _possible_, but since an object full of CLI arguments is a flat key/value structure and
|
||||
the schema is not, this seemed like trouble.
|
||||
|
||||
Instead, Appium validates a value against a specific property _within_ the schema. To do this, it
|
||||
maintains a mapping between a CLI argument definition and its corresponding property. The mapping
|
||||
itself is a `Map` with a unique identifier for the argument as the key, and an `ArgSpec`
|
||||
(`lib/schema/arg-spec.js`) object as the value.
|
||||
|
||||
An `ArgSpec` object stores the following metadata:
|
||||
|
||||
| Property Name | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------- |
|
||||
| `name` | Canonical name of the argument, corresponding to the property name in the schema. |
|
||||
| `extType?` | `driver` or `plugin`, if appropriate |
|
||||
| `extName?` | Extension name, if appropriate |
|
||||
| `ref` | Computed `$id` of the property in the schema |
|
||||
| `arg` | Argument as accepted on CLI, without leading dashes |
|
||||
| `dest` | Property name in parsed arguments object (as returned by `argparse`'s `parse_args()`) |
|
||||
| `defaultValue?` | Value of the `default` keyword in schema, if appropriate |
|
||||
|
||||
When a schema is [finalized](#schema-finalization), the `Map` is populated with `ArgSpec` objects
|
||||
for all known arguments.
|
||||
|
||||
So when the adapter is creating the pipeline of functions for the argument's `type`, it already has
|
||||
an `ArgSpec` for the argument. It creates a function which calls `validate(value, ref)` (in
|
||||
`lib/schema/schema.js`) where `value` is whatever the user provided, and `ref` is the `ref`
|
||||
property of the `ArgSpec`. The concept is that `ajv` can validate using _any_ `ref` it knows about;
|
||||
each property in a schema can be referenced by this `ref` whether it's defined or not. To help
|
||||
visualize, if a schema is:
|
||||
|
||||
```json
|
||||
{
|
||||
"$id": "my-schema.json",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ref` of `foo` would be `my-schema.json#/properties/foo`. Assuming our `Ajv` instance knows
|
||||
about this `my-schema.json`, then we can call its `getSchema(ref)` method (which has a `schema`
|
||||
property, but is a misnomer nonetheless) to get a validation function; `validate(value, ref)` in
|
||||
`schema.js` calls this validation function.
|
||||
|
||||
!!! note
|
||||
|
||||
The schema spec says a schema author can supply an explicit `$id` keyword to override this;
|
||||
it's unsupported by Appium at this time. If needed, extension authors must carefully use `$ref`
|
||||
without custom `$id`s. It's highly unlikely an extension would have a schema so complicated as
|
||||
to need this, however; Appium itself doesn't even use `$ref` to define its own properties!
|
||||
|
||||
Next, let's take a look at how Appium loads schemas. This actually happens _before_ any argument
|
||||
validation.
|
||||
|
||||
## Schema Loading
|
||||
|
||||
Let's ignore extensions for a moment, and start with the base schema.
|
||||
|
||||
When something first imports the `lib/schema/schema.js` module, an instance of an `AppiumSchema` is
|
||||
created. This is a singleton, and its methods are exported from the module (all of which are bound
|
||||
to the instance).
|
||||
|
||||
The constructor does very little; it instantiates an `Ajv` instance and configures it with Appium's
|
||||
[custom keywords](#custom-keyword-reference) and adds support for the `format` keyword via the
|
||||
[ajv-formats](https://npm.im/ajv-formats) module.
|
||||
|
||||
Otherwise, the `AppiumSchema` instance does not interact with the `Ajv` instance until its
|
||||
`finalize()` method (exported as `finalizeSchema()`) is called. When this method is called, we're
|
||||
saying "we are not going to add any more schemas; go ahead and create `ArgSpec` objects and
|
||||
register schemas with `ajv`".
|
||||
|
||||
When does finalization happen? Well:
|
||||
|
||||
1. When the `appium` executable begins, it _checks for and configures extensions_ (hand-wave) in `APPIUM_HOME`.
|
||||
2. Only then does it start to think about arguments--it instantiates an `ArgParser`, which (as you'll recall) runs the adapter to convert the schema to arguments.
|
||||
3. _Finalization happens here_--when creating the parser. Appium need the schema(s) to be registered with `ajv` in order to create validation functions for arguments.
|
||||
4. Thereafter, Appium parses the arguments with the `ArgParser`.
|
||||
5. Finally, decides what to do with the returned object.
|
||||
|
||||
Without extensions, `finalize()` still knows about the Appium base schema
|
||||
(`appium-config-schema.js`), and just registers that. However, step 1. above is doing a _lot of
|
||||
work_, so let's look at how extensions come into play.
|
||||
|
||||
## Extension Support
|
||||
|
||||
One of the design goals of this system is the following:
|
||||
|
||||
_An extension should be able to register custom CLI arguments with the Appium, and a user should be
|
||||
able to use them like any other argument_.
|
||||
|
||||
Previously, Appium 2.0 accepted arguments in this manner (via `--driverArgs`), but validation was
|
||||
hand-rolled and required extension implementors to use a custom API. It also required the user to
|
||||
awkwardly pass a JSON string as the configuration on the command-line. Further, no contextual help
|
||||
(via `--help`) existed for these arguments.
|
||||
|
||||
Now, by providing a schema for its options, a driver or plugin can register CLI arguments and
|
||||
config file schemas with Appium.
|
||||
|
||||
To register a schema, an extension must provide the `appium.schema` property in its `package.json`.
|
||||
The value may be a schema or a path to a schema. If the latter, the schema should be JSON or
|
||||
a CommonJS module (ESM not supported at this time, nor is YAML).
|
||||
|
||||
For any property in this schema, the property will appear as a CLI argument of the form
|
||||
`--<extension-type>-<extension-name>-<property-name>`. For example, if the `fake` driver provides
|
||||
a property `foo`, the argument will be `--driver-fake-foo`, and will show in `appium server --help`
|
||||
like any other CLI argument.
|
||||
|
||||
The corresponding property in a config file would be
|
||||
`server.<extension-type>.<extension-name>.<property-name>`, e.g.:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"fake": {
|
||||
"foo": "bar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The naming convention described above avoids problems of one extension type having a name conflict
|
||||
with a different extension type.
|
||||
|
||||
!!! note
|
||||
|
||||
While an extension can provide aliases via `appiumCliAliases`, "short" flags are disallowed,
|
||||
since all arguments from extensions are prefixed with `--<extension-type>-<extension-name>-`.
|
||||
The extension name and argument name will be kebab-cased for the CLI, according to [Lodash's
|
||||
rules](https://lodash.com/docs/4.17.15#kebabCase) around kebab-casing.
|
||||
|
||||
The schema object will look much like Appium's base schema, but it will only have top-level
|
||||
properties (nested properties are currently unsupported). Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "my rad schema for the cowabunga driver",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fizz": {
|
||||
"type": "string",
|
||||
"default": "buzz",
|
||||
"$comment": "corresponds to CLI --driver-cowabunga-fizz"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As written in a user's config file, this would be the `server.driver.cowabunga.fizz` property.
|
||||
|
||||
When extensions are loaded, the `schema` property is verified and the schema is registered with the
|
||||
`AppiumSchema` (it is _not_ registered with `Ajv` until `finalize()` is called).
|
||||
|
||||
During finalization, each registered schema is added to the `Ajv` instance. The schema is assigned
|
||||
an `$id` based on the extension type and name (which overrides whatever the extension provides, if
|
||||
anything). Schemas are also forced to disallowed unknown arguments via the `additionalProperties:
|
||||
false` keyword.
|
||||
|
||||
Behind the scenes, the base schema has `driver` and `plugin` properties which are objects. When
|
||||
finalized, a property is added to each--corresponding to an extension name--and the value of this
|
||||
property is a reference to the `$id` of a property in the extension schema. For example, the
|
||||
`server.driver` property will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"driver": {
|
||||
"cowabunga": {
|
||||
"$ref": "driver-cowabunga.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is why we call it the "base" schema--it is _mutated_ when extensions provide schemas. The
|
||||
extension schemas are kept separately, but the _references_ are added to the schema before it's
|
||||
ultimately added to `ajv`. This works because an `Ajv` instance understands references _from_ any
|
||||
schema it knows about _to_ any schema it knows about.
|
||||
|
||||
!!! note
|
||||
|
||||
This makes it impossible to provide a complete static schema for Appium _and_ the installed
|
||||
extensions (as of Nov 5 2021). A static `.json` schema _is_ generated from the base (via a Gulp
|
||||
task), but it does not contain any extension schemas. The static schema also has uses beyond
|
||||
Appium; e.g., IDEs can provide contextual error-checking of config files this way. Let's solve
|
||||
this?
|
||||
|
||||
Just like how we look up the reference ID of a particular argument in the base schema, validation
|
||||
of arguments from extensions happens the exact same way. If the `cowabunga` driver has the schema
|
||||
ID `driver-cowabunga.json`, then the `fizz` property can be referenced from any schema registered
|
||||
with `ajv` via `driver-cowabunga.json#/properties/fizz`. "Base" schema arguments begin with
|
||||
`appium.json#properties/` instead.
|
||||
|
||||
## Development Environment Support
|
||||
|
||||
During the flow of development, a couple extra tasks have been automated to maintain the base
|
||||
schema:
|
||||
|
||||
- As a post-transpilation step, a `lib/appium-config.schema.json` gets generated from
|
||||
- `lib/schema/appium-config-schema.js` (in addition to its CJS counterpart generated by Babel).
|
||||
- This file is under version control. It ends up being _copied_ to
|
||||
- `build/lib/appium-config.schema.json` in this step. A pre-commit hook (see
|
||||
- `scripts/generate-schema-declarations.js` in the root monorepo) generates
|
||||
- a `types/appium-config-schema.d.ts` from the above JSON file. The types in `types/types.d.ts`
|
||||
- depend upon this file. This file is under version control.
|
||||
|
||||
## Custom Keyword Reference
|
||||
|
||||
Keywords are defined in `lib/schema/keywords.js`.
|
||||
|
||||
- `appiumCliAliases`: allows a schema to express aliases (e.g., a CLI argument can be `--verbose` or `-v`). This is an array of strings. Strings shorter than three (3) characters will begin with a single dash (`-`) instead of a double-dash (`--`). Note that any argument provided by an extension will begin with a double-dash, because these are required to have the `--<extension-type>-<extension-name>-` prefix.
|
||||
- `appiumCliDest`: allows a schema to specify a custom property name in the post-`argprase` arguments objects. If not set, this becomes a camelCased string.
|
||||
- `appiumCliDescription`: allows a schema to override the description of the argument when displayed on the command-line. This is useful paired with `appiumCliTransformer` (or `array`/`object`-typed properties), since there's a substantial difference between what a CLI-using user can provide vs. what a config-file-using user can provide.
|
||||
- `appiumCliTransformer`: currently a choice between `csv` and `json`. These are custom functions which post-process a value. They are not used when loading & validating config files, but the idea should be that they result in the same object you'd get if you used whatever the config file wanted (e.g., an array of strings). `csv` is for comma-delimited strings and CSV files; `json` is for raw JSON strings and `.json` files.
|
||||
- `appiumCliIgnore`: If `true`, do not support this property on the CLI.
|
||||
- `appiumDeprecated`: If `true`, the property is considered "deprecated", and will be displayed as such to the user (e.g., in the `--help` output). Note the JSON Schema draft-2019-09 introduces a new keyword `deprecated` which we should use instead if upgrading to this metaschema. When doing so, `appiumDeprecated` should itself be marked as `deprecated`.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: Contributing to Appium
|
||||
---
|
||||
|
||||
This section of Appium's documentation is for those who are interested in contributing to Appium's
|
||||
development. It contains developer overviews, guides, and notes. Use the navigation menu to find
|
||||
a specific topic. All the information in these guides assumes in-depth familiarity with Appium
|
||||
already.
|
||||
|
||||
!!! warning
|
||||
|
||||
Developer information may not be kept up to date as frequently as user-facing information, or
|
||||
it may be most relevant in its current form on the online repository, not in this published
|
||||
version. Always be sure to check the repo or discuss with maintainers. We're always happy to
|
||||
help new contributors get started!
|
||||
|
||||
## Ways to Contribute
|
||||
|
||||
TODO
|
||||
|
||||
## The Appium Development Process
|
||||
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Building Docs for Appium Extensions
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,748 +0,0 @@
|
||||
---
|
||||
title: Building Appium Drivers
|
||||
---
|
||||
|
||||
Appium wants to make it easy for anyone to develop their own automation drivers as part of the
|
||||
Appium ecosystem. This guide will explain what's involved and how you can accomplish various driver
|
||||
development tasks using the tools Appium provides. This guide assumes you (1) are a competent user of
|
||||
Appium, (2) are a competent Node.js developer, and (3) that you have read and understood the
|
||||
[Driver Intro](../intro/drivers.md).
|
||||
|
||||
If that describes you, great! This guide will get you started.
|
||||
|
||||
## Before you create your driver
|
||||
|
||||
Before you get to work implementing your driver, it's important to have a few things sorted out.
|
||||
For example, you need to know what your driver will do. Which platform is it trying to expose
|
||||
WebDriver automation for?
|
||||
|
||||
Appium doesn't magically give you the power to automate any platform. All it does is give you a set
|
||||
of convenient tools for implementing the WebDriver Protocol. So if you want to create, for example,
|
||||
a driver for a new app platform, you'll need to know how to automate apps on that platform *without Appium*.
|
||||
|
||||
This usually means that you need to be very familiar with app development for a given platform. And
|
||||
it usually means that you will rely on tools or SDKs provided by the platform vendor.
|
||||
|
||||
Basically, if you can't answer the question **"how would I launch, remotely trigger behaviours, and
|
||||
read state from an app on this platform?" then you're not quite ready to write an Appium driver**.
|
||||
Make sure you do the research to feel comfortable that there *is* a path forward. Once there is,
|
||||
coding it up and making it available as an Appium driver should be the easy part!
|
||||
|
||||
## Other drivers to reference
|
||||
|
||||
One of the greatest things about building an Appium driver is that there are already a number of
|
||||
open source Appium drivers which you can look at for reference. There is
|
||||
a [fake-driver](https://github.com/appium/appium/tree/2.0/packages/fake-driver) sample driver which
|
||||
does basically nothing other than showcase some of the things described in this guide.
|
||||
|
||||
And of course, all of Appium's official drivers are open source and available in repositories at
|
||||
the project's GitHub organization. So if you ever find yourself asking, "how does a driver do X?",
|
||||
read the code for these drivers! Also don't be afraid to ask questions of the Appium developers if
|
||||
you get stuck; we're always happy to help make sure the driver development experience is a good
|
||||
one!
|
||||
|
||||
## Basic requirements for Appium drivers
|
||||
|
||||
These are the things your driver *must* do (or be), if you want it to be a valid Appium driver.
|
||||
|
||||
### Node.js package with Appium extension metadata
|
||||
|
||||
All Appium drivers are fundamentally Node.js packages, and therefore must have a valid
|
||||
`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in Node.js so it can be loaded by Appium.
|
||||
|
||||
Your `package.json` must include `appium` as a `peerDependency`. The requirements for the
|
||||
dependency versions should be as loose as possible (unless you happen to know your driver will only
|
||||
work with certain versions of Appium). For Appium 2.0, for example, this would look something like
|
||||
`^2.0.0`, declaring that your driver works with any version of Appium that starts with 2.x.
|
||||
|
||||
Your `package.json` must contain an `appium` field, like this (we call this the 'Appium extension
|
||||
metadata'):
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"appium": {
|
||||
"driverName": "fake",
|
||||
"automationName": "Fake",
|
||||
"platformNames": [
|
||||
"Fake"
|
||||
],
|
||||
"mainClass": "FakeDriver"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The required subfields are:
|
||||
|
||||
* `driverName`: this should be a short name for your driver.
|
||||
* `automationName`: this should be the string users will use for their `appium:automationName`
|
||||
capability to tell Appium to use *your* driver.
|
||||
* `platformNames`: this is an array of one or more platform names considered valid for your driver.
|
||||
When a user sends in the `platformName` capability to start a session, it must be included in
|
||||
this list for your driver to handle the session. Known platform name strings include: `iOS`,
|
||||
`tvOS`, `macOS`, `Windows`, `Android`.
|
||||
* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a
|
||||
class which extends Appium's `BaseDriver` (see below).
|
||||
|
||||
### Extend Appium's `BaseDriver` class
|
||||
|
||||
Ultimately, your driver is much easier to write because most of the hard work of implementing the
|
||||
WebDriver protocol and handling certain common logic is taken care of already by Appium. This is
|
||||
all encoded up as a class which Appium exports for you to use, called `BaseDriver`. It is exported
|
||||
from `appium/driver`, so you can use one of these styles to import it and create your *own* class
|
||||
that extends it:
|
||||
|
||||
```js
|
||||
import {BaseDriver} from 'appium/driver';
|
||||
// or: const {BaseDriver} = require('appium/driver');
|
||||
|
||||
export class MyDriver extends BaseDriver {
|
||||
}
|
||||
```
|
||||
|
||||
### Make your driver available
|
||||
|
||||
That's basically it! With a Node.js package exporting a driver class and with correct Appium
|
||||
extension metadata, you've got yourself an Appium driver! Now it doesn't *do* anything, but you can
|
||||
load it up in Appium, start and stop sessions with it, etc...
|
||||
|
||||
To make it available to users, you could publish it via NPM. When you do so, your driver will be
|
||||
installable via the Appium CLI:
|
||||
|
||||
```
|
||||
appium driver install --source=npm <driver-package-on-npm>
|
||||
```
|
||||
|
||||
It's a good idea to test your driver first, of course. One way to see how it works within Appium is
|
||||
to install it locally first:
|
||||
|
||||
```
|
||||
appium driver install --source=local /path/to/your/driver
|
||||
```
|
||||
|
||||
### Developing your driver
|
||||
|
||||
How you develop your driver is up to you. It is convenient, however, to run it from within Appium
|
||||
without having to do lots of publishing and installing. The most straightforward way to do this is
|
||||
to include the most recent version of Appium as a `devDependency`, and then also your own driver,
|
||||
like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
...,
|
||||
"appium": "^2.0.0",
|
||||
"your-driver": "file:.",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, you can run Appium locally (`npm exec appium` or `npx appium`), and because your driver is
|
||||
listed as a dependency alongside it, it will be automatically "installed" and available. You can
|
||||
design your e2e tests this way, or if you're writing them in Node.js, you can simply import
|
||||
Appium's start server methods to handle starting and stopping the Appium server in Node. (TODO:
|
||||
reference an implementation of this in one of the open source drivers when ready).
|
||||
|
||||
Another way to do local development with an existing Appium server install is to simply install
|
||||
your driver locally:
|
||||
|
||||
```
|
||||
appium driver install --source=local /path/to/your/driver/dev/dir
|
||||
```
|
||||
|
||||
## Standard driver implementation ideas
|
||||
|
||||
These are things you will probably find yourself wanting to do when creating a driver.
|
||||
|
||||
### Set up state in a constructor
|
||||
|
||||
If you define your own constructor, you'll need to call `super` to make sure all the standard state
|
||||
is set up correctly:
|
||||
|
||||
```js
|
||||
constructor(args) {
|
||||
super(args);
|
||||
// now do your own thing
|
||||
}
|
||||
```
|
||||
|
||||
The `args` parameter here is the object containing all the CLI args used to start the Appium
|
||||
server.
|
||||
|
||||
### Define and validate accepted capabilities
|
||||
|
||||
You can define your own capabilities and basic validation for them. Users will always be able to
|
||||
send in capabilities that you don't define, but if they send in capabilities you have explicitly
|
||||
defined, then Appium will validate that they are of the correct type (and will check for the
|
||||
presence of required capabilities).
|
||||
|
||||
If you want to turn capability validation off entirely, set `this.shouldValidateCaps` to `false` in
|
||||
your constructor.
|
||||
|
||||
To give Appium your validation constraints, set `this.desiredCapConstraints` to a validation object
|
||||
in your constructor. Validation objects can be somewhat complex. Here's an example from the
|
||||
UiAutomator2 driver:
|
||||
|
||||
```js
|
||||
{
|
||||
app: {
|
||||
presence: true,
|
||||
isString: true
|
||||
},
|
||||
automationName: {
|
||||
isString: true
|
||||
},
|
||||
browserName: {
|
||||
isString: true
|
||||
},
|
||||
launchTimeout: {
|
||||
isNumber: true
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Start a session and read capabilities
|
||||
|
||||
Appium's `BaseDriver` already implements the `createSession` command, so you don't have to. However
|
||||
it's very common to need to perform your own startup actions (launching an app, running some
|
||||
platform code, or doing different things based on capabilities you have defined for your driver).
|
||||
So you'll probably end up overriding `createSession`. You can do so by defining the method in your
|
||||
driver:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) {
|
||||
const [sessionId, caps] = super.createSession(w3cCaps);
|
||||
// do your own stuff here
|
||||
return [sessionId, caps];
|
||||
}
|
||||
```
|
||||
|
||||
For legacy reasons, your function will receive old-style JSON Wire Protocol desired and required
|
||||
caps as the first two arguments. Given that the old protocol isn't supported anymore and clients
|
||||
have all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion
|
||||
about what `otherDriverData` is about, see the section below on concurrent drivers).
|
||||
|
||||
You'll want to make sure to call `super.createSession` in order to get the session ID as well as
|
||||
the processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`
|
||||
locally here would have no effect other than changing what the user sees in the create session
|
||||
response).
|
||||
|
||||
So that's it! You can fill out the middle section with whatever startup logic your driver requires.
|
||||
|
||||
### End a session
|
||||
|
||||
If your driver requires any cleanup or shutdown logic, it's best to do it as part of overriding the
|
||||
implementation of `deleteSession`:
|
||||
|
||||
```js
|
||||
async deleteSession() {
|
||||
// do your own cleanup here
|
||||
// don't forget to call super!
|
||||
await super.deleteSession();
|
||||
}
|
||||
```
|
||||
|
||||
It's very important not to throw any errors here if possible so that all parts of session cleanup
|
||||
can succeed!
|
||||
|
||||
### Access capabilities and CLI args
|
||||
|
||||
You'll often want to read parameters the user has set for the session, whether as CLI args or as
|
||||
capabilities. The easiest way to do this is to access `this.opts`, which is a merge of all options,
|
||||
from the CLI or from capabilities. So for example to access the `appium:app` capability, you could
|
||||
simply get the value of `this.opts.app`.
|
||||
|
||||
If you care about knowing whether something was sent in as a CLI arg *or* a capability, you can
|
||||
access the `this.cliArgs` and `this.caps` objects explicitly.
|
||||
|
||||
In all cases, the `appium:` capability prefix will have been stripped away by the time you are
|
||||
accessing values here, for convenience.
|
||||
|
||||
### Implement WebDriver commands
|
||||
|
||||
You handle WebDriver commands by implementing functions in your driver class. Each member of the
|
||||
WebDriver Protocol, plus the various Appium extensions, has a corresponding function that you
|
||||
implement if you want to support that command in your driver. The best way to see which commands
|
||||
Appium supports and which method you need to implement for each command is to look at Appium's
|
||||
[routes.js](https://github.com/appium/appium/blob/2.0/packages/base-driver/lib/protocol/routes.js).
|
||||
Each route object in this file tells you the command name as well as the parameters you'd expect to
|
||||
receive for that command.
|
||||
|
||||
Let's take this block for example:
|
||||
```js
|
||||
'/session/:sessionId/url': {
|
||||
GET: {command: 'getUrl'},
|
||||
POST: {command: 'setUrl', payloadParams: {required: ['url']}},
|
||||
}
|
||||
```
|
||||
|
||||
Here we see that the route `/session/:sessionId/url` is mapped to two commands, one for a `GET`
|
||||
request and one for a `POST` request. If we want to allow our driver to change the "url" (or
|
||||
whatever that might mean for our driver), we can therefore implement the `setUrl` command, knowing
|
||||
it will take the `url` parameter:
|
||||
|
||||
```js
|
||||
async setUrl(url) {
|
||||
// your implementation here
|
||||
}
|
||||
```
|
||||
|
||||
A few notes:
|
||||
- all command methods should be `async` functions or otherwise return a `Promise`
|
||||
- you don't need to worry about protocol encoding/decoding. You will get JS objects as params, and
|
||||
can return JSON-serializable objects in response. Appium will take care of wrapping it up in the
|
||||
WebDriver protocol response format, turning it into JSON, etc...
|
||||
- all session-based commands receive the `sessionId` parameter as the last parameter
|
||||
- all element-based commands receive the `elementId` parameter as the second-to-last parameter
|
||||
- if your driver doesn't implement a command, users can still try to access the command, and will
|
||||
get a `501 Not Yet Implemented` response error.
|
||||
|
||||
### Implement element finding
|
||||
|
||||
Element finding is a special command implementation case. You don't actually want to override
|
||||
`findElement` or `findElements`, even though those are what are listed in `routes.js`. Appium does
|
||||
a lot of work for you if instead you implement this function:
|
||||
|
||||
```js
|
||||
async findElOrEls(strategy, selector, mult, context) {
|
||||
// find your element here
|
||||
}
|
||||
```
|
||||
|
||||
Here's what gets passed in:
|
||||
|
||||
- `strategy` - a string, the locator strategy being used
|
||||
- `selector` - a string, the selector
|
||||
- `mult` - boolean, whether the user has requested one element or all elements matching the
|
||||
selector
|
||||
- `context` - (optional) if defined, will be a W3C Element (i.e., a JS object with the W3C element
|
||||
identifier as the key and the element ID as the value)
|
||||
|
||||
And you need to return one of the following:
|
||||
|
||||
- a single W3C element (an object as described above)
|
||||
- an array of W3C elements
|
||||
|
||||
Note that you can import that W3C web element identifier from `appium/support`:
|
||||
|
||||
```js
|
||||
import {util} from 'appium/support';
|
||||
const { W3C_WEB_ELEMENT_IDENTIFIER } = util;
|
||||
```
|
||||
|
||||
What you do with elements is up to you! Usually you end up keeping a cache map of IDs to actual
|
||||
element "objects" or whatever the equivalent is for your platform.
|
||||
|
||||
### Define valid locator strategies
|
||||
|
||||
Your driver might only support a subset of the standard WebDriver locator strategies, or it might
|
||||
add its own custom locator strategies. To tell Appium which strategies are considered valid for
|
||||
your driver, create an array of strategies and assign it to `this.locatorStrategies`:
|
||||
|
||||
```js
|
||||
this.locatorStrategies = ['xpath', 'custom-strategy'];
|
||||
```
|
||||
|
||||
Appium will throw an error if the user attempts to use any strategies other than the allowed ones,
|
||||
which enables you to keep your element finding code clean and deal with only the strategies you
|
||||
know about.
|
||||
|
||||
By default, the list of valid strategies is empty, so if your driver isn't simply proxying to
|
||||
another WebDriver endpoint, you'll need to define some. The protocol-standard locator strategies
|
||||
are defined [here](https://www.w3.org/TR/webdriver/#locator-strategies).
|
||||
|
||||
### Throw WebDriver-specific errors
|
||||
|
||||
The WebDriver spec defines a [set of error
|
||||
codes](https://github.com/jlipps/simple-wd-spec#error-codes) to accompany command responses if an
|
||||
error occurred. Appium has created error classes for each of these codes, so you can throw the
|
||||
appropriate error from inside a command, and it will do the right thing in terms of the protocol
|
||||
response to the user. To get access to these error classes, import them from `appium/driver`:
|
||||
|
||||
```
|
||||
import {errors} from 'appium/driver';
|
||||
|
||||
throw new errors.NoSuchElementError();
|
||||
```
|
||||
|
||||
### Log messages to the Appium log
|
||||
|
||||
You can always use `console.log`, of course, but Appium provides a nice logger for you as
|
||||
`this.log` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log
|
||||
levels). If you want to create an Appium logger outside of a driver context (say in a script or
|
||||
helper file), you can always construct your own too:
|
||||
|
||||
```js
|
||||
import {logging} from 'appium/support';
|
||||
const log = logging.getLogger('MyDriver');
|
||||
```
|
||||
|
||||
## Further possibilities for Appium drivers
|
||||
|
||||
These are things your driver *can* do to take advantage of extra driver features or do its job more
|
||||
conveniently.
|
||||
|
||||
### Add a schema for custom command line arguments
|
||||
|
||||
You can add custom CLI args if you want your driver to receive data from the command line when the
|
||||
Appium server is started (for example, ports that a server administrator should set that should not
|
||||
be passed in as capabilities.
|
||||
|
||||
To define CLI arguments (or configuration properties) for the Appium server, your extension must provide a _schema_. In
|
||||
the `appium` property of your extension's `package.json`, add a `schema` property. This will either
|
||||
a) be a schema itself, or b) be a path to a schema file.
|
||||
|
||||
The rules for these schemas:
|
||||
|
||||
- Schemas must conform to [JSON Schema Draft-07](https://ajv.js.org/json-schema.html#draft-07).
|
||||
- If the `schema` property is a path to a schema file, the file must be in JSON or JS (CommonJS) format.
|
||||
- Custom `$id` values are unsupported. To use `$ref`, provide a value relative to the schema root, e.g., `/properties/foo`.
|
||||
- Known values of the `format` keyword are likely supported, but various other keywords may be unsupported. If you find a keyword that is unsupported which you need to use, please [ask for support](https://github.com/appium/appium/issues/new) or send a PR!
|
||||
- The schema must be of type `object` (`{"type": "object"}`), containing the arguments in a `properties` keyword. Nested properties are unsupported.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"test-web-server-port": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535,
|
||||
"description": "The port to use for the test web server"
|
||||
},
|
||||
"test-web-server-host": {
|
||||
"type": "string",
|
||||
"description": "The host to use for the test web server",
|
||||
"default": "sillyhost"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above schema defines two properties which can be set via CLI argument or configuration file. If
|
||||
this extension is a _driver_ and its name is "horace", the CLI args would be
|
||||
`--driver-horace-test-web-server-port` and `--driver-horace-test-web-server-host`, respectively.
|
||||
Alternatively, a user could provide a configuration file containing:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"horace": {
|
||||
"test-web-server-port": 1234,
|
||||
"test-web-server-host": "localhorse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Add driver scripts
|
||||
|
||||
Sometimes you might want users of your driver to be able to run scripts outside the context of
|
||||
a session (for example, to run a script that pre-builds aspects of your driver). To support this,
|
||||
you can add a map of script names and JS files to the `scripts` field within your Appium extension
|
||||
metadata. So let's say you've created a script in your project that lives in a `scripts` directory
|
||||
in your project, named `driver-prebuild.js`. Then you could add a `scripts` field like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"prebuild": "./scripts/driver-prebuild.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, assuming your driver is named `mydriver`, users of your driver can run `appium driver run
|
||||
mydriver prebuild`, and your script will execute.
|
||||
|
||||
### Proxy commands to another WebDriver implementation
|
||||
|
||||
A very common design architecture for Appium drivers is to have some kind of platform-specific
|
||||
WebDriver implementation that the Appium driver interfaces with. For example, the Appium
|
||||
UiAutomator2 driver interfaces with a special (Java-based) server running on the Android device. In
|
||||
webview mode, it also interfaces with Chromedriver.
|
||||
|
||||
If you find yourself in this situation, it is extremely easy to tell Appium that your driver is
|
||||
just going to be proxying WebDriver commands straight to another endpoint.
|
||||
|
||||
First, let Appium know that your driver *can* proxy by implementing the `canProxy` method:
|
||||
|
||||
```js
|
||||
canProxy() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Next, tell Appium which WebDriver routes it should *not* attempt to proxy (there often end up being
|
||||
certain routes that you don't want to forward on):
|
||||
|
||||
```js
|
||||
getProxyAvoidList() {
|
||||
return [
|
||||
['POST', new RegExp('^/session/[^/]+/appium')]
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
The proxy avoidance list should be an array of arrays, where each inner array has an HTTP method as
|
||||
its first member, and a regular expression as its second. If the regular expression matches the
|
||||
route, then the route will not be proxied and instead will be handled by your driver. In this
|
||||
example, we are avoiding proxying all `POST` routes that have the `appium` prefix.
|
||||
|
||||
Next, we have to set up the proxying itself. The way to do this is to use a special class from
|
||||
Appium called `JWProxy`. (The name means "JSON Wire Proxy" and is related to a legacy
|
||||
implementation of the protocol). You'll want to create a `JWProxy` object using the details required to
|
||||
connect to the remote server:
|
||||
|
||||
```js
|
||||
// import {JWProxy} from 'appium/driver';
|
||||
|
||||
const proxy = new JWProxy({
|
||||
server: 'remote.server',
|
||||
port: 1234,
|
||||
base: '/',
|
||||
});
|
||||
|
||||
this.proxyReqRes = proxy.proxyReqRes.bind(proxy);
|
||||
this.proxyCommand = proxy.command.bind(proxy);
|
||||
```
|
||||
|
||||
Here we are creating a proxy object and assigning some of its methods to `this` under the names
|
||||
`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget
|
||||
this step! The `JWProxy` has a variety of other options which you can check out in the source code,
|
||||
as well. (TODO: publish options as API docs and link here).
|
||||
|
||||
Finally, we need a way to tell Appium when the proxy is active. For your driver it might always
|
||||
be active, or it might only be active when in a certain context. You can define the logic as an
|
||||
implementation of `proxyActive`:
|
||||
|
||||
```js
|
||||
proxyActive() {
|
||||
return true; // or use custom logic
|
||||
}
|
||||
```
|
||||
|
||||
With those pieces in play, you won't have to reimplement anything that's already implemented by the
|
||||
remote endpoint you're proxying to. Appium will take care of all the proxying for you.
|
||||
|
||||
### Extend the existing protocol with new commands
|
||||
|
||||
You may find that the existing commands don't cut it for your driver. If you want to expose
|
||||
behaviours that don't map to any of the existing commands, you can create new commands in one of
|
||||
two ways:
|
||||
|
||||
1. Extending the WebDriver protocol and creating client-side plugins to access the extensions
|
||||
1. Overloading the Execute Script command by defining "Execute Methods"
|
||||
|
||||
If you want to follow the first path, you can direct Appium to recognize new methods and add them
|
||||
to its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`
|
||||
static variable in your driver class to an object of the same form as Appium's `routes.js` object.
|
||||
For example, here is the `newMethodMap` for the `FakeDriver` example driver:
|
||||
|
||||
```js
|
||||
static newMethodMap = {
|
||||
'/session/:sessionId/fakedriver': {
|
||||
GET: {command: 'getFakeThing'},
|
||||
POST: {command: 'setFakeThing', payloadParams: {required: ['thing']}},
|
||||
},
|
||||
'/session/:sessionId/fakedriverargs': {
|
||||
GET: {command: 'getFakeDriverArgs'},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
In this example we're adding a few new routes and a total of 3 new commands. For more examples of
|
||||
how to define commands in this way, it's best to have a look through `routes.js`. Now all you need
|
||||
to do is implement the command handlers in the same way you'd implement any other Appium command.
|
||||
|
||||
The downside of this way of adding new commands is that people using the standard Appium clients
|
||||
won't have nice client-side functions designed to target these endpoints. So you would need to
|
||||
create and release client-side plugins for each language you want to support (directions or
|
||||
examples can be found at the relevant client docs).
|
||||
|
||||
An alternative to this way of doing things is to overload a command which all WebDriver clients
|
||||
have access to already: Execute Script. Appium provides some a convenient tool for making this
|
||||
easy. Let's say you are building a driver for stereo system called `soundz`, and you wanted to
|
||||
create a command for playing a song by name. You could expose this to your users in such a way that
|
||||
they call something like:
|
||||
|
||||
```js
|
||||
// webdriverio example. Calling webdriverio's `executeScript` command is what trigger's Appium's
|
||||
// Execute Script command handler
|
||||
driver.executeScript('soundz: playSong', [{song: 'Stairway to Heaven', artist: 'Led Zeppelin'}]);
|
||||
```
|
||||
|
||||
Then in your driver code you can define the static property `executeMethodMap` as a mapping of
|
||||
script names to methods on your driver. It has the same basic form as `newMethodMap`, described
|
||||
above. Once `executeMethodMap` is defined, you'll also need to implement the Execute Script command
|
||||
handler, which according to Appium's routes mapping is called `execute`. The implementation can
|
||||
call a single helper function, `this.executeMethod`, which takes care of looking at the script and
|
||||
arguments the user sent in and routing it to the correct custom handler you've defined. Here's an
|
||||
example:
|
||||
|
||||
```js
|
||||
static executeMethodMap = {
|
||||
'soundz: playSong', {
|
||||
command: 'soundzPlaySong',
|
||||
params: {required: ['song', 'artist'], optional: []},
|
||||
}
|
||||
}
|
||||
|
||||
async soundzPlaySong(song, artist) {
|
||||
// play the song based on song and artist details
|
||||
}
|
||||
|
||||
async execute(script, args) {
|
||||
return await this.executeMethod(script, args);
|
||||
}
|
||||
```
|
||||
|
||||
A couple notes about this system:
|
||||
1. The arguments array sent via the call to Execute Script must contain only zero or one element(s). The
|
||||
first item in the list is considered to be the parameters object for your method. These parameters
|
||||
will be parsed, validated, and then applied to your overload method in the order specified in
|
||||
`executeMethodMap` (the order specified in the `required` parameters list, followed by the
|
||||
`optional` parameters list). I.e., this framework assumes only a single actual argument sent in via
|
||||
Execute Script (and this argument should be an object with keys/values representing the
|
||||
parameters your execute method expects).
|
||||
1. Appium does not automatically implement `execute` (the Execute Script handler) for you. You may
|
||||
wish, for example, to only call the `executeMethod` helper function when you're not in proxy
|
||||
mode!
|
||||
1. The `executeMethod` helper will reject with an error if a script name doesn't match one of the
|
||||
script names defined as a command in `executeMethodMap`, or if there are missing parameters.
|
||||
|
||||
### Implement handling of Appium settings
|
||||
|
||||
Appium users can send parameters to your driver via CLI args as well as via capabilities. But these
|
||||
cannot change during the course of a test, and sometimes users want to adjust parameters mid-test.
|
||||
Appium has a [Settings](../guides/settings.md) API for this purpose.
|
||||
|
||||
To support settings in your own driver, first of all define `this.settings` to be an instance of
|
||||
the appropriate class, in your constructor:
|
||||
|
||||
```js
|
||||
// import {DeviceSettings} from 'appium/driver';
|
||||
|
||||
this.settings = new DeviceSettings();
|
||||
```
|
||||
|
||||
Now, you can read user settings any time simply by calling `this.settings.getSettings()`. This will
|
||||
return a JS object where the settings names are keys and have their corresponding values.
|
||||
|
||||
If you want to assign some default settings, or run some code on your end whenever settings are
|
||||
updated, you can do both of these things as well.
|
||||
|
||||
```js
|
||||
constructor() {
|
||||
const defaults = {setting1: 'value1'};
|
||||
this.settings = new DeviceSettings(defaults, this.onSettingsUpdate.bind(this));
|
||||
}
|
||||
|
||||
async onSettingsUpdate(key, value) {
|
||||
// do anything you want here with key and value
|
||||
}
|
||||
```
|
||||
|
||||
### Make itself aware of resources other concurrent drivers are using
|
||||
|
||||
Let's say your driver uses up some system resources, like ports. There are a few ways to make sure
|
||||
that multiple simultaneous sessions don't use the same resources:
|
||||
|
||||
1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc)
|
||||
1. Just always use free resources (find a new random port for each session)
|
||||
1. Have each driver express what resources it is using, then examine currently-used resources from
|
||||
other drivers when a new session begins.
|
||||
|
||||
To support this third strategy, you can implement `get driverData` in your driver to return what
|
||||
sorts of resources your driver is currently using, for example:
|
||||
|
||||
```js
|
||||
get driverData() {
|
||||
return {specialPort: 1234, specialFile: /path/to/file}
|
||||
}
|
||||
```
|
||||
|
||||
Now, when a new session is started on your driver, the `driverData` response from any other
|
||||
simultaneously running drivers (of the same type) will also be included, as the last parameter of
|
||||
the `createSession` method:
|
||||
|
||||
```js
|
||||
async createSession(jwpCaps, reqCaps, w3cCaps, driverData)
|
||||
```
|
||||
|
||||
You can dig into this `driverData` array to see what resources other drivers are using to help
|
||||
determine which ones you want to use for this particular session.
|
||||
|
||||
!!! warning
|
||||
|
||||
Be careful here, since `driverData` is only passed between sessions of a single running Appium
|
||||
server. There's nothing to stop a user from running multiple Appium servers and requesting your
|
||||
driver simultaneously on each of them. In this case, you won't be able to ensure independence
|
||||
of resources via `driverData`, so you might consider using file-based locking mechanisms or
|
||||
something similar.
|
||||
|
||||
!!! warning
|
||||
|
||||
It's also important to note you will only receive `driverData` for other instances of *your*
|
||||
driver. So unrelated drivers also running may still be using some system resources. In general
|
||||
Appium doesn't provide any features for ensuring unrelated drivers don't interfere with one
|
||||
another, so it's up to the drivers to allow users to specify resource locations or addresses to
|
||||
avoid clashes.
|
||||
|
||||
### Log events to the Appium event timeline
|
||||
|
||||
Appium has an [Event Timing API](../guides/event-timing.md) which allows users to get timestamps
|
||||
for certain server-side events (like commands, startup milestones, etc...) and display them on
|
||||
a timeline. The feature basically exists to allow introspection of timing for internal events to
|
||||
help with debugging or running analysis on Appium driver internals. You can add your own events to
|
||||
the event log:
|
||||
|
||||
```js
|
||||
this.logEvent(name);
|
||||
```
|
||||
|
||||
Simply provide a name for the event and it will be added at the current time, and made accessible
|
||||
as part of the event log for users.
|
||||
|
||||
### Hide behaviour behind security flags
|
||||
|
||||
Appium has a feature-flag based [security model](../guides/security.md) that allows driver authors
|
||||
to hide certain features behind security flags. What this means is that if you have a feature you
|
||||
deem insecure and want to require server admins to opt in to it, you can require that they enable
|
||||
the feature by adding it to the `--allow-insecure` list or turning off server security entirely.
|
||||
|
||||
To support the check within your own driver, you can call `this.isFeatureEnabled(featureName)` to
|
||||
determine whether a feature of the given name has been enabled. Or, if you want to simply
|
||||
short-circuit and throw an error if the feature isn't enabled, you can call
|
||||
`this.assertFeatureEnabled(featureName)`.
|
||||
|
||||
### Use a temp dir for files
|
||||
|
||||
If you want to use a temporary directory for files your driver creates that are not important to
|
||||
keep around between computer or server restarts, you can simply read from `this.opts.tmpDir`. This
|
||||
reads the temporary directory location from `@appium/support`, potentially overridden by a CLI
|
||||
flag. I.e., it's safer than writing to your own temporary directory because the location here plays
|
||||
nicely with possible user configuration. `this.opts.tmpDir` is a string, the path to the dir.
|
||||
|
||||
### Deal with unexpected shutdowns or crashes
|
||||
|
||||
Your driver might run into a situation where it can't continue operating normally. For example, it
|
||||
might detect that some external service has crashed and nothing will work anymore. In this case, it
|
||||
can call `this.startUnexpectedShutdown(err)` with an error object including any details, and Appium
|
||||
will attempt to gracefully handle any remaining requests before shutting down the session.
|
||||
|
||||
If you want to perform some of your own cleanup logic when you encounter this condition, you can
|
||||
either do so immediately before calling `this.startUnexpectedShutdown`, or you can attach a handler
|
||||
to the unexpected shutdown event and run your cleanup logic "out of band" so to speak:
|
||||
|
||||
```js
|
||||
this.onUnexpectedShutdown(handler)
|
||||
```
|
||||
|
||||
`handler` should be a function which receives an error object (representing the reason for the
|
||||
unexpected shutdown).
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Building Appium Plugins
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
title: The Appium Ecosystem
|
||||
---
|
||||
|
||||
Appium has an ecosystem of related software and tools. In this guide we'll discuss important
|
||||
officially-supported and community-supported projects.
|
||||
|
||||
## Appium Inspector
|
||||
|
||||
Appium has a graphical client which can be used to manually perform Appium commands, inspect app
|
||||
hierarchies, view screenshots, and more. It's very useful for Appium test development. You can
|
||||
learn more about the inspector here: [Appium Inspector](https://github.com/appium/appium-inspector)
|
||||
|
||||
## Drivers
|
||||
|
||||
You can't use Appium without at least one driver! Here are the drivers that are officially
|
||||
recognized by Appium. Click on the link for each driver to see the specific installation
|
||||
instructions and documentation for that driver.
|
||||
|
||||
To learn more about what drivers are and how they work, check out the [Driver
|
||||
Intro](../intro/drivers.md)
|
||||
|
||||
|Driver|Installation Key|Platform(s)|Mode(s)|Support|
|
||||
|-|-|-|-|-|
|
||||
|[XCUITest](https://github.com/appium/appium-xcuitest-driver)|`xcuitest`|iOS|Native, Hybrid, Web|Appium Team|
|
||||
|[UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)|`uiautomator2`|Android|Native, Hybrid, Web|Appium Team|
|
||||
|[Espresso](https://github.com/appium/appium-espresso-driver)|`espresso`|Android|Native|Appium Team|
|
||||
|[Mac2](https://github.com/appium/appium-mac2-driver)|`mac2`|macOS|Native|Appium Team|
|
||||
|[Safari](https://github.com/appium/appium-safari-driver)|`safari`|macOS, iOS|Web|Appium Team|
|
||||
|[Gecko](https://github.com/appium/appium-geckodriver)|`safari`|macOS, Windows, Linux, Android|Web|Appium Team|
|
||||
|[Windows](https://github.com/appium/appium-windows-driver)|`windows`|Windows|Native|Community / Microsoft|
|
||||
|[Flutter](https://github.com/appium-userland/appium-flutter-driver)|`flutter`|iOS, Android|Native|Community|
|
||||
|[Tizen](https://github.com/Samsung/appium-tizen-driver)|`tizen`|Android|Native|Community / Samsung|
|
||||
|[Youi](https://github.com/YOU-i-Labs/appium-youiengine-driver)|`youiengine`|iOS, Android, macOS, Linux, tvOS|Native|Community / You.i|
|
||||
|
||||
And of course, you can install any other drivers you find out there by using the Appium driver CLI.
|
||||
|
||||
## Clients
|
||||
|
||||
You need a clients to write and run Appium scripts. To learn more about clients, read our [Client
|
||||
Intro](../intro/clients.md). Here is the list of known Appium clients. You'll want to become very
|
||||
familiar with your client documentation (as well as the documentation of any Selenium client that
|
||||
the Appium client depends on) since that is what you will use as your primary interface to Appium.
|
||||
|
||||
|Client|Language|Support|
|
||||
|-|-|-|
|
||||
|[Appium Java client](https://github.com/appium/java-client)|Java|Appium Team|
|
||||
|[Appium Python client](https://github.com/appium/python-client)|Python|Appium Team|
|
||||
|[Appium Ruby client](https://github.com/appium/ruby_lib)|Ruby|Appium Team|
|
||||
|[WebDriverIO](https://webdriver.io)|Node.js|Community|
|
||||
|[Appium .NET client](https://github.com/appium/appium-dotnet-driver)|C#|Appium Team*|
|
||||
|[RobotFramework](https://github.com/serhatbolsu/robotframework-appiumlibrary)|DSL|Community|
|
||||
|
||||
!!! warning
|
||||
|
||||
Currently, the .NET client has a low level of maintenance/support. Expect bugs and
|
||||
incompatibility. We're looking for help here, so please reach out if you know .NET!
|
||||
|
||||
In general, any W3C WebDriver spec-compatible client will also integrate well with Appium, though
|
||||
some Appium-specific commands may not be implemented in other clients.
|
||||
@@ -1,139 +0,0 @@
|
||||
---
|
||||
title: Capabilities
|
||||
---
|
||||
|
||||
TODO
|
||||
|
||||
## Special Notes for Cloud Providers
|
||||
|
||||
When managing an Appium cloud, your users may wish to target various independent versions of Appium
|
||||
drivers and plugins. It is of course up to each service provider how they wish to implement the
|
||||
discovery, installation, and availability of any official or third party drivers or plugins. _But
|
||||
the Appium team makes the following recommendations in terms of the *capabilities* service
|
||||
providers support, for consistency across the industry._ This is a recommendation only, and not
|
||||
a standard, but adopting it will help users to navigate the increased complexity that working with
|
||||
Appium 2.0 in a cloud environment may bring.
|
||||
|
||||
### Suggested capabilities
|
||||
|
||||
In addition to the standard `platformName`, `appium:deviceName`, `appium:automationName`, and
|
||||
`appium:platformVersion`, we recommend adopting the capability `$cloud:appiumOptions`, where the
|
||||
label `$cloud` is not meant to be interpreted literally but instead should be replaced by your
|
||||
vendor prefix (so for HeadSpin it would be `headspin`, Sauce Labs it would be `sauce`, and
|
||||
BrowserStack it would be `browserstack`, to name just a few examples). The `$cloud:appiumOptions`
|
||||
capability would itself be a JSON object, with the following internal keys:
|
||||
|
||||
| Capability | Used for | Example |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| `version` | Designating which version of the Appium server is used to host and manage drivers. If ommitted, behavior left up to the provider, but the recommendation would be to provide the latest official version. | `2.0.0` |
|
||||
| `automationVersion` | Designating which version of the specified driver should be used. | `1.55.2` |
|
||||
| `automation` | Designating a custom driver to use (see below for more info). This would override `appium:automationName` and `$cloud:automationVersion` | `{"name": "@org/custom-driver", "source": "github", "package": "custom-driver"}` |
|
||||
| `plugins` | Designating the list of plugins (and potentially versions of plugins) to be activated (see below for more info). | `["images", "universal-xml"]` |
|
||||
|
||||
### Basic example
|
||||
|
||||
Appium extensions (drivers and plugins) have a set of properties that specify where they can be
|
||||
installed from. Cloud providers are obviously under no obligation to provide support for
|
||||
arbitrarily specified extensions, seeing as these may represent untrusted code running in a managed
|
||||
environment. In the case where arbitrary extensions are not supported, the `appium:automationName`,
|
||||
`$cloud:automationVersion`, and `$cloud:appiumPlugins` capabilities should be sufficient. See the
|
||||
following JSON object representing capabilities for a session:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:platformVersion": "14.4",
|
||||
"appium:deviceName": "iPhone 11",
|
||||
"appium:app": "Some-App.app.zip",
|
||||
"appium:automationName": "XCUITest",
|
||||
"$cloud:appiumOptions": {
|
||||
"appiumVersion": "2.0.0",
|
||||
"automationVersion": "3.52.0",
|
||||
"plugins": ["images"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This set of capabilities requests an Appium 2+ server supporting the XCUITest driver at version
|
||||
`3.52.0`, and the `images` plugin active. This set is easy for a cloud provider to verify. The
|
||||
cloud provider can obviously do anything it wants in response to these capabilities, including
|
||||
downloading Appium and driver and plugin packages on the fly, or erroring out if the versions
|
||||
requested are not in a supported set, or if the plugin is not supported, etc...
|
||||
|
||||
### Basic example with `appium:options`
|
||||
|
||||
The previous example still looks a bit disorganized, so of course we also recommend that cloud
|
||||
providers support the `appium:options` capability as detailed above, which could turn the previous
|
||||
set of capabilities into the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"appium:options": {
|
||||
"platformVersion": "14.4",
|
||||
"deviceName": "iPhone 11",
|
||||
"app": "Some-App.app.zip",
|
||||
"automationName": "XCUITest"
|
||||
},
|
||||
"$cloud:appiumOptions": {
|
||||
"appiumVersion": "2.0.0",
|
||||
"automationVersion": "3.52.0",
|
||||
"plugins": ["images"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Extension objects
|
||||
|
||||
Some service providers may wish to dynamically allow access to all of the features of the Appium
|
||||
2.0 CLI, including downloading arbitrary drivers and plugins. To represent these extensions, we can
|
||||
define special JSON "extension objects", with the following keys:
|
||||
|
||||
- `name`: the name of the extension. This would be an NPM package name (if downloading from NPM), or a git or GitHub spec (if downloading from a git server or GitHub).
|
||||
- `version`: the version of the extension, e.g., the NPM package version or Git SHA.
|
||||
- (optional) `source`: a denotation of where the extension can be downloaded from. Recommended to support the following values: `appium`, `npm`, `git`, `github`. Here, `appium` means "Appium's own official list", and should be the default value if this key is not included.
|
||||
- (optional) `package`: when downloading extensions from git or github, the NPM package name of the extension must also be provided. This is optional for non-git sources.
|
||||
|
||||
Since each session is handled by a single driver, the `$cloud:appiumOptions`/`$automation`
|
||||
capability could be used with an extension object value to denote this driver, for example:
|
||||
|
||||
```json
|
||||
{
|
||||
"$cloud:appiumOptions": {
|
||||
"automation": {
|
||||
"name": "git+https://some-git-host.com/custom-driver-project.git",
|
||||
"version": "some-git-sha",
|
||||
"source": "git",
|
||||
"package": "driver-npm-package-name"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And since sessions can handle multiple plugins, each value in the list of `$cloud:appiumPlugins`
|
||||
could also be an extension object rather than a string, so that specific versions could be
|
||||
requested:
|
||||
|
||||
```json
|
||||
{
|
||||
"$cloud:appiumOptions": {
|
||||
"plugins": [{
|
||||
"name": "images",
|
||||
"version": "1.1.0"
|
||||
}, {
|
||||
"name": "my-github-org/my-custom-plugin",
|
||||
"version": "a83f2e",
|
||||
"source": "github",
|
||||
"package": "custom-plugin"
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These serve as illustrative examples for the recommendations here. Of course it is up to the
|
||||
service providers to implement the handling of these capabilities at their front end / load
|
||||
balancer, to perform any error checking, or to actually run any of the `appium driver` or `appium
|
||||
plugin` CLI commands that support the end user's request. This section is merely a suggestion as to
|
||||
how service providers might design their user-facing capabilities API in a way which in principle
|
||||
supports all of the capabilities Appium itself would provide to the end user if they were running
|
||||
Appium on their own.
|
||||
@@ -1,95 +0,0 @@
|
||||
---
|
||||
title: The Appium Config File
|
||||
---
|
||||
|
||||
Instead of passing arguments on the command line to Appium, you may add them to a special config
|
||||
file. Appium will read values from this config file when it runs. (Please note that CLI arguments
|
||||
have _precedence_ over configuration files; if a value is set in a config file _and_ via CLI
|
||||
argument, the CLI argument is preferred.)
|
||||
|
||||
## Supported Config File Formats
|
||||
|
||||
You can store your config data in the following kinds of files:
|
||||
|
||||
- JSON
|
||||
- YAML
|
||||
- JS (a JavaScript file exporting a JS object)
|
||||
- CJS (the same as above; the extension is for common JS)
|
||||
|
||||
!!! warning
|
||||
|
||||
Note: Configuration files in ESM format are not currently supported.
|
||||
|
||||
## Supported Config File Locations
|
||||
|
||||
Configuration files can be named anything, but the following filenames will be automatically
|
||||
discovered and loaded by Appium:
|
||||
|
||||
- `.appiumrc.json` (recommended)
|
||||
- `.appiumrc.yaml`
|
||||
- `.appiumrc.yml`
|
||||
- `.appiumrc.js`
|
||||
- `.appiumrc.cjs`
|
||||
- `appium.config.js`
|
||||
- `appium.config.cjs`
|
||||
- `.appiumrc` (which is considered to be JSON)
|
||||
|
||||
Further, _if your project uses Node.js,_ you can use store the configuration inside an `appium` property in your `package.json` and it will be automatically discovered.
|
||||
|
||||
### Config File Search
|
||||
|
||||
Appium will search _up_ the directory tree from the current working directory for one of these
|
||||
files. If it reaches the current user's home directory or filesystem root, it will stop looking.
|
||||
|
||||
To specify a _custom_ location for your config file, use `appium --config-file /path/to/config/file`.
|
||||
|
||||
#### Configuration File Format
|
||||
|
||||
First, you might want to look at some examples:
|
||||
|
||||
- [Appium Configuration - JSON](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.json)
|
||||
- [Appium Configuration - YAML](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.yaml)
|
||||
- [Appium Configuration - JS](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.js)
|
||||
|
||||
A description of the format is available, as well:
|
||||
|
||||
- [Appium Configuration File JSON Schema](https://github.com/appium/appium/blob/master/packages/schema/lib/appium-config.schema.json)
|
||||
- [TypeScript declarations for Appium Configuration](https://github.com/appium/appium/blob/master/packages/types/lib/config.ts)
|
||||
|
||||
To describe in words, the config file will have a root `server` property, and all arguments are
|
||||
child properties. For certain properties which must be supplied on the command-line as comma-delimited lists, JSON strings, and/or external filepaths, these instead will be of their "native" type. For example,
|
||||
`--use-plugins <value>` needs `<value>` to be comma-delimited string or path to a delimited file.
|
||||
However, the config file just wants an array, e.g.,:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"use-plugins": ["my-plugin", "some-other-plugin"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuring extensions (drivers and plugins)
|
||||
|
||||
For `driver`-and-`plugin`-specific configuration, these live under the `server.driver` and
|
||||
`server.plugin` properties, respectively. Each driver or plugin will have its own named property,
|
||||
and the values of any specific configuration it provides are under this. For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"driver": {
|
||||
"xcuitest": {
|
||||
"webkit-debug-proxy-port": 5400
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
The above configuration corresponds to the `--driver-xcuitest-webkit-debug-proxy-port` CLI argument.
|
||||
|
||||
All properties are case-sensitive and will be in [kebab-case](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Delimiter-separated_words). For example, `callback-port` is
|
||||
allowed, but `callbackPort` is not.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: The Context API
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,71 +0,0 @@
|
||||
---
|
||||
title: The Event Timing API
|
||||
---
|
||||
|
||||
Appium comes with the ability to retrieve timing information about startup
|
||||
information and command length. This is an advanced feature that is controlled
|
||||
by the use of the `appium:eventTimings` capability (set it to `true` to log event
|
||||
timings).
|
||||
|
||||
With this capability turned on, the `GET /session/:id` response (i.e., the
|
||||
response to `driver.getSessionDetails()` or similar, depending on client) will
|
||||
be decorated with an `events` property. This is the structure of that `events`
|
||||
property:
|
||||
|
||||
```
|
||||
{
|
||||
"<event_type>": [<occurence_timestamp_1>, ...],
|
||||
"commands": [
|
||||
{
|
||||
"cmd": "<command_name>",
|
||||
"startTime": <js_timestamp>,
|
||||
"endTime": <js_timestamp>
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In other words, the `events` property has 2 kinds of properties of its own:
|
||||
|
||||
* Properties which are the names of event types
|
||||
* The `commands` property
|
||||
|
||||
Properties which are names of event types correspond to an array of timestamps
|
||||
when that event happened. It's an array because events might happen multiple
|
||||
times in the course of a session. Examples of event types include:
|
||||
|
||||
* `newSessionRequested`
|
||||
* `newSessionStarted`
|
||||
|
||||
(Individual drivers will define their own event types, so we do not have an
|
||||
exhaustive list to share here. It's best to actually get one of these responses
|
||||
from a real session to inspect the possible event types.)
|
||||
|
||||
The `commands` property is an array of objects. Each object has the name of the
|
||||
Appium-internal command (for example `click`), as well as the time the command
|
||||
started processing and the time it finished processing.
|
||||
|
||||
With this data, you can calculate the time between events, or a strict timeline
|
||||
of events, or statistical information about average length of a certain type of
|
||||
command, and so on.
|
||||
|
||||
You can only receive data about events that have happened when you make the
|
||||
call to `/session/:id`, so the best time to get data about an entire session is
|
||||
right before quitting it.
|
||||
|
||||
The Appium team maintains an event timings parser tool that can be used to
|
||||
generate various kinds of reports from event timings output:
|
||||
[appium/appium-event-parser](https://github.com/appium/appium-event-parser).
|
||||
|
||||
## Add a custom event
|
||||
|
||||
!!! warning "TODO"
|
||||
|
||||
The links to the commands in the following paragraph do not yet work since these docs are under
|
||||
construction.
|
||||
|
||||
You can add custom events that will show up in the event timings data. You can send a custom event
|
||||
name to the Appium server using the [Log Event API](#TODO), and the server will store the
|
||||
timestamp. The [Get Events](#TODO) command can be used to retrieve named events' timestamps later
|
||||
on.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Execute Script Overloads
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Appium and Selenium Grid
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Log Filtering
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Managing Appium Drivers and Plugins
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,217 +0,0 @@
|
||||
---
|
||||
title: Migrating from Appium 1.x to Appium 2.x
|
||||
---
|
||||
|
||||
This document is a guide for those who are using Appium 1.x and wish to migrate to Appium 2.x. It contains a list of breaking changes and how to migrate your environments or test suites to ensure compatibility with Appium 2.0.
|
||||
|
||||
## Overview of Appium 2.0
|
||||
|
||||
Appium 2.0 is the most major new release of Appium in over 5 years. The changes in Appium 2.0 are _not_ primarily related to changes in automation behaviors for specific platforms. Instead, Appium 2.0 reenvisions Appium as a _platform_ where "drivers" (code projects that introduce support for automation of a given platform) and "plugins" (code projects that allow for overriding, altering, extending, or adding behaviors to Appium) can be easily created and shared.
|
||||
|
||||
At the same time, the Appium project is taking the opportunity to remove many old and deprecated bits of functionality.
|
||||
|
||||
Together these do introduce a few breaking changes to how Appium is installed, how drivers and various features are managed, and protocol support. These are detailed below.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
Have a look at the [Appium 2.0 release notes](https://github.com/appium/appium/releases) for the most comprehensive lists of changes. Here we call out the breaking changes and what you need to do do account for them.
|
||||
|
||||
### :bangbang: Installing drivers during setup
|
||||
|
||||
When you installed Appium 1.x, all available drivers would be installed at the same time as the main Appium server. This is no longer the case. Simply installing Appium 2.0 (e.g., by `npm install -g appium@next`), will install the Appium server only, but no drivers. To install drivers, you must instead use the new [Appium extension CLI](../cli/extensions.md). For example, to install the latest versions of the XCUITest and UiAutomator2 drivers, after installing Appium you would run the following commands:
|
||||
|
||||
```
|
||||
appium driver install xcuitest
|
||||
appium driver install uiautomator2
|
||||
```
|
||||
|
||||
At this point, your drivers are installed and ready. There's a lot more you can do with this CLI so be sure to check out the docs on it.
|
||||
If you're running in a CI environment or want to install Appium along with some drivers all in one step, you can do so using some special flags during install, for example:
|
||||
|
||||
```
|
||||
npm install --global appium --drivers=xcuitest,uiautomator2
|
||||
```
|
||||
|
||||
This will install Appium and the two drivers for you in one go.
|
||||
|
||||
### :bangbang: Chromedriver installation flags
|
||||
|
||||
In Appium 1.x it was possible to customize the way Chromedriver was installed (as part of the UiAutomator2 driver for example), using the following command line flags:
|
||||
|
||||
* `--chromedriver-skip-install`
|
||||
* `--chromedriver-version`
|
||||
* `--chromedriver-cdnurl`
|
||||
|
||||
Because Appium 2.0 now installs drivers for you, and because these flags were implemented as NPM config flags, they will no longer work. Instead, use the following environment variables during driver installation:
|
||||
|
||||
* `APPIUM_SKIP_CHROMEDRIVER_INSTALL`
|
||||
* `CHROMEDRIVER_VERSION`
|
||||
* `CHROMEDRIVER_CDNURL`
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
APPIUM_SKIP_CHROMEDRIVER_INSTALL=1 appium driver install uiautomator2
|
||||
```
|
||||
|
||||
### :bangbang: Driver-specific command line options
|
||||
|
||||
With Appium 1.x, command-line options specific to particular drivers were all hosted on the main Appium server. So, for example, `--chromedriver-executable` was a CLI parameter you could use with Appium to set the location of a specific Chromedriver version for use with, say, the UiAutomator2 driver.
|
||||
|
||||
With Appium 2.x, all driver- and platform-specific CLI params have been moved to the drivers themselves. To access them, you'll now need to prepend the argument with the extension type (either `driver` or `plugin`) and the name of the extension. For example, `--chromedriver-executable` becomes `--driver-uiautomator2-chromedriver-executable`.
|
||||
|
||||
### :bangbang: Driver-specific automation commands
|
||||
|
||||
The definition of certain commands that pertain only to specific drivers has been moved to those
|
||||
drivers' implementations. For example, `pressKeyCode` is specific to the UiAutomator2 driver and is
|
||||
now understood only by that driver. In practice, the only breaking change here is the kind of error
|
||||
you would encounter if the appropriate driver is not installed. Previously, you would get a `501
|
||||
Not Yet Implemented` error if using a driver that didn't implement the command. Now, you will get
|
||||
a `404 Not Found` error because if a driver that doesn't know about the command is not active, the
|
||||
main Appium server will not define the route corresponding to the command.
|
||||
|
||||
### :bangbang: Driver updates
|
||||
|
||||
In the past, to get updates to your iOS or Android drivers, you'd simply wait for those updates to be rolled into a new release of Appium, and then update your Appium version. With Appium 2.x, the Appium server and the Appium drivers are versioned and released separately. This means that drivers can be on their own release cadence and that you can get driver updates as they happen, rather than waiting for a new Appium server release. The way to check for driver updates is with the CLI:
|
||||
|
||||
```bash
|
||||
appium driver list --updates
|
||||
```
|
||||
|
||||
If any updates are available, you can then run the `update` command for any given driver:
|
||||
|
||||
```bash
|
||||
appium driver update xcuitest
|
||||
```
|
||||
|
||||
(For a complete description of the update command, check out the [Extension
|
||||
CLI](../cli/extensions.md) doc)
|
||||
|
||||
To update the Appium server itself, you do the same thing as in the past: `npm install -g appium`. Now, installing new versions of the Appium server will leave your drivers intact, so the whole process will be much more quick.
|
||||
|
||||
### :bangbang: Protocol changes
|
||||
|
||||
Appium's API is based on the [W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/), and it has supported this protocol for years. Before the W3C WebDriver Protocol was designed as a web standard, several other protocols were used for both Selenium and Appium. These protocols were the "JSONWP" (JSON Wire Protocol) and "MJSONWP" (Mobile JSON Wire Protocol). The W3C Protocol differs from the (M)JSONWP protocols in a few small ways.
|
||||
|
||||
Up until Appium 2.0, Appium supported both protocols, so that older Selenium/Appium clients could still communicate with newer Appium servers. Moving forward, support for older protocols will be removed.
|
||||
|
||||
### :bangbang: _Capabilities_
|
||||
|
||||
One significant difference between old and new protocols is in the format of capabilities. Previously called "desired capabilities", and now called simply "capabilities", there is now a requirement for a so-called "vendor prefix" on any non-standard capabilities. The list of standard capabilities is given in the [WebDriver Protocol spec](https://www.w3.org/TR/webdriver/#capabilities), and includes a few commonly used capabilities such as `browserName` and `platformName`.
|
||||
|
||||
These standard capabilities continue to be used as-is. All other capabilities must include a "vendor prefix" in their name. A vendor prefix is a string followed by a colon, such as `appium:`. Most of Appium's capabilities go beyond the standard W3C capabilities and must therefore include vendor prefixes (we recommend that you use `appium:` unless directed otherwise by documentation). For example:
|
||||
|
||||
- `appium:app`
|
||||
- `appium:noReset`
|
||||
- `appium:deviceName`
|
||||
|
||||
This requirement may or may not be a breaking change for your test suites when targeting Appium 2.0. If you're using an updated Appium client, the client will add the `appium:` prefix for you on all necessary capabilities. New versions of the Appium Inspector tool will also do this. Cloud-based Appium providers may also do this. So simply be aware that if you get any messages to the effect that your capabilities lack a vendor prefix, this is how you solve that problem.
|
||||
|
||||
On a related note, it will no longer be possible to start Appium sessions using WebDriver clients that don't support the W3C protocol (see below for a comment to this effect for the WD library).
|
||||
|
||||
To make everyone's lives a bit easier, we've also introduced the option of wrapping up all Appium-related capabilities into one object capability, `appium:options`. You can bundle together anything that you would normally put an `appium:` prefix on into this one capability. Here's an example (in raw JSON) of how you might start an iOS session on the Safari browser using `appium:options`:
|
||||
|
||||
```json
|
||||
{
|
||||
"platformName": "iOS",
|
||||
"browserName": "Safari",
|
||||
"appium:options": {
|
||||
"platformVersion": "14.4",
|
||||
"deviceName": "iPhone 11",
|
||||
"automationName": "XCUITest"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(Of course, each client will have a different way of creating structured capabilities like `appium:options` or other ones that you might have seen such as `goog:chromeOptions`). NB: capabilities that show up in `appium:options` will overwrite capabilities of the same name that show up at the top level of the object.
|
||||
|
||||
For more information on capabilities, have a look at the [Capabilities Guide](caps.md).
|
||||
|
||||
### :bangbang: _Removed Commands_
|
||||
|
||||
In addition to commands which have been moved to driver implementations, commands which were a part of the old JSON Wire Protocol and not a part of the W3C Protocol are no longer available:
|
||||
|
||||
- TODO (these commands are being identified and removed and will be updated here when complete)
|
||||
|
||||
If you use a modern Appium or Selenium client, you should no longer have access to these anyway, so any breaking changes should appear on the client side first and foremost.
|
||||
|
||||
### :bangbang: Image analysis features moved to plugin
|
||||
|
||||
One of the design goals for Appium 2.0 is to migrate non-core features into special extensions called [plugins](../ecosystem/index.md). This allows people to opt into features which require extra time to download or extra system setup. The various image-related features of Appium (image comparison, finding elements by image, etc...) have been moved into an officially supported plugin called [images](https://github.com/appium/appium/tree/master/packages/images-plugin).
|
||||
|
||||
If you use these image-related methods, to continue accessing them you will need to do two things.
|
||||
|
||||
1. Install the plugin: `appium plugin install images`
|
||||
2. Ensure you start the Appium server with access to run the plugin by including it in the list of plugins designated on the command line, e.g., `appium --use-plugins=images`
|
||||
|
||||
Image-related commands will also be removed on the client side of things, which means you will need to follow the instructions on the plugin README for installing client-side plugins to access these features.
|
||||
|
||||
### :bangbang: Execute Driver Script command moved to plugin
|
||||
|
||||
If you use the advanced Execute Driver Script feature (which allows you to send in a WebdriverIO script to have it executed completely on the server instead of command-by-command from the client), this functionality has been moved to a plugin. Here's what to do to keep using it:
|
||||
|
||||
1. Install the plugin: `appium plugin install execute-driver`
|
||||
2. Ensure you start the Appium server with access to run the plugin by including it in the list of plugins designated on the command line, e.g., `appium --use-plugins=execute-driver`
|
||||
|
||||
### :bangbang: External Files No Longer Supported for `--nodeconfig`, `--default-capabilities`, `--allow-insecure` and `--deny-insecure`
|
||||
|
||||
These options can be provided as strings on the command line (a JSON string for `--nodeconfig` and a comma-separated list of strings for `--allow-insecure` and `--deny-insecure`). Arguments provided on the command line will likely need to be quoted or escaped.
|
||||
|
||||
The recommended method to provide these options is now via a [configuration file](#tada-configuration-files).
|
||||
|
||||
In summary, if you are using a JSON Appium config file, you can simply cut-and-paste the contents of your "nodeconfig" JSON file into the value of the `server.nodeconfig` property. Any CSV-like files you had previously provided for `--allow-insecure` and `--deny-insecure` become the values of the `server.allow-insecure` and `server.deny-insecure` properties in the Appium config files (respectively); both are arrays of strings.
|
||||
|
||||
### :bangbang: Old drivers removed
|
||||
|
||||
The old iOS and Android (UiAutomator 1) drivers and related tools (e.g., `authorize-ios`) have been removed. They haven't been relevant for many years anyway.
|
||||
|
||||
### :warning: Internal packages renamed
|
||||
|
||||
Some Appium-internal NPM packages have been renamed (for example, `appium-base-driver` is now `@appium/base-driver`). This is not a breaking change for Appium users, only for people who have built software that directly incorporates Appium's code.
|
||||
|
||||
### :warning: "WD" JavaScript client library no longer supported
|
||||
|
||||
For many years, some of Appium's authors maintained the [WD](https://github.com/admc/wd) client library. This library has been deprecated and has not been updated for use with the W3C WebDriver protocol. As such, if you're using this library you'll need to move to a more modern one. We recommend [WebdriverIO](https://webdriver.io).
|
||||
|
||||
### :warning: Appium Inspector split out from Appium Desktop
|
||||
|
||||
The inspecting portion of Appium Desktop has been moved to its own app, Appium Inspector: [github.com/appium/appium-inspector](https://github.com/appium/appium-inspector). It's fully compatible with Appium 2.0 servers. Simply download it and run it on its own. You no longer need the GUI Appium Desktop server to inspect apps. The Appium Desktop server will continue to be supported at its original site: [github.com/appium/appium-desktop](https://github.com/appium/appium-desktop). It will simply no longer bundle the Inspector with it.
|
||||
|
||||
You can also now use the Appium Inspector without downloading anything, by visiting the [web version of Appium Inspector](https://inspector.appiumpro.com). Note that to test against local servers, you'll need to start the server with `--allow-cors` so that the browser-based version of Appium Inspector can access your Appium server to start sessions.
|
||||
|
||||
## Major New Features
|
||||
|
||||
Apart from the breaking changes mentioned above, in this section is a list of some of the major new features you may wish to take advantage of with Appium 2.0.
|
||||
|
||||
### Plugins
|
||||
|
||||
#### :tada: _Server Plugins_
|
||||
|
||||
Appium extension authors can now develop their own server plugins, which can intercept and modify
|
||||
any Appium command, or even adjust the way the underlying Appium HTTP server itself works. To learn
|
||||
more about plugins, read the new [Appium Introduction](../intro/index.md). Interested in building
|
||||
a plugin? Check out the [Building Plugins](../ecosystem/build-plugins.md) guide.
|
||||
|
||||
#### :tada: _Client Plugins_
|
||||
|
||||
TODO
|
||||
|
||||
### :tada: Install drivers and plugins from anywhere
|
||||
|
||||
You're no longer limited to the drivers that come with Appium, or that the Appium team even knows
|
||||
about! Appium extension authors can now develop custom drivers, which can be downloaded or
|
||||
installed via Appium's [Extension CLI](../cli/extensions.md) from NPM, Git, GitHub, or even the
|
||||
local filesystem. Interested in building a driver? Check out the [Building
|
||||
Drivers](../ecosystem/build-drivers.md) guide.
|
||||
|
||||
### :tada: Configuration Files
|
||||
|
||||
Appium now supports _configuration files_ in addition to command-line arguments. In a nutshell, nearly all arguments which Appium 1.x required to be provided on the CLI are now able to be expressed via a configuration file. Configuration files may be in JSON, JS, or YAML format. See the [Config Guide](config.md) for a full explanation.
|
||||
|
||||
## Special Notes for Cloud Providers
|
||||
|
||||
The rest of this document has applied to Appium generally, but some of the architectural changes in Appium 2.0 will constitute breaking changes for Appium-related service providers, whether a cloud-based Appium host or an internal service. At the end of the day, the maintainer of the Appium server is responsible for installing and making available the various Appium drivers and plugins that end users may wish to use.
|
||||
|
||||
We encourage cloud providers to thoroughly read and understand our [recommendation for cloud
|
||||
provider capabilities](caps.md#special-notes-for-cloud-providers) in order to support user needs in
|
||||
an industry-compatible way!
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Appium Server Security
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: The Settings API
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -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 >= 14
|
||||
* [NPM](https://npmjs.com) version >= 8 (NPM is usually bundled with Node.js, but can be upgraded
|
||||
independently)
|
||||
|
||||
By itself, Appium is relatively lightweight and doesn't have significant disk space or RAM
|
||||
requirements. It can even be run in resource-constrained environments like Raspberry Pi, so long as
|
||||
Node.js is available.
|
||||
|
||||
To use Appium to automate a particular platform, please refer to the documentation of the [Appium
|
||||
driver(s)](../ecosystem/index.md#drivers) for that platform for additional dependencies. It is
|
||||
almost universally the case that Appium drivers for a given platform will require the developer
|
||||
toolchain and SDKs for that platform to be available.
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
title: Quickstart Intro
|
||||
---
|
||||
|
||||
Let's get up and running with Appium! To successfully use this quickstart, it's recommended that
|
||||
you first have read the [Introduction](../intro), so that you understand the concepts involved in
|
||||
running Appium and writing Appium scripts.
|
||||
|
||||
The basic plan for this quickstart is as follows:
|
||||
|
||||
1. Install Appium
|
||||
1. Install an Appium driver and its dependencies (we'll be using the [UiAutomator2
|
||||
driver](https://github.com/appium/appium-uiautomator2-driver) for these examples)
|
||||
1. Install an Appium client library in your language or choice (this guide contains options for
|
||||
JavaScript, Python, and Java, though [Appium clients](../ecosystem/index.md#clients) also exist in other language).
|
||||
1. Write and run a simple Appium automation script using a sample application
|
||||
|
||||
### Requirements
|
||||
|
||||
Before getting started, make sure your system satisfies the
|
||||
[requirements](../intro/requirements.md) for running the Appium server. Additional requirements
|
||||
will be discussed in conjunction with installing the UiAutomator2 driver. The guide also assumes
|
||||
you're basic command line proficiency on your platform, for example being able to run commands, set
|
||||
and persist environment variables, etc...
|
||||
|
||||
Now you're ready to get started! So head on over to [Installing Appium](./install.md).
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
title: Install Appium
|
||||
---
|
||||
|
||||
Installing Appium is as easy as running a single NPM command:
|
||||
|
||||
```bash
|
||||
npm i -g appium@next
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
Currently, you must use `appium@next` instead of just `appium`. Once Appium 2.0 has been
|
||||
officially published, you can simply use `appium`.
|
||||
|
||||
This command installs Appium globally on your system so that you can access it from the command
|
||||
line simply by running the `appium` command. Go ahead and run it now:
|
||||
|
||||
```
|
||||
appium
|
||||
```
|
||||
|
||||
You should see some output that starts with a line like this:
|
||||
|
||||
```
|
||||
[Appium] Welcome to Appium v2.0.0
|
||||
```
|
||||
|
||||
That's it! If you get this kind of output, the Appium server is up and running. Go ahead and quit
|
||||
it (CTRL-C) and move on to the next step, where we'll install a driver for automating Android apps.
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
title: Next Steps
|
||||
---
|
||||
|
||||
Now that you've successfully set up your system for Android automation and run a simple test,
|
||||
you'll want to continue exploring this documentation. In particular, these are good guides and
|
||||
reference materials especially for beginners:
|
||||
|
||||
- [Managing Appium Drivers and Plugins](../guides/managing-exts.md)
|
||||
- [Capabilities](../guides/caps.md)
|
||||
- The list of available [Drivers and Plugins](../ecosystem/index.md)
|
||||
|
||||
You'll also find that the [Appium Inspector](https://github.com/appium/appium-inspector) is an
|
||||
indispensable tool for use in Appium test-writing, as it enables visual inspection of apps and
|
||||
helps you to discover element locators for use in your test scripts.
|
||||
|
||||
You might also take advantage of one of the many online Appium courses available to you.
|
||||
|
||||
Good luck and have fun!
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Write a Test (Java)
|
||||
---
|
||||
|
||||
TODO
|
||||
@@ -1,68 +0,0 @@
|
||||
---
|
||||
title: Write a Test (JS)
|
||||
---
|
||||
|
||||
To write an Appium test in JavaScript (Node.js), we need to choose an Appium-compatible client
|
||||
library. The best-maintained library and the one the Appium team recommends using is
|
||||
[WebdriverIO](https://webdriver.io), so let's use that. Since we already have Appium installed we
|
||||
know our Node and NPM requirements are already satisfied. So just create a new project directory
|
||||
somewhere on your computer and then initialize a new Node.js project in it:
|
||||
|
||||
```bash
|
||||
npm init
|
||||
```
|
||||
|
||||
It doesn't really matter what you put in the prompts, just so long as you end up with a valid
|
||||
`package.json`.
|
||||
|
||||
|
||||
Now, install the `webdriverio` package via NPM:
|
||||
|
||||
```bash
|
||||
npm i --save-dev webdriverio
|
||||
```
|
||||
|
||||
Once this is done, your `package.json` file should include a section like the following:
|
||||
|
||||
```json title="package.json"
|
||||
--8<-- "./sample-code/quickstarts/js/package.json"
|
||||
```
|
||||
|
||||
Now it's time to type up the test itself. Create a new file called `test.js` with the following
|
||||
contents:
|
||||
|
||||
```js title="test.js"
|
||||
--8<-- "./sample-code/quickstarts/js/test.js"
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
It's not within the scope of this guide to give a complete run-down on the WebdriverIO client
|
||||
library or everything that's happening here, so we'll leave the code itself unexplained in
|
||||
detail for now. You may want to read up particularly on Appium
|
||||
[Capabilities](../guides/caps.md) in addition to familiarizing yourself with the excellent
|
||||
[WebdriverIO documentation](https://webdriver.io/docs/gettingstarted) for a fuller explanation
|
||||
of the various API commands you see and what their purpose is.
|
||||
|
||||
Basically, this code is doing the following:
|
||||
|
||||
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
|
||||
kind of thing you want to automate.
|
||||
1. Starting an Appium session on the built-in Android settings app.
|
||||
1. Finding the "Battery" list item and clicking it.
|
||||
1. Pausing for a moment purely for visual effect.
|
||||
1. Ending the Appium session.
|
||||
|
||||
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
|
||||
running in another terminal session, otherwise you'll get an error about not being able to connect
|
||||
to one. Then, you can execute the script:
|
||||
|
||||
```bash
|
||||
node test.js
|
||||
```
|
||||
|
||||
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the
|
||||
app closes again.
|
||||
|
||||
Congratulations, you've started your Appium journey! Read on for some next steps to explore.
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
title: Write a Test (Python)
|
||||
---
|
||||
|
||||
The [Appium Python Client](https://github.com/appium/python-client) is
|
||||
an official Appium client in Python, which is available via pypi under the [Appium-Python-Client](https://pypi.org/project/Appium-Python-Client/) package name.
|
||||
It inherits from the [Selenium Python Binding](https://pypi.org/project/selenium/),
|
||||
so installing the Appium Python Client includes the selenium binding.
|
||||
|
||||
```bash
|
||||
pip install Appium-Python-Client
|
||||
```
|
||||
|
||||
This example uses Python's built-in `unittest` module, though you can use any Python test framework you want.
|
||||
The Appium Python client adds the `appium:` vendor prefix automatically.
|
||||
You usually do not need to worry about the prefix.
|
||||
|
||||
```python title="test.py"
|
||||
--8<-- "./sample-code/quickstarts/py/test.py"
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
It's not within the scope of this guide to give a complete run-down on the Python client
|
||||
library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.
|
||||
- You may want to read up particularly on Appium [Capabilities](../guides/caps.md).
|
||||
- [functional test code](https://github.com/appium/python-client/tree/master/test/functional) in Python Client GitHub repository should help to find more working example.
|
||||
- [Documentation](https://appium.github.io/python-client-sphinx/) also helps to find methods
|
||||
defined in the Appium Python Client.
|
||||
|
||||
Basically, this code is doing the following:
|
||||
|
||||
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
|
||||
kind of thing you want to automate.
|
||||
1. Starting an Appium session on the built-in Android settings app.
|
||||
1. Finding the "Battery" list item and clicking it.
|
||||
1. Pausing for a moment purely for visual effect.
|
||||
1. Ending the Appium session.
|
||||
|
||||
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
|
||||
running in another terminal session, otherwise you'll get an error about not being able to connect
|
||||
to one. Then, you can execute the script:
|
||||
|
||||
```bash
|
||||
python test.py
|
||||
```
|
||||
|
||||
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the
|
||||
app closes again.
|
||||
|
||||
Congratulations, you've started your Appium journey! Read on for some next steps to explore.
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
title: Write a Test (Ruby)
|
||||
---
|
||||
|
||||
|
||||
The [AppiumLib](https://github.com/appium/ruby_lib) and the [AppiumLibCore](https://github.com/appium/ruby_lib_core) are Appium officcial client libraries in Ruby, which are available via gem under the [appium_lib](https://rubygems.org/gems/appium_lib) and the [appium_lib_core](https://rubygems.org/gems/appium_lib_core) package names. The appium_lib_core inherits from the Selenium Ruby Binding, and the appium_lib inherits from the appium_lib_core, so intalling these libraries include the selenium binding.
|
||||
|
||||
```bash
|
||||
gem install appium_lib
|
||||
# or
|
||||
gem install appium_lib_core
|
||||
```
|
||||
|
||||
The `appium_lib_core` is the main part as an Appium client.
|
||||
`appium_lib` has various helper methods, but the driver instance was ordinally designed to be used as a global variable. It could causes an issue to handle the instance.
|
||||
`appium_lib_core` does not have such a global variable.
|
||||
|
||||
This example is by the `appium_lib_core` with `test-unit` gem module.
|
||||
Tes code in `appium_lib` should be similar.
|
||||
|
||||
```python title="test.py"
|
||||
--8<-- "./sample-code/quickstarts/rb/test.rb"
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
It's not within the scope of this guide to give a complete run-down on the Ruby client
|
||||
library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.
|
||||
|
||||
- You may want to read up particularly on Appium [Capabilities](../guides/caps.md).
|
||||
- [functional test code](https://github.com/appium/ruby_lib_core/tree/master/test/functional) in the appium_lib_core GitHub repository should help to find more working example.
|
||||
- Documentation [appium_lib_core](https://www.rubydoc.info/github/appium/ruby_lib_core) and [appium_lib](https://www.rubydoc.info/github/appium/ruby_lib) also helps to find avvailable methods.
|
||||
|
||||
|
||||
Basically, this code is doing the following:
|
||||
|
||||
1. Defining a set of "Capabilities" (parameters) to send to the Appium server so Appium knows what
|
||||
kind of thing you want to automate.
|
||||
1. Starting an Appium session on the built-in Android settings app.
|
||||
1. Finding the "Battery" list item and clicking it.
|
||||
1. Pausing for a moment purely for visual effect.
|
||||
1. Ending the Appium session.
|
||||
|
||||
That's it! Let's give it a try. Before you run the test, make sure that you have an Appium server
|
||||
running in another terminal session, otherwise you'll get an error about not being able to connect
|
||||
to one. Then, you can execute the script:
|
||||
|
||||
```bash
|
||||
bundle install
|
||||
bundle exec ruby test.rb
|
||||
```
|
||||
|
||||
If all goes well, you'll see the Settings app open up and navigate to the "Battery" view before the
|
||||
app closes again.
|
||||
|
||||
Congratulations, you've started your Appium journey! Read on for some next steps to explore.
|
||||
@@ -1,99 +0,0 @@
|
||||
---
|
||||
title: Install the UiAutomator2 Driver
|
||||
---
|
||||
|
||||
You can't do much with Appium unless you have a [driver](../intro/drivers.md), which is an
|
||||
interface that allows Appium to automate a particular platform.
|
||||
|
||||
!!! info
|
||||
|
||||
For this quickstart guide, we're going to be automating an app on the Android platform, because
|
||||
the system requirements for Android automation via Appium are the same as for Appium itself
|
||||
(whereas the iOS driver, for example, requires you to be using macOS).
|
||||
|
||||
The driver we're going to use is called the [UiAutomator2
|
||||
Driver](https://github.com/appium/appium-uiautomator2-driver). It's worth visiting that driver's
|
||||
documentation and bookmarking it, because it will be an invaluable reference down the line.
|
||||
|
||||
## Set up Android automation requirements
|
||||
|
||||
According to the driver, in addition to a working Appium server, we also need to do the following:
|
||||
|
||||
- Download [Android SDK platform tools](https://developer.android.com/studio/releases/platform-tools). You will probably want to download [Android Studio](https://developer.android.com/studio) and manage the SDK tools from within it for the easiest experience.
|
||||
- Set an environment variable pointing to the directory on disk where the Android tools are
|
||||
installed. You can usually find the path to this directory in the Android Studio SDK manager. It
|
||||
will contain the `platform-tools` and other directories. We need to define and persist the
|
||||
environment variable as `ANDROID_HOME` (or alternatively `ANDROID_SDK_ROOT`).
|
||||
- Use the Android SDK manager to download whichever Android platform we want to automate (for
|
||||
example, API level 30)
|
||||
- Install the Java JDK (for the most recent Android API levels, JDK 9 is required, otherwise JDK
|
||||
8 is required). It's easiest to use the [OpenJDK packages](https://openjdk.java.net/install/). Make
|
||||
sure you get the JDK and not the JRE.
|
||||
- When the JDK is installed, you'll need to find the path to the JDK home directory as it was
|
||||
installed on your system. This will be the directory that *contains* the `bin`, `include`, and
|
||||
other directories. The path must be persisted as an environment variable named `JAVA_HOME`, so that
|
||||
Appium can find the appropriate Java tooling that is required to work with the Android platform.
|
||||
- Use Android Studio to create and launch an Android Virtual Device (an AVD, otherwise known as an
|
||||
emulator). You may need to download the system images for the API level of the emulator you want to
|
||||
create. Using the AVD creation wizard in Android Studio is generally the easiest way to do all of
|
||||
this.
|
||||
|
||||
!!! note
|
||||
|
||||
You can also use a physical Android device, so long as it is configured for debugging and
|
||||
development
|
||||
|
||||
- With the emulator or device connected, you can run `adb devices` (via the binary located at
|
||||
`$ANDROID_HOME/platform-tools/adb`) to verify that your device shows up as connected.
|
||||
|
||||
Once your device shows up as connected in ADB, and you've verified that the environment variables
|
||||
are set up correctly in the terminal context where you are going to run Appium, you should be good
|
||||
to go! If you ran into problems with any of these steps, refer to the driver documentation, or the
|
||||
various Android or Java documentation sites as necessary.
|
||||
|
||||
Also, congratulations: whether or not you intended to, you now have the Android developer toolchain
|
||||
set up on your system, so you can get busy making Android apps if you want!
|
||||
|
||||
## Install the driver itself
|
||||
|
||||
Since the UiAutomator2 driver is maintained by the core Appium team, it has an 'official' driver
|
||||
name that you can use to install it easily via the [Appium Extension CLI](../cli/extensions.md):
|
||||
|
||||
```bash
|
||||
appium driver install uiautomator2
|
||||
```
|
||||
|
||||
It should produce output that looks something like:
|
||||
|
||||
```
|
||||
Attempting to find and install driver 'uiautomator2'
|
||||
✔ Installing 'uiautomator2' using NPM install spec 'appium-uiautomator2-driver'
|
||||
Driver uiautomator2@2.0.5 successfully installed
|
||||
- automationName: UiAutomator2
|
||||
- platformNames: ["Android"]
|
||||
```
|
||||
|
||||
Running this command will locate and install the latest version of the UiAutomator2 driver, making
|
||||
it available for automation. Note that when it is installed it tells you what platforms it is valid
|
||||
for (in this case, `Android`), and what automation name (the `appium:automationName`
|
||||
[capability](../guides/caps.md)) must be used to select this driver for use during an Appium
|
||||
session (in this case, `UiAutomator2`).
|
||||
|
||||
!!! note
|
||||
|
||||
In this quickstart we have used the Extension CLI to install the UiAutomator2 driver, but if you
|
||||
are incorporating Appium into a Node.js project, you might prefer to use NPM to manage Appium
|
||||
and its connected drivers. To learn more about this technique, visit the guide on [managing
|
||||
Appium extensions](../guides/managing-exts.md).
|
||||
|
||||
Now, start the Appium server again (run `appium`), and you should see that the newly-installed
|
||||
driver is listed as available:
|
||||
|
||||
```
|
||||
[Appium] Available drivers:
|
||||
[Appium] - uiautomator2@2.0.5 (automationName 'UiAutomator2')
|
||||
```
|
||||
|
||||
With the Android setup complete and the UiAutomator2 driver installed, you're ready to write your
|
||||
first test! So pick the language you're most comfortable with under the quickstart menu and give it
|
||||
a shot.
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
title: Additional Resources
|
||||
---
|
||||
|
||||
Here you can find links to additional Appium resources around the web:
|
||||
|
||||
## Websites
|
||||
|
||||
- [Appium Pro](https://appiumpro.com) - a blog and newsletter written by one of Appium's
|
||||
maintainers, Jonathan Lipps, with lots of useful guides
|
||||
|
||||
## Online Courses
|
||||
|
||||
- [Appium and Selenium Fundamentals](https://ui.headspin.io/university/learn/appium-selenium-fundamentals-2020) - a comprehensive video course on learning Python, Selenium, and Appium by Jonathan Lipps
|
||||
- [Mobile Test Automation with Appium](https://testautomationu.applitools.com/appium-java-tutorial/) - a video course by Moataz Nabil
|
||||
- [Advanced Appium](https://www.linkedin.com/learning/advanced-appium) - a video course by Jonathan Lipps
|
||||
@@ -1,23 +0,0 @@
|
||||
## Appium サーバーをサポートしているクライアントライブラリの一覧
|
||||
|
||||
これらのライブラリは、標準の Selenium クライアントライブラリをラップして、[JSON Wire プロトコル](https://w3c.github.io/webdriver/webdriver-spec.html) によって指定されたすべての通常の Selenium コマンドを提供し、**マルチタッチジェスチャー** や **画面の向き** などのモバイルデバイスの制御に関連した追加コマンドを追加します。
|
||||
|
||||
Appium クライアントライブラリは、[Mobile JSON Wire プロトコル](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) (標準プロトコルの公式ドラフト拡張) と、[W3C Webdriver 仕様](https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html) (トランスポートに依存しない自動化仕様。ここでは MultiAction API が定義されています) の要素を実装しています。
|
||||
|
||||
Appium サーバー自体が公式プロトコルへのカスタム拡張を定義しており、Appium ユーザーに様々なデバイスの動作 (テストセッションの途中でアプリをインストール/アンインストールするなど) を実現する便利な入り口を提供します。これが、「素」な Selenium クライアントだけでなく、Appium 固有のクライアントが必要な理由です。もちろん、Appium クライアントライブラリは機能を**追加**するだけなので (実際には、標準の Selenium クライアントを拡張するだけです)、通常の Selenium セッションに使用できます。
|
||||
|
||||
言語/フレームワーク | Github のリポジトリとインストール手順 |
|
||||
----- | ----- |
|
||||
Ruby | [https://github.com/appium/ruby_lib](https://github.com/appium/ruby_lib), [https://github.com/appium/ruby_lib_core](https://github.com/appium/ruby_lib_core)
|
||||
Python | [https://github.com/appium/python-client](https://github.com/appium/python-client)
|
||||
Java | [https://github.com/appium/java-client](https://github.com/appium/java-client)
|
||||
C# (.NET) | [https://github.com/appium/appium-dotnet-driver](https://github.com/appium/appium-dotnet-driver)
|
||||
|
||||
### Community based
|
||||
|
||||
言語/フレームワーク | Github のリポジトリとインストール手順 |
|
||||
----- | ----- |
|
||||
JavaScript (Node.js) | [https://github.com/admc/wd](https://github.com/admc/wd)
|
||||
JavaScript (Node.js) | [https://github.com/webdriverio/webdriverio](https://github.com/webdriverio/webdriverio)
|
||||
JavaScript (Browser) | [https://github.com/projectxyzio/web2driver](https://github.com/projectxyzio/web2driver)
|
||||
RobotFramework | [https://github.com/serhatbolsu/robotframework-appiumlibrary](https://github.com/serhatbolsu/robotframework-appiumlibrary)
|
||||
@@ -1,274 +0,0 @@
|
||||
## はじめに
|
||||
|
||||
このドキュメントでは、簡単な Appium テストを実施して、
|
||||
Appium の基本的な考え方をご紹介します。
|
||||
Appium の概念をより包括的に紹介するためには、[概念的な紹介](/docs/ja/about-appium/intro.md)をご覧ください。
|
||||
|
||||
### Appium のインストール
|
||||
|
||||
Appium は、[NPM](https://npmjs.com) 経由でインストールするか、
|
||||
Appium サーバーを起動するためのグラフィカルなデスクトップベースの方法である [Appium Desktop](https://github.com/appium/appium-desktop) をダウンロードする
|
||||
2つの方法のいずれかでインストールすることができます。
|
||||
|
||||
#### NPM 経由でのインストール
|
||||
|
||||
`npm install` で Appium を実行したり、Appium でハックしたり、Appium に貢献したりするには、
|
||||
[Node.js と NPM](http://nodejs.org) が必要です
|
||||
(Node.js をインストールするには、
|
||||
[nvm](https://github.com/creationix/nvm)、[n](https://github.com/visionmedia/n)、`brew install node` を使用してください。
|
||||
`sudo` で Node や Appium をインストールしていないことを確認してください)。
|
||||
Appium は Node 10+ をサポートしていますが、
|
||||
最新の安定版を推奨します。
|
||||
|
||||
実際のインストールはこんな感じで簡単です。
|
||||
|
||||
```
|
||||
npm install -g appium
|
||||
```
|
||||
|
||||
#### デスクトップアプリのダウンロードからのインストール
|
||||
|
||||
[リリースページ](https://github.com/appium/appium-desktop/releases)から
|
||||
Appium Desktop の最新版をダウンロードするだけです。
|
||||
|
||||
### ドライバー固有の設定
|
||||
|
||||
iOS や Android アプリケーションのように、
|
||||
特定のものを自動化するために Appium を使用したいと思うでしょう。
|
||||
特定のプラットフォームの自動化のサポートは、Appium の「ドライバ」によって提供されます。
|
||||
さまざまな種類の自動化技術へのアクセスを提供するこのようなドライバは多数あり、
|
||||
それぞれが各々のセットアップ要件を持っています。
|
||||
これらの要件のほとんどは、特定のプラットフォームでのアプリ開発と同じ要件です。
|
||||
例えば、Android ドライバを使用して Android アプリケーションを自動化するには、
|
||||
お使いのシステム上で設定された Android SDK が必要です。
|
||||
|
||||
ある時点で、自動化したいプラットフォームのドライバのドキュメントを確認して、
|
||||
システムが正しくセットアップされていることを確認してください。
|
||||
|
||||
- [XCUITest Driver](/docs/en/drivers/ios-xcuitest.md) (iOS と tvOS アプリ用)
|
||||
- [Espresso ドライバー](/docs/en/drivers/android-espresso.md) (Android アプリ用)
|
||||
- [UiAutomator2 ドライバー](/docs/en/drivers/android-uiautomator2.md) (Android アプリ用)
|
||||
- [Windows ドライバー](/docs/en/drivers/windows.md) (Windows デスクトップアプリ用)
|
||||
- [Mac ドライバー](/docs/en/drivers/mac.md) (Mac デスクトップアプリ用)
|
||||
|
||||
### インストールの確認
|
||||
|
||||
Appium の依存関係がすべて満たされていることを確認するには、`appium-doctor` を使うことができます。
|
||||
`npm install -g appium-doctor` でインストールし、
|
||||
`appium-doctor` コマンドを実行して `--ios` または `--android` フラグを指定して、
|
||||
すべての依存関係が正しく設定されていることを確認します。
|
||||
|
||||
### Appium クライアント
|
||||
|
||||
すべてが呼ばれた時、Appium はただの HTTP サーバーです。
|
||||
それはその状態でクライアントからの接続を待ち、
|
||||
クライアントはどのような種類のセッションを開始するか、セッションが開始されるとどのような自動化動作を実行するかを Appium に指示します。
|
||||
これは、Appium を単独では決して使用しないことを意味します。
|
||||
常に何らかの種類のクライアントライブラリ (または、冒険的な場合は cURL!) と一緒に使用する必要があります。
|
||||
|
||||
幸いなことに、Appium は WebDriver プロトコルと呼ばれる [Selenium](http://www.seleniumhq.org/) と同じプロトコルを話します。
|
||||
標準の Selenium クライアントの 1 つを使用するだけで、
|
||||
Appium で多くのことを行うことができます。
|
||||
あなたのシステムにはすでにこれらのクライアントがあるかもしれません。
|
||||
特にモバイルプラットフォーム上の Web ブラウザをテストする目的で Appium を使用している場合は、
|
||||
それだけで十分です。
|
||||
|
||||
しかし、モバイルデバイスが Web ブラウザではできないことを行えるように、
|
||||
Appium は Selenium ではできないことを行えます。
|
||||
そのため、私たちは様々なプログラミング言語の
|
||||
Appium クライアントを用意しています。
|
||||
クライアントのリストとダウンロード手順へのリンクは
|
||||
[Appium クライアントのリスト](/docs/en/about-appium/appium-clients.md)で見ることができます。
|
||||
|
||||
先に進む前に、お好きな言語でクライアントをダウンロードし、
|
||||
準備ができていることを確認してください。
|
||||
|
||||
### Appium の開始
|
||||
|
||||
(NPMのインストールが成功したと仮定して)
|
||||
これで、以下のようにコマンドラインから実行することで、Appium サーバーをキックアップすることができます。
|
||||
|
||||
```
|
||||
appium
|
||||
```
|
||||
|
||||
または、Appium Desktop 内の巨大な Start Server ボタンをクリックしてください。
|
||||
|
||||
Appium は、実行している Appium のバージョンとどのポートを待ち受けているかを示す小さなウェルカムメッセージを表示します
|
||||
(デフォルトは `4723` です)。
|
||||
このポートで Appium に接続するようにテストクライアントを設定する必要があるので、
|
||||
このポート情報は重要です。
|
||||
ポートを変更したい場合は、
|
||||
Appium を起動する際に `-p` フラグを使用して変更することができます
|
||||
([サーバーパラメータ](/docs/en/writing-running-appium/server-args.md)の全リストを確認してください)。
|
||||
|
||||
### 最初のテストの実行
|
||||
|
||||
このセクションでは、基本的な "Hello World" の Android テストを実行します。
|
||||
Android を選択したのは、すべてのプラットフォームで利用可能だからです。
|
||||
[UiAutomator2 Driver](/docs/en/drivers/android-uiautomator2.md)を使用しますので、
|
||||
そのドキュメントを読み、システムを適切に設定してください。
|
||||
また、言語として JavaScript を使用しますので、
|
||||
追加の依存関係に対処する必要はありません。
|
||||
|
||||
(Android 以外のものを
|
||||
JavaScript 以外のものを使って自動化したいと思うこともあるでしょう。
|
||||
その場合は、多くの言語やプラットフォームに対応した
|
||||
[コードサンプル](https://github.com/appium/appium/tree/master/sample-code)を用意しています。)
|
||||
|
||||
#### 前提条件
|
||||
|
||||
- あなたが Android 8.0 エミュレータを設定して実行していると仮定します
|
||||
(例は、バージョン番号を調整することで
|
||||
より低バージョンで動作します。)
|
||||
- あなたが[このテスト APK](https://github.com/appium/appium/raw/master/sample-code/apps/ApiDemos-debug.apk) をダウンロードして、
|
||||
ローカルファイルシステム上で
|
||||
利用可能であると仮定します
|
||||
|
||||
#### Appium クライアントの設定
|
||||
|
||||
この例では、Appium クライアントとして [Webdriver.io](http://webdriver.io) を使用します。
|
||||
この例のディレクトリを作成し、実行します。
|
||||
|
||||
```
|
||||
npm init -y
|
||||
```
|
||||
プロジェクトを初期化したら、`webdriverio` をインストールします:
|
||||
```
|
||||
npm install webdriverio
|
||||
```
|
||||
|
||||
#### セッションの初期化
|
||||
|
||||
ここで `index.js` という名前のテストファイルを作成し、
|
||||
クライアントオブジェクトを初期化します:
|
||||
|
||||
```js
|
||||
// javascript
|
||||
const wdio = require("webdriverio");
|
||||
```
|
||||
|
||||
次にやるべきことは、Appium セッションを開始することです。
|
||||
これを行うには、サーバーオプションと Desired Capabilities のセットを定義し、
|
||||
それらを使って `wdio.remote()` を呼び出します。
|
||||
Desired Capabilities は、セッションの初期化中に Appium サーバーに送信されるキーと値の集合で、
|
||||
どのようなことを自動化したいかを Appium に伝えます。
|
||||
どのような Appium ドライバでも、以下の項目が必要な capabilities の最小セットになります。
|
||||
|
||||
- `platformName`: 自動化するプラットフォームの名前
|
||||
- `platformVersion`: 自動化するプラットフォームのバージョン
|
||||
- `deviceName`: 自動化するデバイスの種類
|
||||
- `app`: 自動化したいアプリへのパス (ただし、Web ブラウザを自動化する場合は代わりに
|
||||
`browserName` capability を使用します)
|
||||
- `automationName`: 使用するドライバーの名前
|
||||
|
||||
Desired Capabilities の詳細と、
|
||||
Appium で使用できるすべての機能のリストについては、
|
||||
[Capabilities doc](/docs/en/writing-running-appium/caps.md)を参照してください。
|
||||
|
||||
ここでは、以下のテストファイルでセッションを構築する方法を説明します:
|
||||
|
||||
```js
|
||||
// javascript
|
||||
const opts = {
|
||||
path: '/wd/hub',
|
||||
port: 4723,
|
||||
capabilities: {
|
||||
platformName: "Android",
|
||||
platformVersion: "8",
|
||||
deviceName: "Android Emulator",
|
||||
app: "/path/to/the/downloaded/ApiDemos-debug.apk",
|
||||
appPackage: "io.appium.android.apis",
|
||||
appActivity: ".view.TextFields",
|
||||
automationName: "UiAutomator2"
|
||||
}
|
||||
};
|
||||
|
||||
async function main () {
|
||||
const client = await wdio.remote(opts);
|
||||
|
||||
await client.deleteSession();
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
#### テストコマンドの実行
|
||||
|
||||
Appium ポートを指定し、要件に一致するように Desired Capabilities を構築したことがわかります
|
||||
(ただし、パスをあなたのシステムの実際のダウンロードパスに置き換えることを忘れないでください)。
|
||||
この事実を `webdriverio` に登録して、
|
||||
Appium サーバーへの接続を表すクライアントオブジェクトができました。
|
||||
ここから先に進み、セッションを開始し、いくつかのテストコマンドを実行し、セッションを終了することができます。
|
||||
ここでは、テキストフィールドに入力して、
|
||||
正しいテキストが入力されたかどうかを確認します:
|
||||
|
||||
```js
|
||||
// javascript
|
||||
|
||||
const field = await client.$("android.widget.EditText");
|
||||
await field.setValue("Hello World!");
|
||||
const value = await field.getText();
|
||||
assert.strictEqual(value, "Hello World!");
|
||||
```
|
||||
|
||||
ここで何が起こっているのかというと、セッションを作成してアプリを起動した後、
|
||||
アプリ階層で要素を見つけて入力するように Appium に指示しています。
|
||||
次に、同じフィールドにテキストを問い合わせ、
|
||||
期待通りのテキストであることを主張します。
|
||||
|
||||
すべてをまとめると、ファイルは次のようになります:
|
||||
|
||||
```js
|
||||
// javascript
|
||||
|
||||
const wdio = require("webdriverio");
|
||||
const assert = require("assert");
|
||||
|
||||
const opts = {
|
||||
path: '/wd/hub',
|
||||
port: 4723,
|
||||
capabilities: {
|
||||
platformName: "Android",
|
||||
platformVersion: "8",
|
||||
deviceName: "Android Emulator",
|
||||
app: "/path/to/the/downloaded/ApiDemos-debug.apk",
|
||||
appPackage: "io.appium.android.apis",
|
||||
appActivity: ".view.TextFields",
|
||||
automationName: "UiAutomator2"
|
||||
}
|
||||
};
|
||||
|
||||
async function main () {
|
||||
const client = await wdio.remote(opts);
|
||||
|
||||
const field = await client.$("android.widget.EditText");
|
||||
await field.setValue("Hello World!");
|
||||
const value = await field.getText();
|
||||
assert.strictEqual(value,"Hello World!");
|
||||
|
||||
await client.deleteSession();
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
このテストを自分で実行してみることができます。
|
||||
保存して `node` を使って実行するだけです:
|
||||
```
|
||||
node index.js
|
||||
```
|
||||
すべてが正しく設定されている場合、
|
||||
Appium がたくさんのログを吐き出し始め、
|
||||
最終的にはアプリが画面上にポップアップし、見えないユーザーがタップしているかのように動作を開始するのがわかります。
|
||||
|
||||
### 次は何をするか
|
||||
|
||||
Appium でできることについては、まだ表面上のことに過ぎません。
|
||||
これらのリソースをチェックして、あなたの旅に役立たせてください:
|
||||
|
||||
- Appium [コマンドリファレンス](https://appium.io/docs/en/commands/status/) - どのようなコマンドが利用可能か、特定のクライアントライブラリでの使用方法などについて学びます
|
||||
- [サンプルコード](https://github.com/appium/appium/tree/master/sample-code) ディレクトリには、他にもたくさんのコードサンプルがあります
|
||||
|
||||
- [discuss.appium.io](https://discuss.appium.io) - これは Appium コミュニティのフォーラムです。バグに遭遇したかもしれないと思った場合、または始めるための助けを得るために最初に行くのに最適な場所です
|
||||
- Appium [不具合トラッカー](https://github.com/appium/appium/issues) - バグを見つけたと思ったら、Appium メンテナに知らせてください
|
||||
@@ -1,138 +0,0 @@
|
||||
## Appium 入門
|
||||
|
||||
Appium は、iOS モバイル、Android モバイル、Windows デスクトッププラットフォーム上の
|
||||
ネイティブ、モバイル Web、ハイブリッドアプリケーションを自動化するためのオープンソースツールです。
|
||||
**ネイティブアプリ**とは、iOS、Android、または Windows SDK を使用して開発されたアプリのことです。
|
||||
**モバイル Web アプリ**は、モバイルブラウザを使用してアクセスする Web アプリです (Appium は、iOS では Safari、Android では Chrome または標準の Browser アプリをサポートしています)。
|
||||
**ハイブリッドアプリ**は、Web コンテンツとのインタラクションを可能にする標準的な仕組みである「WebView」のラッパーを持っています。
|
||||
[Apache Cordova](https://cordova.apache.org) のようなプロジェクトでは、
|
||||
Web 技術を使用してアプリを簡単に構築することができ、
|
||||
それをネイティブのラッパーにバンドルしてハイブリッドアプリを作成することができます。
|
||||
|
||||
重要なことは、Appium は「クロスプラットフォーム」であるということです。
|
||||
つまり、同じ API を使用して、複数のプラットフォーム (iOS、Android、Windows) に対してテストを書くことができます。
|
||||
これにより、iOS、Android、Windows のテストスイート間でコードを再利用することができます。
|
||||
|
||||
Appium がそのプラットフォームを「サポート」することの意味、
|
||||
および自動化の様式についての具体的な情報は、
|
||||
[プラットフォームサポートドキュメント](/docs/ja/about-appium/platform-support.md)を参照してください。
|
||||
|
||||
### Appium の理念
|
||||
|
||||
Appium は、次の4つの信条によって概説された理念に従って、
|
||||
モバイルオートメーションのニーズを満たすように設計されました。
|
||||
|
||||
1. アプリを自動化するために、
|
||||
アプリを再コンパイルしたり、修正したりする必要はありません
|
||||
2. テストを書いて実行するために、
|
||||
特定の言語やフレームワークに縛られるべきではありません
|
||||
3. モバイルオートメーションフレームワークは、
|
||||
自動化 API に関しては、車輪の再発明をしてはいけません
|
||||
4. モバイルオートメーションフレームワークは、名前だけでなく、
|
||||
精神的にも実践的にもオープンソースでなければなりません!
|
||||
|
||||
### Appium のデザイン
|
||||
|
||||
では、Appium プロジェクトの構造はどのようにしてこの理念を実現しているのでしょうか?
|
||||
ベンダーが提供する自動化フレームワークを基盤に利用することで、要件 1 を満たしています。
|
||||
この方法では、Appium 固有のコードやサードパーティのコードやフレームワークをアプリに組み込む必要はありません。
|
||||
つまり、**出荷するアプリと同じアプリをテストしていることになります**。
|
||||
使用しているベンダー提供のフレームワークは以下の通りです。
|
||||
|
||||
* iOS 9.3 以上: Apple の [XCUITest](https://developer.apple.com/reference/xctest)
|
||||
* iOS 9.3 以下: Apple の [UIAutomation](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
|
||||
* Android 4.3 以上: Google の [UiAutomator/UiAutomator2](https://developer.android.com/training/testing/ui-automator)
|
||||
* Windows: Microsoft の [WinAppDriver](http://github.com/microsoft/winappdriver)
|
||||
|
||||
ベンダーが提供するフレームワークを
|
||||
[WebDriver](http://docs.seleniumhq.org/projects/webdriver/) API という1つの API でラップすることで要件 2 を満たしています。
|
||||
WebDriver (別名 "Selenium WebDriver") は、([JSON Wire Protocol](https://w3c.github.io/webdriver/webdriver-spec.html) として知られる)
|
||||
クライアント - サーバープロトコルを指定します。
|
||||
このクライアント - サーバーアーキテクチャを考えると、任意の言語で書かれたクライアントを使用して、
|
||||
適切な HTTP リクエストをサーバーに送信することができます。
|
||||
既に[あらゆる一般的なプログラミング言語で書かれたクライアント](http://appium.io/downloads)
|
||||
が存在します。
|
||||
これはまた、好きなテストランナーやテストフレームワークを
|
||||
自由に使用できることを意味します。
|
||||
言い換えれば、Appium と WebDriver クライアントは技術的には「テストフレームワーク」ではなく、
|
||||
「自動化ライブラリ」です。
|
||||
テスト環境を
|
||||
好きなように管理することができます。
|
||||
|
||||
同様に要件 3 を満たしています。
|
||||
WebDriver は、Web ブラウザを自動化するためのデファクトスタンダードとなっており、
|
||||
[W3C のワーキングドラフト](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html)です。
|
||||
なぜモバイル用に全く違うことをするのでしょうか?
|
||||
その代わりに、モバイルの自動化に役立つ API メソッドを追加して
|
||||
[プロトコルを拡張](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)しました。
|
||||
|
||||
要件 4 が与えられたものであることは明らかなはずです。
|
||||
あなたがこれを読んでいるのは、[Appium がオープンソース](https://github.com/appium/appium)だからです。
|
||||
|
||||
### Appium の概念
|
||||
|
||||
#### **クライアント/サーバー アーキテクチャ**
|
||||
|
||||
Appium は、REST API を公開する Web サーバーです。
|
||||
クライアントからの接続を受信し、コマンドを待ち受け、
|
||||
モバイル デバイス上でそれらのコマンドを実行し、コマンドの実行結果を表す HTTP レスポンスで応答します。
|
||||
クライアント/サーバー アーキテクチャがあるという事実は、多くの可能性を開きます。
|
||||
HTTP クライアントの API を持つどの言語でもテストコードを書くことができますが、
|
||||
[Appium クライアントライブラリ](http://appium.io/downloads)の 1 つを使用する方が簡単です。
|
||||
テストが実行されているマシンとは別のマシンにサーバーを置くことができます。
|
||||
テストコードを書き、コマンドを受信して解釈するために
|
||||
[Sauce Labs](https://saucelabs.com/products/mobile-app-testing) や [LambdaTest](https://www.lambdatest.com/feature) のようなクラウドサービスに頼ることもできます。
|
||||
|
||||
#### **セッション**
|
||||
オートメーションは常にセッションのコンテキストで実行されます。
|
||||
クライアントはそれぞれのライブラリに固有の方法でサーバーとのセッションを開始しますが、
|
||||
最終的にはサーバーに `POST /session` リクエストを送信し、'desired capabilities' オブジェクトと呼ばれる JSON オブジェクトを送信します。
|
||||
この時点で、サーバーはオートメーションセッションを起動し、
|
||||
さらにコマンドを送信するために使用されるセッション ID で応答します。
|
||||
|
||||
#### **Desired capabilities**
|
||||
Desired capabilities とは、どのような種類の自動化セッションの起動に興味があるかをサーバーに伝えるために、
|
||||
Appium サーバーに送られるキーと値のセット (すなわち、マップやハッシュ) です。
|
||||
また、自動化中にサーバーの動作を変更できる様々な機能があります。
|
||||
例えば、Android や Windows のセッションではなく、
|
||||
iOS のセッションが必要であることを Appium に伝えるために、
|
||||
`platformName` capability を `iOS` に設定することができます。
|
||||
また、Safari の自動化セッション中に JavaScript を使用して新しいウィンドウを開くことができるようにするために、
|
||||
`safariAllowPopups` の capability を `true` に設定することもできます。
|
||||
Appium で利用可能な機能の完全なリストについては、[capabilities のドキュメント](/docs/en/writing-running-appium/caps.md) を参照してください。
|
||||
|
||||
#### **Appium サーバー**
|
||||
Appium は Node.js で書かれたサーバーです。
|
||||
ソースからビルドしてインストールすることもできますし、
|
||||
[NPM](https://www.npmjs.com/package/appium) から直接インストールすることもできます。
|
||||
|
||||
```
|
||||
$ npm install -g appium
|
||||
$ appium
|
||||
```
|
||||
|
||||
Appium の `ベータ版` は `npm install -g appium@beta` で NPM 経由で公開されています。
|
||||
開発版なので、変更点があるかもしれません。
|
||||
新しいバージョンをインストールする前に
|
||||
`appium@beta` をアンインストールしてください (`npm uninstall -g appium@beta`)。
|
||||
|
||||
#### **Appium クライアント**
|
||||
WebDriver プロトコルへの Appium の拡張をサポートする
|
||||
クライアントライブラリ (Java、Ruby、Python、PHP、JavaScript、および C#) があります。
|
||||
Appium を使用する場合は、
|
||||
通常の WebDriver クライアントの代わりにこれらのクライアントライブラリを使用します。
|
||||
ライブラリの完全なリストは[ここ](/docs/en/about-appium/appium-clients.md)で見ることができます。
|
||||
|
||||
#### **[Appium デスクトップ](https://github.com/appium/appium-desktop)**
|
||||
Appium サーバーの GUI ラッパーがあり、どのプラットフォーム用にもダウンロードできます。
|
||||
Appium サーバーを実行するために必要なすべてのものがバンドルされているので、
|
||||
Node について心配する必要はありません。
|
||||
また、インスペクタが付属しており、アプリの階層をチェックアウトすることができます。
|
||||
これはテストを書くときに便利です。
|
||||
|
||||
### はじめに
|
||||
|
||||
おめでとうございます!
|
||||
これで、Appium の使用を開始するのに十分な知識が身につきました。
|
||||
より詳細な要件と指示のために、
|
||||
[始め方のドキュメント](/docs/en/about-appium/getting-started.md) をご覧になってみてはいかがでしょうか?
|
||||
@@ -1,97 +0,0 @@
|
||||
## Appium プラットフォームのサポート
|
||||
|
||||
Appium は、さまざまなプラットフォームとテストの様式
|
||||
(ネイティブ、ハイブリッド、Web、リアルデバイス、シミュレータなど) をサポートしています。
|
||||
このドキュメントは、これらのそれぞれのサポートレベルと要件を明示するように設計されています。
|
||||
もしくは、それぞれの適切なページへ案内します。
|
||||
|
||||
## Appium team support
|
||||
|
||||
以下はAppiumの開発チームによりサポートされるドライバーです。
|
||||
|
||||
### iOS のサポート
|
||||
|
||||
iOS の自動化は2つのドライバーでサポートされています:
|
||||
|
||||
* [XCUITest Driver](/docs/en/drivers/ios-xcuitest.md)
|
||||
* (非推奨) [UIAutomation Driver](/docs/en/drivers/ios-uiautomation.md)
|
||||
* [safaridriver](/docs/en/drivers/safari.md) は Apple の [safaridriver](https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari?language=objc)
|
||||
|
||||
設定方法については、これらのドライバーのドキュメントを参照してください。
|
||||
|
||||
* バージョン: 12.2 以上 (原則として、Appium は iOS の最新バージョン2つをサポートしています)
|
||||
* デバイス: iPhone、iPad、tvOS 用のシミュレータと実機
|
||||
* ネイティブアプリのサポート: はい、デバッグバージョンの .app (シミュレータ)
|
||||
または正しく署名された .ipa (実機) を使用しています。
|
||||
基本的なサポートは、Apple の [XCUITest](https://developer.apple.com/reference/xctest) (古いバージョンでは [UIAutomation](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)) フレームワークによって
|
||||
提供されています
|
||||
* モバイル Web のサポート: はい、モバイル Safari の自動化機構を経由できます。
|
||||
手順については、[モバイル Web ドキュメント](/docs/en/writing-running-appium/web/mobile-web.md)を参照してください
|
||||
* ハイブリッドサポート: はい。
|
||||
手順については、[ハイブリッドドキュメント](/docs/en/writing-running-appium/web/hybrid.md)を参照してください
|
||||
* 1つのセッションで複数のアプリの自動化をサポート: いいえ
|
||||
* 複数のデバイスの同時自動化のサポート: はい
|
||||
* ベンダー提供またはサードパーティ製アプリの自動化をサポート: はい。予め端末にインストールされている必要があります。
|
||||
* カスタムの非標準 UI コントロールの自動化のサポート: 最小限の設定です。
|
||||
基本的な自動化を可能にするコントロールに
|
||||
アクセシビリティ情報を設定する必要があります
|
||||
|
||||
### Android のサポート
|
||||
|
||||
Android の自動化は2つのドライバーでサポートされています:
|
||||
|
||||
* [UiAutomator2 Driver](/docs/en/drivers/android-uiautomator2.md)
|
||||
* [Espresso Driver](/docs/en/drivers/android-espresso.md)
|
||||
* (非推奨) [UiAutomator Driver](/docs/en/drivers/android-uiautomator.md)
|
||||
* Firefox や [GeckoView](https://wiki.mozilla.org/Mobile/GeckoView) 向けの [geckodriver](/docs/en/drivers/gecko.md)
|
||||
|
||||
設定方法については、これらのドライバーのドキュメントを参照してください。
|
||||
|
||||
* バージョン: 4.3 以上
|
||||
* バージョン 4.3 以降は、Appium の [UiAutomator と UiAutomator2](http://developer.android.com/tools/testing-support-library/index.html#UIAutomator) ライブラリを介してサポートされています。
|
||||
UiAutomator はデフォルトのドライバーです
|
||||
* デバイス: Android エミュレータと実機の Android 端末
|
||||
* ネイティブアプリのサポート: はい
|
||||
* モバイル Web のサポート: はい。自動化は、バンドルされている [Chromedriver](http://chromedriver.chromium.org) サーバーを
|
||||
プロキシとして使用して行われます。
|
||||
4.3 では、公式の Chrome ブラウザまたは Chromium 上でのみ自動化が動作します。
|
||||
4.4 以上では、自動化は標準の「ブラウザ」アプリでも動作します。
|
||||
Chrome / Chromium / Browser がテスト対象のデバイスに既にインストールされている必要があります。
|
||||
手順については、[モバイル Web ドキュメント](/docs/en/writing-running-appium/web/mobile-web.md)を参照してください
|
||||
* ハイブリッドサポート: はい。[ハイブリッドドキュメント](/docs/en/writing-running-appium/web/hybrid.md)を参照してください
|
||||
* デフォルトの Appium オートメーションバックエンドを使用した場合: バージョン 4.4 以降
|
||||
* 1つのセッションで複数のアプリの自動化をサポート: はい
|
||||
* 複数のデバイスの同時自動化のサポート: はい。
|
||||
ただし、Appium はサーバーパラメータ `--port`、`--bootstrap-port` や `--chromedriver-port` に対して
|
||||
異なるポートを使用して起動しなければなりません。
|
||||
これらのパラメータの詳細については
|
||||
[サーバー引数のドキュメント](/docs/en/writing-running-appium/server-args.md) を参照してください
|
||||
* ベンダー提供またはサードパーティ製アプリの自動化をサポート: はい
|
||||
* カスタムの非標準 UI コントロールの自動化のサポート: いいえ
|
||||
|
||||
|
||||
### macOS サポート
|
||||
|
||||
macOS の自動化は以下のドライバーによってサポートされます。
|
||||
|
||||
* macOS 10.15 以上 [Mac2Driver](/docs/en/drivers/mac2.md)
|
||||
* macOS 10.15 未満 (非推奨) [MacDriver](/docs/en/drivers/mac.md)
|
||||
|
||||
### Windows デスクトップのサポート
|
||||
|
||||
Windows の自動化は以下のドライバーによってサポートされます。
|
||||
|
||||
* [WinAppDriver](/docs/en/drivers/windows.md)
|
||||
* Firefox と [GeckoView](https://wiki.mozilla.org/Mobile/GeckoView) は [geckodriver](/docs/en/drivers/gecko.md)
|
||||
|
||||
## ベンダー/コミュニティー
|
||||
|
||||
以下はベンダーやコミュニティーによってサポートされるドライバーです。
|
||||
|
||||
### You.i Engine Support
|
||||
|
||||
* [You.i Engine](https://github.com/YOU-i-Labs/appium-youiengine-driver)
|
||||
|
||||
### Flutter Support
|
||||
|
||||
* [Flutter Driver](https://github.com/truongsinh/appium-flutter-driver)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user