Compare commits

..
1204 changed files with 46707 additions and 69991 deletions
-9
View File
@@ -1,9 +0,0 @@
**/coverage/**
**/node_modules/**
examples/javascript-wd
**/build/**
**/*.min.js
sample-code
**/*.d.ts
**/build-fixtures/**
**/*.ts
-47
View File
@@ -1,47 +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/*/test/**/*.js",
"rules": {
"no-restricted-properties": [
"error",
{
"object": "sinon",
"property": "spy",
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.spy()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
},
{
"object": "sinon",
"property": "stub",
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.stub()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
},
{
"object": "sinon",
"property": "mock",
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.mock()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
}
]
}
}
]
}
-40
View File
@@ -1,40 +0,0 @@
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
# Visit https://fossa.com to learn more
version: 3
project:
id: github.com/appium/appium
name: appium
paths:
exclude:
- ./sample-code
- '**/fixtures/**'
- '**/demo/**'
- '**/example/**'
- '**/examples/**'
targets:
only:
- type: npm
path: .
- type: npm
path: ./packages/appium
- type: npm
path: ./packages/base-driver
- type: npm
path: ./packages/doctor
- type: npm
path: ./packages/eslint-config-appium
- type: npm
path: ./packages/fake-driver
- type: npm
path: ./packages/gulp-plugins
- type: npm
path: ./packages/support
- type: npm
path: ./packages/test-support
revision:
branch: 2.0
-33
View File
@@ -1,33 +0,0 @@
## The problem
Briefly describe the issue you are experiencing (or the feature you want to see added to Appium). Tell us what you were trying to do and what happened instead. Remember, this is _not_ a place to ask questions. For that, go to http://discuss.appium.io!
## Environment
* Appium version (or git revision) that exhibits the issue:
* Last Appium version that did not exhibit the issue (if applicable):
* Desktop OS/version used to run Appium:
* Node.js version (unless using Appium.app|exe):
* Npm or Yarn package manager:
* Mobile platform/version under test:
* Real device or emulator/simulator:
* Appium CLI or Appium.app|exe:
## Details
If necessary, describe the problem you have been experiencing in more detail.
## Link to Appium logs
Create a [GIST](https://gist.github.com) which is a paste of your _full_ Appium logs, and link them here.
Do _NOT_ paste your full Appium logs here, as it will make this issue very long and hard to read!
If you are reporting a bug, _always_ include Appium logs!
## Code To Reproduce Issue [ Good To Have ]
Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it.
Please git clone https://github.com/appium/appium and from the `examples` directory, use one of your favourite languages and sample apps to reproduce the issue.
In case a similar scenario is missing in examples, please submit a PR with one of the sample apps provided.
-28
View File
@@ -1,28 +0,0 @@
## Proposed changes
Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
## Types of changes
What types of changes does your code introduce to Appium?
_Put an `x` in the boxes that apply_
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation Update (if none of the other choices apply)
## Checklist
_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
- [ ] I have read the [CONTRIBUTING](https://github.com/appium/appium/blob/master/CONTRIBUTING.md) doc
- [ ] I have signed the [CLA](https://cla.js.foundation/appium/appium)
- [ ] Lint and unit tests pass locally with my changes
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] I have added necessary documentation (if appropriate)
- [ ] Any dependent changes have been merged and published in downstream modules
## Further comments
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
-20
View File
@@ -1,20 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/sample-code/javascript-webdriverio"
schedule:
interval: daily
time: "11:00"
open-pull-requests-limit: 10
- package-ecosystem: npm
directory: "/sample-code/javascript-wd"
schedule:
interval: daily
time: "11:00"
open-pull-requests-limit: 10
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
time: "11:00"
open-pull-requests-limit: 10
-26
View File
@@ -1,26 +0,0 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 365
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: false
# Limit to only `issues` or `pulls`
only: issues
-49
View File
@@ -1,49 +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]
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 17.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install latest npm
run: npm install -g npm
- name: Install dependencies
run: npm install
- name: Run all tests
run: npm run test:ci
lint:
name: Lint & Check Types
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: ESLint
run: npm run lint
- name: Check types
run: npm run build:types
docs:
name: Build Command Documentation
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: Generate docs
run: npm run generate-docs
-21
View File
@@ -1,21 +0,0 @@
name: License Checks
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
fossa-check:
name: Run FOSSA Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: '2.0'
- name: fossa analyze
run: |
npm install
curl -sS -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash
fossa analyze
fossa test
env:
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
+4 -34
View File
@@ -2,16 +2,14 @@
*.swp
.DS_Store
node_modules
package-lock.json
sample-code
*.trace
xcuserdata
*.sublime-*
test/functional/_joined
*.iml
!examples/java/*.iml
*.autosave
.idea/
!examples/java/.idea/
*.log
*.t
artifacts
@@ -25,39 +23,11 @@ lib/devices/android/bootstrap/target/
.*~
*~
org.eclipse.ltk.core.refactoring.prefs
/selendroid
.appiumconfig*
build/
.idea
lib/devices/ios/uiauto/lib/status.js
lib/devices/ios/uiauto/appium/xpath.js
*DerivedData
__pycache__
# csharp
*.pyc
*.pdb
.vs
old
.tern-project
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
+64
View File
@@ -0,0 +1,64 @@
[submodule "submodules/instruments-without-delay"]
path = submodules/instruments-without-delay
url = https://github.com/facebook/instruments-without-delay.git
[submodule "submodules/ApiDemos"]
path = submodules/ApiDemos
url = https://github.com/appium/android-apidemos.git
[submodule "submodules/appium.io"]
path = submodules/appium.io
url = https://github.com/appium/appium.io.git
[submodule "submodules/selendroid"]
path = submodules/selendroid
url = https://github.com/selendroid/selendroid.git
[submodule "submodules/fruitstrap"]
path = submodules/fruitstrap
url = https://github.com/tborys/fruitstrap.git
[submodule "submodules/io.appium.gappium.sampleapp"]
path = submodules/io.appium.gappium.sampleapp
url = https://github.com/appium/io.appium.gappium.sampleapp.git
[submodule "submodules/udidetect"]
path = submodules/udidetect
url = https://github.com/vaskas/udidetect.git
[submodule "submodules/unlock_apk"]
path = submodules/unlock_apk
url = https://github.com/appium/unlock_apk.git
[submodule "submodules/SafariLauncher"]
path = submodules/SafariLauncher
url = https://github.com/snevesbarros/SafariLauncher.git
[submodule "submodules/libimobiledevice-macosx"]
path = submodules/libimobiledevice-macosx
url = https://github.com/benvium/libimobiledevice-macosx.git
[submodule "submodules/ForceQuitUnresponsiveApps"]
path = submodules/ForceQuitUnresponsiveApps
url = https://github.com/appium/ForceQuitUnresponsiveApps.git
[submodule "submodules/appium-atoms"]
path = submodules/appium-atoms
url = https://github.com/appium/appium-atoms.git
branch = published
[submodule "submodules/appium-instruments"]
path = submodules/appium-instruments
url = https://github.com/appium/appium-instruments.git
branch = published
[submodule "submodules/appium-uiauto"]
path = submodules/appium-uiauto
url = https://github.com/appium/appium-uiauto.git
branch = published
[submodule "submodules/appium-adb"]
path = submodules/appium-adb
url = https://github.com/appium/appium-adb.git
[submodule "submodules/io.appium.android.ime"]
path = submodules/io.appium.android.ime
url = https://github.com/appium/io.appium.android.ime.git
[submodule "submodules/io.appium.settings"]
path = submodules/io.appium.settings
url = https://github.com/appium/io.appium.settings.git
[submodule "submodules/sample-code"]
path = submodules/sample-code
url = https://github.com/appium/sample-code
[submodule "submodules/deviceconsole"]
path = submodules/deviceconsole
url = https://github.com/rpetrich/deviceconsole.git
[submodule "submodules/appium-ci-gulper"]
path = submodules/appium-ci-gulper
url = https://github.com/appium/appium-ci-gulper.git
branch = master
+13
View File
@@ -0,0 +1,13 @@
{
"excludeFiles": ["submodules/**", "node_modules/**",
"./lib/server/static/**", "./lib/devices/firefoxos/atoms/*.js",
"./sample-code/**", "/Users/baba/Work/appium/ci/standalone-tools/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
}
}
+5
View File
@@ -0,0 +1,5 @@
submodules
node_modules
lib/server/static
lib/devices/firefoxos/atoms
/Users/baba/Work/appium/ci/standalone-tools/node_modules
+11
View File
@@ -0,0 +1,11 @@
{
"laxcomma": true,
"strict": true,
"undef": true,
"unused": true,
"node": true,
"eqeqeq": true,
"trailing": true,
"indent": 2,
"shelljs": false
}
-12
View File
@@ -1,12 +0,0 @@
// @ts-check
'use strict';
module.exports = {
require: [
require.resolve('./test/setup.js')
],
// forbids use of .only() in CI
forbidOnly: Boolean(process.env.CI),
color: true
};
+26
View File
@@ -0,0 +1,26 @@
assets/
submodules/
bin/publish.sh
reset.sh
reset.bat
bin/test.sh
sample-code/
test/
lib/devices/android/bootstrap/bin/
lib/devices/android/bootstrap/target/
lib/devices/android/bootstrap/local.properties
lib/devices/android/bootstrap/project.properties
lib/devices/android/bootstrap/.classpath
_vimrc_local.vim
*.swp
*.swo
*~
.*~
.DS_Store
.travis.yml
*.log
*.trace
*.sublime-
*.prefs
.jshintrc
./.npmignore
-4
View File
@@ -1,4 +0,0 @@
# Do not disable package-lock. Disabling package-lock also disables npm-shrinkwrap
package-lock=true
save-exact=true
-23
View File
@@ -1,23 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"args": ["--colors", "--timeout", "0", "${file}"],
"internalConsoleOptions": "openOnSessionStart",
"name": "Test - Current File",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"runtimeArgs": ["--require", "@babel/register"],
"request": "launch",
"skipFiles": ["<node_internals>/**", "**/node_modules/mocha/**"],
"type": "pwa-node",
"sourceMaps": true,
"cwd": "${workspaceFolder}",
"outfiles": [],
"env": {
"NODE_ENV": "test",
"BABEL_ENV": "test"
},
"autoAttachChildProcesses": true,
}
]
}
-14
View File
@@ -1,14 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "dev",
"group": {"kind": "build", "isDefault": true},
"problemMatcher": ["$tsc-watch"],
"label": "npm: dev",
"detail": "npm run dev",
"isBackground": true
}
]
}
-68
View File
@@ -1,68 +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/**/*',
'./packages/*/test/**/mocks.js',
'./packages/*/test/helpers.js',
'./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/**/*',
},
{
instrument: false,
pattern: './packages/gulp-plugins/build/**/*',
},
// this setup file is special
{
instrument: false,
pattern: './test/setup.js'
},
'!**/local_appium_home/**'
],
testFramework: 'mocha',
tests: [
'./packages/*/test/**/*-specs.js',
'./packages/*/test/unit/**/*.spec.js',
'!./packages/*/test/**/*-e2e-specs.js',
'!./packages/*/test/e2e/**/*',
'!./packages/*/node_modules/**',
// this is more of an E2E test and it's tedious to run
'!./packages/gulp-plugins/test/transpile-specs.js',
'!**/local_appium_home/**'
],
workers: {
restart: true,
},
setup() {
require('./test/setup');
},
runMode: 'onsave'
};
};
-1
View File
@@ -14,7 +14,6 @@ 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>
-3917
View File
File diff suppressed because it is too large Load Diff
+1786
View File
File diff suppressed because it is too large Load Diff
-48
View File
@@ -1,48 +0,0 @@
## Code of Conduct
### What is this code of conduct for?
Appium is a piece of technology, but **the core of the Appium community is the people in it**. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, socioeconomic status, religion (or lack thereof), or other marginalized aspect of comunity members. We expect all members of the Appium community to abide by this Code of Conduct whenever interacting in Appium venues (pull requests, GitHub issues, 1-1 or group chat, meetups, conferences, etc...)
### Examples of inappropriate behavior
Because we come from a variety of backgrounds, we don't want to assume that everyone has the same assumptions about what is and isn't appropriate. Here are some examples of inappropriate behavior that are incompatible with our community's ethos:
* Spamming, trolling, intentionally disrupting conversations, or irrelevant solicitation or advertisement
* Making demeaning or discriminatory comments
* Making negative assumptions about someone's background, abilities, or intentions
* Harassing or stalking individuals (online or in person)
* Giving someone unwelcome sexual attention or making unwelcome physical contact (in the case of an IRL event)
* Sharing sexual images or using sexually explicit language
In general: treat others how you would like to be treated, were you in their place. Don't be a jerk. _Do_ ask questions. _Do_ keep conflicts productively focused on technical issues. _Do_ think before you speak; remember that what is perceived as a funny witticism in your group of friends might be hurtful or reinforce hurtful stereotypes in the context of our diverse online community. _Do_ remember that we are all people, not robots, and all equally deserving of sensitivity and respect. (If and when robots join our community, let's treat them with respect too!)
### What will organizers do about inappropriate behavior?
If we notice you doing or saying something inappropriate, an organizer will explain why it's inappropriate and ask you to stop. We won't demonize or vilify you. But please do stop the inappropriate behavior so we can get back to writing and discussing code in a safe environment. If you have philosophical disagreements about what's actually inappropriate, please take them to a separate public or private conversation with an Appium maintainer so we don't turn pull requests into an ethics debate.
If you keep doing unacceptable things, we'll likely ban you, report you to GitHub, or take other appropriate action.
### What if I see or am subject to what feels like inappropriate behavior?
Let us know! Please notify a community organizer as soon as possible. Full contact information is listed in the [Contact Info](#contact-info) section of this document. All communications will be kept strictly confidential, unless otherwise required by law. No issue will be considered too inconsequential or unimportant for us to have a conversation about.
### Contact Info
If you need to report an incident, please contact any of the following organizers directly:
* Isaac Murchie [email](mailto:isaac@saucelabs.com) [twitter](https://twitter.com/imurchie)
* Jonathan Lipps [email](mailto:jlipps@saucelabs.com) [twitter](https://twitter.com/jlipps)
### Credit, License, and Attribution
This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).
It's inspired among other things by:
* [Citizen Code of Conduct](http://citizencodeofconduct.org/)
* [npmjs](https://www.npmjs.com/policies/conduct)
* [Geek Feminism](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy)
* [Ashe Dryden](http://www.ashedryden.com/blog/codes-of-conduct-101-faq)
* [Model View Culture](https://modelviewculture.com/issues/events)
* [Open Source & Feelings](http://osfeels.com/conduct).
+7 -58
View File
@@ -1,63 +1,12 @@
# 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).
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 changes to the Appium code or docs
Make sure you read and follow the setup instructions in the README first.
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!
### Running Appium from Source and doing dev on Appium
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).
This is all detailed in our [running from source doc](/docs/en/contributing-to-appium/appium-from-source.md)
-100
View File
@@ -1,100 +0,0 @@
# Appium Project Governance
The Appium Project wants as much as possible to operate using procedures that
are fair, open, inviting, and ultimately good for the community. For that
reason we find it valuable to codify some of the ways that the Project goes
about its day-to-day business. We want to make sure that no matter who you are,
you have the opportunity to contribute to Appium. We want to make sure that no
one corporation can exert undue influence on the community or hold the Project
hostage. And likewise we want to make sure that corporations which benefit from
Appium are also incentivized to give back.
### The Technical Committee
The project is officially led by a Technical Committee (TC), currently
consisting of:
* [@jlipps](https://github.com/jlipps)
* [@bootstraponline](https://github.com/bootstraponline)
* [@penguinho](https://github.com/penguinho)
* [@dandoveralba](https://github.com/dandoveralba)
* [@mykola-mokhnach](https://github.com/mykola-mokhnach)
* [@imurchie](https://github.com/imurchie)
* [@TikhomirovSergey](https://github.com/TikhomirovSergey)
* [@KazuCocoa](https://github.com/KazuCocoa)
They all represent different companies and different types of contribution to
the Appium Project. The TC is responsible for high-level decisions (like
establishing a feature roadmap, accepting sponsorship, organizing conferences,
etc...), adjudicating conflicts between members of the community, and making
changes to the project's governance processes.
* Membership in the TC is granted by unanimous vote of current TC members.
* TC members can step down at any time.
* No more than 1/3 of TC members may belong to the same company.
* Changes to project governance require unanimous vote of the TC.
### Project Committers
Most of the project maintenance is handled by committers, community members who
have been granted commit access to the Appium organization on GitHub. The
responsibilities of committers include: reviewing and merging pull requests,
walking through changes with developers, weighing in on architectural issues,
and so on.
* Any two TC members can decide to make someone a project committer, providing that person has shown an appropriate understanding of the Appium codebase through prior contributions of code.
* In general any committer can review and merge a PR. In general committers should only merge code they are qualified to review, which might entail pinging another committer who has greater ownership over a specific code area.
* Debates between committers about whether code should be merged should happen in GitHub pull requests.
* Proposals for large changes to the project's code (architectural changes, etc...) should be brought forward as a GitHub issue (with the label `Proposal`), and all committers should be pinged so they can weigh in on the discussion if desired. Substantial changes, whether in proposal stage or in pull request stage should be signed off on by 1 TC member and at least 2 other committers. To assist in the discussion, a small proof of concept can be undertaken on a subset of the Appium ecosystem and raised as a strawman PR, to give flesh to the proposal and make discussion more helpfully concrete.
* In general disputes about code should be resolved by discussion, not votes. If there is substantial disagreement, aim for consensus. If that is not possible, committers can bring the dispute to the TC for a vote, with the outcome determined by a majority.
* Any committer can decide to close a PR or issue if they determine the change doesn't suit the project.
* Appium has a large ecosystem of repositories. Some are 'core' in the sense of being central subpackages with a lot of traffic like `appium/appium` or `appium/appium-ios-driver`. Others are 'peripheral' in the sense of receiving few changes, being maintained by 1 person or no one, etc..., like `appium/ruby_lib` or `appium/appium_thor` For 'core' repos, committers should not merge their own code straightaway. Like all contributors they should open a PR and get a +1 from another committer. For 'peripheral' repos for which they are the sole maintainer or for which they have a good understanding, it is obtuse to insist on another contributor's +1 and this rule should be relaxed in that case. In sum: use good judgment and don't ram code through without a review when you can help it.
The current committers are (in addition to the TC members above):
* [@hugs](https://github.com/hugs)
* [@filmaj](https://github.com/filmaj)
* [@aluedeke](https://github.com/aluedeke)
* [@sebv](https://github.com/sebv)
* [@vgrigoruk](https://github.com/vgrigoruk)
* [@DylanLacey](https://github.com/DylanLacey)
* [@maudineormsby](https://github.com/maudineormsby)
* [@titusfortner](https://github.com/titusfortner)
* [@bayandin](https://github.com/bayandin)
* [@jdeff](https://github.com/jdeff)
* [@moizjv](https://github.com/moizjv)
* [@gempesaw](https://github.com/gempesaw)
* [@Jonahss](https://github.com/Jonahss)
* [@JamieEdge](https://github.com/JamieEdge)
* [@saikrishna321](https://github.com/saikrishna321)
* [@sravanmedarapu](https://github.com/sravanmedarapu)
* [@peepa](https://github.com/peepa)
* [@scottdixon](https://github.com/scottdixon)
* [@drpy](https://github.com/drpy)
* [@Astro03](https://github.com/Astro03)
* [@sbonebrake](https://github.com/sbonebrake)
* [@SrinivasanTarget](https://github.com/SrinivasanTarget)
* [@triager](https://github.com/triager)
* [@ddkjin](https://github.com/ddkjin)
* [@stuartbrussell-intuit](https://github.com/stuartbrussell-intuit)
* [@vmaxim](https://github.com/vmaxim)
### Contributors
Other, less formal, kinds of contribution are outlined in our
[CONTRIBUTING](/CONTRIBUTING.md) doc.
### Sponsorship
The Appium project welcomes sponsorship of various organizations. Specific
details are not yet available but in general we will accept monetary donations,
contribution of code, contribution of dedicated committers, or donations of
other goods or service (internet hosting, etc...). To begin the conversation,
reach out to one of the TC members.
### Raising Issues Related to Governance
This governance model necessarily leaves many situations unspecified. If
questions arise as to how a given situation should proceed according to the
overall goals of the project, the best thing to do is to open a GitHub issue
and ping the TC members.
+127
View File
@@ -0,0 +1,127 @@
"use strict";
var path = require('path')
, gruntHelpers = require('./grunt-helpers.js')
, authorize = gruntHelpers.authorize
, tail = gruntHelpers.tail
, buildApp = gruntHelpers.buildApp
, buildSafariLauncherApp = gruntHelpers.buildSafariLauncherApp
, signApp = gruntHelpers.signApp
, setupAndroidBootstrap = gruntHelpers.setupAndroidBootstrap
, setupAndroidApp = gruntHelpers.setupAndroidApp
, buildAndroidBootstrap = gruntHelpers.buildAndroidBootstrap
, buildSelendroidServer = gruntHelpers.buildSelendroidServer
, buildAndroidApp = gruntHelpers.buildAndroidApp
, buildSelendroidAndroidApp = gruntHelpers.buildSelendroidAndroidApp
, fixSelendroidAndroidManifest = gruntHelpers.fixSelendroidAndroidManifest
, installAndroidApp = gruntHelpers.installAndroidApp
, generateServerDocs = gruntHelpers.generateServerDocs
, generateAppiumIo = gruntHelpers.generateAppiumIo
, setDeviceConfigVer = gruntHelpers.setDeviceConfigVer
, setBuildTime = gruntHelpers.setBuildTime
, getSampleCode = gruntHelpers.getSampleCode
, setGitRev = gruntHelpers.setGitRev
, getGitRev = require('./lib/helpers').getGitRev;
var GULP_BIN = 'node_modules/.bin/gulp';
module.exports = function (grunt) {
grunt.initConfig({
mochaTest: {
appiumutils: ['test/functional/appium/appiumutils.js']
}
, mochaTestConfig: {
options: {
timeout: 60000,
reporter: 'spec'
}
}
, maxBuffer: 2000 * 1024
, exec: {
'gulp-test-unit': GULP_BIN + ' test-unit --color',
'gulp-jshint': GULP_BIN + ' jshint --color',
'gulp-jscs': GULP_BIN + ' jscs --color',
'gulp-lint': GULP_BIN + ' lint --color'
},
});
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-exec');
grunt.registerTask('jshint', 'exec:gulp-jshint');
grunt.registerTask('jscs', 'exec:gulp-jscs');
grunt.registerTask('lint', 'exec:gulp-lint');
grunt.registerTask('test', 'exec:gulp-test-unit');
grunt.registerTask('unit', 'exec:gulp-test-unit');
grunt.registerTask('default', ['test']);
grunt.registerTask('travis', ['jshint','jscs', 'unit']);
grunt.registerTask('buildApp', "Build the test app", function (appDir, sdk) {
buildApp(appDir, this.async(), sdk);
});
grunt.registerTask('buildSafariLauncherApp', "Build the SafariLauncher app", function (sdk, xcconfig) {
buildSafariLauncherApp(this.async(), sdk, xcconfig);
});
grunt.registerTask('signApp', "Sign the test app", function (certName) {
signApp("TestApp", certName, this.async());
});
grunt.registerTask('authorize', "Authorize developer", function (insecure) {
authorize(grunt, insecure, this.async());
});
grunt.registerTask('log', "Tail appium.log", function () {
tail(grunt, path.resolve(__dirname, "appium.log"), this.async());
});
grunt.registerTask('configAndroidBootstrap', function () {
setupAndroidBootstrap(grunt, this.async());
});
grunt.registerTask('buildAndroidBootstrap', function () {
buildAndroidBootstrap(grunt, this.async());
});
grunt.registerTask('buildSelendroidServer', function () {
buildSelendroidServer(this.async());
});
grunt.registerTask('fixSelendroidAndroidManifest', function () {
var destDir = path.resolve(__dirname, "build", "selendroid");
var dstManifest = path.resolve(destDir, "AndroidManifest.xml");
fixSelendroidAndroidManifest(dstManifest, this.async());
});
grunt.registerTask('configAndroidApp', function (appName) {
setupAndroidApp(grunt, appName, this.async());
});
grunt.registerTask('buildAndroidApp', function (appName) {
buildAndroidApp(grunt, appName, this.async());
});
grunt.registerTask('buildSelendroidAndroidApp', function (appName) {
buildSelendroidAndroidApp(grunt, appName, this.async());
});
grunt.registerTask('installAndroidApp', function (appName) {
installAndroidApp(grunt, appName, this.async());
});
grunt.registerTask('docs', function () {
generateServerDocs(grunt, this.async());
});
grunt.registerTask('generateAppiumIo', function () {
generateAppiumIo(grunt, this.async());
});
grunt.registerTask('setConfigVer', function (device) {
setDeviceConfigVer(grunt, device, this.async());
});
grunt.registerTask('setBuildTime', function () {
setBuildTime(grunt, this.async());
});
grunt.registerTask('getSampleCode', function (hardcore) {
if (typeof hardcore !== "undefined" && hardcore === "hardcore") {
hardcore = true;
}
getSampleCode(grunt, hardcore, this.async());
});
grunt.registerTask('setGitRev', function (rev) {
var done = this.async();
if (typeof rev === "undefined") {
getGitRev(function (err, rev) {
if (err) throw err;
setGitRev(grunt, rev, done);
});
} else {
setGitRev(grunt, rev, done);
}
});
};
-16
View File
@@ -1,16 +0,0 @@
Google Summer of Code Ideas
=====
Appium is excited to participate as a [Google Summer of Code](https://summerofcode.withgoogle.com/) sponsor project. Here's a fun list of ideas that a Summer of Code student participant can use as a foundation for thinking about what to contribute to Appium!
|Idea|Description|
|----|-----------|
|Apple tvOS Support|Our users have been asking for an Appium driver for Apple tvOS apps. Is this possible? We're not entirely sure! Why not be awesome and build it?|
|Test App revamp|Appium uses a number of poorly-designed mobile applications in its own testing. We have to use a variety of apps because we need to test that Appium can automate all the various controls and platform features that mobile vendors provide. Really what we need is one cross-platform app (or one app per platform) that exhibit all and only the features we need to test. This would be a fun project to build some mobile apps used for testing and also demoing Appium at events and in training videos, etc...|
|Tooling and Performance|We haven't instrumented Appium with very many performance metrics, and don't really know if we're missing some low-hanging fruit in terms of performance. Maybe you can help us do that?|
|Babel|We have a lot of repos, and they're all on a really old version of Babel. They all need to stay in sync. How can we make this situation better, and upgrade to the latest and greatest?|
|Unity3d Driver|Historically, Appium hasn't been great at automating games. We don't have any particular support for the frameworks used to create games. Unity is a popular one, for example. What if we could write an Appium driver that talked to an embedded process in a test version of a Unity game, that allowed us to find and interact with 3d elements? It would be amazing! You can also be amazing and lead Appium into this new world.|
|Testing the Internet of Things|Appium's architecture makes it dead simple to integrate drivers for automating new technologies. What about _really_ new technologies like IoT devices? Help to redefine the semantics of the WebDriver protocol for use with IoT, and build a driver for an IoT device to prove it out.|
|Driver for X|Have an idea of something else Appium could automate that it doesn't already? Build a driver for it! This would involve some awesome Node.js code, plus whatever else is needed to integrate with the platform you have in mind.|
Hopefully this gives you some ideas of fun projects that would be substantial and long-lasting contributions to the Appium community.
+1 -189
View File
@@ -1,192 +1,4 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright JS Foundation and other contributors, https://js.foundation
Copyright 2012-2013 Appium Committers
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+108 -79
View File
@@ -1,120 +1,149 @@
## Appium
[![NPM version](https://badge.fury.io/js/appium.svg)](https://npmjs.org/package/appium)
[![Node.js CI](https://github.com/appium/appium/actions/workflows/node.js.yml/badge.svg?branch=2.0)](https://github.com/appium/appium/actions/workflows/node.js.yml)
[![NPM version](https://badge.fury.io/js/appium.png)](https://npmjs.org/package/appium)
[![Dependency Status](https://david-dm.org/appium/appium.svg)](https://david-dm.org/appium/appium)
[![devDependency Status](https://david-dm.org/appium/appium/dev-status.svg)](https://david-dm.org/appium/appium#info=devDependencies)
[![Monthly Downloads](https://img.shields.io/npm/dm/appium.svg)](https://npmjs.org/package/appium)
[![Build Status](https://team-appium.ci.cloudbees.com/job/appium-master/badge/icon)](https://team-appium.ci.cloudbees.com/job/appium-master/)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
Appium is an open source, cross-platform test automation tool for native, hybrid and mobile web apps, tested on simulators (iOS, FirefoxOS), emulators (Android), and real devices (iOS, Android, FirefoxOS).
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.
**Note:** we have just recently released Appium 1.0. If you already have a bunch of Appium tests, you might want to check out the [Migrating to 1.0](/docs/en/advanced-concepts/migrating-to-1-0.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)
* FirefoxOS
See the [platform support doc](/docs/en/appium-setup/platform-support.md) for more detailed information.
### 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).
to use of standard automation APIs on all platforms.
2. You can write tests with your favorite dev tools using any [WebDriver](https://code.google.com/p/selenium/wiki/JsonWireProtocol)-compatible
language such as Java, [Objective-C](https://github.com/appium/selenium-objective-c),
JavaScript with Node.js (in [promise, callback](https://github.com/admc/wd) or [generator](https://github.com/jlipps/yiewd) flavors),
PHP, Python, [Ruby](https://github.com/appium/ruby_lib), C#, Clojure, or Perl
with the Selenium WebDriver API and language-specific client libraries.
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.
Investing in the [WebDriver](https://code.google.com/p/selenium/wiki/JsonWireProtocol) protocol means you are betting on a single, free and open protocol for testing that has become a defacto 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 use Apple's UIAutomation library without Appium you can only write tests
using JavaScript and you can only run tests through the Instruments application.
Similarly, with Google's UiAutomator you can only write tests in Java. Appium
opens up the possibility of true cross-platform native mobile automation. 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).
### I don't get it yet...
If you're new to Appium, or want a fuller 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+.
Your environment needs to be setup for the particular mobile platforms that you
want to run tests on. See below for particular platform requirements.
### Get Started
If you want to run Appium via an `npm install`, hack with or contribute to Appium, you will need
[node.js and npm](http://nodejs.org) 0.10 or greater (use [n](https://github.com/visionmedia/n) or
`brew install node` to install Node.js. Make sure you have not installed Node or Appium with `sudo`,
otherwise you'll run into problems). We recommend the latest stable version.
Check out our [Getting Started](/docs/en/about-appium/getting-started.md) guide
to get going with Appium.
To verify that all of Appium's dependencies are met you can use `appium-doctor`.
Run `appium-doctor` and supply the `--ios` or `--android` flags to verify that all
of the dependencies are set up correctly. If running from source, you may have to use
`./bin/appium-doctor.js` or `node bin/appium-doctor.js`.
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)!
You also need to download the Appium client for your language so you can write tests. The Appium clients are simple extensions to the WebDriver clients. You can see the list of clients and links to download instructions at the [Appium clients list](/docs/en/about-appium/appium-clients.md).
### Documentation
#### iOS Requirements
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.
* Mac OS X 10.7 or higher, 10.9.2 recommended
* XCode &gt;= 4.6.3, 5.1.1 recommended
* Apple Developer Tools (iPhone simulator SDK, command line tools)
* [Ensure you read our documentation on setting yourself up for iOS testing!](/docs/en/appium-setup/running-on-osx.md)
[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.
#### Android Requirements
Once the PR has been merged, the latest documentation will be in [appium.io](http://appium.io)
* [Android SDK](http://developer.android.com) API &gt;= 17 (Additional features require 18/19)
* Appium supports Android on OS X, Linux and Windows. Make sure you follow the
directions for setting up your environment properly for testing on different OSes:
* [linux](/docs/en/appium-setup/running-on-linux.md)
* [osx](/docs/en/appium-setup/running-on-osx.md)
* [windows](/docs/en/appium-setup/running-on-windows.md)
#### FirefoxOS Requirements
* [Firefox OS Simulator](https://developer.mozilla.org/en/docs/Tools/Firefox_OS_Simulator)
### Quick Start
Kick up an Appium server, and then run a test written in your favorite [WebDriver](https://code.google.com/p/selenium/wiki/JsonWireProtocol)-compatible language!
You can run an Appium server using node.js or using the application, see below.
#### Using Node.js
```center
$ npm install -g appium
$ appium &
```
#### Using the App
* [Download the Appium app](https://github.com/appium/appium/releases)
* Run it!
### Writing Tests for Appium
The main guide for getting started writing and running tests is [the running tests](/docs/en/writing-running-appium/running-tests.md) doc, which includes explanations for iOS, Android, and Android older devices. If you're interested in testing on physical hardware, you might be interested in our [real devices guide](/docs/en/appium-setup/real-devices.md).
Essentially, we support a subset of the [Selenium WebDriver JSON Wire Protocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol), and extend it so that you can specify mobile-targeted [desired capabilities](/docs/en/writing-running-appium/caps.md) to run your test through Appium.
You find elements by using a subset of WebDriver's element-finding strategies.
See [finding elements](/docs/en/writing-running-appium/finding-elements.md) for detailed information. We also have several extensions to the JSON Wire Protocol for [automating mobile gestures](/docs/en/writing-running-appium/touch-actions.md) like tap, flick, and swipe.
You can also automate web views in hybrid apps! See the [hybrid app guide](/docs/en/advanced-concepts/hybrid.md)
This repository contains [many examples of tests in a variety of different languages](https://github.com/appium/sample-code)!
For the full list of Appium doc pages, visit [this directory](/docs/en/).
### How It Works
Appium drives various native automation frameworks and provides an API based on
Selenium's [WebDriver JSON wire protocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol).
Appium drives Apple's UIAutomation library for iOS support, which is based on
[Dan Cuellar's](http://github.com/penguinho) work on iOS Auto.
Android support uses the UiAutomator framework for newer platforms and
[Selendroid](http://github.com/DominikDary/selendroid) for older Android platforms.
FirefoxOS support leverages [Marionette](https://developer.mozilla.org/en-US/docs/Marionette),
an automation driver that is compatible with WebDriver and is used to automate
Gecko-based platforms.
### Contributing
Please take a look at our [contribution documentation](CONTRIBUTING.md)
for instructions on how to build, test, and run Appium from the source.
for instructions on how to build, test and run Appium from source.
### Roadmap
### Project Credits & Inspiration
Interested in where Appium is heading in the future? Check out the [Roadmap](ROADMAP.md)
[Credits](/docs/en/contributing-to-appium/credits.md)
### Project History, Credits & Inspiration
### Mailing List
* [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!
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.
We put together a [troubleshooting guide](/docs/en/appium-setup/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
### Using Robots
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)
Using Appium with [Tapster](https://github.com/hugs/tapsterbot) and other robots is possible,
check out the [Appium Robots](https://github.com/appium/robots) project!
-59
View File
@@ -1,59 +0,0 @@
Appium Roadmap
---------------
This document is designed to be a living record of the current and projected
priorities for the Appium project. It is, of course, always subject to change
and exists solely to give the community an idea of where we're going. The
roadmap is set by the Appium core team. If you have feature suggestions for
Appium, please submit a [GitHub issue](https://github.com/appium/appium/issues)
and, if of sufficient size and approved by the team, it will be added here. If
you have concerns about the roadmap, you can e-mail the Appium devs at
`appium-developers@googlegroups.com` or raise a GitHub issue. Note that
bugfixes and miscellaneous features are not considered "roadmap projects", and
will be addressed in the due course of normal Appium development. This page
exists to outline large-scale future plans for Appium.
## Current Roadmap Projects
| Project | Description | ETD | Projected Appium Release |
|---------|-------------|-----|--------------------------|
|[Appium CI + Metrics Improvements](https://github.com/appium/appium/issues/7168)|We have CI servers running via Cloudbees that we don't understand and which break. Let's document and own them so they work reliably. Also, let's implement gathering various metrics about driver performance so we can track this over time and ensure we're not releasing a driver which has decreased in performance or reliability.|Q2 2017|N/A|
## Upcoming Projects (in rough order of priority)
| Project | Description |
|---------|-------------|
|[Appium Client Library Updates](https://github.com/appium/appium/issues/7170)|It's been too long since we ensured that Appium's client libraries were up to date with the server|
|[Test App Overhaul](https://github.com/appium/appium/issues/7172)|Our current test applications (the ones used to test Appium's iOS and Android support) are not ideal. We use too many of them and the ones we use have a random hodgepodge of app SDK features, sometimes not enough to sufficiently test automation support. It'd be great to find a way to ensure our test app(s) have all the features we need to test, and keep in sync with our requirements.|
|[iOS Test Startup Time Improvement](https://github.com/appium/appium/issues/7173)|iOS startup times have gotten progressively longer with each iOS release. In part this is Apple's fault and there's not anything we can do about it. But we should investigate and see if we can be more efficient in how we start, especially given that we can now focus on XCUITest and leave Instruments behind|
|[Appium Dearchitecture](https://github.com/appium/appium/issues/7174)|OK, we went a bit overboard in Appium 1.5 by exploding Appium into 40+ repos and NPM packages. Let's think a little more critically about it and consolidate into the minimal number of repos/packages that make sense for our code and community patterns.|
|[Appium 2.0](https://github.com/appium/appium/issues/7175)|Appium, rather than bundling all the separate drivers by default, becomes a driver management interface (in addition to continuing to play the role of automation frontend server). Appium gets a set of CLI tools for users to pick and choose which drivers and versions of drivers they want to use via Appium|
## Projects Under Consideration (unplanned and unprioritized)
| Project | Description |
|---------|-------------|
|Windows Phone Support|There has been some work done on automating Windows Phone apps. We could take this all the way to integration with Appium in the form of a WindowsDriver.|
|Apple Watch support|Appium should support Apple Watch apps via the Watch simulator|
|Unity3d backend POC|This is a research project to determine whether we can add some kind of support for 3d game automation, probably based on the Unity3d game development platform.|
## Completed Roadmap Projects
| Project | Description | Completed | Appium Release | Notes |
|---------|-------------|-----------|----------------|-------|
|[Sample Code Overhaul](https://github.com/appium/appium/issues/7171)|Our sample code repo has grown tangled and broken. Let's make a new one with minimal examples which are the same across every language, and actually maintain the repo so as not to let it become overgrown.|
|[Onboarding Overhaul](https://github.com/appium/appium/issues/7169)|Have a new site built with MkDocs that documents all of the Selenium and Appium commands with code samples|1/2018|n/a|appium.io|
|[New Appium GUIs](https://github.com/appium/appium/issues/7167)|The current Appium GUIs (Appium.app and Appium.exe) have a number of issues. They aren't maintained by the core Appium team. They're written in Objective-C and C# respectively: two languages, and specifically, two languages other than Appium's core language. Because of this they lag behind the Appium server and are often broken. However, users love them primarily because of the Inspector feature (the thing that lets them graphically navigate their app), so we have to field a ton of complaints about these projects. There's an opportunity to start over. With [Electron](http://electron.atom.io/), we'd be able to take the new version of Appium we're working on and embed it directly inside a Node-based GUI app written using the languages and technologies the core team is experienced with. We'd have one codebase and could distribute the app on Mac, Windows, and Linux. The GUIs would become an official part of Appium's release cycle so they wouldn't be broken.|3/2017|N/A|[Appium Desktop website](https://github.com/appium/appium-desktop)|
|[Android 7.1.1 Support](https://github.com/appium/appium/issues/7165)|Google has released Android 7.1.1 (API Level 25). Ensure it works with UiAutomator 1/2|2/2017|1.6.4||
|[Android 7.0 Support](https://github.com/appium/appium/issues/7156)|Support Android 7 (Nougat)|11/2016|1.6.3||
|[iOS 10.2 Support](https://github.com/appium/appium/issues/7166)|Support iOS 10.2|11/2016|1.6.1||
|[iOS 10.1 Support](https://github.com/appium/appium/issues/7105)|Support iOS 10.1|11/2016|1.6.1||
|UiAutomator2 integration|Google has released [UiAutomator 2](http://developer.android.com/reference/android/support/test/uiautomator/package-summary.html), and it promises to fix some issues and limitations with the previous UiAutomator support. We will build this inside of Selendroid since it requires an instrumentation context.|10/2016?|1.6.0|
|XCUITest integration / iOS 10 support|Instruments + UIAutomation has been working well for many Appium users, but requires crazy workarounds to deal with bugs which remain unfixed on the Apple side. Also, UIAutomation has been removed in favor of XCUITest for iOS 10+. This new backend would exist alongside the UIAutomation backend.|10/2016|1.6.0||
|iOS 9.3 support|Appium should support iOS 9.3 / Xcode 7.3|3/2016|1.5.1||
|[Architecture Overhaul](https://github.com/appium/appium/issues/5169)|Appium's architecture has grown unwieldy enough that adding new features and preventing regressions has become difficult. A rearchitecture is in order to solve these issues as well as migrate the codebase to a form of JS much easier to work in and understand.|2/2015|1.5.0||
|iOS 9.2 support|Appium should support iOS 9.2 / Xcode 7.2|11/2015|1.4.14||
|iOS 9.1 support|Appium should support iOS 9.1 / Xcode 7.1|10/2015|1.4.12||
|iOS 9.0 support|Appium should support iOS 9.0 / Xcode 7.0|10/2015|1.4.11||
|iOS 8.4 support|Appium should support iOS 8.4 / Xcode 6.2|5/2015|1.4.0||
|Appium CI|Appium has unique needs for Continuous Integration because of the highly specialized environments required (iOS simulators, Xcode, Android emulators, the Android SDK, etc...). We therefore need to create a custom CI solution (perhaps sitting underneath Cloudbees or some other OSS-friendly CI server) that can be used for all Appium projects which need integration tests.|5/2015|_N/A_|Usage instructions at [appium/appium-ci](https://github.com/appium/appium-ci)|
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
-32
View File
@@ -1,32 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "12"
},
"shippedProposals": true
}
]
],
"plugins": ["source-map-support", "@babel/plugin-transform-runtime"],
"comments": false,
"sourceMaps": "both",
"env": {
"coverage": {
"plugins": [
[
"istanbul",
{
"exclude": ["test", "build"]
}
]
]
},
"test": {
"retainLines": true,
"comments": true
}
}
}
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env node
"use strict";
var IOSChecker = require('../lib/doctor/ios.js').IOSChecker
, AndroidChecker = require('../lib/doctor/android.js').AndroidChecker
, DevChecker = require('../lib/doctor/dev.js').DevChecker
, common = require("../lib/doctor/common.js")
, eol = require('os').EOL
, async = require('async')
, isMac = process.platform === 'darwin';
// , isWindows = process.platform === 'win32';
var argv = process.argv
, doAndroid = argv.indexOf('--android') > -1
, doIOS = argv.indexOf('--ios') > -1
, doDev = argv.indexOf('--dev') > -1
// , verbose = argv.indexOf('--verbose') > -1
, broadcast = argv.indexOf('--port') > -1
, port = null;
if (broadcast) {
port = argv[argv.indexOf("--port") + 1];
}
if (!doIOS && !doAndroid) {
doIOS = isMac;
doAndroid = true;
}
var log = new common.Log(port);
var runiOSChecks = function (cb) {
if (doIOS) {
if (!isMac) {
log.fail("iOS Checks cannot be run on Windows.");
log.exitDoctor();
}
var iosChecker = new IOSChecker(log);
log.comment("Running iOS Checks");
iosChecker.runAllChecks(function (err) {
if (!err) {
log.pass("iOS Checks were successful." + eol);
cb();
} else {
log.exitDoctor();
}
});
} else {
cb();
}
};
var runAndroidChecks = function (cb) {
if (doAndroid) {
var androidChecker = new AndroidChecker(log);
log.comment("Running Android Checks");
androidChecker.runAllChecks(function (err) {
if (!err) {
log.pass("Android Checks were successful." + eol);
cb();
} else {
log.exitDoctor();
}
});
} else {
cb();
}
};
var runDevChecks = function (cb) {
if (doDev) {
var devChecker = new DevChecker(log);
log.comment("Running Dev Checks");
devChecker.runAllChecks(function (err) {
if (!err) {
log.pass("Dev Checks were successful." + eol);
cb();
} else {
log.exitDoctor();
}
});
} else {
cb();
}
};
if (require.main === module) {
var mainMethod = function () {
async.series([
runiOSChecks,
runAndroidChecks,
runDevChecks
], function (err) {
if (!err) {
log.pass("All Checks were successful");
log.stopBroadcast();
} else {
log.exitDoctor();
}
});
};
if (log.broadcast) {
log.startBroadcast(mainMethod);
} else {
mainMethod();
}
}
Executable
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env node
"use strict";
var net = require('net')
, repl = require('repl')
, logFactory = require('../lib/server/logger.js')
, parser = require('../lib/server/parser.js');
require('colors');
var args = parser().parseArgs();
logFactory.init(args);
var appium = require('../lib/server/main.js');
var startRepl = function () {
var help = function () {
console.log("\nWelcome to the Appium CLI".cyan);
console.log(" - Access the appium object via the object: 'appium'".grey);
console.log(" - appium.run is the function to start the server".grey);
console.log(" - args is the default params data structure".grey);
console.log(" - set args.app then run appium.run(args);\n".grey);
return 'Thanks for asking';
};
help();
var r = repl.start('(appium): ');
r.context.appium = appium;
r.context.parser = parser();
r.context.help = help;
r.context.args = {
app: '/path/to/test/app'
, udid: null
, address: '127.0.0.1'
, port: 4723
};
var connections = 0;
var server = net.createServer(function (socket) {
connections += 1;
socket.setTimeout(5 * 60 * 1000, function () {
socket.destroy();
});
repl.start("(appium): ", socket);
}).listen(process.platform === "win32" ? "\\\\.\\pipe\\node-repl-sock-" + process.pid : "/tmp/node-repl-sock-" + process.pid);
r.on('exit', function () {
server.close();
process.exit();
});
};
if (process.argv[2] && process.argv[2].trim() === "--shell") {
startRepl();
} else {
appium.run(args, function () { /* console.log('Rock and roll.'.grey); */ });
}
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env node
"use strict";
var authorize = require('../grunt-helpers.js').authorize;
var gruntMock = {
fatal: function (msg) {
console.error(msg);
process.exit(0);
},
log: {
writeln: function (msg) {
console.log(msg);
}
}
};
if (require.main === module) {
authorize(gruntMock, false, function (err) {
if (err) throw err;
console.log("Authorization successful");
});
}
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env node
/*
* Small tool, launching and monitoring ios-web-kit-proxy, and relauching
* on predefined errors.
*
* Usage:
* ./bin/ios-webkit-debug-proxy-launcher.js [args]
* args: ios-webkit-debug-proxy args (they will be passed over)
*
* Example:
* ./bin/ios-webkit-debug-proxy-launcher.js -c <UDID>:27753 -d
*
* Note:
* For iOS8.1 try this first:
* brew install --HEAD ideviceinstaller
*/
"use strict";
var spawn = require('child_process').spawn,
_ = require('underscore');
var args = process.argv.slice(2);
var RESTART_ON_MESSAGES = [
'Invalid message _rpc_applicationUpdated',
'Invalid message _rpc_applicationSentListing'];
var PROXY_CMD = 'ios_webkit_debug_proxy';
function startProxy() {
console.log('RUNNING:', PROXY_CMD, args.join(' '));
var proxy = spawn(PROXY_CMD, args);
proxy.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
proxy.stderr.on('data', function (data) {
console.log('stderr: ' + data);
var restartMessage = _(RESTART_ON_MESSAGES).find(function (message) {
return ('' + data).indexOf(message) >= 0;
});
if (restartMessage) {
console.log('Detected error message:', restartMessage);
console.log('Killing proxy!');
proxy.kill('SIGTERM');
process.nextTick(startProxy);
}
});
proxy.on('close', function (code) {
console.log('child process exited with code ' + code);
});
}
startProxy();
Executable
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash
ACTION='usage'
ALL_PACKAGES=(
'appium-atoms'
'appium-instruments'
'appium-uiauto'
'appium-adb'
)
PACKAGES=()
for i in "$@"
do
case $i in
-l|--link)
ACTION='link'
shift
;;
-u|--unlink)
ACTION='unlink'
shift
;;
-m|--master)
MASTER=true
shift
;;
*)
PACKAGES+=($i)
shift
;;
esac
done
if [[ ${#PACKAGES[*]} == 0 ]]; then
PACKAGES=("${ALL_PACKAGES[@]}")
fi
function npmlink {
git submodule update --init submodules/$1
pushd submodules/$1
if [[ $MASTER ]]; then
git checkout master
fi
npm link
popd
npm link $1
}
if [[ $ACTION == 'usage' ]]; then
echo 'Usage:'
echo ' link all: dev.sh --link [--master]'
echo ' unlink all: dev.sh --unlink'
echo ' link specific packages: dev.sh --link [--master] <pkg1> <pkg2>...'
echo ' unlink specific packages: dev.sh --unlink <pkg1> <pkg2>...'
echo 'Short verion:'
echo ' link all: dev.sh -l [-m]'
echo ' unlink all: dev.sh -u'
echo ' link specific packages: dev.sh -l [-m] <pkg1> <pkg2>...'
echo ' unlink specific packages: dev.sh -u <pkg1> <pkg2>...'
fi
if [[ $ACTION == 'link' ]]; then
for i in "${PACKAGES[@]}"
do
npmlink $i
done
fi
if [[ $ACTION == 'unlink' ]]; then
for i in "${PACKAGES[@]}"
do
npm unlink $i
done
fi
Executable
+65
View File
@@ -0,0 +1,65 @@
#!/bin/bash
set +e
if [[ "$1" = "" ]]; then
branch="master"
else
branch="$1"
fi
XCODE_PATH=$(xcode-select -print-path)
if test -d $XCODE_PATH/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk ||
[ -e /Library/Developer/CoreSimulator/Profiles/Runtimes/iOS\ 7.1.simruntime ]; then
echo "Confirmed iOS7.1 SDK available"
else
echo "You don't have iOS 7.1 SDK available. Switch to Xcode 5?"
exit 1
fi
node --version | grep "v0.10" >/dev/null
if [ $? -gt 0 ]; then
echo "You need to publish Appium using Node 0.10.x, not $(node --version)"
exit 1;
else
echo "Node version OK"
fi
git remote | grep "upstream" >/dev/null
if [ $? -gt 0 ]; then
echo "You need to have an 'upstream' remote to pull from / push tags to"
exit 1
else
echo "Git remote OK"
fi
git status | grep -E "nothing to commit.+working directory clean" >/dev/null
if [ $? -gt 0 ]; then
echo "Working directory isn't clean, commit/clean then publish"
exit 1
else
echo "Working directory clean"
fi
git status | grep "Your branch is ahead" >/dev/null
if [ $? -eq 0 ]; then
echo "Your branch isn't in sync with origin"
exit 1
else
echo "In sync with origin"
fi
set -e
echo "Getting latest from upstream:$branch"
git pull upstream $branch
echo "Resetting"
./reset.sh --hardcore --real-safari --chromedriver-install-all --chromedriver-version 2.14
version=$(cat package.json | $(npm bin)/underscore extract version | sed 's/\"//g')
echo "Clearing npm cache"
npm cache clear appium
echo "Publishing on npm"
if [[ "$version" =~ "beta" ]]; then
npm publish --tag beta
else
npm publish
fi
echo "Git tagging"
git tag -a "v$version" -m "tag appium@$version for npm publish"
git push --tags upstream $branch
+15
View File
@@ -0,0 +1,15 @@
param([string]$mochaArgs = "", [switch]$android, [switch]$selendroid)
$all = !($android -or $selendroid)
$appiumMocha="mocha --recursive -t 90000 -R spec $mochaArgs "
if ($android -or $all){
"RUNNING ANDROID TESTS"
"---------------------"
Invoke-Expression ($appiumMocha + "test\functional\android test\functional\common -g '@skip-android-all' -i")
}
if ($selendroid -or $all){
"RUNNING SELENDROID TESTS"
"------------------------"
Invoke-Expression ($appiumMocha + "test\functional\selendroid -g '@skip-selendroid-all' -i")
}
Executable
+171
View File
@@ -0,0 +1,171 @@
#!/bin/sh
set -e
mocha_args=""
ios_only=false
ios6_only=false
ios7_only=false
ios71_only=false
ios8_only=false
ios81_only=false
ios82_only=false
android_only=false
android_chrome=false
selendroid_only=false
gappium_only=false
real_device=false
all_tests=true
xcode_switch=true
xcode_path=""
if command -v xcode-select 2>/dev/null; then
xcode_path="$(xcode-select -print-path | sed s/\\/Contents\\/Developer//g)"
fi
did_switch_xcode=false
for arg in "$@"; do
if [ "$arg" = "--ios" ]; then
ios_only=true
all_tests=false
elif [ "$arg" = "--android" ]; then
android_only=true
all_tests=false
elif [ "$arg" = "--android-chrome" ]; then
android_chrome=true
all_tests=false
elif [ "$arg" = "--selendroid" ]; then
selendroid_only=true
all_tests=false
elif [ "$arg" = "--gappium" ]; then
gappium_only=true
all_tests=false
elif [ "$arg" = "--ios6" ]; then
ios6_only=true
all_tests=false
elif [ "$arg" = "--ios7" ]; then
ios7_only=true
all_tests=false
elif [ "$arg" = "--ios71" ]; then
ios71_only=true
all_tests=false
elif [ "$arg" = "--ios8" ]; then
ios8_only=true
all_tests=false
elif [ "$arg" = "--ios81" ]; then
ios81_only=true
all_tests=false
elif [ "$arg" = "--ios82" ]; then
ios82_only=true
all_tests=false
elif [ "$arg" = "--no-xcode-switch" ]; then
xcode_switch=false
elif [ "$arg" = "--real-device" ]; then
real_device=true
elif [ "$arg" =~ " " ]; then
mocha_args="$mocha_args \"$arg\""
else
mocha_args="$mocha_args $arg"
fi
done
appium_mocha="./node_modules/.bin/mocha --recursive $mocha_args"
run_ios_tests() {
echo "RUNNING IOS $1 TESTS"
echo "---------------------"
if $xcode_switch; then
if test -d /Applications/Xcode-$1.app; then
echo "Found Xcode for iOS $1, switching to it"
sudo xcode-select -switch /Applications/Xcode-$1.app
did_switch_xcode=true
else
echo "Did not find /Applications/Xcode-$1.app, using default"
fi
fi
DEVICE=$2 time $appium_mocha -g $3 -i \
test/functional/common \
test/functional/ios
}
if $ios6_only || $ios_only || $all_tests; then
run_ios_tests "6.1" "ios6" "@skip-ios6|@skip-ios-all"
fi
if $ios7_only || $all_tests; then
run_ios_tests "7.0" "ios7" "@skip-ios7|@skip-ios-all"
fi
if $ios71_only || $all_tests; then
run_ios_tests "7.1" "ios71" "@skip-ios71|@skip-ios7|@skip-ios-all|@skip-ios7up"
fi
if $ios8_only || $all_tests; then
run_ios_tests "8.0" "ios8" "@skip-ios8|@skip-ios-all|@skip-ios7up"
fi
if $ios81_only || $all_tests; then
run_ios_tests "8.1" "ios81" "@skip-ios81|@skip-ios8|@skip-ios-all|@skip-ios7up"
fi
if $ios82_only || $all_tests; then
run_ios_tests "8.2" "ios82" "@skip-ios82|@skip-ios81|@skip-ios8|@skip-ios-all|@skip-ios7up"
fi
if $did_switch_xcode; then
echo "Switching back to default Xcode ($xcode_path)"
sudo xcode-select -switch $xcode_path
fi
if $android_only || $all_tests; then
echo "RUNNING ANDROID TESTS"
echo "---------------------"
if $real_device; then
DEVICE=android REAL_DEVICE=true time $appium_mocha \
-g '@skip-android-all|@android-arm-only|@skip-real-device' -i \
test/functional/common \
test/functional/android
else
DEVICE=android time $appium_mocha \
-g '@skip-android-all|@android-arm-only' -i \
test/functional/common \
test/functional/android
fi
fi
if $android_chrome; then
echo "RUNNING ANDROID CHROME TESTS"
echo "---------------------"
if $real_device; then
DEVICE=android REAL_DEVICE=true time $appium_mocha \
-g '@skip-chrome|@skip-android-all' -i \
test/functional/android/chrome
else
DEVICE=android time $appium_mocha \
-g '@skip-chrome|@skip-android-all' -i \
test/functional/android/chrome
fi
fi
if $selendroid_only || $all_tests; then
echo "RUNNING SELENDROID TESTS"
echo "---------------------"
DEVICE=selendroid time $appium_mocha -g '@skip-selendroid-all' -i \
test/functional/selendroid
fi
if $gappium_only || $all_tests; then
echo "RUNNING GAPPIUM TESTS"
echo "---------------------"
DEVICE=ios81 time $appium_mocha test/functional/gappium
# disabling, ios6 not working yet xcode 6
#DEVICE=ios6 time $appium_mocha test/functional/gappium
echo "Start the android emulator api 19 and press Enter."
read
DEVICE=android time $appium_mocha test/functional/gappium
# disabling gappium test, see https://github.com/selendroid/selendroid/issues/658
#echo "Start the android emulator api 16 and press Enter."
#read
#DEVICE=selendroid time $appium_mocha test/functional/gappium
fi
-40
View File
@@ -1,40 +0,0 @@
# parameters: # No params yet, but may add later
jobs:
- job: generate_docs
pool:
vmImage: "macOS 10.14"
variables:
CC: gcc
CXX: g++
steps:
- task: NodeTool@0
inputs:
versionSpec: '12.x'
- script: |
# do git stuff
npm install
brew install hub
hub --version
git remote add triager https://triager:$GITHUB_TOKEN@github.com/appium/appium
git checkout -b generate-docs-$BUILD_SOURCEVERSION
git status
displayName: Checkout Generate Docs Branch
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
- script: |
# Generate the docs
npm run generate-docs
git add .
# log the status so we know what is going on, on failure
git status -s
# If docs were generated, make a PR to update the docs
if [[ -n $(git status -s) ]]; then
git commit -a -n -m 'Update generated docs [ci skip]'
git push triager generate-docs-$BUILD_SOURCEVERSION
hub pull-request -b "appium:master" -h "appium:generate-docs-$BUILD_SOURCEVERSION" -m "docs: Update auto-generated docs"
fi
displayName: Generate Docs and Make PR
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
-2
View File
@@ -1,2 +0,0 @@
jobs:
- template: templates/bundle-template.yml
-3
View File
@@ -1,3 +0,0 @@
const semver = require('semver');
const { version } = require('../../package.json');
console.log(semver(version).prerelease[0]); //eslint-disable-line no-console
@@ -1,22 +0,0 @@
const path = require('path');
const { fs, logger } = require('appium-support');
const { asyncify } = require('asyncbox');
const packageJson = require('../../package.json');
const log = new logger.getLogger('Create Release Branch:');
async function setPackageJsonVersion (version = `${process.env.MINOR_BRANCH_NAME}.0-rc.0`) {
packageJson.version = version;
log.info(`Setting version to: ${version}`);
await fs.writeFile(
path.resolve(__dirname, '..', '..', 'package.json'),
JSON.stringify(packageJson, null, 2),
'utf8',
);
}
if (require.main === module) {
asyncify(setPackageJsonVersion);
}
module.exports = setPackageJsonVersion;
-40
View File
@@ -1,40 +0,0 @@
# parameters: # No params yet, but may add later
jobs:
- job: bundle_and_upload_appium_zip
pool:
vmImage: 'macOS 10.14'
variables:
CC: gcc
CXX: g++
steps:
- script: gcc --version
displayName: Print GCC Version
- task: NodeTool@0
inputs:
versionSpec: '12.x'
- script: npm install
displayName: Install NPM Dependencies
- script: npm run build
displayName: npm run build
- script: npm prune --production
displayName: Get rid of dev dependencies
- script: |
curl -o node-darwin.tar.gz https://nodejs.org/dist/v12.16.1/node-v12.16.1-darwin-x64.tar.gz
mkdir node-darwin-unpacked
tar -xzf node-darwin.tar.gz -C node-darwin-unpacked/ --strip-components 1
rm -f node-darwin.tar.gz
cp node-darwin-unpacked/bin/node node-darwin
rm -rf node-darwin-unpacked
displayName: Download NodeJS
- script: npm run zip
displayName: Create the bundle zip
- script: npm install
displayName: Reinstall dev dependencies
- task: PublishPipelineArtifact@0
inputs:
targetPath: appium.zip
artifactName: appium
- script: npm run upload
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
displayName: Upload to appium/appium-build-store Github Releases
-31
View File
@@ -1,31 +0,0 @@
# parameters: # No params yet, but may add later
jobs:
- job: update_appium_io
pool:
vmImage: 'Ubuntu-18.04'
variables:
CC: gcc
CXX: g++
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
- script: |
pip install mkdocs==0.16.3
git config --global user.email "maintainers@appium.io"
git config --global user.name "Appium Triager"
git clone https://triager:$GITHUB_TOKEN@github.com/appium/appium.io.git --branch=gh-pages
pushd appium.io
git remote add triager https://triager:$GITHUB_TOKEN@github.com/appium/appium.io
git checkout -b docs-$BUILD_SOURCEVERSION
bundle install
npm install
npm run build:docs
git add docs
git commit -a -n -m "docs: Update documentation for latest version"
git push triager docs-$BUILD_SOURCEVERSION
hub pull-request -b "appium:gh-pages" -h "appium:docs-$BUILD_SOURCEVERSION" -m "docs: Update documentation for latest version"
popd
displayName: Make branch with Updated Docs and make PR
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
Executable
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
{ set -e; } 2>/dev/null
{ set -x; } 2>/dev/null
# Loading appium-ci-gulper submodule
export APPIUM_ROOT="$(pwd)"
git submodule update --remote --init submodules/appium-ci-gulper
pushd submodules/appium-ci-gulper
git pull origin master
{ set +x; } 2>/dev/null
# Running appium-ci-gulper submodule
# This sets up node etc...
source ./setup
{ set -x; } 2>/dev/null
-23
View File
@@ -1,23 +0,0 @@
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": 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"
]
}
}
+4 -9
View File
@@ -1,16 +1,11 @@
# docs
## doc site
##doc site
Formatted doc is [here](http://appium.io/documentation.html?lang=en).
## doc translation
##doc translation
At the moment we are focusing on improving the English documentation. When it
is done, we are planning to establish proper i18n and l10n processes so that it is
At the moment we are focusing on improving the english documentation. When it
is done we are planning to setup proper i18n l10n processes so that it is
easier for people to help in translating the documentation.
## Bump supported NodeJS version
- Refer to the [Node.js Release Working Group README](https://github.com/nodejs/release#readme) to check LTS, maintenance, and EOL Node.js versions
- Example to bump supported NodeJS version: appium/appium#15000
-1
View File
@@ -1 +0,0 @@
The latest doc in Chinese, maintained by TesterHome Appium 中文文档小组.
-33
View File
@@ -1,33 +0,0 @@
## 支持 Appium 服务器的客户端程序库列表
这些库封装了标准的 Selenium 客户端,提供了所有 [JSON Wire protocol](https://w3c.github.io/webdriver/webdriver-spec.html) 指定的常规 selenium 命令,并额外添加操控移动设备相关的命令,例如 **多点触控手势** 和 **屏幕方向**。
Appium 客户端程序库实现了 [Mobile JSON Wire Protocol](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 用户使用各种设备操作(例如在测试会话过程中安装 / 卸载应用)。这就是为什么我们需要 Appium 特定的客户端,而不只是「原生(vanilla)」的 Selenium 客户端。当然,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)
---
EOF.
由 @黑水 翻译,TesterHome 社区 id:sanlengjingvv
@lihuazhang 校验
翻译:@[Pandorym](https://github.com/Pandorym)
Last english version: ef49649f5e53a644f6732575734aeaea78068234, Feb 22, 2019
-73
View File
@@ -1,73 +0,0 @@
## Appium 介绍
Appium 是一个开源工具,用于自动化 iOS 手机、 Android 手机和 Windows 桌面平台上的原生、移动 Web 和混合应用。**「原生应用」**指那些用 iOS、 Android 或者 Windows SDKs 编写的应用。**「移动 Web 应用」**是用移动端浏览器访问的应用( Appium 支持 iOS 上的 Safari 、Chrome 和 Android 上的内置浏览器)。**「混合应用」**带有一个「webview」的包装器——用来和 Web 内容交互的原生控件。类似于 [Apache Cordova](https://cordova.apache.org) 项目,创建一个混合应用使得用 Web 技术开发然后打包进原生包装器创建一个混合应用变得容易了。
重要的是,Appium 是跨平台的:它允许你用同样的 API 对多平台(iOS、Android、Windows)写测试。做到在 iOS、Android 和 Windows 测试套件之间复用代码。
了解 Appium “支持”这些平台意味着什么、有哪些自动化方式的详细信息,请参见 [Appium 支持的平台](/docs/cn/about-appium/platform-support.md)。
### Appium 的理念
Appium 旨在满足移动端自动化需求的理念,概述为以下四个原则:
1. 你不应该为了自动化而重新编译你的应用或以任何方式修改它。
2. 你不应该被限制在特定的语言或框架上来编写运行测试。
3. 移动端自动化框架不应该在自动化接口方面重造轮子。
4. 移动端自动化框架应该开源,在精神、实践以及名义上都该如此。
### Appium 的设计
那么 Appium 项目的架构是如何实现这些理念的呢?为了实现理念#1,我们使用了系统自带的自动化框架。这样,我们不需要把 Appium 特定的或者第三方的代码编译进你的应用,这意味着**你测试使用的应用与最终发布的应用并无二致**。我们使用以下系统自带的自动化框架:
* iOS 9.3 及以上: 苹果的 [XCUITest](https://developer.apple.com/reference/xctest)
* iOS 9.3 及以下: 苹果的 [UIAutomation](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
* Android 4.3+: 谷歌的 [UiAutomator / UiAutomator2](https://developer.android.com/training/testing/ui-automator)
* Android 2.3+: 谷歌的 [Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html). (通过绑定独立的项目—— [Selendroid](http://selendroid.io) 提供对 Instrumentation 的支持)
* Windows: 微软的 [WinAppDriver](http://github.com/microsoft/winappdriver)
为了实现理念#2,我们把这些系统本身提供的框架包装进一套 API —— [WebDriver](http://docs.seleniumhq.org/projects/webdriver/) API 中。WebDriver(也叫「Selenium WebDriver」)规定了一个客户端-服务器协议(称为 [JSON Wire Protocol](https://w3c.github.io/webdriver/webdriver-spec.html)),按照这种客户端-服务器架构,可以使用任何语言编写的客户端向服务器发送适当的 HTTP 请求。已经有为 [各个流行编程语言编写的客户端](http://appium.io/downloads) 。这也意味着你可以自由使用任何你想用的的测试运行器和测试框架;客户端程序库不过是一个简单的 HTTP 客户端,可以以任何你喜欢的方式混入你的代码。换句话说,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 的概念
**客户端 / 服务器架构**<br/>
Appium 的核心一个是暴露 REST API 的 WEB 服务器。它接受来自客户端的连接,监听命令并在移动设备上执行,答复 HTTP 响应来描述执行结果。实际上客户端 / 服务器架构给予了我们许多可能性:我们可以使用任何有 http 客户端 API 的语言编写我们的测试代码,不过选一个 [Appium 客户端程序库](http://appium.io/downloads) 用起来更为容易。我们可以把服务器放在另一台机器上,而不是执行测试的机器。我们可以编写测试代码,并依靠类似 [Sauce Labs](https://saucelabs.com/products/mobile-app-testing) 的云服务接收和解释命令。
**会话(Session)**<br/>
自动化始终在一个会话的上下文中执行,这些客户端程序库以各自的方式发起与服务器的会话,但最终都会发给服务器一个 `POST /session` 请求,请求中包含一个被称作「预期能力(Desired Capabilities)」的 JSON 对象。这时服务器就会开启这个自动化会话,并返回一个用于发送后续命令的会话 ID。
**预期能力(Desired Capabilities)**<br/>
预期能力(Desired Capabilities)是一些发送给 Appium 服务器的键值对集合(比如 map 或 hash),它告诉服务器我们想要启动什么类型的自动化会话。也有许多能力(Capabilities)可以修改服务器在自动化过程中行为。例如,我们可以将 `platformName` 能力设置为 `iOS`,以告诉 Appium 我们想要 iOS 会话,而不是 Android 或者 Windows 会话。或者我们也可以设置 `safariAllowPopups` 能力为 `true` ,确保我们在 Safari 自动化会话期间可以使用 JavaScript 打开新窗口。有关 Appium 能力的完整列表,请参阅 [能力文档](/docs/cn/writing-running-appium/caps.md) 。
**Appium 服务器**<br/>
Appium 是一个用 Node.js 写的服务器。可以从[源码](https://github.com/appium/appium/blob/master/docs/cn/contributing-to-appium/appium-from-source.md)构建安装或者从 [NPM](https://www.npmjs.com/package/appium) 直接安装:
```
$ npm install -g appium
$ appium
```
Appium 的 `beta` 版本可以通过 NPM 使用 `npm install -g appium@beta` 指令进行安装。它是开发版本,所以可能存在破坏性的变更。在安装新版本请卸载 `appium@beta` (`npm uninstall -g appium@beta`)以获得一组干净的依赖。
**Appium 客户端**<br/>
有一些客户端程序库(分别在 Java、Ruby、Python、PHP、JavaScript 和 C# 中实现),它们支持 Appium 对 WebDriver 协议的扩展。你需要用这些客户端程序库代替常规的 WebDriver 客户端。你可以在[这里](/docs/cn/about-appium/appium-clients.md)浏览所有程序库的列表。
**[Appium Desktop](https://github.com/appium/appium-desktop)**<br/>
这有一个 Appium 服务器的图形界面封装可以下载,它适用于任何平台。它打包了 Appium 服务器运行需要的所有东西,所以你不需要为 Node 而烦恼。它们还提供一个 Inspector 使你可以查看应用程序的层级结构。这在写测试时可以派上用场。
### 入门指南
恭喜!你现在有足够的知识来使用 Appium 了。 为什么不前往 [入门指南](/docs/en/about-appium/getting-started.md)(English) 了解更多详细的要求和指南呢?
---
EOF.
由 @黑水 翻译,TesterHome 社区 id:sanlengjingvv</br>
@lihuazhang 校验
翻译:@[Pandorym](https://github.com/Pandorym)
Last english version: ef7a1b17124966dbb87442d7356614791fe5e9ce, Oct 8, 2018
-39
View File
@@ -1,39 +0,0 @@
## Appium 支持的平台
Appium 支持多种平台以及各种测试方式(native,hybrid,web,真机,模拟器,等等...)。这份文档的设计初衷就是为了搞清楚所支持平台的版本,以及所需的条件。
### iOS 平台支持
获取 iOS 平台下所需的必备条件和安装说明,请查阅 [XCUITest Driver](/docs/en/drivers/ios-xcuitest.md)(English)
* 版本:9.0 及以上版本
* 设备:iPhone 模拟器,iPad 模拟器,以及 iPhone 和 iPad 的真机
* 是否支持 Native 应用:支持。如在模拟器执行,需要 debug 版本的 .app 包,在真机上运行则需要已签名的 .ipa 包。底层的框架是由苹果的 [XCUITest](https://developer.apple.com/reference/xctest) (或 [UIAutomation](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/) 支持更旧的版本) 所提供支持
* 是否支持移动端浏览器:支持。我们通过移动端的 Safari 进行自动化测试。对于真机,`ios-webkit-remote-debugger` 工具是必须的。可惜的是对于 Safari 的 native 部分的自动化目前还不支持。更多介绍请查看 [mobile web doc](/docs/en/writing-running-appium/web/mobile-web.md)(English)。
* 是否支持 Hybrid 应用:支持。如使用真机,ios-webkit-remote-debugger 工具也是必须的。更多介绍请查看 [hybrid doc](/docs/cn/writing-running-appium/web/hybrid.md)。
* 是否支持在一个 session 中多个应用的自动化:不支持
* 是否支持多设备同时执行自动化:不支持
* 是否支持第三方应用的自动化:仅支持在模拟器上仅有的第三方应用(设置,地图,等等...)。若在 iOS 10 及以上的版本,你同样可以在 home 界面做自动化。
* 是否支持自定义的、非标准的 UI 控件的自动化:只支持小部分。你需要在控件设置可识别的信息,从而对一些元素进行一些基础的自动化操作。
### Android 平台支持
* 版本:4.3 及以上版本
* 4.3 以及更高的版本是通过 Appium 自己的 [UiAutomator](http://developer.android.com/tools/testing-support-library/index.html#UIAutomator) 库实现。这是默认的自动化后台。
* 设备:Android 模拟器以及 Android 真机
* 是否支持 Native 应用:支持
* 是否支持移动端浏览器:支持(除了使用 Selendroid 后台的时候)。Appium 绑定了一个 [Chromedriver](http://chromedriver.chromium.org) 服务,使用这个代理服务进行自动化测试。在 4.2 和 4.3 版本,只能在官方的 Chrome 浏览器或者 Chromium 执行自动化测试。在 4.4 及更高版本,可以在内置的 “浏览器” 应用上进行自动化了。更多介绍请查看 [mobile web doc](/docs/en/writing-running-appium/web/mobile-web.md)(English)。
* 是否支持 Hybrid 应用:支持。更多介绍请查阅 [hybrid doc](/docs/cn/writing-running-appium/web/hybrid.md)。
* 默认的 Appium 自动化后台:支持 4.4 以及更高版本
* Selendroid 自动化后台:支持 2.3 以及更高版本
* 是否支持多个 app 在同一个 session 中自动化:支持(除了使用 Selendroid 后台的时候)
* 是否支持多个设备同时进行自动化:支持,即使 Appium 在开始的时候,使用不同的端口号作为服务器参数,`--port`, `--bootstrap-port` (或者 `--selendroid-port`) 还有 `--chromedriver-port`. 更多介绍请查看 [server args doc](/docs/cn/writing-running-appium/server-args.md)。
* 支持第三方引用:支持(除了使用 Selendroid 后台的时候)
* 支持自定义的、非标准的 UI 控件的自动化:不支持
### Windows 桌面支持
* [Windows App Testing](/docs/en/drivers/windows.md)(English)
本文由 thanksdanny 翻译,由 lihuazhang 校验。
@@ -1,36 +0,0 @@
## 跨域 iFrame 的自动化
[同源策略](https://en.wikipedia.org/wiki/Same-origin_policy) 会阻止 Appium 对和父页面不同域的 iFrame 进行自动化测试。
### 子域名的解决方案
如果父页面和 iFrame 使用同一个 domain (比如 `site.com` 和 `shop.site.com`),你可以在父页面和 iFrame 里将 `document.domain` 设置为一个共同的domain。这就解决了同源问题。
父页面:
```
<html>
<head>
<script>
document.domain = 'site.com';
</script>
</head>
<body>
<iframe src="http://shop.site.com" width="200" height="200"></iframe>
</body>
</html>
```
子 iFrame:
```
<html>
<head>
<script>
document.domain = 'site.com';
</script>
</head>
<body>
<p>This is an iFrame!</p>
</body>
</html>
```
本文由 [lihuazhang](https://github.com/lihuazhang) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
@@ -1,45 +0,0 @@
## Appium 事件计时
Appium 提供了一个能力,可以获取关于启动信息和命令执行时间的计时信息。这是由 `eventTimings` 这个初始化参数控制的高级功能(把这个参数设置为 `true` 来记录事件的计时信息)
打开这个参数,`GET /session/:id` 这个接口的响应结果(也就是,`driver.getSessionDetails()` 的响应结果,或者类似的,取决于客户端实现)中会包含 `events` 属性。下面是 `events` 属性的结构
```json
{
"<event_type>": [<occurence_timestamp_1>, ...],
"commands": [
{
"cmd": "<command_name>",
"startTime": <js_timestamp>,
"endTime": <js_timestamp>
},
...
]
}
```
换句话说,`events` 属性包含两种类别的属性。
* 事件类型的名字属性
* `commands` 属性
事件类型的名字属性对应的是事件发生时的时间戳列表。因为在一个会话周期内,事件可能发生多次,所以时间戳是个列表。事件的类型包含:
* `newSessionRequested`
* `newSessionStarted`
(个别 driver 会定义属于它们自己的事件类型,所以在这里我们没法列出一个完整的事件列表。最好是从一个会话得到响应结果之后去检查各种可能的事件类型。)
`commands` 属性是一个对象列表。每个对象都包括一个 appium 的内部命令的名字(例如 `click`),也包括这个命令执行的开始时间和结束时间。
通过这些数据,你可以计算出时间之间的间隔,或者事件的精确时间轴,或者某个事件的平均时间的统计信息等等。
你只能获得调用 `/session/:id` 这个接口期间发生的事件数据,所以获取会话周期数据的最佳时间是在你正好要退出会话之前。
Appium团队维护了一个事件计时解析工具,这个工具可以解析事件计时的输出,然后生成各种报告:
[appium/appium-event-parser](https://github.com/appium/appium-event-parser).
本文由 yanqiang@douban.com 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
-58
View File
@@ -1,58 +0,0 @@
## Selenium Grid
通过服务器参数 `--nodeconfig`,可以将 appium 服务器注册到本地的 [Selenium grid](https://github.com/SeleniumHQ/selenium/wiki/Grid2)
```center
> appium --nodeconfig /path/to/nodeconfig.json
# 或者使用源文件执行
> node . --nodeconfig /path/to/nodeconfig.json
```
在 Selenium 节点(Node)的配置文件里,你需要定义 `browserName`、`version` 和 `platform`,然后 Grid 会通过这些参数将你的测试重定向到正确的设备上。你还需要配置 `host` 和 `selenium grid` 的详细信息。详细的参数列表和描述信息,请查看 这里。
一旦你启动了 appium 服务器并且在 grid 里注册了信息,就可以在 grid 控制台看到你的设备:
"http://**\<grid-ip-adress\>**:**\<grid-port\>**/grid/console"
### Grid 节点的示例 JSON 配置文件
```xml
{
"capabilities":
[
{
"browserName": "<e.g._iPhone5_or_iPad4>",
"version":"<version_of_iOS_e.g._7.1>",
"maxInstances": 1,
"platform":"<platform_e.g._MAC_or_ANDROID>"
}
],
"configuration":
{
"cleanUpCycle":2000,
"timeout":30000,
"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
"url":"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub",
"host": <host_name_appium_server_or_ip-address_appium_server>,
"port": <appium_port>,
"maxSession": 1,
"register": true,
"registerCycle": 5000,
"hubPort": <grid_port>,
"hubHost": "<Grid_host_name_or_grid_ip-address>"
"hubProtocol": "<Protocol_of_Grid_defaults_to_http>"
}
}
```
如果没有给出 `url`、`host` 和 `port`,配置会自动指向 `localhost:whatever-port-Appium-started-on`。
如果你的 Appium Server 和 Selenium Grid 没有运行在同一台机器上,为确保 Selenium Grid 连接正常,请在你的 `host` & `url` 上使用外部域名或 IP 地址,而不是 `localhost` 和 `127.0.0.1`。
---
EOF.
本文由 [tobecrazy](https://github.com/tobecrazy) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
翻译:@[Pandorym](https://github.com/Pandorym)
Last english version: 048ca4be43d15e078f583ddb973e2dbe0212a988, Mar 29, 2018
-137
View File
@@ -1,137 +0,0 @@
# 自动化混合应用
Appium 其中一个理念就是你不能为了测试应用而修改应用。为了符合这个方法学,我们可以使用 Selenium 测试传统 web 应用的方法来测试混合 web 应用 (比如,iOS 应用里的元素 "[UIAWebView](https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAWebViewClassReference/)") ,这是有可能的。这里会有一些技术性的复杂,Appium 需要知道你是想测试原生部分呢还是web部分。幸运的是,我们还能遵守 WebDriver 的协议。
在 Appium 测试里,你需要以下几步来和 web 页面交涉:
1. 切到 webview 部分
1. 调用 [GET session/:sessionId/contexts](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)
1. 这会返回一个我们能访问的 context 的列表,比如 'NATIVE_APP' 或者 'WEBVIEW_1'
1. 用 context 的 id 作为参数,调用[POST session/:sessionId/context](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)方法,切换到 webview 中去。
1. (这会将你的 Appium session 放入一个模式, 在这个模式下,所有的命令都会被解释成自动化 web 视图而不是原生的部分。比如,当你运行 getElementByTagName,它会在 web 视图的 DOM 上操作,而不是返回 UIAElements。当然,一个 Webdriver 的方法只能在一个上下文中有意义,所以如果在错误的上下文,你会收到错误信息。)
1. 如果你想停止 web 视图的自动化,回到原生部分,你可以简单地用 `context` 调用来离开 web 层,参数传原生 context id 即可。
```javascript
// javascript
// 假定你已经初始化driver
driver
   .contexts().then(function (contexts) { // 获取view列表,返回数组格式: ["NATIVE_APP","WEBVIEW_1"]
       return driver.context(contexts[1]); // 选择 webview context
})
   // 执行web测试
   .elementsByCss('.green_button').click()
.context('NATIVE_APP') // leave webview context
   //把native操作放这里
   
   .quit() // 退出driver
```
```java
// java
// 假定我们设置了capabilities
driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
Set<String> contextNames = driver.getContextHandles();
for (String contextName : contextNames) {
   System.out.println(contextNames); //输出 NATIVE_APP \n WEBVIEW_1
}
driver.context(contextNames.toArray()[1]); // 设置当前 context 为 WEBVIEW_1
//执行web测试
String myText = driver.findElement(By.cssSelector(".green_button")).click();
driver.context("NATIVE_APP");
//如果需要此次放置native测试脚本
driver.quit();
```
```ruby
# ruby
# 假定我们设置了capabilities
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => SERVER_URL)
# I switch to the last context because its always the webview in our case, in other cases you may need to specify a context
# View the appium logs while running @driver.contexts to figure out which context is the one you want and find the associated ID
# Then switch to it using @driver.switch_to.context("WEBVIEW_6")
Given(/^I switch to webview$/) do
webview = @driver.contexts.last
@driver.switch_to.context(webview)
end
Given(/^I switch out of webview$/) do
@driver.switch_to.context(@driver.contexts.first)
end
# Now you can use CSS to select an element inside your webview
And(/^I click a webview button $/) do
@driver.find_element(:css, ".green_button").click
end
```
```python
# python
# assuming we have an initialized `driver` object for an app
# switch to webview
webview = driver.contexts.last
driver.switch_to.context(webview)
# do some webby stuff
driver.find_element(:css, ".green_button").click
# switch back to native view
driver.switch_to.context(driver.contexts.first)
# do more native testing if we want
driver.quit()
```
```php
// php
// assuming we have an initialized `driver` object in an AppiumTestCase
public function testThings()
{
$expected_contexts = array(
0 => 'NATIVE_APP',
1 => 'WEBVIEW_1'
);
$contexts = $this->contexts();
$this->assertEquals($expected_contexts, $contexts);
$this->context($contexts[1]);
$context = $this->context();
$this->assertEquals('WEBVIEW_1', $context);
// do webby stuff
$this->context('NATIVE_APP');
// do mobile stuff
}
```
## 自动化 Android 的混合应用
Appium 通过 Chromedriver 内建混合应用支持。Appium 也可以使用 Selendroid 支持 4.4 之前的设备的 webview 测试。(你需要在 desired capability 里指定 `"device": "selendroid"`)。
请确保
[setWebContentsDebuggingEnabled](http://developer.android.com/reference/android/webkit/WebView.html#setWebContentsDebuggingEnabled(boolean)) 设置为 true。具体见[remote debugging docs](https://developer.chrome.com/devtools/docs/remote-debugging#configure-webview).
一旦你设置了 desired capabilities,开始一个 appium 会话,遵循上面的教程。
## 自动化 iOS 混合应用
Appium 使用 remote debugger 创建和 webview 的交互连接。当在模拟器上执行下面例子的时候,我们可以直接建立连接,因为模拟器和 appium 服务器在同一台机器上。
一旦你设置了 desired capabilities,开始一个 appium 会话,遵循上面的教程。
本文由 [tobecrazy](https://github.com/tobecrazy) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
-17
View File
@@ -1,17 +0,0 @@
## 为 xcode 7 和 iOS >= 9.0 配置无延迟 instruments(iwd)
iOS >= 9.0 时,需要手动通过命令行传递二进制文件来配置无延迟的 instruments (在 xcode < 7 时 appium 会自动加上 ),参阅 [iwd](https://github.com/lawrencelomax/instruments-without-delay/tree/xcode7-quirks#xcode-7--ios-9-support)
在 xcode >= 7 时启用 iwd :
- 下载 [appium-instruments](https://github.com/appium/appium-instruments)
- 在 `<appium-instruments>/bin/` 下根据以下指示的参数运行 `xcode-iwd.sh` :
```
sh <appium-instruments>/bin/xcode-iwd.sh <path to xcode> <path to appium-instruments>
```
比如: `sh ./bin/xcode-iwd.sh /Applications/Xcode.app /Users/xyz/appium-instruments/`
注意:Xcode 7 的 iwd 只在 iOS >= 9.0 时有效,你可以在 iOS < 9.0 时切换一个旧版本的 Xcode
由 @黑水 翻译,TesterHome 社区 id:sanlengjingvv
由 [@chenhengjie123](https://github.com/chenhengjie123) 校验
@@ -1,168 +0,0 @@
*这是一个旧文档,只有从早期版本迁移到 Appium 1.x 的用户才有兴趣。*
## 将您的测试从 Appium 0.18.x 迁移到 Appium 1.x
Appium 1.0 中删除了许多之前版本就不推荐使用的功能。 本指南将帮助您了解在测试套件中需要做哪些修改才可以很好利用Appium 1.0。
### 新的客户端库
The biggest thing you need to worry about is using the new Appium client libraries instead of the vanilla WebDriver clients you are currently using. Visit the [Appium client list](/docs/cn/about-appium/appium-clients.md) to find the client for your language. Downloads and instructions for integrating into your code are available on the individual client websites.
您最需要担心的是使用新的 Appium 客户端库,而不是您正在使用的普通 WebDriver 客户端。 访问[Appium客户端列表](/docs/cn/about-appium/appium-clients.md)以找到匹配您的语言的客户端。 你可以在各个客户端网站上找到下载地址和如何集成到你的测试代码的教程。
最终,你会做以下一些事情(以Python为例):
```center
from appium import webdriver
```
代替:
```center
from selenium import webdriver
```
### 新的 desired capabilities
不再使用以下的 capabilities:
* `device`
* `version`
使用这些功能替换:
* `platformName`(“iOS”或“Android”)
* `platformVersion`(你想要的手机操作系统版本)
* `deviceName`(你想要的那种设备,就像“iPhone模拟器”)
* `automationName`(“Selendroid”如果你想使用,可以使用Selendroid,除此之外,可以省略这一点)
`app` capability 保持不变,但现在专指非浏览器 app。 要使用 Safari 或 Chrome 等浏览器,请使用标准的 `browserName` capability。这意味着 `app` 和 `browserName` 是互斥的。
针对 Appium 服务端的 capability,我们统一了驼峰式风格。这意味着像 `app-package` 或 `app-wait-activity` 这样的上限现在分别是 `appPackage` 和 `appWaitActivity`。当然,由于 Android 应用的包名和 activity 现在已被自动检测到,在大多数情况下,您应该可以完全省略它们。
### 新的定位策略
我们删除了以下定位器策略:
* `name`
* `tag name`
我们添加了 `accessibility_id` 策略来替代 `name` 曾经的作用。具体细节将与您的 Appium 客户端相关。
`tag name` 已被 `class name`替换。 所以要通过 UI 类型找到一个元素,在你的客户脚本里使用类名定位器策略。
Note about `class name` and `xpath` strategies: these now require the fully-qualified class name for your element. This means that if you had an xpath selector that looked like this:
关于 `class name` 和 `xpath` 策略的注意事项:这些策略现在需要元素完全限定类名。 这意味着如果你有一个如下所示的 xpath 选择器:
```center
//table/cell/button
```
现在需要:
```center
//UIATableView/UIATableCell/UIAButton
```
(同样对于Android:`button` 现在需要是 `android.widget.Button`)
我们还添加了以下定位器策略:
* `-ios uiautomation`
* `-android uiautomator`
参考你的客户端了解如何使用这些新的定位策略。
### XML, not JSON
App source methods, which previously returned JSON, now return XML, so if you have code that relies on parsing the app source, it will need to be updated.
以前返回 JSON 的 app source 方法现在返回 XML,因此如果您有代码依赖于解析 app source,则需要更新。
### Hybrid 通过 context 支持,而不是 window
以前通过在 "windows" 之间切换支持 hybrid app
* `window_handles`
* `window`
* `switch_to.window`
现在 Appium 使用概念上更加贴切的 "context"。要获得所有可用的 context,或应用程序特定的 context,您可以使用以下方法
```python
# python
driver.contexts
current = driver.context
```
```javascript
// javascript
driver.contexts().then(function (contexts) { /*...*/ })
```
```c#
// c#
driver.GetContexts ()
driver.GetContext ()
```
```java
// java
Set<String> contextNames = driver.getContextHandles();
String context = driver.getContext();
```
```php
// php
$contexts = $this->contexts();
$context = $this->context();
```
```ruby
# ruby
contexts = available_contexts
context = current_context
```
在他们之间切换,你使用以下方法
```python
# python
driver.switch_to.context("WEBVIEW")
```
```javascript
// javascript
driver.currentContext().then(function (context) { /*...*/ })
```
```c#
// c#
driver.SetContext ("WEBVIEW");
```
```java
java
driver.context(contextName);
```
```php
// php
$this->context('WEBVIEW');
```
```ruby
# ruby
set_context "WEBVIEW"
```
### 不再有 `execute_script("mobile: xxx")`
所有 `mobile: ` 方法已被删除,并已被 Appium 客户端库中的原生方法所替代。这意味着像 `driver.execute("mobile: lock", [5])` 的方法调用,现在可能会是 `driver.lock(5)`(其中 `lock` 已经变成原生的客户端方法)。 当然,调用这些方法的细节会因客户端而异。
特别值得注意的是,手势方法已被新的 TouchAction / MultiAction API 所取代,该 API 允许一种更强大更普遍的方法将手势自动化放在一起。有关TouchAction / MultiAction 的使用说明,请参考您的Appium客户端。
就是这样!快乐的迁移!
本文由 高鹏 翻译,由 lihuazhang 校验。
@@ -1,256 +0,0 @@
# 从 Appium1.x 迁移到 Appium2.x
如果你正在使用 Appium1.x,并期望迁移至 Appium2.x,这份文档可以作为您的迁移指南。它包含了一系列我们重大变化的修改、您如何改变您的环境或测试套件来对 Appium2.0进行兼容。
## Appium 2.0 概述
Appium 2.0 是 Appium 近5年来最重要的新版本。首先,Appium2.0 最大的变化,*并不是* 对不同平台上的测试行为发生了改变。相反的,Appium 2.0 将Appium 重新定义为一个*平台*,它(Appium2.0)让驱动 (driver)(引入对给定平台自动化支持的代码项目)、插件(plugin)(允许覆盖、修改、扩展或向Appium添加行为的代码项目)变得更易创建与分享。
与此同时,Appium项目正在利用这个机会删除许多旧的和被弃用的功能。
这些都对Appium的安装方式、驱动程序和各种特性的管理方式以及协议支持等方面带来了一些重大变化。以下是详细说明。
## 重大变化
查看[Appium 2.0发布说明](https://github.com/appium/appium/releases/tag/v2.0.0-beta)以获得更全面的变更列表。这里有我们所郑重展示的重大变化,与您需要为他们做的一些事情。
#### :bangbang: 在准备过程中安装需要的驱动(drivers)
如果您使用过 Appium1.x,所有的能支持使用的驱动(driver)都会在同一时间通过Appium主服务安装好。现在已经不是这样了。简单地安装 Appium 2.0(例如,通过' npm install -g Appium '),将只会安装没有任何驱动(driver)的 Appium 的主服务。如果想要安装驱动(driver),您必须使用新的 [Appium 扩展命令行工具(Appium extension CLI)](../drivers/driver-cli.md)。例如,要安装XCUITest和UiAutomator2驱动程序的最新版本,在安装Appium之后,您将运行以下命令:
```
appium driver install xcuitest
appium driver install uiautomator2
```
执行安装命令后,您的驱动程序已经安装就绪。使用这个CLI可以做的事情还有很多,所以一定要查看它的文档。
如果您正在CI环境中运行,或期望在安装后接着安装一些驱动(driver),可以在安装时添加一些参数,如:
```
npm install -g appium --drivers=xcuitest,uiautomator2
```
这将为您一次性安装Appium和两个驱动程序。
#### :bangbang: 驱动(driver)更新
在过去,要更新 iOS 或 Android 驱动程序,你只需等待这些更新被整合到新发行的 Appium 中,然后更新你的 Appium 版本。在 Appium2.0,Appium 服务器和Appium 驱动(driver)的版本和发布是分开的。这意味着驱动(driver)的更新可以按照驱动本身的发布节奏进行发布,您可以在驱动程序更新发生时进行更新,而不是等待新的Appium服务器发布。检查驱动程序更新的方法是使用CLI:
```
appium driver list --updates
```
如果有任何驱动(driver)可以更新了,你可以对任何给定的驱动(driver)执行' update '命令:
```
appium driver update xcuitest
```
要更新 Appium 服务器本身,您需要执行与过去相同的操作:' npm install -g Appium '。现在,安装新版本的 Appium 服务器将不会影响您的驱动程序,因此整个过程将会更快。
#### :bangbang: 协议的变更
Appium 的 API 基于[W3C WebDriver协议](https://www.w3.org/TR/webdriver/),并且多年来一直遵循该协议。在 W3C WebDriver 协议被设计成 web 标准之前,Selenium 和 Appium 都曾使用了其他几个协议。这些协议是 "JSONWP" (JSON有线协议) 和 "MSJONWP"(移动JSON有线协议)。W3C协议与(M)JSONWP协议有几处不同。
在Appium 2.0之前,Appium支持这两种协议,因此较老的Selenium/Appium客户端(client)仍然可以与较新的Appium服务器通信。今后,对旧协议的支持将被移除。
:bangbang: *功能*
新旧协议之间的一个重要区别是功能的格式。以前称为“所需的功能”,现在简单地称为“功能”,现在对任何非标准功能都需要一个所谓的“供应商前缀”。标准的功能列表在[WebDriver协议规范](https://www.w3.org/TR/webdriver/#capabilities)中给出,包括一些常用的功能,如“browserName”和“platformName”。
这些标准功能仍可以按原来的方式使用。但是所有功能的名称中必须包含一个“供应商前缀”。vendor前缀是一个冒号后面的字符串,例如' appium: '。Appium的大多数功能都超出了标准的W3C功能,因此必须包含供应商前缀(我们建议您使用' appium: ',除非文档另有指示)。例如:
* `appium:app`
* `appium:noReset`
* `appium:deviceName`
针对Appium 2.0的测试套件来说,这些改变,可能是也可能不是一个重大的变化。如果你正在使用一个已经适配更新的 Appium 客户端(如:Appium-java-client等),客户端会在所有必要的功能上为你添加' appium: '前缀。新版本的Appium Inspector工具(如:Appium Desktop 或 Appium inspector)也会这样做。
基于云的Appium提供商也可能这样做。因此,只要注意:如果您得到提示消息,说您的功能缺少供应商前缀,这就是解决问题的方法。
另外,使用不支持W3C协议的WebDriver客户端启动Appium会话将不再允许(请参阅下面关于WD库这种效果的注释)。
为了让每个人的生活更容易一些,我们还引入了一个选项,将所有与appium相关的功能打包到一个对象功能中,即 "appium:options"。你可以将任何你通常会在这个功能上添加' appium: '前缀的东西捆绑在一起。以下是一个关于如何在Safari浏览器上使用 "appium:options" 启动 iOS 会话的示例(基于原始JSON):
```json
{
"platformName": "iOS",
"browserName": "Safari",
"appium:options": {
"platformVersion": "14.4",
"deviceName": "iPhone 11",
"automationName": "XCUITest"
}
}
```
(当然,每个客户端都有不同的方式来创建结构化功能,如“appium:options”或其他你可能见过的功能,如“goog:chromeOptions”)。注意:在“appium:options”中显示的能力将覆盖在对象顶层显示的相同名称的能力。
:bangbang: *被删除的命令*
那些旧的JSON有线协议的一部分,并且不是W3C协议的一部分的命令不再可用:
* TODO (这些命令正在被归纳和删除,完成后将在这里进行更新)
如果您使用最新的 Appium 或 Selenium 客户端(client),那么无论如何您都不应该再访问这些文件,因此任何重大的改变都会首先在客户端体现。
#### :bangbang: 图像分析功能移至插件(plugin)
Appium 2.0 的设计目标之一,是将非核心特性迁移到称为[插件(plugins)](#TODO)的特殊扩展中。这会让大家选择性地、按需地花费功夫去安装并设置这些。
Appium 的各种图像相关特性(图像比较、根据图像查找元素等)已经转移到官方支持的插件[图像插件(images)](https://github.com/appium/appium-plugins/tree/master/packages/images)中。
如果您使用了这些与图像相关的方法,并且需要继续使用它们,您需要做两件事。
1. 安装插件:`appium plugin install images`
2. 确保你启动了Appium服务器,通过在命令行指定的插件列表中包含它来运行插件,例如,`appium --plugins=images`
与图像相关的命令也将在客户端删除,这意味着您需要按照插件README上的说明安装客户端插件来访问这些功能。
#### :bangbang: 删除一些旧的驱动(driver)
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.
旧版本的 iOS 与 Android 驱动(driver)(UiAutomator 1) 及相关联的工具(如:`authorize-ios`)已经被删除。他们已经很多年不被使用了。
#### :warning: 内部包重命名
一些 appium 内部的 NPM 包被重命名 (如:`appium-base-driver` 改为 `@appium/base-driver`)。这并不是一个突破性的变化,只是为了那些已经构建了直接合并Appium代码的软件的人来进行了解。
#### :warning: 不再支持“WD”JavaScript客户端库
多年来,Appium的一些作者维护了[WD](https://github.com/admc/wd)客户库。此库已弃用,并没有更新以与W3C WebDriver协议一起使用。因此,如果您正在使用这个库,您将需要转向一个更新的库。我们建议(WebdriverIO) (https://webdriver.io)。
#### :warning: 将 Appium 检查器(Appium Inspector)从 Appium Desktop 中分离出来
Appium Desktop 的检查器部分(查看页面元素树的功能)已经转移到它自己的app,Appium 检查器(Appium Inspector): [github.com/appium/appium-inspector](https://github.com/appium/appium-inspector)。它完全兼容Appium 2.0服务器。如果您只需要对页面元素树进行检查与操作,那么下载并运行检查器单独的app即可,不需要一定得下载GUI 版本的 Appium Desktop了。Appium Desktop 仍在原来的地方维护中,[github.com/appium/appium-desktop](https://github.com/appium/appium-desktop)。只是它不再会与检查器完全捆绑在一起了。
您也可以不需要下载 Appium 检查器(Appium Inspector),直接从网页访问[web version of Appium Inspector](https://inspector.appiumpro.com)。注意,要针对本地服务器进行测试,您需要使用`--allow-cors`启动服务器,以便基于浏览器的Appium Inspector可以访问您的Appium服务器来启动会话。
## 重要的新特性
除了上面提到的重大变化之外,本节列出了一些您也许会喜欢的 Appium 2.0 重要的新特性。
#### 插件(Plugins)
:tada: *服务端插件(Server Plugins)*
TODO
:tada: *客户端插件(Client Plugins)*
TODO
#### :tada: 从任何地方下载驱动(driver)与插件(plugin)
TODO
#### :tada: 驱动(driver)与插件(plugin)的命令行参数
TODO
## 云提供商的特别说明
本文之外的地方一般是Appium的通用部分,但Appium 2.0中的一些架构更改将对与Appium相关的服务提供商(无论是基于云的Appium主机还是内部服务)构成重大变化。最终,Appium服务器的维护者负责安装和提供终端用户可能希望使用的各种Appium驱动程序和插件。
有了 Appium 2.0,我们进入了一个新时代,终端用户可以使用各种独立版本的驱动(driver)和插件(plugin)。在 Appium 1.x 上,这是无法实现的。因为任何给定的 Appium 版本都会包含且仅包含每个驱动(driver)的一个版本。当然,这取决于每个服务提供商希望如何实现任何官方或第三方驱动程序或插件的发现、安装和可用性。但 Appium 团队希望就服务提供商支持的功能提出建议,以确保整个行业的一致性。这只是一个建议,而不是一个标准,但是采用它将帮助用户应对在云环境中使用 Appium 2.0 可能带来的日益增加的复杂性。
### 建议使用的功能
除了标准的`platformName`, `appium:deviceName`, `appium:automationName`, 与 `appium:platformVersion`,我们建议使用 `$cloud:appiumOptions`, 当标签为:`$cloud` 并不是要直接按这个写,而是应该被你的供应商前缀替换(举几个例子,HeadSpin应该是' HeadSpin ', Sauce Labs应该是' Sauce ', BrowserStack应该是' BrowserStack ')。`appium:platformVersion` 功能本身将是一个JSON对象,具有以下内部key:
|能力(Capability)|作用域(Used for)|示例(Example)|
|----------|-------|-------|
|`version`|指定用于托管和管理驱动程序的 Appium 服务器版本。如果不写,按提供商提供的为准,但建议提供最新的官方版本|`2.0.0`|
|`automationVersion`|指定应该使用指定驱动程序的哪个版本。|`1.55.2`|
|`automation`|指定要使用的自定义驱动程序(参见下面的更多信息)。将会覆盖: `appium:automationName` and `$cloud:automationVersion`|`{"name": "org/custom-driver", "source": "github", "package": "custom-driver"}`|
|`plugins`|指定要激活的插件列表(以及可能的插件版本)(参见下面的更多信息)。|`["images", "universal-xml"]`|
### 基础示例
Appium扩展(驱动程序和插件)有一组属性,指定它们可以从哪里安装。云提供商显然没有义务为任意指定的扩展提供支持,因为这些扩展可能使得在托管环境中运行的不可信代码。在不支持任意扩展的情况下,`appium:automationName`, `$cloud:automationVersion`, 与 `$cloud:appiumPlugins`的功能应该足够了。以下JSON对象表示会话的功能:
```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"],
}
}
```
这组功能参数,指示 Appium 2.0 服务器支持 `3.52.0` 版本的 XCUITest 驱动程序,并激活`images`插件。云提供商很容易验证这个集合。显而易见,云提供商可以通过这些功能参数,做任何它想做的事情来响应这些功能,包括:动态下载Appium、驱动程序和插件包,或者如果请求的版本不在一个支持的集中,或者提示插件不支持,等等……
### `appium:options`的基础示例
前面的例子看起来仍然有点混乱,所以我们当然也建议云提供商支持 `appium:options` 参数,就像上面详细描述的那样,这可以将之前的功能集变成以下参数:
```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"],
}
}
```
### 扩展对象
一些服务提供商可能希望动态地允许访问 Appium 2.0 CLI 的所有特性,包括下载任意驱动程序和插件。为了支持使用这些扩展,我们可以定义特殊的JSON“扩展对象”,关键字如下:
* `name`: 扩展名。这是一个NPM包名(如果是从NPM下载),或者是一个git或GitHub规格(如果是从git服务器或GitHub下载)。
* `version`: 扩展的版本,例如NPM包版本或Git SHA。
* (optional) `source`: 扩展可以从哪里下载的表示。建议支持以下值: `appium`, `npm`, `git`, `github`。 这里的: `appium` 表示" Appium 自己的官方列表",如果不包含此key,`appium` 则应该是默认值。
* (optional) `package`: 当从git或github下载扩展时,扩展的NPM包名也必须提供。对于非git源,这是可选的。
由于每个会话都由单个驱动程序处理,`$cloud:appiumOptions`/`$automation` 功能参数可以与扩展对象值一起使用,以表示该驱动程序,例如:
```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"
},
...
},
...
}
```
由于会话可以处理多个插件,`$cloud:appiumPlugins` 列表中的每个值也可以是一个扩展对象,而不是字符串,这样就可以请求特定的版本:
```json
{
...,
"$cloud:appiumOptions": {
...,
"plugins": [{
"name": "images",
"version": "1.1.0"
}, {
"name": "my-github-org/my-custom-plugin",
"version": "a83f2e",
"source": "github",
"package": "custom-plugin"
}],
...,
}
...
}
```
这些都是本文建议的说明性示例。当然,要由服务提供商在他们的前端/负载均衡器上实现对这些功能的处理,去完成任何情况下的错误检查,或运行任何一个用户请求的`appium driver` 或 `appium plugin` 。本节只是关于服务提供商如何设计他们面向用户的功能 API 的建议,如果他们自己运行 Appium,原则上支持 Appium 为最终用户提供的所有功能。
@@ -1,126 +0,0 @@
## 将你的iOS测试从UIAutomation(iOS 9.3及更低版本)迁移到XCUITest(iOS 9.3及更高版本)
对于 iOS 自动化,Appium 依赖苹果提供的系统框架。对于 iOS 9.2 及更低版本,苹果唯一的自动化技术被称为UIAutomation,它运行在 “Instruments” 中。从 iOS 10 开始,苹果已经完全删除了 UIAutomation 工具,因此 Appium 不可能按照以前的方式进行测试。同时,苹果推出了一款名为 XCUITest 的新型自动化技术,从 iOS 9.3 到 iOS 10 及以上版本,这将是苹果唯一支持的自动化框架。
Appium 从 Appium 1.6 开始支持 XCUITest。在大多数情况下,XCUITest 的功能与 UIAutomation 的功能相匹配,因此,Appium 团队能够确保测试行为保持不变。这是使用 Appium 的好处之一!即使苹果完全改变了测试使用的技术,你的脚本可以保持大致相同!话虽如此,如果您想在 XCUITest 运行它们,还是存在些许差异,您需要关注测试脚本中需要修改的部分。本文将帮助您解决这些差异。
### 元素类名称模式
在 XCUITest 中,苹果已经为构成视图层次结构的 UI 元素提供了不同的类名。例如,`UIAButton` 现在为`XCUIElementTypeButton`。在很多情况下,这两个类之间有直接映射。如果您使用 `class name` 定位器策略来查找元素,Appium 1.6 将为您重写选择器。同样,如果你使用xpath定位器策略,Appium 1.6 将在 XPath 字符串中找到所有 `UIA*` 元素,并适当地重写它们。
但是,这并不能保证你的测试可以完全相同地运行,原因有两个:
1. Appium 通过 XCUITest 和 UIAutomation 看到的应用的层次结构不一定是相同的。如果你有基于路径的 XPath 选择器,则可能需要进行调整。
2. 类名列表也不完全一样。许多由 XCUITest 返回的元素属于`XCUIElementTypeOther类`,这是一种全新的容器。
### 页面源码
如上述,如果你依赖 `page source` 命令返回的 app 源 XML,那么这个输出的 XML 会与基于 UIAutomation 的结果会有显著不同。
### `-ios uiautomation` 定位策略
此定位器策略专门用于 UIAutomation,因此它不包括在 XCUITest 中。 在即将发布的版本中,我们将致力于类似的 “native” 型定位策略。
### `xpath` 定位策略
1. 尽量不要使用 XPath 定位器,除非你完全没有其他选择。 通常,xpath 定位器可能比其他类型的定位器慢,比如accessibility id,类名和谓词(在某些特殊情况下可减缓100倍)。 它们太慢了,因为 xpath 的位置不是苹果的XCTest 框架本身所支持的。
2. 使用
```
driver.findElement(x)
```
而不是使用
```
driver.findElements(x)[0]
```
通过xpath查找单个元素。 您的定位器匹配的UI元素越多,你的脚本越慢。
3. 在通过 xpath 定位元素时,一定要使用非常具体的xpath。 像这样的定位器
```
//*
```
可能需要几分钟才能完成,具体取决于您的应用程序有多少用户界面元素(例如,
```
driver.findElement(By.xpath("//XCUIElementTypeButton[@value='blabla']"))
```
比
```
driver.findElement(By.xpath("//*[@value='blabla']"))
```
或
```
driver.findElement(By.xpath("//XCUIElementTypeButton")))
```
要快很多。
4. 在大多数情况下,执行多个嵌套的 findElement 调用比执行 xpath 单个调用更快(例如,
```
driver.findElement(x).findElement(y)
```
通常比
```
driver.findElement(z)
```
要快
其中x和y不是xpath定位符,z是xpath定位符)。
### 系统依赖
除了升级 XCode 会带来(与Appium无关)许多问题之外,Appium 对 XCUITest 的支持还需要一个新的系统依赖:[Carthage](https://github.com/Carthage/Carthage)。Appium Doctor 现已更新,以确保`carthage`二进制在你的系统路径里。
### API差异
Unfortunately, the XCUITest API and the UIAutomation API are not equivalent. In many cases (like with `tap/click`), the behavior is identical. But some features that were available in the UIAutomation backend are not yet available in the new XCUITest backend. These known lacking features include:
不幸的是,XCUITest API 和 UIAutomation API 还是有差别的。在许多情况下(比如 tap/click),行为是相同的,但在 UIAutomation 作为底层驱动时,可用的某些功能在新的 XCUITest 时尚不可用。下面是已知的缺乏的功能:
* 地理位置支持(例如: `driver.location`)
* 振动设备
* 锁定设备
* 旋转设备(device _orientation_ 是支持的)
We will endeavor to add these features back in future releases of Appium.
我们在努力把这些功能加到 Appium 的未来版本里。
#### 滚动和点击
在之前基于 UIAutomation 的驱动中,如果您尝试单击不在视图中的元素,UIAutomation 将自动滚动到该元素,然后点击它。 使用 XCUITest,不是这样。 点击之前,你需要确保元素可见(与用户看到才能点击的行为一致)。
### 其他已知问题
Finally, a list of known issues with the initial 1.6 release (we'll strike through issues which have been resolved):
最后,列出了初始 1.6 版本的已知问题(已解决的问题会被横线划去):
* <del>无法以横向模式与设备上的元素进行交互(https://github.com/appium/appium/issues/6994)</del>
* `shake` 苹果不支持所以我们没有实现
* `lock` 苹果不支持所以我们没有实现
* 设置地理位置不被苹果支持,我们也不支持
* 通过TouchAction / MultiAction API,`zoom` 手势支持,因为苹果的一个bug,`pinch` 手势不支持。
* <del>通过TouchAction / MultiAction API,`swipe`手势目前不受支持,应该很快解决(https://github.com/appium/appium/issues/7573)</del>
* `autoAcceptAlerts`, `autoDismissAlerts`目前还不能工作,而且我们是否能够在将来实施这些,存在争议。
* iOS SDK 有一个问题,因此使用某些 API 方法构建的 PickerWheels 不能由 XCUITest 自动执行。有关解决方法,请参阅https://github.com/appium/appium/issues/6962,以确保您的 PickerWheels 正确构建。
我们将尽可能添加缺失的功能,并在以后的 Appium 版本中修复其他已知问题。
本文由 校长 翻译,由 lihuazhang 校验。
@@ -1,35 +0,0 @@
## Android 并发测试
Appium 给用户提供了在一个机器上启动多个 Android sessions 的方案。该方案只需要通过不同参数来启动的多个 Appium 服务。
以下是启动多个 Android 会话的一些重要参数:
- `-p` Appium 主要端口
- `-U` 设备 id
- `-bp` Appium bootstrap 端口
- `--chromedriver-port` chromedriver 端口 (若是在使用 webviews 或 chrome)
- `--selendroid-port` selendroid 端口 (若是在使用 selendroid)
更多相关参数的信息可以参考 [这里](../writing-running-appium/caps.md) 。
如果我们有两台设备,且他们的设备 id 分别为 43364 和 32456,我们可以通过以下命令启动两个不同的 Appium 服务器:
`node . -p 4492 -bp 2251 -U 32456`
`node . -p 4491 -bp 2252 -U 43364`
只要你的 Appium 与 Appium bootstrap 的端口在 0 到 65536 之间,且端口号并不相同,这样两个 Appium 服务器就不会去监听同一个端口。确保通过 -u 参数标志的 id 与对应的设备 id 是一致的。这就是 Appium 能知道设备之间是如何通信的原因,因此必须保证参数准确无误。
如果你使用 chromedriver 或 selendroid,记得确保服务器的端口号是独一无二的。
如果你使用 [appium-uiautomator2-driver](https://github.com/appium/appium-uiautomator2-driver),
需要给 systemPort 这个 capability 配置为不同的系统端口。因为有时候如果没有使用不同的端口,会出现冲突,比如[这个问题](https://github.com/appium/appium/issues/7745).
### iOS 并发测试
十分不幸,目前并不能在本地运行 iOS 的并发测试。iOS 同一时间只能启动一个模拟器,不像 Andoid 可以同时多个模拟器去运行测试。
如果你想运行 iOS 的并发测试,你需要使用 Sauce 上传你的 Appium 测试脚本,然后就可以运行多台 iOS 和 Android 的并发测试,只要你的账号允许。
本文由 thanksdanny 翻译,由 lihuazhang 校验。
-58
View File
@@ -1,58 +0,0 @@
## Settings
Settings是appium引入的一个新概念。 它们目前不是Mobile JSON Wire协议或Webdriver规范的一部分。
Settings是用来指定appium server的工作方式。
Settings有以下特点:
- 可变性,Settings在一个会话中是可以被修改的。
- 临时性,Settings只对当前会话生效,新建立的会话会被重置。
- 局限性,Settings只用来控制appium server,不能用于控制被测应用或设备。
以Android的`ignoreUnimportantViews`为例。Android中可以设置`ignoreUnimportantViews`用来忽略所有与当前视图无关的元素,这样可以让用例执行的更快。注意,当用户需要访问这些被忽略的元素时,需要禁用`ignoreUnimportantViews`后并重新启用。
另外一个例子是Settings让appium忽略当前不可见的元素。
Settings通过下面的API实现:
**POST** /session/:sessionId/appium/settings
>Settings使用键值对(name:value)的JSON格式,name为setting的名字,value是setting的取值。
```
{
settings: {
ignoreUnimportantViews : true
}
}
```
**GET** /session/:sessionId/appium/settings
>以JSON格式返回当前所有配置。
```
{
ignoreUnimportantViews : true
}
```
注意,实际的命令因您的脚本所使用的语言而异; 请参阅具体的Appium客户端文档以获取更多信息。
### 支持的Settings
**"ignoreUnimportantViews"** - 布尔类型。设置为false时,Android设备不会忽略任何视图;被设置为true时,会使用`setCompressedLayoutHeirarchy()`忽略标记了IMPORTANT_FOR_ACCESSIBILITY_NO或IMPORTANT_FOR_ACCESSIBILITY_AUTO(以及被系统认为不重要的)的视图,从而尽量让脚本变得简单或执行的更快。
#### Android UiAutomator Configurator
设置[UiAutomator Configurator](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html) 的超时时间和延迟. 只支持Android API 18 及以上版本。
**"actionAcknowledgmentTimeout"** - Int类型,与[setActionAcknowledgmentTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setActionAcknowledgmentTimeout(long))相同。被设置为负数时将取默认值(3 * 1000 毫秒)
**"keyInjectionDelay"** - Int类型,与[setKeyInjectionDelay](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setKeyInjectionDelay(long))相同。被设置为负数时将取默认值(0 毫秒)
**"scrollAcknowledgmentTimeout"** - Int类型,与[setScrollAcknowledgmentTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setScrollAcknowledgmentTimeout(long))相同。被设置为负数时将取默认值(200 毫秒)
**"waitForIdleTimeout"** - Int类型,与[setWaitForIdleTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setWaitForIdleTimeout(long))相同。被设置为负数时将取默认值(10 * 1000 毫秒)
**"waitForSelectorTimeout"** - Int类型,与[setWaitForSelectorTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setWaitForSelectorTimeout(long))相同。被设置为负数时将取默认值(10 * 1000 毫秒)
本文由 [ghost62184](https://github.com/ghost62184) 翻译, 由 [chenhengjie123](https://github.com/chenhengjie123) 校验
@@ -1,283 +0,0 @@
## 如何搭建并定制 WebDriverAgent Server
Appium 的 iOS 版本的后端用的是[Facebook's WebDriverAgent](https://github.com/facebook/WebDriverAgent)。该后端是基于苹果公司的 XCTest 框架,所以也有所有XCTest 框架已知的问题。其中有些问题我们正在设法解决,有一些在现阶段可能无法解决。本文中描述的方法已经能够使您完全掌握在设备上如何构建、管理和运行WDA。通过这种方式,您可以在CI环境中对您的自动化测试进行微调,并使其在长期运行的情况下更加稳定。
重点:
* 如果使用了Appium的默认设置,则不需要如下的步骤。服务器将为您搞定一切,当然你也不能对WDA做太多控制。
* 对连接的被测设备必须有SSH或物理访问权限。
### 安装WDA
```bash
cd /usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent
./Scripts/bootstrap.sh -d
```
不需要进一步的配置步骤,你就可以在iOS模拟器上执行自动化测试。
如果是在真机上进行测试的话,则需要做更多的设置。参考[real device configuration documentation](https://github.com/appium/appium-xcuitest-driver/blob/master/docs/real-device-config.md) 设置代码签名。另外,你还需要安装iproxy工具。
```bash
npm install -g iproxy
```
为了确保 WDA 源代码配置正确,请执行以下操作:
* 用Xcode打开/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/WebDriverAgent.xcodeproj
* 选择 "WebDriverAgentRunner" 工程
* 选择要运行自动化测试的真机/模拟器作为构建目标机
* 在主菜单中选择 Product -> Test
Xcode 会成功构建项目并安装到真机/模拟器上,所以您将在苹果系统的桌面上看到 WebDriverAgentRunner 应用程序的图标。
### 启动WDA
WebDriverAgent 应用程序扮演一个 REST 服务的角色,接收外部 API 请求,然后传递给被测应用的原生 XCTest 调用。如果在模拟器上运行你的测试,REST 服务的地址将是localhost,如果在有实际的 IP 地址的真实设备上运行,REST 服务的地址将是实际的 ip 地址。我们使用 iproxy 将网络请求路由到通过 USB 连接的真实设备上,这意味着可以使用这个工具将模拟器和真实设备上的 WDA 网络地址统一。
这个用Java编写的助手类说明了主要的实现细节:
```java
public class WDAServer {
private static final Logger log = ZLogger.getLog(WDAServer.class.getSimpleName());
private static final int MAX_REAL_DEVICE_RESTART_RETRIES = 1;
private static final Timedelta REAL_DEVICE_RUNNING_TIMEOUT = Timedelta.ofMinutes(4);
private static final Timedelta RESTART_TIMEOUT = Timedelta.ofMinutes(1);
// These settings are needed to properly sign WDA for real device tests
// See https://github.com/appium/appium-xcuitest-driver for more details
private static final File KEYCHAIN = new File(String.format("%s/%s",
System.getProperty("user.home"), "/Library/Keychains/MyKeychain.keychain"));
private static final String KEYCHAIN_PASSWORD = "******";
private static final File IPROXY_EXECUTABLE = new File("/usr/local/bin/iproxy");
private static final File XCODEBUILD_EXECUTABLE = new File("/usr/bin/xcodebuild");
private static final File WDA_PROJECT =
new File("/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/" +
"WebDriverAgent/WebDriverAgent.xcodeproj");
private static final String WDA_SCHEME = "WebDriverAgentRunner";
private static final String WDA_CONFIGURATION = "Debug";
private static final File XCODEBUILD_LOG = new File("/usr/local/var/log/appium/build.log");
private static final File IPROXY_LOG = new File("/usr/local/var/log/appium/iproxy.log");
private static final int PORT = 8100;
public static final String SERVER_URL = String.format("http://127.0.0.1:%d", PORT);
private static final String[] IPROXY_CMDLINE = new String[]{
IPROXY_EXECUTABLE.getAbsolutePath(),
Integer.toString(PORT),
Integer.toString(PORT),
String.format("> %s 2>&1 &", IPROXY_LOG.getAbsolutePath())
};
private static WDAServer instance = null;
private final boolean isRealDevice;
private final String deviceId;
private final String platformVersion;
private int failedRestartRetriesCount = 0;
private WDAServer() {
try {
this.isRealDevice = !getIsSimulatorFromConfig(getClass());
final String udid;
if (isRealDevice) {
udid = IOSRealDeviceHelpers.getUDID();
} else {
udid = IOSSimulatorHelpers.getId();
}
this.deviceId = udid;
this.platformVersion = getPlatformVersionFromConfig(getClass());
} catch (Exception e) {
throw new RuntimeException(e);
}
ensureToolsExistence();
ensureParentDirExistence();
}
public synchronized static WDAServer getInstance() {
if (instance == null) {
instance = new WDAServer();
}
return instance;
}
private boolean waitUntilIsRunning(Timedelta timeout) throws Exception {
final URL status = new URL(SERVER_URL + "/status");
try {
if (timeout.asSeconds() > 5) {
log.debug(String.format("Waiting max %s until WDA server starts responding...", timeout));
}
new UrlChecker().waitUntilAvailable(timeout.asMillis(), TimeUnit.MILLISECONDS, status);
return true;
} catch (UrlChecker.TimeoutException e) {
return false;
}
}
private static void ensureParentDirExistence() {
if (!XCODEBUILD_LOG.getParentFile().exists()) {
if (!XCODEBUILD_LOG.getParentFile().mkdirs()) {
throw new IllegalStateException(String.format(
"The script has failed to create '%s' folder for Appium logs. " +
"Please make sure your account has correct access permissions on the parent folder(s)",
XCODEBUILD_LOG.getParentFile().getAbsolutePath()));
}
}
}
private void ensureToolsExistence() {
if (isRealDevice && !IPROXY_EXECUTABLE.exists()) {
throw new IllegalStateException(String.format("%s tool is expected to be installed (`npm install -g iproxy`)",
IPROXY_EXECUTABLE.getAbsolutePath()));
}
if (!XCODEBUILD_EXECUTABLE.exists()) {
throw new IllegalStateException(String.format("xcodebuild tool is not detected on the current system at %s",
XCODEBUILD_EXECUTABLE.getAbsolutePath()));
}
if (!WDA_PROJECT.exists()) {
throw new IllegalStateException(String.format("WDA project is expected to exist at %s",
WDA_PROJECT.getAbsolutePath()));
}
}
private List<String> generateXcodebuildCmdline() {
final List<String> result = new ArrayList<>();
result.add(XCODEBUILD_EXECUTABLE.getAbsolutePath());
result.add("clean build test");
result.add(String.format("-project %s", WDA_PROJECT.getAbsolutePath()));
result.add(String.format("-scheme %s", WDA_SCHEME));
result.add(String.format("-destination id=%s", deviceId));
result.add(String.format("-configuration %s", WDA_CONFIGURATION));
result.add(String.format("IPHONEOS_DEPLOYMENT_TARGET=%s", platformVersion));
result.add(String.format("> %s 2>&1 &", XCODEBUILD_LOG.getAbsolutePath()));
return result;
}
private static List<String> generateKeychainUnlockCmdlines() throws Exception {
final List<String> result = new ArrayList<>();
result.add(String.format("/usr/bin/security -v list-keychains -s %s", KEYCHAIN.getAbsolutePath()));
result.add(String.format("/usr/bin/security -v unlock-keychain -p %s %s",
KEYCHAIN_PASSWORD, KEYCHAIN.getAbsolutePath()));
result.add(String.format("/usr/bin/security set-keychain-settings -t 3600 %s", KEYCHAIN.getAbsolutePath()));
return result;
}
public synchronized void restart() throws Exception {
if (isRealDevice && failedRestartRetriesCount >= MAX_REAL_DEVICE_RESTART_RETRIES) {
throw new IllegalStateException(String.format(
"WDA server cannot start on the connected device with udid %s after %s retries. " +
"Reboot the device manually and try again", deviceId, MAX_REAL_DEVICE_RESTART_RETRIES));
}
final String hostname = InetAddress.getLocalHost().getHostName();
log.info(String.format("Trying to (re)start WDA server on %s:%s...", hostname, PORT));
UnixProcessHelpers.killProcessesGracefully(IPROXY_EXECUTABLE.getName(), XCODEBUILD_EXECUTABLE.getName());
final File scriptFile = File.createTempFile("script", ".sh");
try {
final List<String> scriptContent = new ArrayList<>();
scriptContent.add("#!/bin/bash");
if (isRealDevice && isRunningInJenkinsNetwork()) {
scriptContent.add(String.join("\n", generateKeychainUnlockCmdlines()));
}
if (isRealDevice) {
scriptContent.add(String.join(" ", IPROXY_CMDLINE));
}
final String wdaBuildCmdline = String.join(" ", generateXcodebuildCmdline());
log.debug(String.format("Building WDA with command line:\n%s\n", wdaBuildCmdline));
scriptContent.add(wdaBuildCmdline);
try (Writer output = new BufferedWriter(new FileWriter(scriptFile))) {
output.write(String.join("\n", scriptContent));
}
new ProcessBuilder("/bin/chmod", "u+x", scriptFile.getCanonicalPath())
.redirectErrorStream(true).start().waitFor(5, TimeUnit.SECONDS);
final ProcessBuilder pb = new ProcessBuilder("/bin/bash", scriptFile.getCanonicalPath());
final Map<String, String> env = pb.environment();
// This is needed for Jenkins
env.put("BUILD_ID", "dontKillMe");
log.info(String.format("Waiting max %s for WDA to be (re)started on %s:%s...", RESTART_TIMEOUT.toString(),
hostname, PORT));
final Timedelta started = Timedelta.now();
pb.redirectErrorStream(true).start().waitFor(RESTART_TIMEOUT.asMillis(), TimeUnit.MILLISECONDS);
if (!waitUntilIsRunning(RESTART_TIMEOUT)) {
++failedRestartRetriesCount;
throw new IllegalStateException(
String.format("WDA server has failed to start after %s timeout on server '%s'.\n"
+ "Please make sure that iDevice is properly connected and you can build "
+ "WDA manually from XCode.\n"
+ "Xcodebuild logs:\n\n%s\n\n\niproxy logs:\n\n%s\n\n\n",
RESTART_TIMEOUT, hostname,
getLog(XCODEBUILD_LOG).orElse("EMPTY"), getLog(IPROXY_LOG).orElse("EMPTY"))
);
}
log.info(String.format("WDA server has been successfully (re)started after %s " +
"and now is listening on %s:%s", Timedelta.now().diff(started).toString(), hostname, PORT));
} finally {
scriptFile.delete();
}
}
public boolean isRunning() throws Exception {
if (!isProcessRunning(XCODEBUILD_EXECUTABLE.getName())
|| (isRealDevice && !isProcessRunning(IPROXY_EXECUTABLE.getName()))) {
return false;
}
return waitUntilIsRunning(isRealDevice ? REAL_DEVICE_RUNNING_TIMEOUT : Timedelta.ofSeconds(3));
}
public Optional<String> getLog(File logFile) {
if (logFile.exists()) {
try {
return Optional.of(new String(Files.readAllBytes(logFile.toPath()), Charset.forName("UTF-8")));
} catch (IOException e) {
e.printStackTrace();
}
}
return Optional.empty();
}
public void resetLogs() {
for (File logFile : new File[]{XCODEBUILD_LOG, IPROXY_LOG}) {
if (logFile.exists()) {
try {
final PrintWriter writer = new PrintWriter(logFile);
writer.print("");
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
```
之前应该调用这段代码来启动 Appium iOS 驱动,例如,在 setUp 方法中:
```java
if (!WDAServer.getInstance().isRunning()) {
WDAServer.getInstance().restart();
}
```
为 Appium 驱动程序设置 webDriverAgentUrl 非常重要,让它知道我们的 WDA 驱动程序可以使用:
```java
capabilities.setCapability("webDriverAgentUrl", WDAServer.SERVER_URL);
```
### 重要注释
* 如果是 jenkins agent 执行的,该进程不能直接访问钥匙串(Keychain),所以我们需要在为真实设备编译 WDA 之前准备钥匙串,否则编码将失败。
* 如果 xcodebuild 和 iproxy 进程已经被冻结,我们在重新启动之前杀死这些进程,以确保编译成功,
* 我们准备一个单独的 bash 脚本并独立于 iproxy / xcodebuild 进程,所以即使在实际的代码执行完成后,它们也可以在后台继续运行。如果在自动化实验室中的同一机器/节点上执行多个测试/套件,最少的人工干预是非常重要的。
* 更改 BUILD_ID 环境变量的值以避免在作业完成后由 Jenkins agent 程序杀死后台进程。
* isRunning 检查是通过验证实际的网络终端来完成的.
* 守护进程的输出会存入日志,因此可以跟踪错误和意外的故障。如果服务器无法启动/重启,日志文件的内容会自动添加到实际的错误消息中。
* 真机设备ID可以从 `system_profiler SPUSBDataType` 输出中解析
* 模拟器ID可以从 `xcrun simctl list` 输出中解析
* UrlChecker 类是从 org.openqa.selenium.net 包导入的
本文由 simple 翻译,由 lihuazhang 校验。
-26
View File
@@ -1,26 +0,0 @@
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file.)
## Appim API 文档
### /docs/en/commands/device/app
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file.)
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file.)
<div class="api-index">
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file.)
<ul>
<li><a href='/docs/en/commands/device/app/install-app.md'>应用安装</a></li>
<li><a href='/docs/en/commands/device/app/is-app-installed.md'>Is App Installed</a></li>
<li><a href='/docs/en/commands/device/app/launch-app.md'>Launch App</a></li>
<li><a href='/docs/en/commands/device/app/background-app.md'>Background App</a></li>
<li><a href='/docs/en/commands/device/app/close-app.md'>Close App</a></li>
<li><a href='/docs/en/commands/device/app/reset-app.md'>Reset App</a></li>
<li><a href='/docs/en/commands/device/app/remove-app.md'>Remove App</a></li>
<li><a href='/docs/en/commands/device/app/activate-app.md'>Activate App</a></li>
<li><a href='/docs/en/commands/device/app/terminate-app.md'>Terminate App</a></li>
<li><a href='/docs/en/commands/device/app/app-state.md'>Get App State</a></li>
<li><a href='/docs/en/commands/device/app/get-app-strings.md'>Get App Strings</a></li>
<li><a href='/docs/en/commands/device/app/end-test-coverage.md'>End Test Coverage</a></li>
</ul>
</div>
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file.)
-126
View File
@@ -1,126 +0,0 @@
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
# 应用激活
在设备上激活指定的 app
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
## 示范用法
```java
// Java
driver.activateApp('com.apple.Preferences');
driver.activateApp('io.appium.android.apis');
```
```python
# Python
driver.activate_app('com.apple.Preferences')
driver.activate_app('io.appium.android.apis')
```
```javascript
// Javascript
// webdriver.io 例子
driver.activateApp(null, 'com.apple.Preferences')
driver.activateApp('io.appium.android.apis')
// wd 例子
// iOS 端仅在使用 XCUITEST 框架前提下支持 `mobile: queryAppState` 命令
```
```ruby
# Ruby
# ruby_lib 例子
activate_app('com.apple.Preferences')
activate_app('io.appium.android.apis')
# ruby_lib_core 例子
@driver.activate_app('com.apple.Preferences')
@driver.activate_app('io.appium.android.apis')
```
```php
# PHP
// iOS 端仅在使用 XCUITEST 框架前提下支持 `mobile: queryAppState` 命令
```
```csharp
// C#
driver.activateApp('com.apple.Preferences');
driver.activateApp('io.appium.android.apis');
```
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
## 说明
通过 XCUITest 框架,iOS 端测试同样可以使用 `mobile: activateApp` 方法。详情请查看[文档](http://appium.io/docs/cn/writing-running-appium/ios/ios-xctest-mobile-apps-management/index.html#mobile-activateapp)。
[//]: # (译者备注:这里要替换为iOS实际的链接**)
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
## 帮助文档
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
### Appium Server
|平台|Driver|平台版本|Appium 版本|Driver 版本|
|--------|----------------|------|--------------|--------------|
| iOS | [XCUITest](/docs/cn/drivers/ios-xcuitest.md) | 9.3+ | 1.6.0+ | All |
| | [UIAutomation](/docs/cn/drivers/ios-uiautomation.md) | None | None | None |
| Android | [Espresso](/docs/cn/drivers/android-espresso.md) | ?+ | 1.9.0+ | All |
| | [UiAutomator2](/docs/cn/drivers/android-uiautomator2.md) | ?+ | 1.6.0+ | All |
| | [UiAutomator](/docs/cn/drivers/android-uiautomator.md) | 4.3+ | All | All |
| Mac | [Mac](/docs/cn/drivers/mac.md) | None | None | None |
| Windows | [Windows](/docs/cn/drivers/windows.md) | None | None | None |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
### Appium 客户端
|语言|是否支持|文档|
|--------|-------|-------------|
|[Java](https://github.com/appium/java-client/releases/latest)| All | [appium.github.io](https://appium.github.io/java-client/io/appium/java_client/InteractsWithApps.html#activateApp-java.lang.String-) |
|[Python](https://github.com/appium/python-client/releases/latest)| All | [appium.github.io](https://appium.github.io/python-client-sphinx/webdriver.extensions.html#webdriver.extensions.applications.Applications.activate_app) |
|[Javascript (WebdriverIO)](http://webdriver.io/index.html)| All | |
|[Javascript (WD)](https://github.com/admc/wd/releases/latest)| All | [github.com](https://github.com/admc/wd/blob/master/lib/commands.js) |
|[Ruby](https://github.com/appium/ruby_lib/releases/latest)| All | [www.rubydoc.info](https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device#activate_app-instance_method) |
|[PHP](https://github.com/appium/php-client/releases/latest)| All | [github.com](https://github.com/appium/php-client/) |
|[C#](https://github.com/appium/appium-dotnet-driver/releases/latest)| All | [github.com](https://github.com/appium/appium-dotnet-driver/) |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
## HTTP API 规范
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
### Endpoint
`POST /session/:session_id/appium/device/activate_app`
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
### URL 参数
|字段名| 说明 |
|----|-----------|
|session_id|通过命令去路由的session id|
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
### JSON 参数
|字段名|类型|说明|
|----|----|-----------|
| bundleId 或 appId | `string` | iOS 端使用 BundleId, Andorid 端使用包名(package name)。 |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
### 响应(Response)
无
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/activate-app.yml)
## 另请参阅
* [JSONWP 说明书](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js#L445)
-126
View File
@@ -1,126 +0,0 @@
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
# 获取 app 的当前状态
在设备中获取 app 当前的状态
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
## 使用范例
```java
// Java
driver.queryAppState('com.apple.Preferences');
driver.queryAppState('io.appium.android.apis');
```
```python
# Python
driver.query_app_state('com.apple.Preferences')
driver.query_app_state('io.appium.android.apis')
```
```javascript
// Javascript
// webdriver.io 例子
driver.queryAppState(null, 'com.apple.Preferences')
driver.queryAppState('io.appium.android.apis')
// wd 例子
// iOS 端仅在使用 XCUITEST 框架前提下支持 `mobile: queryAppState` 命令
```
```ruby
# Ruby
# ruby_lib 例子
app_state('com.apple.Preferences')
query_app_state('io.appium.android.apis') # `query_` 前缀同样可用
# ruby_lib_core 例子
@driver.app_state('com.apple.Preferences')
@driver.query_app_state('io.appium.android.apis') # `query_` 前缀同样可用
```
```php
# PHP
// iOS 端仅在使用 XCUITEST 框架前提下支持 `mobile: queryAppState` 命令
```
```csharp
// C#
// iOS 端仅在使用 XCUITEST 框架前提下支持 `mobile: queryAppState` 命令
```
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
## 说明
iOS tests with XCUITest can also use the `mobile: queryAppState` method. See detailed [documentation](http://appium.io/docs/cn/writing-running-appium/ios/ios-xctest-mobile-apps-management/index.html#mobile-queryappstate).
通过 XCUITest 框架,iOS 端测试同样可以使用 `mobile: queryAppState` 方法。详情请查看[文档](http://appium.io/docs/writing-running-appium/ios/ios-xctest-mobile-apps-management/index.html#mobile-queryappstate)。
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
## 帮助文档
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
### Appium Server
|平台|Driver|平台版本|Appium 版本|Driver 版本|
|--------|----------------|------|--------------|--------------|
| iOS | [XCUITest](/docs/drivers/ios-xcuitest.md) | 9.3+ | 1.6.0+ | All |
| | [UIAutomation](/docs/drivers/ios-uiautomation.md) | None | None | None |
| Android | [Espresso](/docs/drivers/android-espresso.md) | ?+ | 1.9.0+ | All |
| | [UiAutomator2](/docs/drivers/android-uiautomator2.md) | ?+ | 1.6.0+ | All |
| | [UiAutomator](/docs/drivers/android-uiautomator.md) | 4.3+ | All | All |
| Mac | [Mac](/docs/drivers/mac.md) | None | None | None |
| Windows | [Windows](/docs/drivers/windows.md) | None | None | None |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
### Appium 客户端
|语言|是否支持|文档|
|--------|-------|-------------|
|[Java](https://github.com/appium/java-client/releases/latest)| All | [appium.github.io](https://appium.github.io/java-client/io/appium/java_client/InteractsWithApps.html#queryAppState-java.lang.String-) |
|[Python](https://github.com/appium/python-client/releases/latest)| All | [appium.github.io](https://appium.github.io/python-client-sphinx/webdriver.extensions.html#webdriver.extensions.applications.Applications.query_app_state) |
|[Javascript (WebdriverIO)](http://webdriver.io/index.html)| All | |
|[Javascript (WD)](https://github.com/admc/wd/releases/latest)| All | [github.com](https://github.com/admc/wd/blob/master/lib/commands.js) |
|[Ruby](https://github.com/appium/ruby_lib/releases/latest)| All | [www.rubydoc.info](https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Base/Driver#app_state-instance_method) |
|[PHP](https://github.com/appium/php-client/releases/latest)| All | [github.com](https://github.com/appium/php-client/) |
|[C#](https://github.com/appium/appium-dotnet-driver/releases/latest)| All | [github.com](https://github.com/appium/appium-dotnet-driver/) |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
## HTTP API 规范
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
### Endpoint
`GET /session/:session_id/appium/device/app_state`
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
### URL 参数
|字段名| 说明 |
|----|-----------|
|session_id|通过命令去路由的session id|
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
### JSON 参数
|字段名|类型|说明|
|----|----|-----------|
| bundleId 或 appId | `string` | iOS 端使用 BundleId, Andorid 端使用包名(package name)。 |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
### 响应(Response)
当前 app 的状态(通过客户端去封装响应结果)如下所示:`0` 为应用未安装,`1` 为应用未运行,`2` 为应用在后台运行或被挂起,`3` 为应用在后台运行,`4` 为应用正在前台运行。(`number` 类型)
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/app-state.yml)
## 另请参阅
* [JSONWP 说明书](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js#L480)
@@ -1,126 +0,0 @@
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
# 后台应用
将当前正在运行应用的 session 发送给后台
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
## 使用范例
```java
// Java
driver.runAppInBackground(Duration.ofSeconds(10));
```
```python
# Python
self.driver.background_app(10)
```
```javascript
// Javascript
// webdriver.io 例子
driver.background(10);
// wd 例子
await driver.backgroundApp(10);
```
```ruby
# Ruby
# ruby_lib 例子
background_app(10)
# ruby_lib_core 例子
@driver.background_app(10)
```
```php
# PHP
$driver->backgroundApp(10);
```
```csharp
// C#
driver.BackgroundApp(10)
```
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
## 说明
当需要将当前被激活的 app 退出到后台,或使 app 在后台停留一定的时长,又或者需要让 app 完全停止运行的时候,以下有三种类型的参数可以传递给这个方法:
1. 使用类似一个 `{"timeout": secs}` 的对象,`secs` 表示在后台运行多少秒,`secs` 的类型为整型(integer)。若 `secs` 为 -1,则说明 app 已经完全停止运行。
2. `null` 代表完全停止 app 运行。
3. 直接传一个整型(integer):代表在后端停留多少秒,但不建议传此参数。若为 -1,则说明 app 已经完全停止运行。
iOS 端通过 XCUITest 框架也能使用 `mobile: terminateApp` 方法去停止当前 app(详情参考[文档](/docs/cn/writing-running-appium/ios/ios-xctest-mobile-apps-management.md#mobile-terminateapp)),`mobile: activateApp` 可激活被测设备上现有的 app,并将其恢复到前台运行(详情参考[文档](/docs/cn/writing-running-appium/ios/ios-xctest-mobile-apps-management.md#mobile-activateapp))。
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
## 帮助文档
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
### Appium Server
|平台|Driver|平台版本|Appium 版本|Driver 版本|
|--------|----------------|------|--------------|--------------|
| iOS | [XCUITest](/docs/cn/drivers/ios-xcuitest.md) | 9.3+ | 1.6.0+ | All |
| | [UIAutomation](/docs/cn/drivers/ios-uiautomation.md) | 8.0 to 9.3 | All | All |
| Android | [Espresso](/docs/cn/drivers/android-espresso.md) | ?+ | 1.9.0+ | All |
| | [UiAutomator2](/docs/cn/drivers/android-uiautomator2.md) | ?+ | 1.6.0+ | All |
| | [UiAutomator](/docs/cn/drivers/android-uiautomator.md) | 4.3+ | All | All |
| Mac | [Mac](/docs/cn/drivers/mac.md) | None | None | None |
| Windows | [Windows](/docs/cn/drivers/windows.md) | None | None | None |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
### Appium 客户端
|语言|是否支持|文档|
|--------|-------|-------------|
|[Java](https://github.com/appium/java-client/releases/latest)| All | [appium.github.io](https://appium.github.io/java-client/io/appium/java_client/InteractsWithApps.html#runAppInBackground-java.time.Duration-) |
|[Python](https://github.com/appium/python-client/releases/latest)| All | [appium.github.io](https://appium.github.io/python-client-sphinx/webdriver.extensions.html#webdriver.extensions.applications.Applications.background_app) |
|[Javascript (WebdriverIO)](http://webdriver.io/index.html)| All | |
|[Javascript (WD)](https://github.com/admc/wd/releases/latest)| All | [github.com](https://github.com/admc/wd/blob/master/lib/commands.js#L2841) |
|[Ruby](https://github.com/appium/ruby_lib/releases/latest)| All | [www.rubydoc.info](https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device#background_app-instance_method) |
|[PHP](https://github.com/appium/php-client/releases/latest)| All | [github.com](https://github.com/appium/php-client/) |
|[C#](https://github.com/appium/appium-dotnet-driver/releases/latest)| All | [github.com](https://github.com/appium/appium-dotnet-driver/) |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
## HTTP API 规范
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
### Endpoint
`POST /session/:session_id/appium/app/background`
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
### URL 参数
|字段名| 说明 |
|----|-----------|
|session_id|通过命令去路由的session id|
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
### JSON 参数
|字段名|类型|说明|
|----|----|-----------|
| 秒数 | `number` | app 在后台运行时长 |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
### 响应(Response)
无
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/background-app.yml)
## 另请参阅
* [JSONWP 说明书](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js#L556)
-111
View File
@@ -1,111 +0,0 @@
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
# 终止 App 运行
终止 app 在设备上运行
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
## 示范用法
```java
// Java
driver.closeApp();
```
```python
# Python
self.driver.close_app()
```
```javascript
// Javascript
// webdriver.io 例子
driver.closeApp();
// wd 例子
await driver.closeApp();
```
```ruby
# Ruby
# ruby_lib 例子
close_app
# ruby_lib_core 例子
@driver.close_app
```
```php
# PHP
$driver->closeApp();
```
```csharp
// C#
driver.CloseApp();
```
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
## 帮助文档
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
### Appium Server
|平台|Driver|平台版本|Appium 版本|Driver 版本|
|--------|----------------|------|--------------|--------------|
| iOS | [XCUITest](/docs/cn/drivers/ios-xcuitest.md) | 9.3+ | 1.6.0+ | All |
| | [UIAutomation](/docs/cn/drivers/ios-uiautomation.md) | 8.0 to 9.3 | All | All |
| Android | [Espresso](/docs/cn/drivers/android-espresso.md) | None | None | None |
| | [UiAutomator2](/docs/cn/drivers/android-uiautomator2.md) | ?+ | 1.6.0+ | All |
| | [UiAutomator](/docs/cn/drivers/android-uiautomator.md) | 4.3+ | All | All |
| Mac | [Mac](/docs/cn/drivers/mac.md) | None | None | None |
| Windows | [Windows](/docs/cn/drivers/windows.md) | None | None | None |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
### Appium 客户端
|语言|是否支持|文档|
|--------|-------|-------------|
|[Java](https://github.com/appium/java-client/releases/latest)| All | [appium.github.io](https://appium.github.io/java-client/io/appium/java_client/InteractsWithApps.html#closeApp--) |
|[Python](https://github.com/appium/python-client/releases/latest)| All | [appium.github.io](https://appium.github.io/python-client-sphinx/webdriver.extensions.html#webdriver.extensions.applications.Applications.close_app) |
|[Javascript (WebdriverIO)](http://webdriver.io/index.html)| All | |
|[Javascript (WD)](https://github.com/admc/wd/releases/latest)| All | [github.com](https://github.com/admc/wd/blob/master/lib/commands.js#L2798) |
|[Ruby](https://github.com/appium/ruby_lib/releases/latest)| All | [www.rubydoc.info](https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device#close_app-instance_method) |
|[PHP](https://github.com/appium/php-client/releases/latest)| All | [github.com](https://github.com/appium/php-client/) |
|[C#](https://github.com/appium/appium-dotnet-driver/releases/latest)| All | [github.com](https://github.com/appium/appium-dotnet-driver/blob/master/src/Appium.Net/Appium/AppiumDriver.cs) |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
## HTTP API 规范
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
### Endpoint
`POST /session/:session_id/appium/app/close`
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
### URL 参数
|字段名| 说明 |
|----|-----------|
|session_id|通过命令去路由的session id|
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
### JSON 参数
无
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
### 响应(Response)
无
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/close-app.yml)
## 另请参阅
* [JSONWP 说明书](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js#L550)
@@ -1,114 +0,0 @@
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
# 结束测试覆盖率
获取覆盖率测试数据
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
## 使用范例
```java
// Java
driver.endTestCoverage("Intent", "/path");
```
```python
# Python
self.driver.end_test_coverage("Intent", "/path")
```
```javascript
// Javascript
// webdriver.io 例子
driver.endCoverage("Intent", "/path");
// wd 例子
await driver.endTestCoverageForApp("Intent", "/path");
```
```ruby
# Ruby
# ruby_lib 例子
end_coverage("Intent", "/path")
# ruby_lib_core 例子
@driver.end_coverage("Intent", "/path")
```
```php
# PHP
$driver->endTestCoverage('Intent', '/path');
```
```csharp
// C#
driver.EndTestCoverage("Intent", "/path");
```
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
## 帮助文档
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
### Appium Server
|平台|Driver|平台版本|Appium 版本|Driver 版本|
|--------|----------------|------|--------------|--------------|
| iOS | [XCUITest](/docs/cn/drivers/ios-xcuitest.md) | None | None | None |
| | [UIAutomation](/docs/cn/drivers/ios-uiautomation.md) | None | None | None |
| Android | [Espresso](/docs/cn/drivers/android-espresso.md) | ?+ | 1.9.0+ | All |
| | [UiAutomator2](/docs/cn/drivers/android-uiautomator2.md) | ?+ | 1.6.0+ | All |
| | [UiAutomator](/docs/cn/drivers/android-uiautomator.md) | 4.3+ | All | All |
| Mac | [Mac](/docs/cn/drivers/mac.md) | None | None | None |
| Windows | [Windows](/docs/cn/drivers/windows.md) | None | None | None |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
### Appium 客户端
|语言|是否支持|文档|
|--------|-------|-------------|
|[Java](https://github.com/appium/java-client/releases/latest)| All | [appium.github.io](https://appium.github.io/java-client/io/appium/java_client/android/AndroidDriver.html#endTestCoverage-java.lang.String-java.lang.String-) |
|[Python](https://github.com/appium/python-client/releases/latest)| All | [appium.github.io](https://appium.github.io/python-client-sphinx/webdriver.extensions.android.html#webdriver.extensions.android.common.Common.end_test_coverage) |
|[Javascript (WebdriverIO)](http://webdriver.io/index.html)| All | |
|[Javascript (WD)](https://github.com/admc/wd/releases/latest)| All | [github.com](https://github.com/admc/wd/blob/master/lib/commands.js#L2858) |
|[Ruby](https://github.com/appium/ruby_lib/releases/latest)| None | [www.rubydoc.info](https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Android/Device#end_coverage-instance_method) |
|[PHP](https://github.com/appium/php-client/releases/latest)| All | [github.com](https://github.com/appium/php-client/) |
|[C#](https://github.com/appium/appium-dotnet-driver/releases/latest)| All | [github.com](https://github.com/appium/appium-dotnet-driver/blob/master/src/Appium.Net/Appium/Android/AndroidDriver.cs) |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
## HTTP API 规范
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
### Endpoint
`POST /session/:session_id/appium/app/end_test_coverage`
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
### URL 参数
|字段名| 说明 |
|----|-----------|
|session_id|通过命令去路由的session id|
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
### JSON 参数
|字段名|类型|说明|
|----|----|-----------|
| intent | `string` | Intent 的 broadcast |
| path | `string` | .ec 文件的路径 |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
### 响应(Response)
无
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/end-test-coverage.yml)
## 另请参阅
* [JSONWP 说明书](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js#L559)
@@ -1,114 +0,0 @@
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
# 获取 App 字符串
获取 App 字符串
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
## 使用范例
```java
// Java
Map<String, String> appStrings = driver.getAppStringMap("en", "/path/to/file");
```
```python
# Python
appStrings = self.driver.app_strings("en", "/path/to/file")
```
```javascript
// Javascript
// webdriver.io 例子
let appStrings = driver.getStrings("en");
// wd 例子
let appStrings = await driver.getAppStrings();
```
```ruby
# Ruby
# ruby_lib 例子
app_strings("en")
# ruby_lib_core 例子
@driver.app_strings("en")
```
```php
# PHP
$strings = $driver->appStrings();
```
```csharp
// C#
Dictionary<string, object> appStrings = driver.GetAppStringDictionary("end", "/path/to/file");
```
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
## 帮助文档
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
### Appium Server
|平台|Driver|平台版本|Appium 版本|Driver 版本|
|--------|----------------|------|--------------|--------------|
| iOS | [XCUITest](/docs/cn/drivers/ios-xcuitest.md) | 9.3+ | 1.6.0+ | All |
| | [UIAutomation](/docs/cn/drivers/ios-uiautomation.md) | 8.0 to 9.3 | All | All |
| Android | [Espresso](/docs/cn/drivers/android-espresso.md) | ?+ | 1.9.0+ | All |
| | [UiAutomator2](/docs/cn/drivers/android-uiautomator2.md) | ?+ | 1.6.0+ | All |
| | [UiAutomator](/docs/cn/drivers/android-uiautomator.md) | 4.3+ | All | All |
| Mac | [Mac](/docs/cn/drivers/mac.md) | None | None | None |
| Windows | [Windows](/docs/cn/drivers/windows.md) | None | None | None |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
### Appium 客户端
|语言|是否支持|文档|
|--------|-------|-------------|
|[Java](https://github.com/appium/java-client/releases/latest)| All | [appium.github.io](https://appium.github.io/java-client/io/appium/java_client/HasAppStrings.html#getAppStringMap--) |
|[Python](https://github.com/appium/python-client/releases/latest)| All | [appium.github.io](https://appium.github.io/python-client-sphinx/webdriver.extensions.html#webdriver.extensions.applications.Applications.app_strings) |
|[Javascript (WebdriverIO)](http://webdriver.io/index.html)| All | |
|[Javascript (WD)](https://github.com/admc/wd/releases/latest)| All | [github.com](https://github.com/admc/wd/blob/master/lib/commands.js#L2916) |
|[Ruby](https://github.com/appium/ruby_lib/releases/latest)| All | [www.rubydoc.info](https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device#app_strings-instance_method) |
|[PHP](https://github.com/appium/php-client/releases/latest)| All | [github.com](https://github.com/appium/php-client/) |
|[C#](https://github.com/appium/appium-dotnet-driver/releases/latest)| All | [github.com](https://github.com/appium/appium-dotnet-driver/blob/master/src/Appium.Net/Appium/AppiumDriver.cs) |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
## HTTP API 规范
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
### Endpoint
`POST /session/:session_id/appium/app/strings`
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
### URL 参数
|字段名| 说明 |
|----|-----------|
|session_id|通过命令去路由的session id|
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
### JSON 参数
|字段名|类型|说明|
|----|----|-----------|
| language | `string` | 语言代码 (可选) |
| stringFile | `string` | 字符文件串路径 (可选) |
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
### 响应(Response)
无
[//]: # (DO NOT EDIT THIS FILE! This is an auto-generated file. Editing for this document happens in /commands-yml/commands/device/app/get-app-strings.yml)
## 另请参阅
* [JSONWP 说明书](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js#L562)
@@ -1,122 +0,0 @@
## 从源码运行Appium
你想从源码运行Appium并帮助修复BUG和添加功能吗?
真棒!只需要fork工程,添加一个修改,然后发送pull请求即可!
在开始之前请阅读我们的代码风格指南([Style Guide](style-guide.md)。
在发送pull请求前请确保通过单元和功能测试;关于如何运行测试等更多信息,请继续阅读!
首先,确保你阅读README文件且按照设置说明走。
### 从源码配置 Appium
Appium 的配置涉及:
1. Appium Server —— 在你的测试代码和设备或模拟器之间通过 Appium Server 来回发送消息
2. 测试脚本 —— 任何客户端语言都可以,只要和 Appium 兼容
运行 Appium Server,然后运行你的测试。
快速开始:
```center
git clone https://github.com/appium/appium.git
cd appium
npm install
npm run build
node .
```
```center
git clone https://github.com/appium/appium.git
cd appium
npm install
npm run build # 需要gulp,往下看
node .
```
### 捣鼓改造 Appium
Make sure you have `ant`, `maven`, `adb` installed and added to system `PATH`, also you
would need the android-16 sdk (for Selendroid) and android-19 sdk installed.
From your local repo's command prompt, install the following packages using the
following commands (if you didn't install `node` using Homebrew, you might have
to run `npm` with sudo privileges):
确保已安装 `ant`、 `maven`、 `adb` 且已添加到 `PATH` 环境变量,还需要安装 android-16 的 sdk(Selendroid需要使用)和 android-19 的 sdk。在 Appium 本地仓库打开命令行,使用以下命令安装以下包(如果你没有使用Homebrew安装过 node,可能需要使用 sudo 运行 npm):
```center
npm install -g appium-doctor && appium-doctor --dev
npm install
gulp transpile
```
前两个命令安装测试和构建工具(如果您通过 Homebrew 安装了 nodejs,则 `sudo` 可能不是必需的)。 第三个命令验证所有依赖关系是否正确设置(因为构建 Appium 的依赖关系不同于简单运行 Appium 的依赖项),而第四个命令将安装所有应用程序依赖关系并构建支持二进制文件和测试应用程序。 最终的命令将转换所有代码,以便 nodejs 可以运行它。
When pulling new code from GitHub, if there are changes to `package.json` it
is necessary to remove the old dependencies and re-run `npm install`:
当从 GitHub 中拉出新的代码时,如果 `package.json` 有更改,需要删除旧的依赖关系并重新运行 `npm install`:
```center
rm -rf node_modules
npm install
npm run build
```
此时,您将可以启动 Appium Server:
```center
node .
```
完整的参数列表,请参考[the server documentation](/docs/cn/writing-running-appium/server-args.md)
#### 鼓捣 Android 上的Appium
通过运行以下命令配置Appium:
```center
rm -rf node-modules
npm install
npm run build
```
确保您只有一个 Android 模拟器或设备运行,例如,通过在另一个进程中运行此命令(假设 `emulator` 命令在您的路径上):
```center
emulator -avd <MyAvdName>
```
现在,您可以通过 `node .` 运行Appium服务器了。
#### 确保你的代码是最新的
由于Appium使用某些软件包的开发版本,因此通常需要安装新 `npm` 软件包或更新各种软件。运行 `npm install` 将更新所需的一切。当 Appium 升级版本时,您还需要执行此操作。在运行 `npm install` 之前,建议先删除 `node_modules` 目录中的所有旧依赖项:
```center
rm -rf node-modules
npm install
npm run build
```
### 运行测试
首先,请查看我们关于[running tests in
general](/docs/cn/writing-running-appium/running-tests.md) 的文档,确保您的系统正确设置为您希望测试的平台。
一旦您的系统配置完毕,您的代码是最新的,您可以运行单元测试:
```center
npm run test
```
您可以对所有受支持的平台运行功能测试(确保在另一个窗口中运行Appium `node .`)与:
```center
npm run e2e-test
```
在提交代码之前,请运行 `npm run test` 一些基本测试,并根据代码质量标准检查您的更改。
本文由 校长 翻译,由 lihuazhang 校验。
@@ -1,256 +0,0 @@
# Appium 简述
![Appium packages](./appium-packages.png)
## appium
- 运行时的基本检查
- 节点版本(>= 4)
- CLI 参数检查
- 包含所有可用和支持的CLI参数
- 检是否有冲突和弃用
- 统一存放日志
- 统一存放npmlog, winston和appium-logger
- 启动AppiumDriver(继承Basedriver)
- 为iOS/Android/Selendroid/Fake Driver 建立会话
- 创建/删除Appium会话
- 启动baseServer (appium-express)
- 通过驱动给出的路径
## appium-express (部分appium basedriver)
- 启动express server(允许x-domain-origin)
- 从AppiumDriver初始化
- 超时处理
- 提供一个用于测试的静态页面
- 将req/res事件记入日志
## mobile-json-wire-protocol (部分appium basedriver)
- 提供了Appium命令列表
- 通过协议的驱动子类
-客户端和驱动程序之间的中间件
- 处理驱动程序的jwp代理
- 包含所有类型错误的错误类
- 消除错误响应
- 将参数封装/解封到命令中
- 检查所需参数,验证参数
## appium basedriver
- 每个实例化都有一个单独的测试会话
- 包含对caps的约束 (platformName必须存在等)
- 验证功能
- 运行具有单个并发性的命令
- 处理会话重启
- 处理滑动选项
- DeviceSettings负责设备的get/update管理
- 包含基本命令
- 找到元素
- 创建/删除会话
- 处理超时
- 设备的set/update设置
- 为命令提供帮助方法
## appiium iosdriver
- 也可以作为独立服务器运行(从appium-express继承了小部分服务)
- 支持的策略:“name”,“xpath”,“id”,“-ios uiautomation”,“class name”,“accessibility id”
- 可以启动一个模拟器或一个真实的设备(需要标明udid)
- 每个类型的说明
- removeInstrumentsSocket
- setBundleIdFromApp
- createInstruments
- runSimReset, isolateSimDevice, setLocale || runRealDeviceReset
- setPreferences || runRealDeviceReset
- startLogCapture
- prelaunchSimulator || (noop)
- startInstruments
- onInstrumentsLaunch
- configureBootstrap
- setBundleId
- setInitialOrientation
- initAutoWebview
- waitForAppLaunched
- 所有帮助说明都在driver.js中
- 包含一组更具体的功能约束
- 有使用appium-xcode构建和运行Safari(safari-launcher)的逻辑
- 实现iOSdriver的命令
- Selenium命令被编译为ui-automator命令
- 命令将会发送到uiAutoClient(appium-uiauto)
- 连接到appium远程调试器
## appium-xcode
- 运行shell命令从Xcode返回有用的数据,比如
- getPath
- getVersion
- getAutomationTraceTemplatePath
- getMaxIOSSDK
- …
- 内置自动重试
## appium-uiauto
- 封装 iOS UI Automation 框架的
- 通过socket连接进行通信
- 运行由sendCommand函数填充的命令队列
- 处理来自ui-automation的响应(作为缓冲区)
- 使用osascript旋转屏幕截图
- 提供bootstrap simulator/realdevice (dynamic-bootstrap)的方法
- 在iOS UI自动化上下文(非节点)中运行的JavaScript文件
- 负责执行实际的iOS UI Automation命令
- 参考 [UIAutomation docs](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
- 命令流程就像
- Webdriver 命令-> iOS driver 命令 -> uiauto-命令
## appium-instruments
- 封装运行instruments的命令
- 很多exec调用与instruments二进制义互
- 所有这些都采取回调来获取结果
- 必须使用“iwd”包编译软件包
- 特殊的Instruments包不存在命令延迟
- 还包含较旧版本的iwd instrument(v4 - v7)
## appium-ios日志
- 捕获iOS模拟器或实际设备的控制台,性能和崩溃日志
- 通过调用tail来从系统路径获取日志(模拟器设备)
- 或通过调用deviceconsole(实际设备)
- 使用远程调试器来抓取性能日志
- 崩溃日志保留在系统上的“.crash”文件中
## appium-iOS-模拟器
- 封装iOS模拟器应用程序
- 启动和关闭(杀死所有)模拟器
- 更新设置和本地
- 更新/清除 safari
- 获取有关模拟器设备的元数据
- 使用simctl与模拟器通信
- 适用于Xcode 6和7
## node-simctl
- 封装simctl二进制(cli实用程序来控制iOS模拟器)
- 作为xcrun的子命令执行(从命令行查找或调用开发人员工具)
- 包含功能
- 安装/删除应用程序
- 启动和关闭模拟器
- 创建/清除/删除设备
- 获取设备列表
## appium-cookies
- 简单的包来创建和接收cookie
- 在appium-iosdriver中使用,以在Web上下文中实现jswonwire cookie命令
## appium-chromedriver
- 封装 chromedriver
- 下载并安装chromedriver二进制文件
- 启动,重新启动并停止(或杀死所有)chrome实例
- 使用appium-jsonwp-proxy向驱动程序发送json wire protocol命令
## jsonwp-proxy (部分appium basedriver)
- 允许将json wire协议命令发送到了解它的服务器(浏览器驱动程序)
- 解析json的响应
- 允许代理服务器的请求
- 用于在Chromium-Chromedriver和appium-selendroiddriver中进行通信
## appium-androiddriver
- 类似于appium-iosdriver,它可以作为独立服务运行
- 自动化模拟器和实际设备上的本地,混合和移动Web应用程序
- 负责安装Android软件包到设备
- 如果需要,运行chromedriver会话
- 包含一组更具体的功能约束
- 使用appium-adb与emulator/simulator/realdevice进行交互
- 和appium-android-bootstrap来执行实际的命令
- 包含帮忙找出哪个网页视图属于哪个应用程序包,反之亦然
## appium-adb
- 封装 Android Debug Bridge(adb)
- 包含一些基本的rpc到adb二进制的命令
- 容纳jar文件来运行特殊用例,例如签名,验证应用程序或移动清单
- 允许与webdriver协议无关的特殊(移动专用)模拟器命令
- 锁定屏幕
- 按返回按钮
- 按home按钮
- 设置/获取飞行模式
- 设置/获取wifi状态
- 捕获logcat
- 处理模拟器/模拟器动作(例如重启)
## appium-androidbootstrap
- JavaScript界面​​和Java代码,用于与Android UI Automator进行交互
- 构建包含执行命令的逻辑的AppiumBootstrap.jar
- 对应的 iOS 上的 appium-uiauto
- 一旦启动,就会创建一个到设备的web scoket连接
- 应用程序提供启动/关闭/发送命令接口
- 命令流程如下:
- Selenium 命令 - > appium-adb - > appium-androidbootstrap - > 使用Android UI Automator 框架的 Java 代码
## appium-uiautomator
- 启动和关闭uiautomator服务器由appium-android-bootstrap jar建立
- 命令流程就像
- appium-android-bootstrap:start -> appium-uiautomator:start -> appium-adb:install bootstrap
## appium-selendroiddriver
- 类似于appium-androiddriver,它可以作为独立服务运行
- 使用appium-selendroid-installer下载并安装Selendroid
- 包含几个Selendroid特定的逻辑,以确保无缝集成
- 包含一组更具体的功能约束
- 使用jsonwp-proxy与服务器交互
- 使用appium-adb启用在Selendroid中未实现的命令
## appium-selendroid 安装程序
- 包含并导出设置逻辑
- 下载Selendroid
- 确定AndroidManifest的位置
- 确定Server APK的位置
- 提取这两个文件
- 复制和清理文件
## appium-android-ime
- 允许从 Android 设备发送和接收 unicode 字符
- 将文本编码为UTF-7将其发送到设备并将其重新编码为 Unicode
- 由 appium-androiddriver 和 appium-selendroiddriver 使用
## appium-doctor
- 在启动Appium之前诊断,报告和修复常见的Node,iOS和Android配置问题
- 暴露cli命令“appium-doctor”
- 它检查
- Android:
- android sdk存在并正确配置
- env变量和路径检查
- iOS:
- 安装了xcode(使用命令行工具)
- 开发工具安全检查
- auth检查
- nodejs 检查
## appium-gulp-plugins
- 具有定制插件的开发包使用交叉应用模块(仅适用于Appium开发)
- 包含任务
- e2e和单元测试(覆盖率报告)
- 将ES2016 转换成 ES5
- 静态代码分析(jshint)
- 开发人员的任务
## appium-remote-debugger
- RPC客户端将Appium连接到iOS网页浏览
- 可以连接到WebKit devtools
- 仅适用于iOS
- 有两个rpc客户端类
- remote-debugger-rpc-client:使用连接到localhost的tcp6:27753
- webkit-rpc-client:使用WebSockets连接到ws:// localhost:27753 / devtools / page / $ {pageId}
## node-teen_process
- 助手模块暴露:
- exec:在引擎盖下使用spawn的exec的ES7(async / await)实现
- SubProcess:在使用spawn时减少样板(特别是在async / await上下文中使用时)
## appium 日志
- 运行时,日志器默认为 npmlog,
- 暴露了几乎所有的Appium软件包使用的getLogger函数
- 如果有一个已经运行的记录器,那么所有的东西都会记录
## appium-support
- 用于支持跨应用程序包的库的实用程序函数。
- 为一些常见的操作提供封装,如
- 系统方法(isWindows,isLinux ...)
- 实用程序方法,如hasValue,escapeSpace
- 一堆fs方法
- plist帮助解析和更新plist文件
本文由 校长 翻译,由 lihuazhang 校验。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

-22
View File
@@ -1,22 +0,0 @@
## 鸣谢
### 以下项目在Appium的开发过程中予我们以启示,或是让Appium变得更棒:
* [Apple UIAutomation](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
* [GhostDriver](https://github.com/detro/ghostdriver)
* [IOS Auto](https://github.com/penguinho/applecart)
* [IOS Driver](https://github.com/ios-driver/ios-driver)
* [Mechanic.js](https://github.com/jaykz52/mechanic)
* [node-webkit](https://github.com/rogerwang/node-webkit)
* [Remote Debug](https://github.com/leftlogic/remote-debug)
* [Selenium Project](https://www.selenium.dev/)
* [deviceconsole](https://github.com/rpetrich/deviceconsole)
* [WinAppDriver](http://github.com/Microsoft/WinAppDriver)
* [WebDriverAgent](https://github.com/facebook/webdriveragent)
--
EOF.
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
Last english version: c986e4a62718b00976b26acb39e07e55f0c204d5, May 25, 2018
@@ -1,137 +0,0 @@
## 一个开发人员对于Appium的概述
在阅读这个此文档之前,请确保你已经阅读并理解了关于[Appium的基本概念](/docs/cn/about-appium/intro.md),
以及关于如何参与[Appium贡献说明](https://github.com/appium/appium/blob/master/CONTRIBUTING.md)
### 技术愿景
Appium致力于成为一个移动JSONWP前端,实现最佳的应用自动化技术。仅此而已。我们想要采用所有不同的
但自带亮点的自动化引擎,通过制作Appium驱动程序来平滑它们的差异和瑕疵,同时将它们纳入Appium。这与
Selenium项目有异曲同工之妙。对于我们而言,我们想要每一个驱动都是一个独立的实体(单独的repo, 测试,
等等)即便它们使用共享库,这一举措会使Appium驱动程序的开发变得尽可能简单,而且不拘泥于样板。我们之所以
使用现今流行的JavaScript,因为它们无处不在,而且对于很多开发人员而言容易理解并易于贡献。
### 开发者社区
欢迎任何人成为Appium开发人员,你仅需要阅读此指南并把你的一些代码合并进来,那么你就成为了我们一员。
如果你坚持不懈并且广施善缘,我们将会把你升级为一名提交者,这样你能继续帮助社区发展而且省去很多纷繁复杂。
如果你在开发Appium的时候遇到疑问,请前往我们的开发人员社区`appium-developers@googlegroups.com`.
请注意,这是一个为_开发_疑问而设的邮件列表,而不是关于_使用_疑问或bug提交。 有关使用问题请前往[discuss.appium.io](https://discuss.appium.io)
Github问题跟踪只是用于bug提交和功能需求。
### 敏捷开发工作流程
Appium团队根据轻量化的scrum版本来运行开发。每两个星期我们开始一个新的“sprint”,或者每一段时间,我们
会决定团队下一阶段需要完成的事情。我们欢迎任何熟悉Appium代码库的人参加我们的sprint计划,并将视作SCRUM参与团队成员。
参与者无需是代码长期提交者。sprint期间,我们将在[Appium slack 团队](https://appium.slack.com)的
`#standup` 聊天室更新我们每个人的进程(没有实时的每天站立会议)。sprint结束时,我们将举行“回顾”活动,以此来
庆祝我们取得的成就并总结活动进展如何,这可能会生成一个关于如何进行不同尝试又或者如何做的更好的总结列表。
最终,我们的目标是在每一个sprint结束时发布一个Appium版本,也就是说每两个星期一个周期。我们还没有实现这个目标,但希望
我们能很快达成。
当前会议时间:
* sprint计划: 每两个周一 10:00 AM - 10:45 AM (太平洋时间)
* sprint回顾: 每三个周五 1:00 PM - 1:30 PM(太平洋时间)
我们使用[Zoom](https://zoom.us)视讯来举行会议
如果你有意参加sprint,你可以在Appium Slack群组里联系`@jlipps` 或者 `@isaac`,又或者直接在推特
上联系`@jlipps`,我们将会在下一次sprint里分享如何加入视频聊天。
### 构造
Appium主要是一个[node.js](http://nodejs.org)包的集合,以此组合形成一个运行的node.js服务器。
这些包都被单独维护并拥有各自的GitHub repo, CI和发布流程。一些软件包(比如 `appium-ios-driver`)
很大,并且给Appinum添加了很重要的功能。相比而言,其他软件包则扮演着一个辅助的角色,而且高度曝光其某个
特定并被反复使用的功能。
有关软件包的层次结构和每一个包所起的作用,请前往我们[包的概述](/docs/cn/contributing-to-appium/appium-packages.md)文档。
### 转化
Appium是用JavaScript的新形式编写的,称为ES6(或现在的ES2015)。因为这个版本的语言尚未被老版本
node.js的原生支持,Appium代码是_被移植_到ES5(JS更为广泛支持的版本)。这个转化过程必须发生在所有
代码运行之前。除了ES6的新语言特性,我们也从JS的_后续_版本中采用了很重要的关键词,`async` 和 `await`,
这有助于编写整洁的异步代码。因为这个代换的步骤,Appium软件包囊括了观察代码变化和重新编排代码的工具。
通常而言,同样的工具会自动运行单元测试,同时确保没有任何小的纰漏。大多Appium软件包在运行`gulp`的时候
把上述过程当做默认行为。
### 排查和代码风格
对于所有Appium的JS而言,代码外观和使用感觉同样重要。这包括样式常规,编码模式以及我们解决各种问题时使用的
库。你应该熟悉我们新的[ES2015 风格指南](/docs/cn/contributing-to-appium/style-guide.md)。
当转化时,Appium包将自动运行JSHint或其他lint工具,并在代码不符合我们规范的时候提供警告或错误反馈。
这些工具不一定能顾全我们关心的种种风格问题,所以我们在review代码的时候也应该注意代码规范问题。这不是
吹毛求疵,而是为了有一个整洁,一致并且可读的代码库。
### 提交代码
将你的代码提交到Appium很容易:你只需要提交一个pull请求到我们的repos并在代码review的过程中与我们的
维护者进行互动。我们对代码提交有一系列的要求(但是不用担心!如果下面所列的太过繁复,我们将会为你一一道来)。
那我们就从你提交PR的那一步开始吧:
* 参考其他代码的样式和我们的样式指南
* Atomic 提交 -- 每个逻辑变化进行一次提交(例如:确保你的提交不用进入组论即可以正常运行,而且它在任何指定提交下都应该正常运行)这通常意味着每个PR一个提交。你将想要非常熟悉的`git rebase -i` 和压缩。
* 没有合并提交:在提交你的PR之前,通常在最新的master之上进行rebase(或者其它你想要merge进去的branch)。
* 几乎所有的更改都应该有测试。关于漏洞修复,至少应该有单元测试以证明这个bug已被修复。新功能应该有单元测试,并且在大多数情况下进行e2e测试,以证明该功能正常工作。我们将乐意带你浏览测试的创建过程。阅读其他的测试代码会是一个很好的开始。我们的CI系统通常运行测试覆盖率统计,而且我们不大可能去合并那些会降低测试覆盖率的代码。
如果你在提交之前做了所有这些事情,你的代码将可能很快被接受。当然,如果你打算对Appium进行大量的改造工作,你可以联系开发人员,以确保这些改变符合我们的理念,这样在你开动之前确保我们会接受这些改动。
### 测试
始终确保你的更改已经被测试过! 除了单测试和e2e测试,请确保在你开始进行更改和提交review之前,所有现有测试都被运行。
我们有为每一个Appium repo设置CI作为安全网,这样便于审阅者知晓代码是否已经通过测试。在任何Appium包运行测试都很容易!
以下是你可以做的事情(除非README另有说明):
```
gulp # 监测目录下重编译代码更改,以及运行单元测试
gulp once # 同上,当不提供监测
gulp unit-test # 转化和运行单元测试
gulp e2e-test # 转化以及运行端到端/功能测试
_FORCE_LOGS=1 <command> # 显示测试运行期间的模块日志输出
```
请注意,单元测试的文件后缀通常为 `-specs.js` ,而e2e测试文件后缀则为`-e2e-specs.js`.
### 发布
任何非Appium主包的发布流程都是非常简洁明了的(请注意:如果你想要发布它,你需要成为一个NPM的所有者。
所有权由Appium提交者管理; 如果你对所有者有任何疑问,请联系@jlipps 或者 @imurchie)。
0. `rm -rf node_modules && rm -rf package-lock.json && npm install` 并运行测试以确保全新安装正常工作
0. 根据[SemVer](http://semver.org/) 规则决定我们是否需要发布一个补丁(漏洞修复),微调(功能)或者是主要(迭代)(请参考 [how SemVer works with NPM](https://docs.npmjs.com/getting-started/semantic-versioning).
0. 通过任何适当的更改和提交来更新CHANGELOG以README文件。大多数子包没有CHANGELOG。
0. 通过适当的版本类型运行 `npm version <version-type>`
0. 将适当的分支推送到GitHub, 不要忘记加入`--tags` 来标记刚由 `npm version`创建的标志.
0. 运行 `npm publish` (如果不是正式版, 请使用`--tag beta`).
对于Appium的主包发布,上述步骤必须执行,但有以下改变。一个原因是对于主包,我们使用NPM收缩包装
以确保依赖在安装的时候不更改。另一个原因是我们在master上开发和各种分支上发布。它的工作方式
如下:我们经常在master上开发和增加新的代码。 当我们准备好了做一个新的次要或主要版本(例如`1.5.0`
或`2.0.0`),我们创建一个发布分支(分别为`1.5`或`2.0`)。然后我们发布该分支。 一旦我们认为需要修复补丁,
我们首先将补丁拉到master中,然后将单个补丁挑选到发布分支(甚至是多个发布分支)。 然后我们再次
从这些分支发布更新的补丁版本(例如`1.5.1`或`2.0.1`)。
**关于 `npm shrinkwrap`的注释:** 我们使用[npm shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap)是为了在发布时锁定依赖关系。
没有它,任何依赖包上的开发将在安装Appium时反应出来,这可能会导致问题。 由于配置文件`npm-shrinkwrap.json`仅存在于发布分支上,
因此有必要在发布过程中手动管理它。 它需要与对`package.json`的更改一起提交到GitHub。
0. 如果 NPM shrinkwrap JSON 文件存在,请移除.
0. `rm -rf node_modules && rm -rf package-lock.json && npm install` 并运行测试以确保全新安装正常工作
0. `rm -rf node_modules && rm -rf package-lock.json && npm install --production` 以获取仅production部分.
0. `npm shrinkwrap` 来编写新的 NPM shrinkwrap JSON 文件.
0. 根据SemVer来决定我们是否需要发布一个补丁(漏洞修复),微调(功能)或者是主要(迭代)
0. 用合适的新版本信息来更新`package.json`
0. 对CHANGELOG/README进行合适的更改,同shrinkwrap 和 `package.json`的改变一起以PR的形式进行提交审核。待它被合并之后,把它`pull`进`release`分支。
0. 在发布分支(通常是一个小分支,如`1.5`或`1.4`)上创建一个形式为`v <version>`的标签:`git tag -av <version>`,例如`git tag -a 1.5.0`。 这对测试版本不是必需的。
0. 把标签推送到上游分支: `git push --tags <remote> <branch>`
0. 安装dev依赖 (或者至少`gulp` 和 `appium-gulp-plugins`)
0. 运行`npm publish`(如果这不是正式版本,请使用`--tag beta` )。
0. 在appium.io更新文档。 从github的check out appium.io repo,check out`gh-pages`分支和并更新到最新版本。 然后运行`rake publish`。
0. 在GitHub上创建一个新版本:转到`https://github.com/appium/appium/releases/tag/v <VERSION>`并点击“编辑标签”。 输入发布名称为`<VERSION>`(例如,`2.0.5`),然后粘贴到更改日志(但不是此版本的changelog标题)。 如果是试用版,请标记为预发布。
0. 在 discuss.appium.io 创建新的帖子来宣布release. 请创建于 "News"类别. 粘贴在changelog和任何可选的评论。 置顶当前帖子并取消置顶上一个release帖子。
0. 开始发布`appium-desktop`。
0. 请告知 @jlipps,以便他可以发布一个链接到讨论帖子。
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
-17
View File
@@ -1,17 +0,0 @@
## Appium gulp命令
[Gulp](http://gulpjs.com)就像Node.js的`make`一样!我们使用它来自动化各种应用开发任务。
以下是你可以执行的操作:
|任务|说明|
| ---- | ----------- |
| gulp once |清理,验错,转译以及运行单元测试|
| gulp watch |当代码更改时,自动运行`gulp once`|
| gulp lint |运行 JSLint |
| gulp jshint |运行 JSHint |
| gulp transpile |将我们的ES7/ES2015代码转译为ES5,生成`/build`目录+内容|
| gulp unit-test |运行单元测试|
| gulp e2e-test |运行e2e 测试 |
| gulp docs |生成 docs/en/writing-running-appium/server-args.md 文档|
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
@@ -1,55 +0,0 @@
## 如何编写文档
`##`用于写一个 h2 头。每个文档必须以 h2 开头。
这是为了支持 appium.io 文档生成。不要使用`---`下划线方法创建标题。
不要对标题使用 h1 `#` 或 `===`,因为目录表不支持这样(文件夹名称将用作 h1)。
### 副标题
`###` 用于编写副标题
### 常规标题
`####` 用于不出现在目录里的标题。
不要使用 h5 `#####` 或是 h6 `######`。
### 换行符
不要使用 `--` 或者 `---`这样的换行符。
### 链接
链接到 readme :
`[readme](../../README.md)`
链接到捐赠:
`[捐赠](../../CONTRIBUTING.md)`
链接到另一个文件
`[链接文本](filename.md)`
### 写指令(Commands)文档
指令文档位于 `docs/en/commands`,是程序生成的文档,不需要直接编辑。该指令文档定义在`commands-yml/commands`。
### 生成指令(Commands)文档
运行 `npm run generate-docs` 生成指令文档。这将在 `docs/en/commands` 下生成 Markdown 文件,然后需要将生成的文件提交并推送。
### 添加文档到 Appium.io
`docs/` 目录下的 Markdown 文件不会自动添加到站点。为了添加文档到 [appium.io](https://appium.io),你需要在目录表([toc.js](https://github.com/appium/appium/blob/master/docs/toc.js))中的合适的位置添加一个入口。
#### 出版
要在 [appium.io](https://appium.io) 上发布文档,请参阅 [appium.io](https://github.com/appium/appium.io).
---
EOF.
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
翻译:@[Pandorym](https://github.com/Pandorym)
Last english version: be2acb207c07503b9b1af3ba9315e7bee092a55a, Feb 12, 2018
@@ -1,257 +0,0 @@
## 给贡献者的风格指南
感谢您对Appium的贡献!以下是我们编写javascript代码时需要遵守的准则,请确认你的提交能符合这些规范,这有利于我们合并你的代码时能保持良好的编码风格。其中最核心的准则是:*使你的代码与其他代码的编码风格保持一致*。
### 衍合(Rebasing)
每个 pull 请求中的提交(commits)都应该包含[逻辑变更(logical changes)](https://github.com/appium/appium/pull/920#issuecomment-21588553)。
如果有多位贡献者,请确保他们各自都有自己的提交记录,修改作者信息不是一个好主意。合并(merge)提交必须从 pull 请求中 rebase 。
### 检错(Linting)
所有的代码(除了使用了 Apple 私有方法的`bootstrap.js`代码)必须通过 JSLint 的检错测试。你可以在 Appium 存储目录下,运行`grunt lint`来检查你的代码。如果你已创建一个新的 .js 文件,请确认它在`grunt.js`中被通配符覆盖,或者被专门添加。
编辑器的即时检错集成很简单,并且这会使得整个编码过程更加顺利。 我们喜欢 [jshint](http://www.jshint.com), 因为它已经与许多源代码编辑器集成了。将文件`.jshintrc`加入到仓库中,当通过添加jshint到你的编辑器时,你将大受即时检错的裨益。
因为jshint不再强制检查代码风格,我们也使用 [jscs](https://github.com/mdevils/node-jscs),它也集成在一些源代码编辑器中。
这些配置文件定义了哪些警告类型将会出现在你的编辑器中。 查看 [this page for jshint](http://www.jshint.com/platforms/) 和 [this page for jscs](https://github.com/mdevils/node-jscs#friendly-packages) ,找到它们各自支持的编辑器和平台的列表,以及如何设置你的编辑器使之能自动化检错。
### 风格注释(Style notes)
我们使用前沿版本的 JavaScript,并利用Babel将其渲染到支持当前版本的 Node.js。我们使用 [ES2015](https://babeljs.io/)(以前称为ES6)中的一些非标准特性,如[`async / await`](http://babeljs.io/docs/plugins/syntax-async-functions/)。在所有Appium的贡献中必须严格遵循如下编码风格!
* 使用两个空格来缩进, *不要使用 tabs*
* 在运算符两边,分别添加一个空格:
```javascript
var x = 1;
```
而不是
```javascript
var x=1;
```
* 在列表(lists),对象(objects),函数调用(function calls)等语句块中,逗号和冒号后面需要添加一个空格:
```javascript
var x = myFunc("lol", {foo: bar, baz: boo});
```
而不是
```javascript
var x = myFunc("lol",{foo:bar,baz:boo});
```
*   代码始终以分号结尾
* 以逗号开头
```javascript
var x = {
foo: 'bar'
, baz: 'boo'
, wuz: 'foz'
};
```
* 左花括号应该和`function`,`if`等写在同一行,`else`应该被夹在两个花括号中间:
```javascript
if (foo === bar) {
// do something
} else {
// do something else
}
```
* `if`,`for`, 和`function`之后需要添加空格:
```javascript
if (foo === bar) {
```
```javascript
for (var i = 0; i < 10; i ++) {
```
```javascript
var lol = function (foo) {
```
而不是
```javascript
if(foo === bar) {
```
```javascript
for(var i = 0; i < 10; i ++) {
```
```javascript
var lol = function(foo) {
```
* 只有一行代码时,`if`语句块的花括号也应该添加上:
```javascript
if (foo === bar) {
foo++;
}
```
而不是
```javascript
if (foo === bar)
foo++;
```
除了出错后直接调用回调函数(callback)处理错误(error)的语句
```javascript
if (err) return cb(err);
```
* 一般情况下,使用`===`, 而不是`==`;使用`!==`, 而不是`!=`;
* 单行长度不应超过79个字符;
* 截断长字符串使用如下方法:
```javascript
myFunc("This is a really long string that's longer " +
"than 79 characters so I broke it up, woo");
```
* 注释需要和上一行代码左对齐:
```javascript
if (foo === 5) {
myFunc(foo);
// foo++;
}
```
not
而不是
```javascript
if (foo === 5) {
myFunc(foo);
//foo++;
}
```
* 通过拓展原型,来创建子类:
```javascript
var _ = require('underscore');
var SuperClass = function () {
this.init();
};
SuperClass.prototype.init = function () {
// initialize
};
// Create a subclass
var SubClass = function () {
this.init();
};
_.extend(SubClass.prototype, SuperClass.prototype);
```
* 函数定义中,最后使用回调函数:
```javascript
var foo = function (arg1, arg2, cb) {
...
};
```
* 使用变量来定义函数:
```javascript
var myFunc = function (a, b, c) {};
```
而不是
```javascript
function myFunc (a, b, c) {}
```
* 变量名应该是驼峰式大小写风格:
```javascript
var myVariable = 42;
```
而不是
```javascript
var my_variable = 42;
```
* 检查是否有未定义的变量:
```javascript
typeof myVariable === "undefined"
```
而不是
```javascript
myVariable === undefined
```
* 给变量定义默认值:
```javascript
var x = y || z;
```
而不是
```javascript
var x = y ? y : z;
```
### 测试代码风格(Test Style):
在代码语义通顺和长度许可下,可以保持在同一行:
样例:
```javascript
driver.elementByTagName('el1').should.become("123")
.nodeify(done);
driver
.elementsByTagName('el1').should.eventually.have.length(0)
.nodeify(done);
```
或者使用缩进来提高代码的可读性:
```javascript
h.driver
.elementById('comments')
.clear()
.click()
.keys("hello world")
.getValue()
.should.become("hello world")
.elementById('comments')
.getValue().should.become("hello world")
.nodeify(done);
h.driver
.execute("'nan'--")
.should.be.rejectedWith("status: 13")
.nodeify(done);
```
本文由 [wanyukang](https://github.com/wanyukang) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
@@ -1,284 +0,0 @@
## 给贡献者的风格指南
感谢您对Appium的贡献!以下是我们编写javascript代码时需要遵守的准则,请确认你的提交能符合这些规范,这有利于我们合并你的代码时能保持良好的编码风格。其中最核心的准则是:*使你的代码与其他代码的编码风格保持一致*。
### 衍合(Rebasing)
每个 pull 请求中的提交(commits)都应该包含[逻辑变更(logical changes)](https://github.com/appium/appium/pull/920#issuecomment-21588553)。
如果有多位贡献者,请确保他们各自都有自己的提交记录,修改作者信息不是一个好主意。合并(merge)提交必须从 pull 请求中 rebase 。
### 检错(Linting)
所有的代码(除了使用了 Apple 私有方法的`bootstrap.js`代码)必须通过 JSLint 的检错测试。你可以在 Appium 存储目录下,运行`grunt lint`来检查你的代码。如果你已创建一个新的 .js 文件,请确认它在`grunt.js`中被通配符覆盖,或者被专门添加。
编辑器的即时检错集成很简单,并且这会使得整个编码过程更加顺利。 我们喜欢 [jshint](http://www.jshint.com), 因为它已经与许多源代码编辑器集成了。将文件`.jshintrc`加入到仓库中,它的内容是:
```json
{
"laxcomma": true,
"strict": true,
"undef": true,
"unused": true,
"node": true,
"eqeqeq": true,
"trailing": true,
"indent": 2
}
```
因为jshint不再强制检查代码风格,我们也使用 [jscs](https://github.com/mdevils/node-jscs),它也集成在一些源代码编辑器中。配置文件为:
```json
{
"excludeFiles": ["submodules/**", "node_modules/**",
"./lib/server/static/**", "./lib/devices/firefoxos/atoms/*.js",
"./test/harmony/**/*.js", "./sample-code/examples/node/**/*-yiewd.js",
"./sample-code/apps/**", "./sample-code/examples/php/vendor/**"],
"requireCurlyBraces": ["for", "while", "do", "try", "catch"],
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch",
"return", "try", "catch", "function"],
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
}
}
```
这些配置文件定义了哪些警告类型将会出现在你的编辑器中。 查看 [this page for jshint](http://www.jshint.com/platforms/) 和 [this page for jscs](https://github.com/mdevils/node-jscs#friendly-packages) ,找到它们各自支持的编辑器和平台的列表,以及如何设置你的编辑器使之能自动化检错。
### 风格注释(Style notes)
* 使用两个空格来缩进, *不要使用 tabs*
* 在运算符两边,分别添加一个空格:
```javascript
var x = 1;
```
而不是
```javascript
var x=1;
```
* 在列表(lists),对象(objects),函数调用(function calls)等语句块中,逗号和冒号后面需要添加一个空格:
```javascript
var x = myFunc("lol", {foo: bar, baz: boo});
```
而不是
```javascript
var x = myFunc("lol",{foo:bar,baz:boo});
```
*   代码始终以分号结尾
× 以逗号开头
```javascript
var x = {
foo: 'bar'
, baz: 'boo'
, wuz: 'foz'
};
```
* 左花括号应该和`function`,`if`等写在同一行,`else`应该被夹在两个花括号中间:
```javascript
if (foo === bar) {
// do something
} else {
// do something else
}
```
* `if`,`for`, 和`function`之后需要添加空格:
```javascript
if (foo === bar) {
```
```javascript
for (var i = 0; i < 10; i ++) {
```
```javascript
var lol = function (foo) {
```
而不是
```javascript
if(foo === bar) {
```
```javascript
for(var i = 0; i < 10; i ++) {
```
```javascript
var lol = function(foo) {
```
* 只有一行代码时,`if`语句块的花括号也应该添加上:
```javascript
if (foo === bar) {
foo++;
}
```
而不是
```javascript
if (foo === bar)
foo++;
```
除了出错后直接调用回调函数(callback)处理错误(error)的语句
```javascript
if (err) return cb(err);
```
* 一般情况下,使用`===`, 而不是`==`;使用`!==`, 而不是`!=`;
* 单行长度不应超过79个字符;
* 截断长字符串使用如下方法:
```javascript
myFunc("This is a really long string that's longer " +
"than 79 characters so I broke it up, woo");
```
* 注释需要和上一行代码左对齐:
```javascript
if (foo === 5) {
myFunc(foo);
// foo++;
}
```
而不是
```javascript
if (foo === 5) {
myFunc(foo);
//foo++;
}
```
* 通过拓展原型,来创建子类:
```javascript
var _ = require('underscore');
var SuperClass = function () {
this.init();
};
SuperClass.prototype.init = function () {
// initialize
};
// Create a subclass
var SubClass = function () {
this.init();
};
_.extend(SubClass.prototype, SuperClass.prototype);
```
* 函数定义中,最后使用回调函数:
```javascript
var foo = function (arg1, arg2, cb) {
...
};
```
* 使用变量来定义函数:
```javascript
var myFunc = function (a, b, c) {};
```
而不是
```javascript
function myFunc (a, b, c) {}
```
* 变量名应该是驼峰式大小写风格:
```javascript
var myVariable = 42;
```
而不是
```javascript
var my_variable = 42;
```
* 检查是否有未定义的变量:
```javascript
typeof myVariable === "undefined"
```
而不是
```javascript
myVariable === undefined
```
* 给变量定义默认值:
```javascript
var x = y || z;
```
而不是
```javascript
var x = y ? y : z;
```
### 测试代码风格(Test Style):
在代码语义通顺和长度许可下,可以保持在同一行:
样例:
```javascript
driver.elementByTagName('el1').should.become("123")
.nodeify(done);
driver
.elementsByTagName('el1').should.eventually.have.length(0)
.nodeify(done);
```
或者使用缩进来提高代码的可读性:
```javascript
h.driver
.elementById('comments')
.clear()
.click()
.keys("hello world")
.getValue()
.should.become("hello world")
.elementById('comments')
.getValue().should.become("hello world")
.nodeify(done);
h.driver
.execute("'nan'--")
.should.be.rejectedWith("status: 13")
.nodeify(done);
```
本文由 [wanyukang](https://github.com/wanyukang) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
@@ -1,53 +0,0 @@
# Appium 版本, 分支和发布模式
## 版本控制
1.3.6版本之后, Appium 使用语义版本控制: `major | minor | patch | [-beta{N}]`. 例如, `1.4.1` or `2.4.0-Beta4`.
* Major: API 突破性变化;新功能
* Minor: 向后兼容的变化; 可能包含或不包括新功能
* Patch: 快速修复工程; 没有新功能
这使得 Appium 的版本与 NPM 生态系统中的其他主要项目一致。它也适用于下面描述的基于主干的开发模式。
## 分支和发布模式
Appium 使用 [Trunk Based Development](http://paulhammant.com/2013/04/05/what-is-trunk-based-development/)。正如 Paul Hammant 所说,
>Trunk Based Development (TBD) 是所有开发人员(针对特定可部署单元)在源控制下提交到一个共享分支。那个分支俗称为 trunk。
>
>⋯ 分支是为了发布而创建的。开发人员不得在共享的地方建立分支。只有发布工程师才能对这些分支进行 commit,并且实际上得去创建这些分支。如果有必要的话,发布工程师可能会 cherry-pick 一些提交到发布分支。
>
>⋯ 发布分支将在短时间内被另一个发布分支替代,每个发布分支在创建时要从 trunk 中获取所有内容。在合并方面,只支持从主干到发布分支的 cherry-pick。
## 里程碑
我们根据版本控制和发布模式来设定 Appium 的里程碑. 下一个里程碑一直会是 Major.Minor 的发布。 与接下来要发布的 Major.Minor 版本不相干的产品缺陷修复和新功能,将会被积压到下一个以修复 BUG 或者新功能的命名分支上发布(即 Bugs 和 Features)。一般来说,我们每次的 minor 发布周期为 8 到 10 周一次。这包括大约一周的 Beta 测试和另外一周的修复和最终更改。 修补程序在 Major.Minor 版本之间根据需要发布(Major.Minor.Patch)。这样我们可以快速解决问题,同时最大限度地减少回归的风险。
## Workflow
对于Appium,基本流程如下所示:
1. 所有 PRs 都提交到 `master` (aka `trunk`).
2. 由发布工程师(Release engineer,简称RE)来主导发布行为。 当发布分支已经准备好共享(“Beta”状态或更好)时,RE将创建一个新的分支v[Major].[Minor].[Patch]-branch。
3. PRs 持续提交到 `master`.
4. 如果有修复相关的发布提交到 `master`, RE将这些提交到发布分支。
5. 发布分支可以修改与后续补丁修补程序发布。 这使得团队可以小心地将小型变更集放在一起,以便快速发布。修复也可以在需要时被并入以前的分支。
6. 冲洗,重复。
开发人员可以随他们的意愿维护他们开发中的分支,这些仅是个人使用。但所有“官方”分支机构均应符合上述规定。
### 例如
1. 今天 6 月 1 日, Appium 团队计划于7月15日发布 20.1-beta,8 月 1 日发布全面的 20.1 版本。
2. 在接下来的六个星期里,这个团队将他们的代码提交到 `master`.
3. 7月15日,执行 RE 创建 20.1-branch。第一个节点被标记为 “20.1.0 Beta”。
4. 一个团队成员开始修复测试版中的错误。这些修复会被提交到 `master`.
5. 其他贡献者开始按计划提交代码到 `20.2` 中去。这些内容也会被提交到 `master`。
6. RE把修复的内容cherry picks到 `20.1-branch`, 并保留 `master` 的其他变更。
7. 该团队庆祝 8 月 1 日发布的所有测试版本都已修复。
8. RE 标签的 HEAD 20.1-branch 为 20.1.0 发布版本。
9. 几周后,发现 20.1.0 存在崩溃,用户现在需要修复。
10. 执行 RE 将主机的崩溃修复程序拉入 20.1-branch,将 HEAD 标记为 20.1.1 并发布修补程序。
11. 一旦 20.2 发布完毕,循环就会重复。
本文由 大东 翻译,由 lihuazhang 校验。
-102
View File
@@ -1,102 +0,0 @@
## Android 的 UiAutomator2 驱动
Appium 目前官方推荐使用 `UiAutomator2` 作为安卓app在自动化测试中的驱动。
_(如果你是Appium新手? 可以参阅 [introduction to Appium drivers(TODO)](#TODO))_.
这个驱动使用了谷歌的 [UiAutomator2](https://developer.android.com/training/testing/ui-automator.html) 技术,让自动化测试可以更方便地在安卓真机或者模拟器上运行。
UiAutomator2 驱动的开发过程,记录在了[appium-uiautomator2-driver](https://github.com/appium/appium-uiautomator2-driver) 代码仓库中。
在更早期的安卓设备驱动中,包括了以下驱动:
* [UiAutomator 驱动](/docs/en/drivers/android-uiautomator.md)
### 需求与依赖
在 Appium 常规依赖之外:
* 需要在您的设备上,安装并配置好 Java 8
* 在 Mac,Windows 或者 Linux OS 设备上,需要安装好 Android SDK
* Android SDK 中 Build Tools 的版本需要大于等于 24
此外,UiAutomator2 驱动是不支持对 Android 5.0 (Lollipop, API level 21)以下的设备进行自动化测试的,如果对这类版本的设备进行自动化测试,建议使用:[UiAutomator 驱动](/docs/en/drivers/android-uiautomator.md);
### 使用方式
通过 UiAutomator2 驱动启动一个测试任务时,需要传递一个`automationName` [capability] 的参数在 [新会话的请求](#TODO) 中,并且 `automationName` 的值需要是:`UiAutomator2`。当然,你至少也需要再传递这些参数:`platformName` (=`Android`), `platformVersion`, `deviceName`, 与 `app`。
同时,强烈建议您传递:`appPackage` 与 `appActivity` 这两个参数,以便让 Appium 知道您想要拉起哪个 App 和哪个 activity。如果没有的话,Appium 将会自己从 App 的 manifest 文件中自动去查找。
### 功能参数
UiAutomator2 驱动支持许多通用的功能参数:[Appium
capabilities](/docs/en/writing-running-appium/caps.md),同时,有许多特有的功能参数,可以参考这篇文档查找这些功能参数:[Android
section](/docs/en/writing-running-appium/caps.md#android-only)。
对于 web 测试,是测试 Chrome 而不是去测试您自己的应用程序,需要保证 `app` 参数为空,并且设置 `browserName` 为 `Chrome`。需要提醒您的是:您需要保证 Chrome 是在安卓模拟器/真机上运行,并且与 [version compatible with
Chromedriver](/docs/en/writing-running-appium/web/chromedriver.md) 兼容。
### 命令
如果需要查看 Appium 支持的命令,及它们是如何映射到 UiAutomator2 驱动的,可以参考:[API
Reference](#TODO)。
### 基础设置
1. 确保您拥有 Appium 的基础依赖(例如:Node 与 NPM)来安装和配置 Appium。
1. 确保 Java ( 这里指的是 JDK 而不是 JRE )已经成功安装并且在环境变量中配置好了 Java 的路径。这一步的具体操作,在 Mac/Linux 与 Windows 等不同平台上操作不同,这里为您提供一个在 Windows 平台上设置路径的方法:[点击查看](https://www.java.com/en/download/help/path.xml)。
1. 确保环境变量: `JAVA_HOME` 已经成功设置为 JDK 的路径。举一个 Mac/Linux 的例子(这个路径的具体地址,根据您安装的实际情况有所不同):
```
export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home"
```
在 Windows 电脑上,可以通过 「控制面板」来配置。
[Android Studio](https://developer.android.com/studio/index.html) 同样提供了一个 JDK,像这样的一个路径: `/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home` (示例为Mac电脑版本)。您同样可以指定这个路径。
1. 安装 [Android SDK](http://developer.android.com/sdk/index.html)。当前最常用的方法是通过:[Android
Studio](https://developer.android.com/studio/index.html) 来安装配置。可以在桌面应用程序中,通过GUI界面操作,选中一个路径来下载 Android SDK。
1. 设置 `ANDROID_HOME` 环境变量。举个例子,如果您下载 Android SDK 在 `/usr/local/adt` 这个路径下,您将在这个路径下,找到一个包含 SDK 文件的、名称为: `sdk` 的文件夹。在这种情况下,打开
Mac 和 Linux 的配置文件(如:`~/.bashrc`, `~/.bash_profile` 及其他类型的文件),将这个环境变量与路径记录在其中。
```
export ANDROID_HOME="/usr/local/adt/sdk"
```
在 Windows 机器上,按照相同的步骤,将环境变量设置在「控制面板」中。
1. 通过 SDK manager,确保您安装了您所需要的、对应 Android API 版本的 SDK(例如:24)。
1. 在 Windows 电脑上,需确保您的 Appium 是通过管理员模式来运行的。
到此,您基础的系统配置已经完成了。接下来的步骤,需要看您是选择在模拟器运行测试还是在真机上运行测试。需要准备好待测 App (最好是Debug 版本)APK 的本地路径或下载链接,这个路径或链接,在运行测试时,需要设置为 `app` 参数的内容。
### 模拟器设置
使用模拟器运行测试是,需要使用 Android Studio 或 SDK 提供的 AVD Manager。通过使用这个工具,来创建您所需要的模拟器。在模拟器启动时,Appium 将会自动找到并使用它进行测试。同时,如果您指定了 `avd` 这个功能参数为您所制定的设备名称时,Appium 会启动您指定的模拟器来运行测试。
关于模拟器的一些小提示:
* Android 模拟器可以设置硬件加速,尽管它有一些局限性。可以通过 Intel 网站下载,或者通过 Android SDK manager。了解更多信息,[可以点击这里查看](https://github.com/intel/haxm)。
* 如果您想在 Appium 测试中使用电源相关的命令,请确保在 AVD 的 `config.ini` 文件中,设置了:`hw.battery=yes` (在 Android 5.0 上,为默认设置)。
### 真机设置
对于 Android 自动化测试,除了以下一些简单操作外,不需要其他复杂的设置:
* 确保打开了设备的 [开发者模式](https://developer.android.com/studio/debug/dev-options.html)。
* 确保设备通过 USB 连接到 Appium 服务启动的设备上,并且可以被 [ADB](https://developer.android.com/studio/command-line/adb.html) 找到
( 执行 `adb devices` 确认 )。
* 确保设置中的“验证应用程序”是关闭的,以允许 Appium 安装一些辅助软件,而不用手动点击确认。
( 对于一些特殊的指令,设备可能需要被 root ,尽管这并不是经常会遇到的。 )
-77
View File
@@ -1,77 +0,0 @@
## Appium 2.0 驱动的命令行工具 Command Line Interface (CLI)
Appium 将使用某种利用自动化技术,实现某个平台自动化的软件称为"驱动程序(driver)"。包括 iOS、Android 及其他平台。在 Appium 2.0 上,将不会您下载 Appium 时,按以往那样,默认下载所有驱动(driver)。因为这样被下载的驱动太多了。取而代之的,是您可以使用一个特殊的命令行来指导 Appium 为您安装和注册驱动程序,以便能够真正用到您需要的驱动。本文档强调了该界面中可用的各种命令。
### 概述
所有这些命令都可以在输入`appium driver`后使用。例如,在本文档中,定义为`list`的命令将以以下方式使用:
```
appium driver list
```
*公共参数*
这里有些所有命令都可用的公共参数:
|参数|描述|默认值|
|----|-----------|-------|
|`-ah`, `--home`, `--appium-home`|设置 APPIUM_HOME 目录的路径,该目录将安装驱动程序和插件,并将维护驱动程序/插件清单,|如果设置了该参数,默认值为设置的地址,否则默认地址为:`$HOME/.appium`|
|`--json`|只输出JSON格式的命令返回结果,而不输出人们可读的日志信息|默认值为false。通过包含此标志设置为true。|
### `list`
该命令无参数时,按名称列出可安装的驱动程序,以及通过任何方式安装的驱动。
|参数|描述|默认值|
|----|-----------|-------|
|`--installed`|只展示已安装的|否|
|`--updates`|对于通过NPM安装的驱动程序,检查并显示任何更新|否|
|示例|描述|
|-------|-----------|
|`appium driver list`|列出可用的驱动程序|
|`appium driver list --installed`|列出已安装的驱动程序|
|`appium driver list --updates`|列出已安装且可更新的驱动程序|
### `install`
该命令使用驱动名称或规格,或来源标识(如果它不是正式驱动程序)来作为参数,
|参数|描述|默认值|
|----|-----------|-------|
|`--source`|如果不是官方驱动,可以按以下几种方式之一来表示: `npm`, `local`, `github`, `git`|None|
注意,对于任何通过NPM安装的驱动程序(包括官方驱动程序,以及使用`--source=npm`安装的驱动),你可以在驱动程序名称后面使用任何有效的NPM安装规范,如:`xcuitest@2.1.2` 将会安装指定版本的XCUITest驱动程序。
|示例|描述|
|-------|-----------|
|`appium driver install xcuitest`|下载安装官方 XCUITest 驱动|
|`appium driver install xcuitest@2.1.2`|下载安装官方指定版本的 XCUITest 驱动|
|`appium driver install --source=npm appium-fake-driver`|通过 NPM 下载安装 `appium-fake-driver` |
|`appium driver install --source=github appium/appium-fake-driver`|从 github 下载安装 `appium-fake-driver` 驱动|
|`appium driver install --source=local /path/to/driver/directory`|从本地文件安装|
### `update`
该命令通过添加已经安装的驱动名称,或关键词 `installed`,来自动更新一个或所有的驱动(如果用了: `installed`)。
注意:这将更新驱动程序到最高可用的小版本(minor version),但将*不*更新到新的大版本(major version)。因为可能包含一些重大变化。如果期望更新到大版本,使用参数:`--unsafe`
|参数|描述|默认值|
|----|-----------|-------|
|`--unsafe`|更新到一个大版本|None|
|示例|描述|
|-------|-----------|
|`appium driver update xcuitest`|更新 XCUITest 驱动到最新的安全版本|
|`appium driver update installed`|更新所有已安装的驱动到最新的安全版本|
|`appium driver update --unsafe xcuitest`|更新 XCUITest 驱动到最新版本 (即使是最新的大版本)|
### `uninstall`
删除一个驱动.
|示例|描述|
|-------|-----------|
|`appium driver uninstall xcuitest`|删除 XCUITest 驱动|

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