mirror of
https://github.com/appium/appium.git
synced 2026-11-10 20:05:42 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33e033f175 |
@@ -1,13 +0,0 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -1,11 +0,0 @@
|
||||
**/coverage/**
|
||||
**/node_modules/**
|
||||
examples/javascript-wd
|
||||
**/build/**
|
||||
**/*.min.js
|
||||
sample-code
|
||||
**/*.d.ts
|
||||
**/build-fixtures/**
|
||||
**/*.ts
|
||||
packages/appium/docs/**/assets/**
|
||||
**/*.tsx
|
||||
@@ -1,53 +0,0 @@
|
||||
{
|
||||
"extends": "@appium/eslint-config-appium",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "packages/fake-driver/**/*",
|
||||
"rules": {"require-await": "off"}
|
||||
},
|
||||
{"files": "packages/support/**/*", "globals": {"BigInt": "readonly"}},
|
||||
{
|
||||
"files": "packages/*/test/**/*",
|
||||
"rules": {"func-names": "off"}
|
||||
},
|
||||
{
|
||||
"files": ["packages/*/index.js", "packages/*/scripts/**/*.js", "test/*.js"],
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"packages/appium/support.js",
|
||||
"packages/appium/driver.js",
|
||||
"packages/appium/plugin.js"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "./packages/*/test/**/*.js",
|
||||
"rules": {
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
{
|
||||
"object": "sinon",
|
||||
"property": "spy",
|
||||
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.spy()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
|
||||
},
|
||||
{
|
||||
"object": "sinon",
|
||||
"property": "stub",
|
||||
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.stub()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
|
||||
},
|
||||
{
|
||||
"object": "sinon",
|
||||
"property": "mock",
|
||||
"message": "Use `sandbox = sinon.createSandbox()` and `sandbox.mock()` instead. Don't forget to call `sandbox.restore()` in `afterEach`"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
|
||||
# Visit https://fossa.com to learn more
|
||||
|
||||
version: 3
|
||||
|
||||
project:
|
||||
id: appium
|
||||
name: appium
|
||||
|
||||
paths:
|
||||
exclude:
|
||||
- ./sample-code
|
||||
- '**/fixtures/**'
|
||||
- '**/demo/**'
|
||||
- '**/example/**'
|
||||
- '**/examples/**'
|
||||
|
||||
targets:
|
||||
only:
|
||||
- type: npm
|
||||
path: .
|
||||
- type: npm
|
||||
path: ./packages/appium
|
||||
- type: npm
|
||||
path: ./packages/base-driver
|
||||
- type: npm
|
||||
path: ./packages/doctor
|
||||
- type: npm
|
||||
path: ./packages/eslint-config-appium
|
||||
- type: npm
|
||||
path: ./packages/fake-driver
|
||||
- type: npm
|
||||
path: ./packages/support
|
||||
- type: npm
|
||||
path: ./packages/test-support
|
||||
- type: npm
|
||||
path: ./packages/types
|
||||
- type: npm
|
||||
path: ./packages/schema
|
||||
- type: npm
|
||||
path: ./packages/universal-xmlplugin
|
||||
- type: npm
|
||||
path: ./packages/opencv
|
||||
- type: npm
|
||||
path: ./packages/images-plugin
|
||||
- type: npm
|
||||
path: ./packages/base-plugin
|
||||
- type: npm
|
||||
path: ./packages/relaxed-caps-plugin
|
||||
- type: npm
|
||||
path: ./packages/fake-plugin
|
||||
- type: npm
|
||||
path: ./packages/docutils
|
||||
|
||||
revision:
|
||||
- branch: master
|
||||
@@ -1,4 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
# Handle as a text file but merge as binary.
|
||||
package-lock.json merge=binary
|
||||
@@ -1,80 +0,0 @@
|
||||
name: 🐞 Bug Report
|
||||
description: File a new bug report
|
||||
title: 'bug: <title>'
|
||||
labels: [Bug, Needs Triage]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: ':stop_sign: _For support questions, please visit [http://discuss.appium.io](http://discuss.appium.io) instead._'
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 'Is there an existing issue for this?'
|
||||
description: 'Please [search :mag: the issues](https://github.com/appium/appium/issues) to check if this bug has already been reported.'
|
||||
options:
|
||||
- label: 'I have searched the existing issues'
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Current Behavior'
|
||||
description: 'Describe the problem you are experiencing. **Please do not paste your logs here.** Screenshots are welcome.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Expected Behavior'
|
||||
description: 'Describe what you expect to happen instead.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Minimal Reproducible Example'
|
||||
description: |
|
||||
Please provide a the _smallest, complete code snippet_ that Appium's maintainers can run to reproduce the issue ([read more about what this entails](https://stackoverflow.com/help/minimal-reproducible-example)). Failing this, any sort of reproduction steps are better than nothing!
|
||||
|
||||
An easy way to get started is to copy [sample code](https://github.com/appium/appium/tree/master/packages/appium/sample-code) and modify it accordingly.
|
||||
|
||||
If the result is more than a screenful of text _or_ requires multiple files, please:
|
||||
|
||||
- _Attach_ (do not paste) it to this textarea, _or_
|
||||
- Put it in a [Gist](https://gist.github.com) and paste the link, _or_
|
||||
- Provide a link to a new or existing public repository exhibiting the issue
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Environment'
|
||||
description: 'Please provide the following information about your environment; feel free to remove any items which are not relevant.'
|
||||
value: |
|
||||
- Operating system:
|
||||
- If running via `appium` CLI...
|
||||
- Appium CLI version (output of `appium --version`):
|
||||
- Node.js version (output of `node --version`):
|
||||
- `npm` version (output of `npm --version`):
|
||||
- Last `appium` version which did _not_ exhibit the problem:
|
||||
- If running Appium Desktop, its version:
|
||||
- Appium driver(s) and their version(s):
|
||||
- Appium plugin(s) and their version(s):
|
||||
- Platform and version under test:
|
||||
- Real device or emulator/simulator:
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: 'Link to Appium Logs'
|
||||
description: |
|
||||
Create a [Gist](https://gist.github.com)—which contains your _full_ Appium logs—and link it here. Alternatively, you can attach a logfile to this issue (drag it into the "Further Information" field below).
|
||||
|
||||
:warning: _Remember to redact or remove any sensitive information!_
|
||||
placeholder: 'https://gist.github.com/...'
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Futher Information
|
||||
description: |
|
||||
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||
|
||||
_Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in._
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: ':stop_sign: _For support questions, please visit [http://discuss.appium.io](http://discuss.appium.io) instead._'
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[Feat]:"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -1,28 +0,0 @@
|
||||
## Proposed changes
|
||||
|
||||
Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
|
||||
|
||||
## Types of changes
|
||||
|
||||
What types of changes does your code introduce to Appium?
|
||||
_Put an `x` in the boxes that apply_
|
||||
|
||||
- [ ] Bugfix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Documentation Update (if none of the other choices apply)
|
||||
|
||||
## Checklist
|
||||
|
||||
_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
|
||||
|
||||
- [ ] I have read the [CONTRIBUTING](https://github.com/appium/appium/blob/master/CONTRIBUTING.md) doc
|
||||
- [ ] I have signed the CLA
|
||||
- [ ] Lint and unit tests pass locally with my changes
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] I have added necessary documentation (if appropriate)
|
||||
- [ ] Any dependent changes have been merged and published in downstream modules
|
||||
|
||||
## Further comments
|
||||
|
||||
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
|
||||
@@ -1,26 +0,0 @@
|
||||
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
|
||||
|
||||
# Number of days of inactivity before a closed issue or pull request is locked
|
||||
daysUntilLock: 365
|
||||
|
||||
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
||||
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
|
||||
skipCreatedBefore: false
|
||||
|
||||
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
|
||||
exemptLabels: []
|
||||
|
||||
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
||||
lockLabel: false
|
||||
|
||||
# Comment to post before locking. Set to `false` to disable
|
||||
lockComment: >
|
||||
This thread has been automatically locked since there has not been
|
||||
any recent activity after it was closed. Please open a new issue for
|
||||
related bugs.
|
||||
|
||||
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||
setLockReason: false
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
@@ -1,47 +0,0 @@
|
||||
name: Appium Build
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x, 18.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- name: Install latest npm
|
||||
run: npm install -g npm
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@1a235c31658a322a3b024444759650ee6345c26d # tag=v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
install-command: npm ci --foreground-scripts
|
||||
- name: Run smoke, unit & E2E tests
|
||||
run: npm run test:ci
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@1a235c31658a322a3b024444759650ee6345c26d # tag=v1
|
||||
with:
|
||||
useRollingCache: true
|
||||
install-command: npm ci --foreground-scripts
|
||||
- name: ESLint
|
||||
run: npm run lint
|
||||
- name: Validate Renovate Config
|
||||
uses: rinchsan/renovate-config-validator@1ea1e8514f6a33fdd71c40b0a5fa3512b9e7b936 # tag=v0
|
||||
with:
|
||||
pattern: '{.renovaterc.json,renovate/default.json}'
|
||||
@@ -1,58 +0,0 @@
|
||||
name: Appium Deploy
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
# node-version: [14.x, 16.x, 18.x]
|
||||
node-version: [16.x, 18.x]
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
steps:
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Appium
|
||||
run: |
|
||||
if [[ "$GITHUB_REF_TYPE" == tag ]]; then
|
||||
npm i -g $GITHUB_REF_NAME
|
||||
else
|
||||
npm i -g appium@next
|
||||
fi
|
||||
shell: bash
|
||||
- name: Install drivers and plugins
|
||||
run: |
|
||||
if grep -q macos <<< ${{ matrix.os }}; then
|
||||
appium driver install xcuitest
|
||||
fi
|
||||
appium driver install uiautomator2
|
||||
appium plugin install images
|
||||
shell: bash
|
||||
- name: Verify installation
|
||||
run: |
|
||||
installed_drivers=$(appium driver list --installed 2>&1)
|
||||
if grep -q macos <<< ${{ matrix.os }}; then
|
||||
grep -q xcuitest <<< $installed_drivers
|
||||
fi
|
||||
grep -q uiautomator2 <<< $installed_drivers
|
||||
installed_plugins=$(appium plugin list --installed 2>&1)
|
||||
grep -q images <<< $installed_plugins
|
||||
shell: bash
|
||||
- name: Verify Appium could be executed
|
||||
run: |
|
||||
appium --use-plugins=images &
|
||||
pid=$(echo $!)
|
||||
sleep 5
|
||||
ps -p $pid || exit 1
|
||||
kill -2 $pid
|
||||
shell: bash
|
||||
@@ -1,26 +0,0 @@
|
||||
name: License Checks
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
fossa-check:
|
||||
name: Run FOSSA Analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
|
||||
with:
|
||||
ref: master
|
||||
- name: Install dependencies
|
||||
uses: bahmutov/npm-install@cb39a46f27f14697fec763d60fb23ad347e2befa # tag=v1
|
||||
- name: Install fossa-cli
|
||||
run: ./scripts/install-fossa.sh -d
|
||||
- name: Run FOSSA analysis
|
||||
run: |
|
||||
fossa analyze
|
||||
fossa test
|
||||
env:
|
||||
FOSSA_API_KEY: ${{secrets.FOSSA_API_KEY}}
|
||||
+5
-41
@@ -1,21 +1,17 @@
|
||||
.irb-history
|
||||
*.swp
|
||||
.DS_Store
|
||||
npm*.log
|
||||
node_modules
|
||||
sample-code
|
||||
*.trace
|
||||
xcuserdata
|
||||
*.sublime-*
|
||||
test/functional/_joined
|
||||
*.iml
|
||||
!examples/java/*.iml
|
||||
*.autosave
|
||||
.idea/
|
||||
!examples/java/.idea/
|
||||
*.log
|
||||
*.t
|
||||
artifacts
|
||||
input
|
||||
./output
|
||||
lib/devices/android/bootstrap/bin/*
|
||||
lib/devices/android/bootstrap/local.properties
|
||||
lib/devices/android/bootstrap/project.properties
|
||||
@@ -24,42 +20,10 @@ 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
|
||||
*.tgz
|
||||
typedoc-docs
|
||||
packages/appium/docs/*/reference
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
[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
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npm run lint:commit -- --edit ${1}
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npm run lint:staged
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"excludeFiles": ["submodules/**", "node_modules/**",
|
||||
"./lib/server/static/**", "./lib/devices/firefoxos/atoms/*.js",
|
||||
"./test/harmony/**/*.js", "./sample-code/**",
|
||||
"./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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"laxcomma": true,
|
||||
"strict": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"node": true,
|
||||
"eqeqeq": true,
|
||||
"trailing": true,
|
||||
"indent": 2
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
'*.js': ['eslint --fix', 'prettier --write'],
|
||||
'*.ts': ['prettier --write'],
|
||||
'appium-config-schema.js': () => [
|
||||
'npm run --workspace=./packages/schema build',
|
||||
'git add -A packages/schema/lib/appium-config.schema.json',
|
||||
'npm run --workspace=./packages/types build',
|
||||
'git add -A packages/types/lib/appium-config.ts',
|
||||
],
|
||||
'!(package|package-lock)*.json': ['prettier --write'],
|
||||
};
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
require: [require.resolve('./test/setup.js')],
|
||||
// forbids use of .only() in CI
|
||||
forbidOnly: Boolean(process.env.CI),
|
||||
color: true,
|
||||
// increase default timeout for CI since it can be slow
|
||||
timeout: process.env.CI ? '5s' : '2s',
|
||||
};
|
||||
+26
-1
@@ -1 +1,26 @@
|
||||
tsconfig.tsbuildinfo
|
||||
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
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Do not disable package-lock. Disabling package-lock also disables npm-shrinkwrap
|
||||
package-lock=true
|
||||
save-exact=true
|
||||
foreground-scripts=true
|
||||
@@ -1,13 +0,0 @@
|
||||
**/node_modules/**
|
||||
**/build/**
|
||||
**/fixtures/**
|
||||
**/*.min.*
|
||||
**/*.md
|
||||
package-lock.json
|
||||
package.json
|
||||
**/.vscode/**
|
||||
**/*.html
|
||||
**/generated/**
|
||||
# generated
|
||||
packages/types/lib/appium-config.ts
|
||||
**/*.hbs
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>appium/appium//renovate/default"],
|
||||
"schedule": ["after 10pm and before 5:00am"],
|
||||
"timezone": "America/Vancouver"
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
language: objective-c
|
||||
xcode_sdk: 7.1
|
||||
notifications:
|
||||
email: true
|
||||
slack:
|
||||
secure: E1at9Fi4d2eLagKInwGOfvvcSr8rrVti+N3HzvlcL9UcYavwzfAstMX/nXoHTl8LR5/Dh4Sdja2+NeJp2uVNwlK7aVKk5egQ8q6qAEmcXlWgjqyyTusB1lgiaOQnbOuqsntg/3X5sP8nz5+V3sggelPnOrVwNCCkVXXSff2SHhE=
|
||||
rvm:
|
||||
- 2.1.1
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- "/with\\-ci$/"
|
||||
git:
|
||||
submodules: false
|
||||
env:
|
||||
global:
|
||||
- SAUCE_REST_ROOT=https://saucelabs.com/rest/v1
|
||||
- APPIUM_HOST=ondemand.saucelabs.com
|
||||
- APPIUM_PORT=80
|
||||
- SAUCE_USERNAME=appium
|
||||
- IOS_CONCURRENCY=30
|
||||
- ANDROID_CONCURRENCY=30
|
||||
- SELENDROID_CONCURRENCY=10
|
||||
- GAPPIUM_CONCURRENCY=10
|
||||
- secure: GXGFbQptLEsKlaWnpOL2EB9hqQ4XBT6tqg7REt5j1h1jYBsfHQHSgSLt1jpzOF5kooXVbw2K7IrZyNVBXEUHR00Hp6O72FBOd+SSj8uPCJBLjAOaJWs0ZtujqGHwHpe6gadFfn0L7q0ffoV5OJVeNHHcuw4f9BaA78fTFNfm1jE=
|
||||
- HTTP_RETRIES=5
|
||||
- HTTP_RETRY_DELAY=5000
|
||||
- DEBUG_CONNECTION=1
|
||||
- MOCHA_INIT_TIMEOUT=600000
|
||||
- LAUNCH_TIMEOUT='{"global":90000,"afterSimLaunch":30000}'
|
||||
matrix:
|
||||
- CI_CONFIG=unit
|
||||
# - CI_CONFIG=android
|
||||
# - CI_CONFIG=ios
|
||||
# - CI_CONFIG=gappium
|
||||
# - CI_CONFIG=selendroid
|
||||
before_script:
|
||||
# - gem install --no-rdoc --no-ri appium_doc_lint
|
||||
- "./ci/installers/install-node.sh"
|
||||
- 'echo Node.js version: `node -v`'
|
||||
- npm install -g jshint grunt-cli mocha
|
||||
- npm install
|
||||
#- "./ci/installers/install-sauce-connect.sh"
|
||||
#- "./ci/before-script-extra.sh"
|
||||
#- "ulimit -n 8000"
|
||||
# disabling sauce-connect until travis ichef issue is sorted
|
||||
# - "./ci/start-sauce-connect.sh"
|
||||
script:
|
||||
- "./ci/script.sh"
|
||||
- bash -c 'while true; do ping ondemand.saucelabs.com &> /dev/null; sleep 10; done' &
|
||||
Vendored
-63
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"args": [
|
||||
"--log-level=debug"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {
|
||||
"_FORCE_LOGS": "1"
|
||||
},
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"name": "Run Appium",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/appium",
|
||||
"request": "launch",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"type": "node"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--colors",
|
||||
"--no-timeout",
|
||||
"${file}"
|
||||
],
|
||||
"autoAttachChildProcesses": true,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"name": "Test Current File w/ Mocha",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/mocha",
|
||||
"request": "launch",
|
||||
"runtimeArgs": [
|
||||
"--require",
|
||||
"ts-node/register"
|
||||
],
|
||||
"skipFiles": [
|
||||
"<node_internals>/**",
|
||||
"**/node_modules/mocha/**",
|
||||
"**/node_modules/ts-node/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"type": "node"
|
||||
},
|
||||
{
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"name": "Typedoc",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/typedoc",
|
||||
"args": ["--logLevel", "Verbose"],
|
||||
"request": "launch",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"type": "node"
|
||||
}
|
||||
],
|
||||
"version": "0.2.0"
|
||||
}
|
||||
Vendored
-27
@@ -1,27 +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
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "typedoc",
|
||||
"problemMatcher": [],
|
||||
"label": "npm: typedoc",
|
||||
"detail": "typedoc --logLevel Verbose",
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (wallaby) => {
|
||||
return {
|
||||
compilers: {
|
||||
'**/*.js': wallaby.compilers.typeScript({
|
||||
allowJs: true,
|
||||
allowSyntheticDefaultImports: true,
|
||||
resolveJsonModule: true,
|
||||
isolatedModules: true,
|
||||
}),
|
||||
'**/*.ts?(x)': wallaby.compilers.typeScript(),
|
||||
},
|
||||
debug: true,
|
||||
env: {
|
||||
type: 'node',
|
||||
},
|
||||
files: [
|
||||
'./packages/*/build/**/*',
|
||||
'./packages/*/lib/**/*.(j|t)s',
|
||||
'./packages/*/test/**/*helper*.(j|t)s',
|
||||
'./packages/*/test/**/*mock*.(j|t)s',
|
||||
'./packages/*/package.json',
|
||||
'./packages/*/tsconfig*.json',
|
||||
'./packages/*/test/**/fixture?(s)/**/*',
|
||||
{
|
||||
instrument: false,
|
||||
pattern: './packages/typedoc-plugin-appium/resources/**/*',
|
||||
},
|
||||
{
|
||||
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/typedoc-plugin-appium/lib/theme/resources/**',
|
||||
},
|
||||
'!./packages/*/test/**/*-specs.js',
|
||||
'!./packages/*/test/**/*.e2e.spec.(j|t)s',
|
||||
'!**/local_appium_home/**',
|
||||
],
|
||||
testFramework: 'mocha',
|
||||
tests: ['./packages/*/test/unit/**/*.spec.(j|t)s', '!**/local_appium_home/**'],
|
||||
workers: {
|
||||
// restart: true,
|
||||
},
|
||||
setup(wallaby) {
|
||||
// copied out of `./test/setup.js`
|
||||
|
||||
const chai = require('chai');
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
const sinonChai = require('sinon-chai');
|
||||
|
||||
// The `chai` global is set if a test needs something special.
|
||||
// Most tests won't need this.
|
||||
global.chai = chai.use(chaiAsPromised).use(sinonChai);
|
||||
|
||||
// `should()` is only necessary when working with some `null` or `undefined` values.
|
||||
global.should = chai.should();
|
||||
|
||||
const mocha = wallaby.testFramework;
|
||||
mocha.timeout(10000);
|
||||
},
|
||||
runMode: 'onsave',
|
||||
};
|
||||
};
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+1697
File diff suppressed because it is too large
Load Diff
-48
@@ -1,48 +0,0 @@
|
||||
## Code of Conduct
|
||||
|
||||
### What is this code of conduct for?
|
||||
|
||||
Appium is a piece of technology, but **the core of the Appium community is the people in it**. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, socioeconomic status, religion (or lack thereof), or other marginalized aspect of comunity members. We expect all members of the Appium community to abide by this Code of Conduct whenever interacting in Appium venues (pull requests, GitHub issues, 1-1 or group chat, meetups, conferences, etc...)
|
||||
|
||||
### Examples of inappropriate behavior
|
||||
|
||||
Because we come from a variety of backgrounds, we don't want to assume that everyone has the same assumptions about what is and isn't appropriate. Here are some examples of inappropriate behavior that are incompatible with our community's ethos:
|
||||
|
||||
* Spamming, trolling, intentionally disrupting conversations, or irrelevant solicitation or advertisement
|
||||
* Making demeaning or discriminatory comments
|
||||
* Making negative assumptions about someone's background, abilities, or intentions
|
||||
* Harassing or stalking individuals (online or in person)
|
||||
* Giving someone unwelcome sexual attention or making unwelcome physical contact (in the case of an IRL event)
|
||||
* Sharing sexual images or using sexually explicit language
|
||||
|
||||
In general: treat others how you would like to be treated, were you in their place. Don't be a jerk. _Do_ ask questions. _Do_ keep conflicts productively focused on technical issues. _Do_ think before you speak; remember that what is perceived as a funny witticism in your group of friends might be hurtful or reinforce hurtful stereotypes in the context of our diverse online community. _Do_ remember that we are all people, not robots, and all equally deserving of sensitivity and respect. (If and when robots join our community, let's treat them with respect too!)
|
||||
|
||||
|
||||
### What will organizers do about inappropriate behavior?
|
||||
|
||||
If we notice you doing or saying something inappropriate, an organizer will explain why it's inappropriate and ask you to stop. We won't demonize or vilify you. But please do stop the inappropriate behavior so we can get back to writing and discussing code in a safe environment. If you have philosophical disagreements about what's actually inappropriate, please take them to a separate public or private conversation with an Appium maintainer so we don't turn pull requests into an ethics debate.
|
||||
|
||||
If you keep doing unacceptable things, we'll likely ban you, report you to GitHub, or take other appropriate action.
|
||||
|
||||
### What if I see or am subject to what feels like inappropriate behavior?
|
||||
|
||||
Let us know! Please notify a community organizer as soon as possible. Full contact information is listed in the [Contact Info](#contact-info) section of this document. All communications will be kept strictly confidential, unless otherwise required by law. No issue will be considered too inconsequential or unimportant for us to have a conversation about.
|
||||
|
||||
### Contact Info
|
||||
|
||||
If you need to report an incident, please contact any of the following organizers directly:
|
||||
|
||||
* Isaac Murchie [email](mailto:isaac@saucelabs.com) [twitter](https://twitter.com/imurchie)
|
||||
* Jonathan Lipps [email](mailto:jlipps@saucelabs.com) [twitter](https://twitter.com/jlipps)
|
||||
|
||||
### Credit, License, and Attribution
|
||||
|
||||
This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).
|
||||
|
||||
It's inspired among other things by:
|
||||
* [Citizen Code of Conduct](http://citizencodeofconduct.org/)
|
||||
* [npmjs](https://www.npmjs.com/policies/conduct)
|
||||
* [Geek Feminism](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy)
|
||||
* [Ashe Dryden](http://www.ashedryden.com/blog/codes-of-conduct-101-faq)
|
||||
* [Model View Culture](https://modelviewculture.com/issues/events)
|
||||
* [Open Source & Feelings](http://osfeels.com/conduct).
|
||||
+7
-58
@@ -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
@@ -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.
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
"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;
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
options: {
|
||||
laxcomma: true
|
||||
, node: true
|
||||
, strict: true
|
||||
, indent: 2
|
||||
, undef: true
|
||||
, unused: true
|
||||
, eqeqeq: true
|
||||
},
|
||||
files: {
|
||||
src: ['*.js', './**/*.js'],
|
||||
options: {
|
||||
ignores: ['./submodules/**/*.js', './node_modules/**/*.js', './sample-code/**/*.js', './test/**/*.js', './lib/server/static/**/*.js', './lib/devices/firefoxos/atoms/*.js', './lib/devices/ios/uiauto/**/*.js']
|
||||
}
|
||||
},
|
||||
test: {
|
||||
src: ['test/**/*.js']
|
||||
, options: {
|
||||
ignores: ['./test/harmony/**/*.js', './test/functional/_joined/*.js']
|
||||
, expr: true
|
||||
, globals: {
|
||||
'describe': true
|
||||
, 'it': true
|
||||
, 'before': true
|
||||
, 'after': true
|
||||
, 'beforeEach': true
|
||||
, 'afterEach': true
|
||||
}
|
||||
}
|
||||
},
|
||||
examples: {
|
||||
src: ['sample-code/examples/node/**/*.js']
|
||||
, options: {
|
||||
expr: true
|
||||
, globals: {
|
||||
'describe': true
|
||||
, 'it': true
|
||||
, 'before': true
|
||||
, 'after': true
|
||||
, 'beforeEach': true
|
||||
, 'afterEach': true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
, jscs: {
|
||||
files: [
|
||||
'**/*.js', '!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/**'],
|
||||
options: {
|
||||
config: ".jscs.json"
|
||||
}
|
||||
}
|
||||
, mochaTest: {
|
||||
unit: ['test/unit/*.js']
|
||||
, appiumutils: ['test/functional/appium/appiumutils.js']
|
||||
}
|
||||
, mochaTestConfig: {
|
||||
options: {
|
||||
timeout: 60000,
|
||||
reporter: 'spec'
|
||||
}
|
||||
}
|
||||
, maxBuffer: 2000 * 1024
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-newer');
|
||||
grunt.loadNpmTasks('grunt-mocha-test');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks("grunt-jscs-checker");
|
||||
grunt.registerTask('lint', ['newer:jshint','jscs']);
|
||||
grunt.registerTask('test', 'mochaTest:unit');
|
||||
grunt.registerTask('unit', 'mochaTest: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);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
Google Summer of Code Ideas
|
||||
=====
|
||||
|
||||
Appium is excited to participate as a [Google Summer of Code](https://summerofcode.withgoogle.com/) sponsor project. Here's a fun list of ideas that a Summer of Code student participant can use as a foundation for thinking about what to contribute to Appium!
|
||||
|
||||
|Idea|Description|
|
||||
|----|-----------|
|
||||
|Apple tvOS Support|Our users have been asking for an Appium driver for Apple tvOS apps. Is this possible? We're not entirely sure! Why not be awesome and build it?|
|
||||
|Test App revamp|Appium uses a number of poorly-designed mobile applications in its own testing. We have to use a variety of apps because we need to test that Appium can automate all the various controls and platform features that mobile vendors provide. Really what we need is one cross-platform app (or one app per platform) that exhibit all and only the features we need to test. This would be a fun project to build some mobile apps used for testing and also demoing Appium at events and in training videos, etc...|
|
||||
|Tooling and Performance|We haven't instrumented Appium with very many performance metrics, and don't really know if we're missing some low-hanging fruit in terms of performance. Maybe you can help us do that?|
|
||||
|Babel|We have a lot of repos, and they're all on a really old version of Babel. They all need to stay in sync. How can we make this situation better, and upgrade to the latest and greatest?|
|
||||
|Unity3d Driver|Historically, Appium hasn't been great at automating games. We don't have any particular support for the frameworks used to create games. Unity is a popular one, for example. What if we could write an Appium driver that talked to an embedded process in a test version of a Unity game, that allowed us to find and interact with 3d elements? It would be amazing! You can also be amazing and lead Appium into this new world.|
|
||||
|Testing the Internet of Things|Appium's architecture makes it dead simple to integrate drivers for automating new technologies. What about _really_ new technologies like IoT devices? Help to redefine the semantics of the WebDriver protocol for use with IoT, and build a driver for an IoT device to prove it out.|
|
||||
|Driver for X|Have an idea of something else Appium could automate that it doesn't already? Build a driver for it! This would involve some awesome Node.js code, plus whatever else is needed to integrate with the platform you have in mind.|
|
||||
|
||||
Hopefully this gives you some ideas of fun projects that would be substantial and long-lasting contributions to the Appium community.
|
||||
@@ -1,192 +1,4 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright JS Foundation and other contributors, https://js.foundation
|
||||
Copyright 2012-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.
|
||||
|
||||
@@ -1,214 +1,149 @@
|
||||
## Appium
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://david-dm.org/appium/appium)
|
||||
[](https://david-dm.org/appium/appium#info=devDependencies)
|
||||
[](https://travis-ci.org/appium/appium)
|
||||
[](https://saucelabs.com/u/appium)
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)
|
||||
[](https://saucelabs.com/u/appium)
|
||||
|
||||
[](https://github.com/vshymanskyy/StandWithUkraine/)
|
||||
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).
|
||||
|
||||
[](https://vshymanskyy.github.io/StandWithUkraine/)
|
||||
**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!
|
||||
|
||||
Appium is an open-source, cross-platform test automation tool for native,
|
||||
hybrid, mobile web and desktop apps. Initially created to automate iOS and Android mobile
|
||||
applications Appium has grown to a full-featured platform that provides [WebDriver](https://www.w3.org/TR/webdriver/)-based automation possibilities for the whole set of different mobile and desktop platforms.
|
||||
See [Drivers Maintained By The Appium Team](#drivers-maintained-by-the-appium-team)
|
||||
and [Drivers Provided By Third Parties](#drivers-provided-by-third-parties) sections below for more details.
|
||||
### Supported Platforms
|
||||
|
||||
:bangbang: Major documentation revision in progress
|
||||
* iOS
|
||||
* Android
|
||||
* FirefoxOS
|
||||
|
||||
:bangbang: Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022. All recent versions of officially supported platform drivers are not compatible to Appium 1.x anymore, and require Appium 2 to run. [Please read the migration guide from 1.x to 2.0](https://appium.github.io/appium/docs/en/latest/guides/migrating-1-to-2/) to manage the Appium server.
|
||||
|
||||
Appium is in the final stages of a major revision (to version 2.0). As such, the documentation
|
||||
found around the web may not be correct. The current Appium 2.0 documentation is very much in
|
||||
progress. Currently, it can be found [here](https://appium.github.io/appium/docs/en/latest/).
|
||||
|
||||
### Requirements
|
||||
|
||||
- macOS, Linux or Windows operating system
|
||||
- Node.js 14+
|
||||
- NPM (Node Package Manager) 8+
|
||||
|
||||
These are only server requirements. Each driver might have its own requirements. Consider checking the corresponding driver tutorial for more details.
|
||||
|
||||
### Server
|
||||
|
||||
To install Appium 2 server using Node Package Manager (npm) run the following command:
|
||||
|
||||
```bash
|
||||
npm install -g appium@next
|
||||
```
|
||||
|
||||
:bangbang: Running `npm install -g appium` would still install Appium 1 because version 2 is in its late beta stage.
|
||||
|
||||
### Drivers
|
||||
|
||||
Appium supports app automation across a variety of platforms, like iOS,
|
||||
Android, and Windows. Each platform is supported by one or more "drivers",
|
||||
which know how to automate that particular platform. Since version 2.0
|
||||
all drivers have been isolated from the Appium server app and can
|
||||
be managed independently using the [appium driver](https://appiumpro.com/editions/122-installing-appium-20-and-the-driver-and-plugins-cli) command line interface.
|
||||
|
||||
In general, the drivers management in Appium 2 is as simple as:
|
||||
|
||||
```bash
|
||||
# To install a new driver from npm
|
||||
appium driver install --source=npm appium-xcuitest-driver[@<version>]
|
||||
# To install a driver from a local folder (useful for developers)
|
||||
appium driver install --source=local /Users/me/sources/appium-xcuitest-driver
|
||||
# To install a new driver from github (hm, maybe it's time to publish it to NPM?)
|
||||
appium driver install --source=github appium/appium-xcuitest-driver
|
||||
|
||||
# To list already installed drivers
|
||||
appium driver list --installed
|
||||
|
||||
# To update a driver (it must be already installed)
|
||||
appium driver update xcuitest
|
||||
|
||||
# To uninstall a driver (it won't last forever, wouldn't it?)
|
||||
appium driver uninstall xcuitest
|
||||
```
|
||||
|
||||
You can find a full list of
|
||||
[officially-supported](https://appium.github.io/appium/docs/en/latest/ecosystem/#drivers) and
|
||||
[third-party](https://appium.github.io/appium/docs/en/latest/ecosystem/#other-drivers) drivers at
|
||||
the current Appium 2.0 documentation.
|
||||
|
||||
### Plugins
|
||||
|
||||
The concept of plugins is something new that has been added exclusively to Appium2. Plugins allow you to extend server functionality without changing the server code. Plugins could be managed similarly to drivers:
|
||||
|
||||
```bash
|
||||
# To install an officially supported plugin
|
||||
appium plugin install images
|
||||
# To install a plugin from a local folder (useful for developers)
|
||||
appium plugin install --source=local /Users/me/sources/images
|
||||
# To install a new plugin from npm
|
||||
appium plugin install --source=npm appium-device-farm
|
||||
|
||||
# To list already installed plugins
|
||||
appium plugin list --installed
|
||||
|
||||
# To update a plugins (it must be already installed)
|
||||
appium plugin update appium-device-farm
|
||||
|
||||
# To uninstall a plugin
|
||||
appium plugin uninstall appium-device-farm
|
||||
```
|
||||
|
||||
The main difference between drivers and plugins is that the latter must be explicitly enabled on server startup after it was installed (drivers are enabled by default after installation):
|
||||
|
||||
```bash
|
||||
appium server --use-plugins=device-farm,images
|
||||
```
|
||||
|
||||
You can find a full list of
|
||||
[officially-supported](https://appium.github.io/appium/docs/en/latest/ecosystem/#plugins) and
|
||||
[third-party](https://appium.github.io/appium/docs/en/latest/ecosystem/#other-plugins) plugins at
|
||||
the current Appium 2.0 documentation.
|
||||
|
||||
|
||||
### Server Command Line Interface
|
||||
|
||||
In order to start sending commands to Appium over the wire it must be listening
|
||||
on the URL where your client library expects it to listen.
|
||||
Use the following commands to run and configure Appium server:
|
||||
|
||||
```bash
|
||||
# Start the server on the default port and host (e.g. http://0.0.0.0:4723/)
|
||||
appium server
|
||||
# Start the server on the given port, host and use the base path prefix (the default prefix is /)
|
||||
appium server -p 9000 -a 127.0.0.1 -pa /wd/hub
|
||||
|
||||
# Get the list of all supported command line parameters.
|
||||
# This list would also include descriptions of driver-specific
|
||||
# command line arguments for all installed drivers.
|
||||
# Each driver and plugin must have their command line arguments
|
||||
# exposed in a special JSON schema declared as a part of the corresponding
|
||||
# package.json file.
|
||||
appium server --help
|
||||
```
|
||||
|
||||
Appium supports execution of parallel server processes as well as parallel driver sessions within
|
||||
single server process. Refer the corresponding driver documentations regarding which mode is optimal
|
||||
for the particular driver or whether it supports parallel sessions.
|
||||
See the [platform support doc](/docs/en/appium-setup/platform-support.md) for more detailed information.
|
||||
|
||||
### Why Appium?
|
||||
|
||||
1. You usually don't have to recompile your app or modify it in any way, due
|
||||
to the use of standard automation APIs on all platforms.
|
||||
2. You can write tests with your favorite dev tools using any
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html)-compatible
|
||||
language such as [Java](https://github.com/appium/java-client),
|
||||
[JavaScript](https://webdriver.io/), [Python](https://github.com/appium/python-client),
|
||||
[Ruby](https://github.com/appium/ruby_lib), [C#](https://github.com/appium/dotnet-client)
|
||||
with the Selenium WebDriver API. There are also various third party
|
||||
client implementations for other languages.
|
||||
1. You don't have to recompile your app or modify it in any way, due
|
||||
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. Some drivers, like xcuitest and uiautomator2 ones have built-in mobile web and
|
||||
hybrid app support. Within the same script, you can switch seamlessly between native
|
||||
app automation and webview automation, all using the WebDriver model that's already
|
||||
the standard for web automation.
|
||||
5. You can run your automated tests locally and in a cloud. There are multiple
|
||||
cloud providers that support various Appium drivers (mostly
|
||||
targeting iOS and Android mobile automation).
|
||||
6. [Appium Inspector](https://github.com/appium/appium-inspector) allows
|
||||
visual debugging of automated tests and could be extremely useful for
|
||||
beginners.
|
||||
|
||||
Investing in the
|
||||
[WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means
|
||||
you are betting on a single, free, and open protocol for testing that has become
|
||||
a web standard. Don't lock yourself into a proprietary stack.
|
||||
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...
|
||||
|
||||
### Quickstart
|
||||
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).
|
||||
|
||||
Check out our [Quickstart](https://appium.github.io/appium/docs/en/latest/quickstart/) guide
|
||||
to get going with Appium.
|
||||
### Requirements
|
||||
|
||||
There is also a sample code that contains [many examples of tests in a variety
|
||||
of different languages](https://github.com/appium/appium/tree/1.x/sample-code)!
|
||||
Your environment needs to be setup for the particular mobile platforms that you
|
||||
want to run tests on. See below for particular platform requirements.
|
||||
|
||||
### Documentation
|
||||
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.
|
||||
|
||||
For prettily-rendered docs, please visit [Appium Documentation](https://appium.github.io/appium).
|
||||
You can always find the full list of Appium doc pages at [Appium's GitHub
|
||||
Repo](https://github.com/appium/appium/tree/master/packages/appium/docs) as well.
|
||||
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`.
|
||||
|
||||
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).
|
||||
|
||||
#### iOS Requirements
|
||||
|
||||
* Mac OS X 10.7 or higher, 10.9.2 recommended
|
||||
* XCode >= 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)
|
||||
|
||||
#### Android Requirements
|
||||
|
||||
* [Android SDK](http://developer.android.com) API >= 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
|
||||
|
||||
$ 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](https://appium.github.io/appium/docs/en/latest/intro/history/)
|
||||
|
||||
### 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
|
||||
|
||||
[](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
@@ -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.
Binary file not shown.
Binary file not shown.
Executable
+109
@@ -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
@@ -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); */ });
|
||||
}
|
||||
Executable
+23
@@ -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");
|
||||
});
|
||||
}
|
||||
Executable
+76
@@ -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
+56
@@ -0,0 +1,56 @@
|
||||
#!/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; 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
|
||||
./reset.sh --hardcore --real-safari --chromedriver-install-all --chromedriver-version 2.10
|
||||
npm cache clear appium
|
||||
npm publish
|
||||
version=$(cat package.json | $(npm bin)/underscore extract version | sed 's/\"//g')
|
||||
git tag -a "v$version" -m "tag appium@$version for npm publish"
|
||||
git push --tags upstream $branch
|
||||
@@ -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
+163
@@ -0,0 +1,163 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
mocha_args=""
|
||||
ios_only=false
|
||||
ios6_only=false
|
||||
ios7_only=false
|
||||
ios71_only=false
|
||||
ios8_only=false
|
||||
ios81_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" = "--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 $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=ios71 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
|
||||
@@ -0,0 +1,11 @@
|
||||
export JAVA_HOME=$(/usr/libexec/java_home)
|
||||
|
||||
if [ -f $HOME/tools/ant/env ]; then
|
||||
source $HOME/tools/ant/env
|
||||
fi
|
||||
if [ -f $HOME/tools/maven/env ]; then
|
||||
source $HOME/tools/maven/env
|
||||
fi
|
||||
if [ -f $HOME/tools/android/env ]; then
|
||||
source $HOME/tools/android/env
|
||||
fi
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ "${TARBALL}" == '' ]]; then
|
||||
echo Please set the TARBALL env variable!
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET=/tmp/${TARBALL}
|
||||
|
||||
echo "Starting to archive appium build into ${TARGET}."
|
||||
|
||||
tar \
|
||||
cfj ${TARGET} \
|
||||
-L \
|
||||
--exclude=.git \
|
||||
--exclude=submodules .
|
||||
|
||||
echo "Finished to archive appium build."
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ $CI_CONFIG == 'ios' ]]; then
|
||||
./ci/installers/install-ant.sh
|
||||
./ci/installers/install-maven.sh
|
||||
sudo grunt authorize
|
||||
elif [[ $CI_CONFIG == 'android' ]]; then
|
||||
./ci/installers/install-ant.sh
|
||||
./ci/installers/install-maven.sh
|
||||
./ci/installers/install-android.sh --api-19
|
||||
sudo grunt authorize
|
||||
elif [[ $CI_CONFIG == 'gappium' ]]; then
|
||||
if [[ $TRAVIS_PULL_REQUEST != false ]]; then
|
||||
# Skipping this config for pull requests, it takes too long.
|
||||
exit 0
|
||||
fi
|
||||
./ci/installers/install-ant.sh
|
||||
./ci/installers/install-maven.sh
|
||||
./ci/installers/install-android.sh --api-19 --api-18 --api-16
|
||||
npm install -g cordova
|
||||
sudo grunt authorize
|
||||
elif [[ $CI_CONFIG == 'selendroid' ]]; then
|
||||
if [[ $TRAVIS_PULL_REQUEST != false ]]; then
|
||||
# Skipping this config for pull requests, it takes too long.
|
||||
exit 0
|
||||
fi
|
||||
./ci/installers/install-ant.sh
|
||||
./ci/installers/install-maven.sh
|
||||
./ci/installers/install-android.sh --api-19 --api-16
|
||||
sudo grunt authorize
|
||||
fi
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
TARBALL=appium-${DEVICE_TYPE}-${BUILD_NUMBER}-${GIT_COMMIT:0:10}.tar.bz2
|
||||
|
||||
echo "TARBALL=${TARBALL}" >> ./ci/build-env.properties
|
||||
|
||||
cat ./ci/build-env.properties
|
||||
@@ -0,0 +1,10 @@
|
||||
- SAUCE_USERNAME=appium
|
||||
- SAUCE_REST_ROOT=https://saucelabs.com/rest/v1
|
||||
- APPIUM_HOST=ondemand.saucelabs.com
|
||||
- APPIUM_PORT=80
|
||||
- IOS_CONCURRENCY=30
|
||||
- ANDROID_CONCURRENCY=30
|
||||
- SELENDROID_CONCURRENCY=10
|
||||
- GAPPIUM_CONCURRENCY=10
|
||||
# below is SAUCE_ACCESS_KEY encrypted
|
||||
- secure: GXGFbQptLEsKlaWnpOL2EB9hqQ4XBT6tqg7REt5j1h1jYBsfHQHSgSLt1jpzOF5kooXVbw2K7IrZyNVBXEUHR00Hp6O72FBOd+SSj8uPCJBLjAOaJWs0ZtujqGHwHpe6gadFfn0L7q0ffoV5OJVeNHHcuw4f9BaA78fTFNfm1jE=
|
||||
@@ -0,0 +1,13 @@
|
||||
export SAUCE_REST_ROOT=https://saucelabs.com/rest/v1
|
||||
export APPIUM_HOST=ondemand.saucelabs.com
|
||||
export APPIUM_PORT=80
|
||||
|
||||
export IOS_CONCURRENCY=10
|
||||
export ANDROID_CONCURRENCY=10
|
||||
export SELENDROID_CONCURRENCY=5
|
||||
export GAPPIUM_CONCURRENCY=5
|
||||
export HTTP_RETRIES=2
|
||||
export HTTP_RETRY_DELAY=20000
|
||||
export DEBUG_CONNECTION=1
|
||||
export MOCHA_INIT_TIMEOUT=300000
|
||||
export LAUNCH_TIMEOUT='{"global":60000,"afterSimLaunch":30000}'
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
# Needs to be sourced!
|
||||
|
||||
set -e
|
||||
|
||||
curl -s -o use-node https://repository-cloudbees.forge.cloudbees.com/distributions/ci-addons/node/use-node
|
||||
NODE_VERSION=0.10.26 . ./use-node
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
androids=','
|
||||
|
||||
while test $# != 0
|
||||
do
|
||||
case "$1" in
|
||||
"--api-19") androids+='android-19,';;
|
||||
"--api-18") androids+='android-18,';;
|
||||
"--api-16") androids+='android-16,';;
|
||||
esac
|
||||
|
||||
if [[ -n "$2" ]] && [[ "$2" != --* ]]; then
|
||||
shift
|
||||
shift
|
||||
else
|
||||
shift
|
||||
fi
|
||||
done
|
||||
|
||||
COMPONENTS=build-tools-19.0.3${androids}extra-android-support
|
||||
|
||||
mkdir -p $HOME/tools/android
|
||||
|
||||
( curl -L https://raw.github.com/appium/android-sdk-installer/master/android-sdk-installer | \
|
||||
bash /dev/stdin --dir=$HOME/tools/android --install=$COMPONENTS ) &&\
|
||||
source $HOME/tools/android/env
|
||||
|
||||
# to configure the emulator, add sysimg-18 to COMPONENTS and uncomment the line belor
|
||||
# echo no | android create avd --force -n test -t android-18 --abi armeabi-v7a
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
mkdir -p $HOME/tools/ant
|
||||
cd $HOME/tools/ant
|
||||
wget -P /tmp http://www.us.apache.org/dist/ant/binaries/apache-ant-1.9.4-bin.tar.gz
|
||||
tar xzf /tmp/apache-ant-1.9.4-bin.tar.gz
|
||||
echo 'export PATH=$HOME/tools/ant/apache-ant-1.9.4/bin:$PATH' > $HOME/tools/ant/env
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
mkdir -p $HOME/tools/maven
|
||||
cd $HOME/tools/maven
|
||||
wget -P /tmp http://www.us.apache.org/dist/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz
|
||||
tar xzf /tmp/apache-maven-3.1.1-bin.tar.gz
|
||||
echo 'export PATH=$HOME/tools/maven/apache-maven-3.1.1/bin:$PATH' > $HOME/tools/maven/env
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
git clone https://github.com/visionmedia/n.git /tmp/n
|
||||
cd /tmp/n
|
||||
make install
|
||||
n stable
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
mkdir -p $HOME/tools/sc
|
||||
cd $HOME/tools/sc
|
||||
wget -P /tmp https://saucelabs.com/downloads/sc-4.3-osx.zip
|
||||
unzip /tmp/sc-4.3-osx.zip -d $HOME/tools/sc
|
||||
echo 'export PATH=$HOME/tools/sc/sc-4.3-osx/bin:$PATH' > $HOME/tools/sc/env
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
SAUCE=1 \
|
||||
VERBOSE=1 \
|
||||
TARBALL="${TARBALL}" \
|
||||
DEVICE="android" \
|
||||
VERSION="4.3" \
|
||||
./node_modules/.bin/mocha \
|
||||
-g "@skip-ci|@skip-android-all|@android-arm-only" -i \
|
||||
"$@"
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
SAUCE=1 \
|
||||
VERBOSE=1 \
|
||||
TARBALL="${TARBALL}" \
|
||||
DEVICE="ios71" \
|
||||
VERSION="7.1" \
|
||||
./node_modules/.bin/mocha \
|
||||
-g "@skip-ci|@skip-ios71|@skip-ios7|@skip-ios-all" -i \
|
||||
"$@"
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
SAUCE=1 \
|
||||
VERBOSE=1 \
|
||||
TARBALL="${TARBALL}" \
|
||||
DEVICE="selendroid" \
|
||||
./node_modules/.bin/mocha \
|
||||
-g "@skip-ci|@skip-selendroid-all" -i \
|
||||
"$@"
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source ./ci/env.sh
|
||||
|
||||
function check_tarball {
|
||||
if [[ "${TARBALL}" == '' ]]; then
|
||||
echo Please set the TARBALL env variable!
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function show_functional_test_info {
|
||||
echo "APPIUM_BUILD_NUMBER --> ${APPIUM_BUILD_NUMBER}"
|
||||
echo "APPIUM_JOB_NUMBER --> ${APPIUM_JOB_NUMBER}"
|
||||
echo "TARBALL --> ${TARBALL}"
|
||||
}
|
||||
|
||||
if [[ $CI_CONFIG == 'unit' ]]; then
|
||||
#npm install -g jshint grunt-cli
|
||||
#npm install
|
||||
# cd docs
|
||||
# appium_doc_lint || exit 1
|
||||
# cd -
|
||||
npm test
|
||||
elif [[ $CI_CONFIG == 'build-ios' ]]; then
|
||||
check_tarball
|
||||
unset SUDO_UID
|
||||
echo OS X version: `sw_vers -productVersion`
|
||||
echo Xcode version: `xcodebuild build -version`
|
||||
echo Xcode path: `xcode-select --print-path`
|
||||
./reset.sh --no-npmlink --dev --ios
|
||||
|
||||
if [[ $UPLOAD_TO_SAUCE == 1 ]]; then
|
||||
TARBALL=$TARBALL ./ci/archive-build.sh
|
||||
# TARBALL=$TARBALL ./ci/upload_build_to_sauce.sh
|
||||
fi
|
||||
elif [[ $CI_CONFIG == 'ios-functional-tests' ]]; then
|
||||
check_tarball
|
||||
show_functional_test_info
|
||||
npm install
|
||||
TARBALL=sauce-storage:$TARBALL \
|
||||
./ci/tools/parallel-mocha.js \
|
||||
-p $IOS_CONCURRENCY \
|
||||
-c ios
|
||||
elif [[ $CI_CONFIG == 'build-android' ]]; then
|
||||
check_tarball
|
||||
echo JAVA_HOME: $JAVA_HOME
|
||||
./reset.sh --no-npmlink --dev --android
|
||||
if [[ $UPLOAD_TO_SAUCE == 1 ]]; then
|
||||
TARBALL=$TARBALL ./ci/archive-build.sh
|
||||
# TARBALL=$TARBALL ./ci/upload_build_to_sauce.sh
|
||||
fi
|
||||
elif [[ $CI_CONFIG == 'android-functional-tests' ]]; then
|
||||
check_tarball
|
||||
show_functional_test_info
|
||||
npm install
|
||||
TARBALL=sauce-storage:$TARBALL \
|
||||
./ci/tools/parallel-mocha.js \
|
||||
-p $ANDROID_CONCURRENCY \
|
||||
-c android
|
||||
elif [[ $CI_CONFIG == 'gappium' ]]; then
|
||||
check_tarball
|
||||
if [[ $TRAVIS_PULL_REQUEST != false ]]; then
|
||||
echo "Skipping this config for pull requests, it takes too long."
|
||||
exit 0
|
||||
fi
|
||||
# source ./ci/android_env
|
||||
echo OS X version: `sw_vers -productVersion`
|
||||
echo Xcode version: `xcodebuild build -version`
|
||||
echo Xcode path: `xcode-select --print-path`
|
||||
echo JAVA_HOME: $JAVA_HOME
|
||||
./reset.sh --ios --android --selendroid-quick --no-npmlink
|
||||
./reset.sh --dev --gappium --no-npmlink
|
||||
# if [[ $UPLOAD_TO_SAUCE == 1 ]]; then
|
||||
# TARBALL=$TARBALL ./ci/upload_build_to_sauce.sh
|
||||
# TARBALL=sauce-storage:$TARBALL \
|
||||
# ./ci/tools/parallel-mocha.js \
|
||||
# -p $GAPPIUM_CONCURRENCY \
|
||||
# -c gappium
|
||||
# fi
|
||||
elif [[ $CI_CONFIG == 'selendroid' ]]; then
|
||||
check_tarball
|
||||
if [[ $TRAVIS_PULL_REQUEST != false ]]; then
|
||||
echo "Skipping this config for pull requests, it takes too long."
|
||||
exit 0
|
||||
fi
|
||||
# source ./ci/android_env
|
||||
echo OS X version: `sw_vers -productVersion`
|
||||
echo Xcode version: `xcodebuild build -version`
|
||||
echo Xcode path: `xcode-select --print-path`
|
||||
echo JAVA_HOME: $JAVA_HOME
|
||||
./reset.sh --android --no-npmlink
|
||||
./reset.sh --dev --selendroid-quick --no-npmlink
|
||||
# if [[ $UPLOAD_TO_SAUCE == 1 ]]; then
|
||||
# TARBALL=$TARBALL ./ci/upload_build_to_sauce.sh
|
||||
# TARBALL=sauce-storage:$TARBALL \
|
||||
# ./ci/tools/parallel-mocha.js \
|
||||
# -p $SELENDROID_CONCURRENCY \
|
||||
# -c selendroid
|
||||
# fi
|
||||
fi
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
SC_DIR="/tmp/sc"
|
||||
READY_FILE="sc-ready-$RANDOM"
|
||||
|
||||
mkdir -p $SC_DIR && cd $SC_DIR
|
||||
touch $SC_DIR/sauce_connect.log
|
||||
|
||||
source $HOME/tools/sc/env
|
||||
|
||||
sc \
|
||||
-u $SAUCE_USERNAME \
|
||||
-k $SAUCE_ACCESS_KEY \
|
||||
--readyfile $READY_FILE\
|
||||
--tunnel-identifier $TRAVIS_JOB_NUMBER \
|
||||
-l $SC_DIR/sauce_connect.log \
|
||||
&> /dev/null &
|
||||
|
||||
echo 'waiting for sauce connect to start'
|
||||
tail -f $SC_DIR/sauce_connect.log &
|
||||
|
||||
# Wait for Connect to be ready before exiting
|
||||
while [ ! -f $READY_FILE ]; do
|
||||
sleep .5
|
||||
done
|
||||
@@ -0,0 +1,46 @@
|
||||
module.exports = {
|
||||
'ios':{
|
||||
'mocha-bin': 'ci/mochas/ios71-mocha',
|
||||
'glob-patterns': [
|
||||
'test/functional/common/**/*-specs.js',
|
||||
'test/functional/ios/**/*-specs.js'
|
||||
]
|
||||
},
|
||||
'android':{
|
||||
'mocha-bin': 'ci/mochas/android-mocha',
|
||||
'glob-patterns': [
|
||||
'test/functional/common/**/*-specs.js',
|
||||
'test/functional/android/**/*-specs.js'
|
||||
]
|
||||
},
|
||||
'gappium':[
|
||||
{
|
||||
'mocha-bin': 'ci/mochas/ios71-mocha',
|
||||
'glob-patterns': [
|
||||
'test/functional/gappium/**/*-specs.js'
|
||||
]
|
||||
},
|
||||
// TODO: gappium/android hangs on sauce.
|
||||
// suspect: context/contexts issues on linux
|
||||
// {
|
||||
// 'mocha-bin': 'ci/mochas/android-mocha',
|
||||
// 'glob-patterns': [
|
||||
// 'test/functional/gappium/**/*-specs.js'
|
||||
// ]
|
||||
// },
|
||||
// TODO: gappium/selendroid hangs on sauce.
|
||||
// suspect: context/contexts issues on linux
|
||||
// {
|
||||
// 'mocha-bin': 'ci/mochas/selendroid-mocha',
|
||||
// 'glob-patterns': [
|
||||
// 'test/functional/gappium/**/*-specs.js'
|
||||
// ]
|
||||
// }
|
||||
],
|
||||
'selendroid':{
|
||||
'mocha-bin': 'ci/mochas/selendroid-mocha',
|
||||
'glob-patterns': [
|
||||
'test/functional/selendroid/**/*-specs.js'
|
||||
]
|
||||
}
|
||||
};
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var yaml = require('js-yaml'),
|
||||
fs = require('fs'),
|
||||
_ = require('underscore');
|
||||
|
||||
var args = process.argv.slice(2);
|
||||
|
||||
function usage() {
|
||||
console.warn("Usage:");
|
||||
console.warn(" $(ci/tools/bash-env-tool.js set <config>)");
|
||||
console.warn(" $(ci/tools/bash-env-tool.js unset)");
|
||||
console.warn(" ci/tools/bash-env-tool.js show");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var ENV_VARIABLES = ['SAUCE_USERNAME', 'SAUCE_ACCESS_KEY', 'SAUCE_REST_ROOT',
|
||||
'APPIUM_HOST', 'APPIUM_PORT'];
|
||||
|
||||
if (args.length < 1) usage();
|
||||
|
||||
function set() {
|
||||
if (args.length < 2) usage();
|
||||
var doc = yaml.load(fs.readFileSync(args[1], 'utf8'));
|
||||
_(doc).chain()
|
||||
.filter(function (line) { return typeof line === 'string'; })
|
||||
.map(function (line) {
|
||||
var m = line.match(/^(.+)=(.*)$/);
|
||||
if (m) {
|
||||
return {key: m[1], value: m[2]};
|
||||
}
|
||||
}).filter(function (keyVal) {
|
||||
return ENV_VARIABLES.indexOf(keyVal.key) >= 0;
|
||||
}).each(function (keyVal) {
|
||||
console.log('export', keyVal.key + '=' + keyVal.value);
|
||||
});
|
||||
}
|
||||
|
||||
function unset() {
|
||||
_(ENV_VARIABLES).each(function (key) {
|
||||
console.log('unset', key);
|
||||
});
|
||||
}
|
||||
|
||||
function show() {
|
||||
_(ENV_VARIABLES).each(function (key) {
|
||||
console.log(key, '-->', process.env[key] ? process.env[key] : 'not set');
|
||||
});
|
||||
}
|
||||
|
||||
switch (args[0]) {
|
||||
case 'set':
|
||||
set();
|
||||
break;
|
||||
case 'unset':
|
||||
unset();
|
||||
break;
|
||||
case 'show':
|
||||
show();
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
assert = require('assert');
|
||||
|
||||
var fs = require("fs");
|
||||
var data = JSON.parse(fs.readFileSync(args[0]));
|
||||
assert(data.filename);
|
||||
|
||||
switch (args[1]) {
|
||||
case 'filename':
|
||||
console.log(data.filename);
|
||||
break;
|
||||
default:
|
||||
console.log(data);
|
||||
}
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
Saucelabs = require('saucelabs'),
|
||||
Q = require('q'),
|
||||
_ = require('underscore'),
|
||||
prompt = require('prompt');
|
||||
|
||||
var buildId = args[0];
|
||||
|
||||
if (!buildId) {
|
||||
console.log('\nUsage: ci/tools/green-sauce-jobs <build_id>\n');
|
||||
console.log('\nExample: ci/tools/green-sauce-jobs 4711\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!process.env.SAUCE_ACCESS_KEY) {
|
||||
console.log('\nPlease set the SAUCE_USERNAME and SAUCE_ACCESS_KEY ' +
|
||||
'env variables!\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var account = new Saucelabs({
|
||||
username: process.env.SAUCE_USERNAME,
|
||||
password: process.env.SAUCE_ACCESS_KEY
|
||||
});
|
||||
|
||||
var getJobs = Q.nbind(account.getJobs, account);
|
||||
var updateJob = Q.nbind(account.updateJob, account);
|
||||
|
||||
var selectedJobs;
|
||||
|
||||
getJobs()
|
||||
.then(function (jobs) {
|
||||
return _(jobs).filter(function (job) {
|
||||
return job.build === buildId && !job.passed;
|
||||
}).map(function (job) {
|
||||
return _(job).pick('id', 'name', 'tags', 'build', 'passed', 'error');
|
||||
});
|
||||
}).then(function (jobs) {
|
||||
selectedJobs = jobs;
|
||||
if (jobs.length > 0) {
|
||||
console.log("\nJobs needing greening:\n");
|
||||
console.log(jobs);
|
||||
console.log("\nMark all these jobs as passed? (Y/N):\n");
|
||||
prompt.start();
|
||||
return Q.nfcall(prompt.get, {
|
||||
name: 'YesNo',
|
||||
validator: /^[ynYN]{1}$/m,
|
||||
warning: 'only (Y/N)',
|
||||
required: true
|
||||
});
|
||||
} else {
|
||||
console.log('All jobs are already green.');
|
||||
return false;
|
||||
}
|
||||
}).then(function (result) {
|
||||
if (result && result.YesNo.toLowerCase() === 'y') {
|
||||
console.log('Starting to green jobs.');
|
||||
return Q.all(selectedJobs.map(function (job) {
|
||||
var tags = job.tags || [];
|
||||
if (tags.indexOf('greened') < 0) job.tags.push('greened');
|
||||
return updateJob(job.id, {passed: true, tags: job.tags});
|
||||
})).then(function () { console.log('Finished to green jobs.'); });
|
||||
}
|
||||
}).done();
|
||||
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
Saucelabs = require('saucelabs'),
|
||||
Q = require('q'),
|
||||
_ = require('underscore'),
|
||||
prompt = require('prompt');
|
||||
|
||||
var CONCURRENCY = 10;
|
||||
|
||||
var buildId = args[0];
|
||||
|
||||
if (!buildId) {
|
||||
console.log('\nUsage: ci/tools/kill-sauce-jobs <build_id>\n');
|
||||
console.log('\nExample: ci/tools/kill-sauce-jobs 4711\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!process.env.SAUCE_ACCESS_KEY) {
|
||||
console.log('\nPlease set the SAUCE_USERNAME and SAUCE_ACCESS_KEY ' +
|
||||
'env variables!\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var account = new Saucelabs({
|
||||
username: process.env.SAUCE_USERNAME || 'appium',
|
||||
password: process.env.SAUCE_ACCESS_KEY
|
||||
});
|
||||
|
||||
var getJobs = Q.nbind(account.getJobs, account);
|
||||
var stopJob = Q.nbind(account.stopJob, account);
|
||||
|
||||
var selectedJobs;
|
||||
|
||||
getJobs()
|
||||
.then(function (jobs) {
|
||||
return _(jobs).filter(function (job) {
|
||||
return job.build === buildId &&
|
||||
['in progress','queued'].indexOf(job.status) >= 0;
|
||||
}).map(function (job) {
|
||||
return _(job).pick('id', 'name', 'tags', 'build', 'status');
|
||||
});
|
||||
}).then(function (jobs) {
|
||||
selectedJobs = jobs;
|
||||
if (jobs.length > 0) {
|
||||
console.log("\nWill kill jobs:\n");
|
||||
console.log(jobs);
|
||||
console.log("\nNumber of jobs to kill:", jobs.length, "\n");
|
||||
console.log("\nKill all these jobs? (Y/N):\n");
|
||||
prompt.start();
|
||||
return Q.nfcall(prompt.get, {
|
||||
name: 'YesNo',
|
||||
validator: /^[ynYN]{1}$/m,
|
||||
warning: 'only (Y/N)',
|
||||
required: true
|
||||
});
|
||||
} else {
|
||||
console.log('No jobs to kill.');
|
||||
return false;
|
||||
}
|
||||
}).then(function (result) {
|
||||
if (result && result.YesNo.toLowerCase() === 'y') {
|
||||
console.log('\nStarting to kill jobs.\n');
|
||||
var tasks = selectedJobs.map(function (job) {
|
||||
return function () {
|
||||
console.log('Killing job:', job.id);
|
||||
return stopJob(job.id, {}).then(function () {
|
||||
console.log('Job', job.id, "was killed" );
|
||||
}, function (err) {
|
||||
console.warn('Could not kill', job.id, 'err:', err);
|
||||
});
|
||||
};
|
||||
});
|
||||
var process = function () {
|
||||
console.log('\n');
|
||||
if (tasks.length === 0) return new Q();
|
||||
var batch = [];
|
||||
while (tasks.length >0 && batch.length < CONCURRENCY) {
|
||||
batch.push(tasks.shift()());
|
||||
}
|
||||
return Q.all(batch).then(function () {
|
||||
return process();
|
||||
});
|
||||
};
|
||||
return process().then(function () {
|
||||
console.log('\nFinished to kill jobs.\n');
|
||||
});
|
||||
}
|
||||
}).done();
|
||||
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
_ = require('underscore'),
|
||||
glob = require('glob'),
|
||||
async = require('async'),
|
||||
Q = require("q"),
|
||||
spawn = require('child_process').spawn,
|
||||
argparse = require('argparse');
|
||||
|
||||
|
||||
var parser = new argparse.ArgumentParser({
|
||||
description: 'Parallel Mocha'
|
||||
});
|
||||
parser.addArgument(
|
||||
[ '-p' ],
|
||||
{
|
||||
help: 'number of processes',
|
||||
type: 'int',
|
||||
required: true,
|
||||
dest: 'numOfWorkers'
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '-c' ],
|
||||
{
|
||||
help: 'test config',
|
||||
required: true,
|
||||
dest: 'config'
|
||||
}
|
||||
);
|
||||
var args = parser.parseArgs();
|
||||
|
||||
var config = require('../test-glob-config');
|
||||
|
||||
var fileInfos = config[args.config];
|
||||
if (!(fileInfos instanceof Array)) {
|
||||
fileInfos = [fileInfos];
|
||||
}
|
||||
|
||||
var allGood = true;
|
||||
|
||||
function runOne(mochaBin, filepath) {
|
||||
var deferred = Q.defer();
|
||||
var out = '';
|
||||
var child = spawn(mochaBin, [filepath]);
|
||||
child.on('error', function (err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
|
||||
child.stdout.setEncoding('utf8');
|
||||
child.stdout.on('data', function (data) {
|
||||
out += data;
|
||||
});
|
||||
child.stderr.setEncoding('utf8');
|
||||
child.stderr.on('data', function (data) {
|
||||
out += data;
|
||||
});
|
||||
child.on('close', function (code) {
|
||||
if (code !== 0) {
|
||||
var err = new Error(
|
||||
"Mocha process terminated with code: " + code + '.');
|
||||
err.out = out;
|
||||
return deferred.reject(err);
|
||||
}
|
||||
deferred.resolve(out);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
var queue = async.queue(function (task, done) {
|
||||
var startMs = Date.now();
|
||||
console.log('running ' + task.filepath);
|
||||
|
||||
var interval = setInterval(function () {
|
||||
console.log(task.filepath, 'has been running for',
|
||||
Math.round((Date.now() - startMs)/1000), 'seconds.');
|
||||
}, 300000);
|
||||
|
||||
runOne(task.mochaBin, task.filepath)
|
||||
.then(function (out) {
|
||||
console.log('finished to run', task.filepath,'\n', out);
|
||||
})
|
||||
.catch(function (err) {
|
||||
allGood = false;
|
||||
console.error(err + (err.out ? '\n' + err.out : ''));
|
||||
}).finally(function () { clearInterval(interval); })
|
||||
.nodeify(done);
|
||||
}, args.numOfWorkers);
|
||||
|
||||
queue.drain = function () {
|
||||
if (allGood) {
|
||||
console.log('\n\nALL GOOD\n\n');
|
||||
process.exit(0);
|
||||
}
|
||||
else {
|
||||
throw new Error('FAILING TESTS!');
|
||||
}
|
||||
};
|
||||
|
||||
function fillQueue(fileInfo) {
|
||||
var deferred = Q.defer();
|
||||
async.eachSeries(
|
||||
fileInfo['glob-patterns'],
|
||||
function (globPattern, done) {
|
||||
glob(globPattern, function (err, _files) {
|
||||
if (err) return done(err);
|
||||
_(_files).map(function (file) {
|
||||
queue.push({mochaBin: fileInfo['mocha-bin'], filepath: file});
|
||||
});
|
||||
done();
|
||||
});
|
||||
},
|
||||
function (err) {
|
||||
if (err) {
|
||||
return deferred.reject(err);
|
||||
}
|
||||
deferred.resolve();
|
||||
}
|
||||
);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
queue.pause();
|
||||
Q.all(_(fileInfos).map(function (fileInfo) {
|
||||
return fillQueue(fileInfo);
|
||||
})).then(function () { queue.resume(); })
|
||||
.done();
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
assert = require('assert'),
|
||||
_ = require('underscore');
|
||||
|
||||
if (args.length !==2 ) {
|
||||
console.warn('Usage travis.yml-tool.js <.travis.yml> <config.yml>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var DEFAULTS = {
|
||||
SAUCE_REST_ROOT:'https://saucelabs.com/rest/v1',
|
||||
APPIUM_HOST:'ondemand.saucelabs.com',
|
||||
APPIUM_PORT:80,
|
||||
IOS_CONCURRENCY:10,
|
||||
ANDROID_CONCURRENCY:10,
|
||||
SELENDROID_CONCURRENCY:3,
|
||||
GAPPIUM_CONCURRENCY:3
|
||||
};
|
||||
|
||||
var fs = require("fs");
|
||||
var target = fs.readFileSync(args[0], 'UTF8');
|
||||
var config = fs.readFileSync(args[1], 'UTF8');
|
||||
|
||||
// replace secure env variable
|
||||
var secureLines = config.match(/^\s*- secure.*/gm).join('\n');
|
||||
secureLines = secureLines.replace(/^\s*-/mg, ' -');
|
||||
assert(secureLines);
|
||||
target = target.replace(/(^\s*- secure.*\r?\n)+/m, ' # <SECURE>\n');
|
||||
target = target.replace(/^ # <SECURE>.*$/m, secureLines);
|
||||
|
||||
// replace env variables
|
||||
_([
|
||||
'SAUCE_REST_ROOT', 'APPIUM_HOST','APPIUM_PORT', 'SAUCE_USERNAME',
|
||||
'IOS_CONCURRENCY', 'ANDROID_CONCURRENCY', 'SELENDROID_CONCURRENCY',
|
||||
'GAPPIUM_CONCURRENCY'
|
||||
]).each(function (varName) {
|
||||
var regex = new RegExp('- ' + varName + '=.*');
|
||||
var m = config.match(regex);
|
||||
var line = m ? m[0] : null;
|
||||
if (!line && DEFAULTS[varName]) {
|
||||
line = '- ' + varName + '=' + DEFAULTS[varName];
|
||||
}
|
||||
regex = new RegExp('- ' + varName + '=.*','g');
|
||||
target = target.replace(regex, line);
|
||||
});
|
||||
|
||||
fs.writeFileSync(args[0], target, 'UTF8');
|
||||
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source ./ci/env.sh
|
||||
|
||||
if [[ "${TARBALL}" == '' ]]; then
|
||||
echo Please set the TARBALL env variable!
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE=/tmp/${TARBALL}
|
||||
|
||||
echo "Starting to upload appium from ${SOURCE} to ${TARBALL}."
|
||||
|
||||
UPLOAD_INFO_FILE=./build-upload-info.json
|
||||
|
||||
# zipping/uploading
|
||||
curl \
|
||||
-k \
|
||||
--silent \
|
||||
-u $SAUCE_USERNAME:$SAUCE_ACCESS_KEY \
|
||||
-X POST "${SAUCE_REST_ROOT}/storage/${SAUCE_USERNAME}/${TARBALL}?overwrite=true" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @${SOURCE} \
|
||||
-o $UPLOAD_INFO_FILE
|
||||
|
||||
# --progress-bar \
|
||||
|
||||
# checking/printing result file
|
||||
ci/tools/build-upload-tool.js $UPLOAD_INFO_FILE
|
||||
rm ${SOURCE}
|
||||
echo "Finished to compress and upload appium."
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source ./ci/env.sh
|
||||
|
||||
if [[ "${TARBALL}" == '' ]]; then
|
||||
echo Please set the TARBALL env variable!
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting to compress and upload appium to ${TARBALL}."
|
||||
|
||||
UPLOAD_INFO_FILE=./build-upload-info.json
|
||||
|
||||
# zipping/uploading
|
||||
tar \
|
||||
cfj - \
|
||||
-L \
|
||||
--exclude=.git \
|
||||
--exclude=submodules . | \
|
||||
curl \
|
||||
-k \
|
||||
--silent \
|
||||
-u $SAUCE_USERNAME:$SAUCE_ACCESS_KEY \
|
||||
-X POST "${SAUCE_REST_ROOT}/storage/${SAUCE_USERNAME}/${TARBALL}?overwrite=true" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @- \
|
||||
-o $UPLOAD_INFO_FILE
|
||||
|
||||
# --progress-bar \
|
||||
|
||||
# checking/printing result file
|
||||
ci/tools/build-upload-tool.js $UPLOAD_INFO_FILE
|
||||
|
||||
echo "Finished to compress and upload appium."
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
rules: {
|
||||
'body-leading-blank': [0],
|
||||
'body-max-line-length': [0],
|
||||
'footer-max-line-length': [0],
|
||||
'header-max-length': [0],
|
||||
'subject-case': [0],
|
||||
'subject-full-stop': [0],
|
||||
},
|
||||
};
|
||||
+9
-4
@@ -1,6 +1,11 @@
|
||||
# Docs moved
|
||||
# docs
|
||||
|
||||
The old Appium 1.x docs used to be in this directory. Now, they are available only on the [1.x
|
||||
branch](https://github.com/appium/appium/tree/1.x/docs).
|
||||
##doc site
|
||||
|
||||
Appium 2.x docs are located in [packages/appium/docs](../packages/appium/docs) in this repo.
|
||||
Formatted doc is [here](http://appium.io/documentation.html?lang=en).
|
||||
|
||||
##doc translation
|
||||
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
## List of client libraries with Appium server support
|
||||
|
||||
These libraries wrap standard Selenium client libraries to provide all the regular selenium commands dictated by the [JSON Wire protocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol), and add extra commands related to controlling mobile devices, such as **multi-touch gestures** and **screen orientation**.
|
||||
|
||||
Appium client libraries implement the [Mobile JSON Wire Protocol](https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile) (an official draft extension to the standard protocol), and elements of the [W3C Webdriver spec](https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html) (a transport-agnostic automation spec; this is where the MultiAction API is defined).
|
||||
|
||||
The Appium server itself defines custom extensions to the official protocols, giving Appium users helpful access to various device behaviors (such as installing/uninstalling apps during the course of a test session). This is why we need Appium-specific clients, not just the 'vanilla' Selenium clients. Of course, Appium client libraries only **add** functionality (in fact, they simply extend the standard Selenium clients), so they can still be used to run regular Selenium sessions.
|
||||
|
||||
Language/Framework | Github Repo and Installation Instructions |
|
||||
----- | ----- |
|
||||
Ruby | [https://github.com/appium/ruby_lib](https://github.com/appium/ruby_lib)
|
||||
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)
|
||||
JavaScript (Node.js) | [https://github.com/admc/wd](https://github.com/admc/wd)
|
||||
Objective C | [https://github.com/appium/selenium-objective-c](https://github.com/appium/selenium-objective-c)
|
||||
PHP | [https://github.com/appium/php-client](https://github.com/appium/php-client)
|
||||
C# (.NET) | [https://github.com/appium/appium-dotnet-driver](https://github.com/appium/appium-dotnet-driver)
|
||||
RobotFramework | [https://github.com/jollychang/robotframework-appiumlibrary](https://github.com/jollychang/robotframework-appiumlibrary)
|
||||
@@ -0,0 +1,108 @@
|
||||
## Introduction to Appium
|
||||
|
||||
Appium is an open-source tool for automating native,
|
||||
mobile web, and hybrid applications on iOS and Android platforms.
|
||||
**Native apps** are those written using the iOS or Android SDKs. **Mobile web apps** are web apps accessed using a mobile browser (Appium supports
|
||||
Safari on iOS and Chrome or the built-in 'Browser' app on Android). **Hybrid apps** have a
|
||||
wrapper around a "webview" -- a native control that enables interaction with
|
||||
web content. Projects like [Phonegap](http://phonegap.com/),
|
||||
make it easy to build apps using web technologies that are then bundled into
|
||||
a native wrapper, creating a hybrid app.
|
||||
|
||||
Importantly, Appium is "cross-platform": it allows you to write tests against
|
||||
multiple platforms (iOS, Android), using the same API. This enables code reuse between iOS and Android testsuites.
|
||||
|
||||
For specific information about what it means for Appium to "support" its
|
||||
platforms, and automation modalities, please see the [platform support doc](/docs/en/appium-setup/platform-support.md).
|
||||
|
||||
### Appium Philosophy
|
||||
|
||||
Appium was designed to meet mobile automation needs according to a philosophy outlined by the following four tenets:
|
||||
|
||||
1. You shouldn't have to recompile your app or modify it in any way in order to automate it.
|
||||
2. You shouldn't be locked into a specific language or framework to write and run your tests.
|
||||
3. A mobile automation framework shouldn't reinvent the wheel when it comes to automation APIs.
|
||||
4. A mobile automation framework should be open source, in spirit and practice as well as in name!
|
||||
|
||||
### Appium Design
|
||||
|
||||
So how does the structure of the Appium project live out this philosophy? We
|
||||
meet requirement #1 by using vendor-provided automation frameworks under the
|
||||
hood. That way, we don't need to compile in any Appium-specific or
|
||||
third-party code or frameworks to your app. This means **you're testing the same app you're shipping**. The vendor-provided frameworks we use are:
|
||||
|
||||
* iOS: Apple's [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/_index.html)
|
||||
* Android 4.2+: Google's [UiAutomator](http://developer.android.com/tools/help/uiautomator/index.html)
|
||||
* Android 2.3+: Google's [Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html). (Instrumentation support is provided by bundling a separate project, [Selendroid](http://selendroid.io))
|
||||
|
||||
We meet requirement #2 by wrapping the vendor-provided frameworks in one API,
|
||||
the [WebDriver](http://docs.seleniumhq.org/projects/webdriver/) API.
|
||||
WebDriver (aka "Selenium WebDriver") specifies a client-server protocol
|
||||
(known as the [JSON Wire Protocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol)).
|
||||
Given this client-server architecture, a client written in any language can
|
||||
be used to send the appropriate HTTP requests to the server. There are
|
||||
already [clients written in every popular programming language](http://appium.io/downloads). This also
|
||||
means that you're free to use whatever test runner and test framework you
|
||||
want; the client libraries are simply HTTP clients and can be mixed into your
|
||||
code any way you please. In other words, Appium & WebDriver clients are not
|
||||
technically "test frameworks" -- they are "automation libraries". You can
|
||||
manage your test environment any way you like!
|
||||
|
||||
We meet requirement #3 in the same way: WebDriver has become the de facto
|
||||
standard for automating web browsers, and is a [W3C Working Draft](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html).
|
||||
Why do something totally different for mobile? Instead we have [extended the protocol](https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile)
|
||||
with extra API methods useful for mobile automation.
|
||||
|
||||
It should be obvious that requirement #4 is a given -- you're reading this
|
||||
because [Appium is open source](https://github.com/appium/appium).
|
||||
|
||||
### Appium Concepts
|
||||
|
||||
**Client/Server Architecture**<br/>
|
||||
Appium is at its heart a webserver that exposes a REST API. It receives
|
||||
connections from a client, listens for commands, executes those commands on a
|
||||
mobile device, and responds with an HTTP response representing the result of
|
||||
the command execution. The fact that we have a client/server architecture
|
||||
opens up a lot of possibilities: we can write our test code in any language
|
||||
that has a http client API, but it is easier to use one of the [Appium client
|
||||
libraries](http://appium.io/downloads). We can put the server on a different machine than our
|
||||
tests are running on. We can write test code and rely on a cloud service
|
||||
like [Sauce Labs](https://saucelabs.com/mobile) to receive and interpret the commands.
|
||||
|
||||
**Session**<br/>
|
||||
Automation is always performed in the context of a session. Clients initiate
|
||||
a session with a server in ways specific to each library,
|
||||
but they all end up sending a `POST /session` request to the server,
|
||||
with a JSON object called the 'desired capabilities' object. At this point
|
||||
the server will start up the automation session and respond with a session ID
|
||||
which is used for sending further commands.
|
||||
|
||||
**Desired Capabilities**<br/>
|
||||
Desired capabilities are a set of keys and values (i.e.,
|
||||
a map or hash) sent to the Appium server to tell the server what kind of
|
||||
automation session we're interested in starting up. There are also various
|
||||
capabilities which can modify the behavior of the server during automation.
|
||||
For example, we might set the `platformName` capability to `iOS` to tell
|
||||
Appium that we want an iOS session, rather than an Android one. Or we might
|
||||
set the `safariAllowPopups` capability to `true` in order to ensure that,
|
||||
during a Safari automation session, we're allowed to use JavaScript to open
|
||||
up new windows. See the [capabilities doc](/docs/en/writing-running-appium/caps.md) for the complete list of capabilities available for Appium.
|
||||
|
||||
**Appium Server**<br/>
|
||||
Appium is a server written in Node.js. It can be built and installed from source or installed directly from NPM.
|
||||
|
||||
**Appium Clients**<br/>
|
||||
There are client libraries (in Java, Ruby, Python, PHP, JavaScript, and C#)
|
||||
which support Appium's extensions to the WebDriver protocol. When using Appium,
|
||||
you want to use these client libraries instead of your regular WebDriver
|
||||
client. You can view the full list of libraries [here](appium-clients.md).
|
||||
|
||||
**[Appium.app](https://github.com/appium/appium-dot-app), [Appium.exe](https://github.com/appium/appium-dot-exe)**<br/>
|
||||
There exist GUI wrappers around the Appium server that can be downloaded.
|
||||
These come bundled with everything required to run the Appium server,
|
||||
so you don't need to worry about Node. They also come with an Inspector,
|
||||
which enables you to check out the hierarchy of your app. This can come in handy when writing tests.
|
||||
|
||||
### Getting Started
|
||||
|
||||
Congratulations! You are now armed with enough knowledge to begin using Appium. Why not head to the [getting started doc](/README.md) for more detailed requirements and instructions?
|
||||
@@ -0,0 +1,59 @@
|
||||
## Selenium Grid
|
||||
|
||||
You are able to register your appium server with a local [Selenium grid](https://code.google.com/p/selenium/wiki/Grid2) ([setup docs](http://docs.seleniumhq.org/docs/07_selenium_grid.jsp)) by using the
|
||||
`--nodeconfig` server parameter.
|
||||
|
||||
```center
|
||||
> appium --nodeconfig /path/to/nodeconfig.json
|
||||
# or, if running from source:
|
||||
> node . --nodeconfig /path/to/nodeconfig.json
|
||||
```
|
||||
|
||||
In the node config file you have to define the `browserName`,
|
||||
`version` and `platform` and based on these parameters the grid
|
||||
will re-direct your test to the right device. You will also need to
|
||||
configure your **host** details and the **selenium grid** details. For
|
||||
a full list of all parameters and descriptions look
|
||||
[here](http://code.google.com/p/selenium/source/browse/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties)
|
||||
|
||||
Once you start the appium server and it registers with the grid,
|
||||
you will see your device on the grid console page:
|
||||
|
||||
"http://**\<grid-ip-adress\>**:**\<grid-port\>**/grid/console"
|
||||
|
||||
### Grid Node Configuration Example json file
|
||||
|
||||
```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>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Valid platforms are listed [here](http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/Platform.html)
|
||||
|
||||
If `url`, `host`, and `port` are not given, the config will be auto updated
|
||||
to point to localhost:whatever-port-Appium-started-on.
|
||||
|
||||
If your Appium server is running on a different machine to your Selenium Grid server, make sure you use an external name/IP address in your `host` & `url` docs; `localhost` and `127.0.0.1` will prevent Selenium Grid from connecting correctly.
|
||||
@@ -0,0 +1,201 @@
|
||||
## Automating hybrid apps
|
||||
|
||||
One of the core principles of Appium is that you shouldn't have to change
|
||||
your app to test it. In line with that methodology, it is possible to test
|
||||
hybrid web apps (e.g., the "UIWebView" elements in an iOS app) the same way
|
||||
you can with Selenium for web apps. There is a bit of technical complexity
|
||||
required so that Appium knows whether you want to automate the native aspects
|
||||
of the app or the web views, but thankfully, we can stay within the
|
||||
WebDriver protocol for everything.
|
||||
|
||||
Here are the steps required to talk to a web view in your Appium test:
|
||||
|
||||
1. Navigate to a portion of your app where a web view is active
|
||||
1. Call [GET session/:sessionId/contexts](https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile)
|
||||
1. This returns a list of contexts we can access, like 'NATIVE_APP' or 'WEBVIEW_1'
|
||||
1. Call [POST session/:sessionId/context](https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile)
|
||||
with the id of the context you want to access
|
||||
1. (This puts your Appium session into a mode where all commands are
|
||||
interpreted as being intended for automating the web view,
|
||||
rather than the native portion of the app. For example,
|
||||
if you run getElementByTagName, it will operate on the DOM of the web
|
||||
view, rather than return UIAElements. Of course,
|
||||
certain WebDriver methods only make sense in one context or another,
|
||||
so in the wrong context you will receive an error message).
|
||||
1. To stop automating in the web view context and go back to automating the
|
||||
native portion of the app, simply call `context` again with the native
|
||||
context id to leave the web frame.
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
// assuming we have an initialized `driver` object for an app
|
||||
driver
|
||||
.contexts().then(function (contexts) { // get list of available views. Returns array: ["NATIVE_APP","WEBVIEW_1"]
|
||||
return driver.context(contexts[1]); // choose the webview context
|
||||
})
|
||||
|
||||
// do some web testing
|
||||
.elementsByCss('.green_button').click()
|
||||
|
||||
.context('NATIVE_APP') // leave webview context
|
||||
|
||||
// do more native stuff here if we want
|
||||
|
||||
.quit() // stop webdrivage
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
// assuming we have a set of 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); //prints out something like NATIVE_APP \n WEBVIEW_1
|
||||
}
|
||||
driver.context(contextNames.toArray()[1]); // set context to WEBVIEW_1
|
||||
|
||||
//do some web testing
|
||||
String myText = driver.findElement(By.cssSelector(".green_button")).click();
|
||||
|
||||
driver.context("NATIVE_APP");
|
||||
|
||||
// do more native testing if we want
|
||||
|
||||
driver.quit();
|
||||
```
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
# assuming we have a set of capabilities
|
||||
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => SERVER_URL)
|
||||
|
||||
# I switch to the last window because its always the webview in our case, in other cases you may need to specify a window number
|
||||
# View the appium logs while running @driver.window_handles to figure out which window is the one you want and find the associated number
|
||||
# Then switch to it using @driver.switch_to_window("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(@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(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
|
||||
}
|
||||
```
|
||||
|
||||
### Automating hybrid Android apps
|
||||
|
||||
Appium comes with built-in hybrid support via Chromedriver. Appium also uses
|
||||
Selendroid under the hood for webview support on devices older than 4.4. (In
|
||||
that case, you'll want to specify `"automationName": "selendroid"` as a desired
|
||||
capability).
|
||||
|
||||
Make sure
|
||||
[setWebContentsDebuggingEnabled](http://developer.android.com/reference/android/webkit/WebView.html#setWebContentsDebuggingEnabled(boolean)) is set to true as described in the [remote debugging docs](https://developer.chrome.com/devtools/docs/remote-debugging#configure-webview).
|
||||
|
||||
Once you've set your desired capabilities and started an appium session, follow the generalized instructions above.
|
||||
|
||||
### Automating hybrid iOS apps
|
||||
|
||||
To interact with a web view appium establishes a connection
|
||||
using a remote debugger. When executing against a
|
||||
simulator this connection is established directly as the simulator and
|
||||
the appium server are on the same machine.
|
||||
|
||||
Once you've set your desired capabilities and started an appium session, follow the generalized instructions above.
|
||||
|
||||
### Execution against a real iOS device
|
||||
|
||||
When executing against a real iOS device appium is unable to access the web view directly. Therefore the
|
||||
connection has to be established through the USB lead. To establish this
|
||||
connection we use the [ios-webkit-debugger-proxy](https://github.com/google/ios-webkit-debug-proxy).
|
||||
|
||||
To install the latest tagged version of the ios-webkit-debug-proxy using
|
||||
brew, run the following commands in the terminal:
|
||||
|
||||
``` center
|
||||
# The first command is only required if you don't have brew installed.
|
||||
> ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go/install)"
|
||||
> brew update
|
||||
> brew install ios-webkit-debug-proxy
|
||||
```
|
||||
|
||||
You can also install the latest proxy by cloning it from git and installing
|
||||
it yourself:
|
||||
|
||||
``` center
|
||||
# Please be aware that this will install the proxy with the latest code (and not a tagged version).
|
||||
> git clone https://github.com/google/ios-webkit-debug-proxy.git
|
||||
> cd ios-webkit-debug-proxy
|
||||
> ./autogen.sh
|
||||
> ./configure
|
||||
> make
|
||||
> sudo make install
|
||||
```
|
||||
|
||||
Once installed you can start the proxy with the following command:
|
||||
|
||||
``` center
|
||||
# Change the udid to be the udid of the attached device and make sure to set the port to 27753
|
||||
# as that is the port the remote-debugger uses.
|
||||
> ios_webkit_debug_proxy -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d
|
||||
```
|
||||
|
||||
**NOTE:** the proxy requires the **"web inspector"** to be turned on to
|
||||
allow a connection to be established. Turn it on by going to **settings >
|
||||
safari > advanced**. Please be aware that the web inspector was **added as
|
||||
part of iOS 6** and was not available previously.
|
||||
|
||||
Now you can start an appium test session and follow the generalized instructions above.
|
||||
@@ -0,0 +1,158 @@
|
||||
## Migrating your tests from Appium 0.18.x to Appium 1.x
|
||||
|
||||
Appium 1.0 has removed a number of deprecated features from the previous versions. This guide will help you know what needs to change in your test suite to take advantage of Appium 1.0.
|
||||
|
||||
### New client libraries
|
||||
|
||||
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/en/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.
|
||||
|
||||
Ultimately, you'll be doing something like (to use Python as an example):
|
||||
|
||||
```center
|
||||
from appium import webdriver
|
||||
```
|
||||
|
||||
Instead of:
|
||||
|
||||
```center
|
||||
from selenium import webdriver
|
||||
```
|
||||
|
||||
### New desired capabilities
|
||||
|
||||
The following capabilities are no longer used:
|
||||
|
||||
* `device`
|
||||
* `version`
|
||||
|
||||
Instead, use these capabilities:
|
||||
|
||||
* `platformName` (either "iOS" or "Android")
|
||||
* `platformVersion` (the mobile OS version you want)
|
||||
* `deviceName` (the kind of device you want, like "iPhone Simulator")
|
||||
* `automationName` ("Selendroid" if you want to use Selendroid, otherwise, this can be omitted)
|
||||
|
||||
The `app` capability remains the same, but now refers exclusively to non-browser apps. To use browsers like Safari or Chrome, use the standard `browserName` cap. This means that `app` and `browserName` are exclusive.
|
||||
|
||||
We have also standardized on camelCase for Appium server caps. That means caps like `app-package` or `app-wait-activity` are now `appPackage` and `appWaitActivity` respectively. Of course, since Android app package and activity are now auto-detected, you should be able to omit them entirely in most cases.
|
||||
|
||||
### New locator strategies
|
||||
|
||||
We've removed the following locator strategies:
|
||||
|
||||
* `name`
|
||||
* `tag name`
|
||||
|
||||
We have now added the `accessibility_id` strategy to do what `name` used to do. The specifics will be relative to your Appium client.
|
||||
|
||||
`tag name` has been replaced by `class name`. So to find an element by its UI type, use the class name locator strategy for your client.
|
||||
|
||||
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:
|
||||
|
||||
```center
|
||||
//table/cell/button
|
||||
```
|
||||
|
||||
It would now need to be:
|
||||
|
||||
```center
|
||||
//UIATableView/UIATableCell/UIAButton
|
||||
```
|
||||
|
||||
(And likewise for Android: `button` now needs to be `android.widget.Button`)
|
||||
|
||||
We've also added the following locator strategies:
|
||||
|
||||
* `-ios uiautomation`
|
||||
* `-android uiautomator`
|
||||
|
||||
Refer to your client for ways to use these new locator strategies.
|
||||
|
||||
### 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.
|
||||
|
||||
### Hybrid support through context, not window
|
||||
|
||||
Hybrid apps were previously supported by switching between "windows" using
|
||||
|
||||
* `window_handles`
|
||||
* `window`
|
||||
* `switch_to.window`
|
||||
|
||||
Now Appium supports the more conceptually consistent concept of "context". To get all of the available contexts, or the particular context the application is is, you use
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
And to switch between them, you use
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
### No more `execute_script("mobile: xxx")`
|
||||
|
||||
All the `mobile: ` methods have been removed, and have been replaced by native methods in the Appium client libraries. This means that a method call like `driver.execute("mobile: lock", [5])` will now look something more like `driver.lock(5)` (where `lock` has been turned into a native client method). Of course, the details on calling these methods will differ by client.
|
||||
|
||||
Of particular note, the gesture methods have been replaced by the new TouchAction / MultiAction API which allows for a much more powerful and general way of putting gestural automation together. Refer to your Appium client for usage notes on TouchAction / MultiAction.
|
||||
|
||||
And that's it! Happy migrating!
|
||||
@@ -0,0 +1,40 @@
|
||||
## Settings
|
||||
|
||||
Settings are a new concept introduced by appium. They are currently not a part of the Mobile JSON Wire Protocol, or the Webdriver spec.
|
||||
|
||||
Settings are a way to specify the behavior of the appium server.
|
||||
|
||||
Settings are:
|
||||
- Mutable, they can be changed during a session
|
||||
- Only relevant during the session they are applied. They are reset for each new session.
|
||||
- Control the way the appium server behaves during test automation. They do not apply to controlling the app or device under test.
|
||||
|
||||
An example of a setting would be `ignoreUnimportantViews` for Android. Android can be set to ignore elements in the View Hierarchy which it deems irrelevant. Setting this can cause tests to run faster. A user who *wants* to access the ignored elements however, would want to disable `ignoreUnimportantViews`, and reenable it afterwards.
|
||||
|
||||
Another example of a use-case for settings would be telling appium to ignore elements which are not visible.
|
||||
|
||||
Settings are implemented via the following API endpoints:
|
||||
|
||||
**POST** /session/:sessionId/appium/settings
|
||||
|
||||
>Expects a JSON hash of settings, where keys correspond to setting names, and values to the value of the setting.
|
||||
```
|
||||
{
|
||||
settings: {
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**GET** /session/:sessionId/appium/settings
|
||||
|
||||
>Returns a JSON hash of all the currently specified settings.
|
||||
```
|
||||
{
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
```
|
||||
|
||||
### Supported Settings
|
||||
|
||||
**"ignoreUnimportantViews"** - Boolean which sets whether Android devices should use `setCompressedLayoutHeirarchy()` which ignores all views which are marked IMPORTANT_FOR_ACCESSIBILITY_NO or IMPORTANT_FOR_ACCESSIBILITY_AUTO (and have been deemed not important by the system), in an attempt to make things less confusing or faster.
|
||||
@@ -0,0 +1,14 @@
|
||||
## Intel® Hardware Accelerated Execution Manager
|
||||
|
||||
If you find the android emulator a slow and your system runs on an Intel®
|
||||
cpu, you can check out HAXM. HAXM lets you leverage your hardware for
|
||||
virtualization, accelerating the emulator.
|
||||
|
||||
* To install HAXM open the Android SDK Manager, you will find the package
|
||||
under Extras.
|
||||
* You can find all relevant documentation on [Intel's website][1]
|
||||
* This will require an x86 emulator image
|
||||
* Use Intel's package to install HAXM; The Android SDK Manager appears to not
|
||||
do so successfully, depending on the version you might have installed
|
||||
|
||||
[1]: http://software.intel.com/en-us/articles/intel-hardware-accelerated-execution-manager/
|
||||
@@ -0,0 +1,51 @@
|
||||
## Android Setup
|
||||
|
||||
To get started, you'll need to install node.js (v0.10 or greater). Just
|
||||
follow the [instructions for your flavor of linux](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager).
|
||||
|
||||
Once you've got node.js installed, install the [Android SDK](http://developer.android.com/sdk/index.html).
|
||||
You will need to run the 'android' tool (included in the SDK, under the 'tools' directory).
|
||||
|
||||
Run the 'android' tool and use it to install an API Level 17 or greater.
|
||||
|
||||
(If you want to run Appium from source, you will also need [Apache Ant](http://ant.apache.org/) to build the bootstrap jar that Appium uses for running against Android simulators/devices.)
|
||||
|
||||
Finally, set `$ANDROID_HOME` to be your Android SDK path. If you unzipped the
|
||||
Android SDK to /usr/local/adt/, for example, you should add this to your
|
||||
shell startup:
|
||||
|
||||
export ANDROID_HOME="/usr/local/adt/sdk"
|
||||
|
||||
Now you're set up to run Appium! If you're running Appium from source, run
|
||||
`./reset.sh --android` from your Appium checkout to install all the
|
||||
dependencies.
|
||||
|
||||
### Additional Setup for Older Versions of Android
|
||||
|
||||
Appium uses, and comes prepackaged with, Selendroid for running Android
|
||||
versions 2.3 to 4.1. Appium switches to using Selendroid automatically when it
|
||||
detects older versions, but there is some additional setup required if you're
|
||||
running from source.
|
||||
|
||||
* Make sure you have [Maven 3.1.1](http://maven.apache.org/download.cgi) or
|
||||
newer installed (`mvn`).
|
||||
* Run `./reset.sh --selendroid` from your Appium checkout
|
||||
|
||||
### Running Appium Android Tests
|
||||
|
||||
To run tests on Linux, you will need to have the Android Emulator booted and
|
||||
running an AVD with API Level 17 or greater. Then run Appium (`appium`) after
|
||||
installing via NPM, or `node .` in the source directory if running from source.
|
||||
|
||||
See the [server documentation](/docs/en/writing-running-appium/server-args.md) for all the command line arguments.
|
||||
|
||||
### Notes
|
||||
|
||||
* There exists a hardware accelerated emulator for android, it has its own
|
||||
limitations. For more information you can check out this
|
||||
[page](/docs/en/appium-setup/android-hax-emulator.md).
|
||||
* Make sure that `hw.battery=yes` in your AVD's `config.ini`, if you want to
|
||||
run any of the Appium tests, or use any of the power commands.
|
||||
* Selendroid requires the following permission for your app:
|
||||
`<uses-permission android:name="android.**permission.INTERNET"/>`,
|
||||
please make sure your app has internet permission set when you are using selendroid or older versions of Android i.e. 2.3 to 4.1
|
||||
@@ -0,0 +1,83 @@
|
||||
## Deploying an iOS app to a real device
|
||||
|
||||
To prepare for your Appium tests to run on a real device, you will need to:
|
||||
|
||||
1. Build your app with specific device-targeted parameters
|
||||
1. Use [fruitstrap](https://github.com/ghughes/fruitstrap), a 3rd-party tool,
|
||||
to deploy this build to your device
|
||||
|
||||
### Xcodebuild with parameters:
|
||||
A newer xcodebuild now allows settings to be specified. Taken from [developer.apple.com](https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html):
|
||||
|
||||
```center
|
||||
xcodebuild [-project projectname] [-target targetname ...]
|
||||
[-configuration configurationname] [-sdk [sdkfullpath | sdkname]]
|
||||
[buildaction ...] [setting=value ...] [-userdefault=value ...]
|
||||
```
|
||||
|
||||
This is a resource to explore the available [settings](https://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-DontLinkElementID_10)
|
||||
|
||||
```center
|
||||
CODE_SIGN_IDENTITY (Code Signing Identity)
|
||||
Description: Identifier. Specifies the name of a code signing identity.
|
||||
Example value: iPhone Developer
|
||||
```
|
||||
|
||||
PROVISIONING_PROFILE is missing from the index of available commands,
|
||||
but may be necessary.
|
||||
|
||||
Specify "CODE_SIGN_IDENTITY" & "PROVISIONING_PROFILE" settings in the
|
||||
xcodebuild command:
|
||||
|
||||
```center
|
||||
xcodebuild -sdk <iphoneos> -target <target_name> -configuration <Debug> CODE_SIGN_IDENTITY="iPhone Developer: Mister Smith" PROVISIONING_PROFILE="XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"
|
||||
```
|
||||
|
||||
On success, the app will be built to your ```<app_dir>/build/<configuration>-iphoneos/<app_name>.app```
|
||||
|
||||
### Deploy using Fruitstrap
|
||||
|
||||
Go clone a forked version of fruitstrap as the [ghughes version](https://github.com/ghughes/fruitstrap)
|
||||
is no longer maintained. Success has been confirmed with the [unprompted fork](https://github.com/unprompted/fruitstrap),
|
||||
but others are reportedly functional.
|
||||
|
||||
Once cloned, run `make fruitstrap`
|
||||
Now, copy the resulting `fruitstrap` executable to your app's project or a
|
||||
parent directory.
|
||||
|
||||
Execute fruitstrap after a clean build by running (commands available depend
|
||||
on your fork of fruitstrap):
|
||||
|
||||
```center
|
||||
./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID>
|
||||
```
|
||||
|
||||
If you are aiming to use continuous integration in this setup,
|
||||
you may find it useful to want to log the output of fruitstrap to both
|
||||
command line and log, like so:
|
||||
|
||||
```center
|
||||
./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID> 2>&1 | tee fruit.out
|
||||
```
|
||||
|
||||
Since fruitstrap will need to be killed before the node server can be
|
||||
launched, an option is to scan the output of the fruitstrap launch for some
|
||||
telling sign that the app has completed launching. This may prove useful if
|
||||
you are doing this via a Rakefile and a ``go_device.sh`` script:
|
||||
|
||||
```center
|
||||
bundle exec rake ci:fruit_deploy_app | while read line ; do
|
||||
echo "$line" | grep "text to identify successful launch"
|
||||
if [ $? = 0 ]
|
||||
then
|
||||
# Actions
|
||||
echo "App finished launching: $line"
|
||||
sleep 5
|
||||
kill -9 `ps -aef | grep fruitstrap | grep -v grep | awk '{print $2}'`
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
Once fruitstrap is killed, node server can be launched and Appium tests can run!
|
||||
|
||||
Next: [Running Appium on Real Devices](real-devices.md)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user