Merge pull request #8942 from lihuazhang/master
update Chinese docs to the latest
@@ -1,140 +1 @@
|
||||
## Appium
|
||||
|
||||
[](https://npmjs.org/package/appium)
|
||||
[](https://david-dm.org/appium/appium)
|
||||
[](https://david-dm.org/appium/appium#info=devDependencies)
|
||||
|
||||
[](https://team-appium.ci.cloudbees.com/job/appium-master/)
|
||||
|
||||
Appium 是一个开源的,跨平台的自动化测试工具。
|
||||
它支持模拟器(iOS,FirefoxOS,Android)和真机(iOS, Android, FirefoxOS)上的原生应用,混合应用和移动 web 应用。
|
||||
|
||||
**Note:** 我们最近发布了Appium 1.0。如果已有 Appium 测试脚本,你可以参考这个文件[迁移到 1.0](advanced-concepts/migrating-to-1-0.cn.md)!
|
||||
|
||||
### 支持平台
|
||||
|
||||
* iOS
|
||||
* Android
|
||||
* FirefoxOS
|
||||
|
||||
### 详细请参见[文档网站](http://appium.io/documentation.html?lang=zh)
|
||||
|
||||
### 为什么选择appium ?
|
||||
|
||||
1. 因为 Appium 在所有平台上都使用了标准的自动化接口,
|
||||
所以你不需要以重新编译或者修改你的 app。
|
||||
2. 你可以用你喜欢的开发工具,使用任何 [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) 兼容的语言来编写测试用例。比如
|
||||
Java, [Objective-C](https://github.com/appium/selenium-objective-c),
|
||||
JavaScript with Node.js (in both [callback](https://github.com/admc/wd) and [yield-based](https://github.com/jlipps/yiewd) flavours),
|
||||
PHP, Python, [Ruby](https://github.com/appium/ruby_lib), C#, Clojure, 或者 Perl。
|
||||
可以使用标准的Selenium WebDriver API和特定语言的客户端库。
|
||||
3. 你可以使用任何测试框架。
|
||||
|
||||
投资 [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) 意味着你可以押宝在一个已经成为标准的独立,自由和开放的协议。你不会被任何专利限制。
|
||||
|
||||
|
||||
如果没有 Appium,你就只能用 Javascript 来写 Apple 的 UIAutomation 脚本,并且只能通过Instruments 应用来运行你的测试。同样的,在 Google 的UiAutomator体系下,你只能用 Java 写你的测试案例。Appium 最终开启了跨平台原生移动自动化的可能。
|
||||
|
||||
### 我还是不太明白……
|
||||
|
||||
如果你第一次接触 Appium 或者想要一个完整的描述,请通读我们的 [Introduction to Appium Concepts](about-appium/intro.cn.md)。
|
||||
|
||||
|
||||
### 依赖
|
||||
|
||||
为了运行测试,针对不同的移动平台,你需要配置下环境,下面列出相关的依赖平台的需求。
|
||||
|
||||
如果你想通过 `npm install` 安装的 appium 来运行 Appium 或者研究 Appium 或者为 Appium 贡献力量。你需要安装 [node.js 和 npm](http://nodejs.org) 0.10 或者更高版本 (使用 [n](https://github.com/visionmedia/n)或者`brew install node`来安装 Nodejs,确保安装过程中,你没有使用任何 sudo,否则你会遇到很多问题)。我们推荐最新的稳定版本。
|
||||
|
||||
你可以使用 `appium-doctor` 来验证 Appium 的所有依赖。运行 `appium-doctor`,然后提供 `--ios` 或者 `--android` 参数来验证两个平台的依赖是否配置正确。如果从源代码运行,你可以使用 `bin/appium-doctor.js` 或者 `node bin/appium-doctor.js`
|
||||
|
||||
#### iOS 需求
|
||||
|
||||
* Mac OS X 10.7 或者更高,推荐 10.9.2
|
||||
* XCode >= 4.6.3,推荐 5.1.1
|
||||
* Apple Developer Tools (iPhone simulator SDK, command line tools)
|
||||
* [确保你已经读了我们写的如何配置 iOS 测试环境的文档](appium-setup/running-on-osx.cn.md)
|
||||
|
||||
|
||||
#### Android 需求
|
||||
|
||||
* [Android SDK](http://developer.android.com) API >= 17 (额外的特性需要 18/19)
|
||||
* Appium 支持OS X,Linux,Windows 上的 Android,确保你是按照如下文档的指示来配置不同的测试环境的。
|
||||
* [linux](appium-setup/running-on-linux.cn.md)
|
||||
* [osx](appium-setup/running-on-osx.cn.md)
|
||||
* [windows](appium-setup/running-on-windows.cn.md)
|
||||
|
||||
#### FirefoxOS 需求
|
||||
|
||||
* [Firefox OS Simulator](https://developer.mozilla.org/en/docs/Tools/Firefox_OS_Simulator)
|
||||
|
||||
### 快速开始
|
||||
启动 Appium server,并运行用你喜欢的 [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) 兼容的语言编写的测试用例。
|
||||
你可以用 node.js 或者下面的应用程序来运行 Appium
|
||||
|
||||
#### 使用 Node.js
|
||||
|
||||
```center
|
||||
$ npm install -g appium
|
||||
$ appium &
|
||||
```
|
||||
|
||||
#### 使用 app
|
||||
|
||||
* [下载 Appium app](https://github.com/appium/appium/releases)
|
||||
* 运行它!
|
||||
|
||||
### 为Appium编写测试
|
||||
|
||||
如何开始写测试用例,运行测试用例,可以看[the running tests](writing-running-appium/running-tests.cn.md),这个文档描述了iOS,Android 和老版本的 Android 机器的情况。如果你想在实体机上运行测试的话,
|
||||
你可能会对[真机指南](appium-setup/real-devices.cn.md)感兴趣。
|
||||
|
||||
我们支持 [Selenium WebDriver JSON Wire Protocol](https://github.com/appium/appium/wiki/JSON-Wire-Protocol:-Supported-Methods) 的一个子集,而且在此之上扩展了移动平台相关的特性。所以你可以
|
||||
指定特定移动平台[desired capabilities](writing-running-appium/caps.cn.md) 来运行你的测试。
|
||||
|
||||
你可以通过 [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) 元素定位策略的子集来定位元素。更多信息请参考 [finding elements](writing-running-appium/finding-elements.cn.md)
|
||||
为了支持移动手势[automating mobile gestures](writing-running-appium/touch-actions.cn.md),比如
|
||||
tap,flick 和 swipe,我们扩展了JSON Wire Protocolor。
|
||||
|
||||
你也可以对混合应用中的webview进行自动化 [hybrid app guide](advanced-concepts/hybrid.cn.md)
|
||||
|
||||
该代码库有 [很多不同语言的测试例子](https://github.com/appium/sample-code)!
|
||||
|
||||
### 工作原理
|
||||
|
||||
Appium 可以驱动多种原生自动化框架,同时也提供基于 Selenium 的 [WebDriver JSON wire protocol](https://w3c.github.io/webdriver/webdriver-spec.html) api。
|
||||
|
||||
基于[Dan Cuellar's](http://github.com/penguinho) 在 iOS 自动化上的成果,Appium 通过驱动 Apple 的 UIAutomation 库来提供 iOS 支持。
|
||||
|
||||
而在新版本的 Android 上,我们使用 Uiautomator 框架,老版本的 Android,则使用了
|
||||
[Selendroid](http://github.com/DominikDary/selendroid)
|
||||
|
||||
FirefoxOS 的支持依赖一个基于 Gecko 平台并且兼容 WebDriver 的自动化驱动[Marionette](https://developer.mozilla.org/en-US/docs/Marionette)。
|
||||
|
||||
|
||||
### 如何贡献代码
|
||||
可以看下我们的文档 [contribution documentation](../../CONTRIBUTING.md)
|
||||
以了解如何从源代码中进行编译,测试和运行
|
||||
|
||||
|
||||
## 其他项目的授权和灵感来源
|
||||
|
||||
[Credits](contributing-to-appium/credits.cn.md)
|
||||
|
||||
### 邮件列表
|
||||
|
||||
声明和公告经常放到讨论组 [Discussion Group](https://groups.google.com/d/forum/appium-discuss), 需要注册
|
||||
|
||||
### 问题定位
|
||||
|
||||
我们增加了一个 [问题定位指南](appium-setup/troubleshooting.cn.md)。
|
||||
如果你遇到一些问题,请看下这个问的那个。它包含了一些常见的错误说明,以及在无法解决的情况如何和社区联系。
|
||||
|
||||
|
||||
### 使用Robots扩展
|
||||
可以使用 appium 的一些 robots 扩展。或者其他的 robots。想了解更多可以看看 [Appium Robots](https://github.com/appium/robots)
|
||||
|
||||
|
||||
### 翻译工作
|
||||
文档翻译工作由[testerhome](http://testerhome.com)在推动, 我们会不断补充更多的文档和测试用例.
|
||||
欢迎对 Appium 感兴趣的同学加入我们, 为开源社区贡献中国人的力量.
|
||||
The latest doc in Chinese, maintained by [TesterHome Appium 中文文档小组](https://testerhome.com/appium-doc-cn).
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
## 客户端类库列表及Appium服务端支持
|
||||
|
||||
这些类库封装了标准Selenium客户端类库,为用户提供所有常见的[JSON](https://w3c.github.io/webdriver/webdriver-spec.html) 格式selenium命令以及额外的移动设备控制相关的命令,如多点**触控手势**和**屏幕朝向**。
|
||||
|
||||
Appium客户端类库实现了[Mobile JSON Wire Protocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)(一个标准协议的官方扩展草稿)和[W3C Webdriver spec](https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html)(一个传输不可预知的自动化协议,该协议定义了MultiAction 接口)的元素。
|
||||
|
||||
Appium 服务端定义了官方协议的扩展,为Appium 用户提供了方便的接口来执行各种设备动作,例如在测试过程中安装/卸载app。这就是为什么我们需要Appium 特定的客户端,而不是通用的Selenium 客户端。当然,Appium 客户端类库只是增加了一些功能,而实际上这些功能就是简单的扩展了Selenium 客户端,所以他们仍然可以用来运行通用的selenium会话。
|
||||
|
||||
|
||||
语言/框架 | Github版本库以及安装指南 |
|
||||
----- | ----- |
|
||||
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)
|
||||
22
docs/cn/about-appium/appium-clients.md
Normal file
@@ -0,0 +1,22 @@
|
||||
## 支持 Appium 服务器的客户端程序库列表
|
||||
|
||||
这些库封装了标准的 Selenium 客户端,提供了所有 [JSON Wire protocol](https://w3c.github.io/webdriver/webdriver-spec.html) 指定的常规 selenium 命令,额外添加操控移动设备相关的命令,例如 **多点触控手势** 和 **屏幕方向**。
|
||||
|
||||
Appium 客户端程序库实现了 [Mobile JSON Wire Protocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)(一个基于标准官方协议的扩展草案)和 [W3C Webdriver 规格](https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html)(一个无关传输的自动化规格;定义 MultiAction API 的地方)中的元素。
|
||||
|
||||
Appium 服务端自定义了基于官方协议的扩展,帮助 Appium 用户使用各种设备操作(例如在测试会话过程中安装/卸载应用)。这就是为什么我们需要 Appium 特定的客户端,而不只是“原味”的 Selenium 客户端。当然,Appium 客户端程序库只增加功能(其实它们只是扩展了标准 Selenium 客户端),所以它们仍然适用于常规的 Selenium 会话。
|
||||
|
||||
语言/框架 | Github 仓库和安装指南 |
|
||||
----- | ----- |
|
||||
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)
|
||||
|
||||
由 @黑水 翻译,TesterHome 社区 id:sanlengjingvv
|
||||
|
||||
@lihuazhang 校验
|
||||
@@ -1,64 +0,0 @@
|
||||
# Appium 介绍
|
||||
|
||||
Appium 是一个自动化测试开源工具,支持 iOS 平台和 Android 平台上的原生应用,web 应用和混合应用。
|
||||
|
||||
所谓的“移动原生应用”是指那些用 iOS 或者 Android SDK 写的应用。所谓的“移动 web 应用”是指使用移动浏览器访问的应用(Appium 支持 iOS 上的 Safari 和 Android 上的 Chrome)。所谓的“混合应用”是指原生代码封装网页视图——原生代码和 web 内容交互。比如,像 [Phonegap](http://phonegap.com/),可以帮助开发者使用网页技术开发应用,然后用原生代码封装,这些就是混合应用。
|
||||
|
||||
重要的是,Appium 是一个跨平台的工具:它允许测试人员在不同的平台(iOS,Android)使用同一套API来写自动化测试脚本,这样大大增加了 iOS 和 Android 测试套件间代码的复用性。
|
||||
|
||||
想知道 Appium 如何支持平台,版本和自动化形态的详细信息,请参见[platform support doc](/docs/cn/appium-setup/platform-support.cn.md)。
|
||||
|
||||
## Appium 的理念
|
||||
|
||||
为了满足移动自动化需求,Appium 遵循着一种哲学,重点体现于以下4个需求:
|
||||
|
||||
1. 你无需为了自动化,而重新编译或者修改你的应用。
|
||||
2. 你不必局限于某种语言或者框架来写和运行测试脚本。
|
||||
3. 一个移动自动化的框架不应该在接口上重复造轮子。(移动自动化的接口应该统一)
|
||||
4. 无论是精神上,还是名义上,都必须开源。
|
||||
|
||||
## Appium 设计
|
||||
|
||||
那么 Appium 架构是如何实现这个哲学呢?为了满足第一条,Appium 真正的工作引擎其实是第三方自动化框架。这样,我们就不需在你的应用里植入 Appium 相关或者第三方的代码。这意味着你测试使用的应用与最终发布的应用并无二致。我们使用以下的第三方框架:
|
||||
|
||||
* iOS: 苹果的 [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef)
|
||||
* 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由单独的项目[Selendroid](http://selendroid.io)提供支持 )
|
||||
|
||||
为了满足第二点,我们把这些第三方框架封装成一套 API,[WebDriver](http://docs.seleniumhq.org/projects/webdriver/) API.WebDriver(也就是 "Selenium WebDriver") 指定了客户端到服务端的协议。
|
||||
(参见 [JSON Wire Protocol](https://w3c.github.io/webdriver/webdriver-spec.html))。使用这种客户端-服务端的架构,我们可以使用任何语言来编写客户端,向服务端发送恰当的 HTTP 请求。
|
||||
目前已经实现了大多数流行语言版本的客户端,这意味着你可以使用任何测试套件或者测试框架。客户端库就是简单的HTTP 客户,可以以任何你喜欢的方式潜入你的代码。换句话说,Appium 和 WebDriver 客户端不是技术意义上的“测试框架”,而是“自动化库”。你可以在你的测试环境中随意使用这些自动化库!
|
||||
|
||||
事实上 WebDriver 已经成为 web 浏览器自动化的标准,也成了 W3C 的标准 —— [W3C Working Draft](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html)。我们又何必为移动做一个完全不同的呢?所以我们扩充了[WebDriver 的协议](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md),在原有的基础上添加移动自动化相关的 API 方法,这也满足了第三条理念。
|
||||
|
||||
第四条就不用说了,[Appium 是开源的](https://github.com/appium/appium)。
|
||||
|
||||
## Appium 概念
|
||||
|
||||
**C/S 架构**<br/>
|
||||
Appium 的核心是一个 web 服务器,它提供了一套 REST 的接口。它收到客户端的连接,监听到命令,接着在移动设备上执行这些命令,然后将执行结果放在 HTTP响应中返还给客户端。事实上,这种客户端/服务端的架构给予了许多的可能性:比如我们可以使用任何实现了该客户端的语言来写我们的测试代码。比如我们可以把服务端放在不同
|
||||
的机器上。比如我们可以只写测试代码,然后使用像 [Sauce Labs](https://saucelabs.com/mobile) 这样的云服务来解释命令。
|
||||
|
||||
**Session**<br/>
|
||||
自动化始终围绕一个session进行,客户端初始化一个seesion(会话)来与服务端交互,不同的语言有不同的实现方式,但是他们最终都是发送为一个POST请求给服务端,请求中包含一个JSON对象,被称作“desired capabilities”。此时,服务端就会开启一个自动化的 session,然后返回一个 session ID,session ID将会被用户发送后续的命令。
|
||||
|
||||
**Desired Capabilities**<br/>
|
||||
Desired capabilities 是一些键值对的集合 (比如,一个 map 或者 hash),客户端将这些键值对发给服务端,告诉服务端我们想要怎么测试。比如,我们可以把`platformName` capability 设置为 `iOS`,告诉 Appium 服务端,我们想要一个iOS 的 session,而不是一个 Android 的。我们也可以设置 `safariAllowPopups` capability 为 `true`,确保在 Safari 自动化 session 中,我们可以使用 javascript 来打开新窗口。参见 [capabilities 文档](/docs/cn/writing-running-appium/caps.cn.md),查看完整的 capabilities 列表。
|
||||
|
||||
**Appium Server**<br/>
|
||||
Appium server 是用 Node.js 写的。我们可以用源码编译或者从 NPM 直接安装。
|
||||
|
||||
**Appium 服务端**<br/>
|
||||
|
||||
Appium 服务端有很多语言库 Java, Ruby, Python, PHP, JavaScript 和 C#,这些库都实现了
|
||||
Appium 对 WebDriver 协议的扩展。当使用 Appium 的时候,你只需使用这些库代替常规的 WebDriver 库就可以了。
|
||||
你可以从[这里](appium-clients.cn.md)看到所有的库的列表。
|
||||
|
||||
**[Appium.app](https://github.com/appium/appium-dot-app), [Appium.exe](https://github.com/appium/appium-dot-exe)**<br/>
|
||||
|
||||
我们提供了 GUI 封装的 Appium 服务端下载,它封装了运行 Appium服务端的所有依赖,而不需要担心怎样安装Node.js。其中还包括一个Inspector工具,可以帮助你检查应用的界面层级,这样写测试用例时更方便。
|
||||
|
||||
## Getting Started
|
||||
|
||||
恭喜!你现在有足够的知识来使用 Appium 了。 来我们回到 [getting started doc](/docs/cn/README.md) 继续了解更加
|
||||
细节的需求和指南。
|
||||
64
docs/cn/about-appium/intro.md
Normal file
@@ -0,0 +1,64 @@
|
||||
## Appium 介绍
|
||||
|
||||
Appium 是一个开源工具,用于自动化 iOS 手机 、 Android 手机和 Windows 桌面平台上的原生、移动 Web 和混合应用。“原生应用”指那些用 iOS 、 Android 或者 Windows SDK 编写的应用。“移动 web 应用”是用移动端浏览器访问的应用(Appium 支持 iOS 上的 Safari 、Chrome 和 Android 上的内置浏览器)。“混合应用”带有一个 "webview" 的包装器——用来和 Web 内容交互的原生控件。类似 [Phonegap](http://phonegap.com/) 的项目,让用 Web 技术开发然后打包进原生包装器创建一个混合应用变得容易了。
|
||||
|
||||
重要的是,Appium 是跨平台的:它允许你用同样的 API 对多平台写测试,做到在 iOS 、Android 和 Windows 测试套件之间复用代码。
|
||||
|
||||
了解 Appium “支持”这些平台意味着什么、有哪些自动化方式的详细信息,请参见[ Appium 支持的平台](/docs/cn/appium-setup/platform-support.md)。
|
||||
|
||||
### Appium 的理念
|
||||
|
||||
Appium 旨在满足移动端自动化需求的理念,概述为以下四个原则:
|
||||
1. 你没有必要为了自动化而重新编译你的应用或者以任何方式修改它。
|
||||
2. 你不应该被限制在特定的语言或框架上来编写运行测试。
|
||||
3. 移动端自动化框架在自动化接口方面不应该重造轮子。
|
||||
4. 移动端自动化框架应该开源,不但在名义上而且在精神和实践上都要实至名归。
|
||||
|
||||
### Appium 的设计
|
||||
|
||||
那么 Appium 项目的架构如何实现这一理念呢?为了实现第一点要求,我们其实使用了系统自带的自动化框架。这样,我们不需要把 Appium 特定的或者第三方的代码编译进你的应用。这意味着你测试使用的应用与最终发布的应用并无二致。我们使用以下系统自带的自动化框架:
|
||||
|
||||
* iOS 9.3 及以上:苹果的 [XCUITest](https://developer.apple.com/reference/xctest)
|
||||
* iOS 9.3 及以下:苹果的 [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
|
||||
* Android 4.2+: 谷歌的 [UiAutomator](http://developer.android.com/tools/help/uiautomator/index.html)
|
||||
* Android 2.3+: 谷歌的 [Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html)(通过绑定另外的项目——[ Selendroid ](http://selendroid.io)提供 Instrumentation 的支持)
|
||||
* Windows: 微软的 [WinAppDriver](http://github.com/microsoft/winappdriver)
|
||||
|
||||
为了实现第二点要求,我们把这些(系统本身的)供应商提供的框架包装进一套 API —— [WebDriver](http://docs.seleniumhq.org/projects/webdriver/) API 中。WebDriver(也叫 "Selenium WebDriver")规定了一个客户端-服务器协议(称为 [JSON Wire Protocol](https://w3c.github.io/webdriver/webdriver-spec.html)),按照这种客户端-服务器架构,可以使用任何语言编写的客户端向服务器发送适当的 HTTP 请求。已经有[各个流行编程语言编写的客户端](http://appium.io/downloads)了。这也意味着你可以自由使用任何你想要的测试运行器和测试框架;客户端程序库不过是 HTTP 客户端,可以以任何你喜欢的方式混入你的代码。换句话说,Appium 和 WebDriver 客户端不是严格意义上的“测试框架”,而是“自动化程序库”。你可以以任何你喜欢的方式管理你的测试环境!
|
||||
|
||||
我们以同样的方式实现第三点要求:WebDriver 已经成为 Web 浏览器自动化事实上的标准,并且是一个[ W3C 工作草案](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html)。何必在移动端做完全不同的尝试?我们通过附加可用于移动端自动化的 API 方法[扩展了协议](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)。
|
||||
|
||||
显然第 4 点是你在阅读的前提——[ Appium 是开源的](https://github.com/appium/appium)
|
||||
|
||||
### Appium 概念
|
||||
|
||||
**客户端/服务器架构**<br/>
|
||||
Appium 的核心是暴露 REST API 的网络服务器。它接受来自客户端的连接,监听命令并在移动设备上执行,答复表示执行结果的 HTTP 响应。客户端/服务器架构实际给予了许多可能性:我们可以使用任何有 http 客户端 API 的语言编写我们的测试代码,不过选一个[ Appium 客户端程序库
|
||||
](http://appium.io/downloads)用更容易。我们可以把服务器放在另一台机器上,而不是执行测试的机器。我们可以编写测试代码,并依靠类似 [Sauce Labs](https://saucelabs.com/mobile) 的云服务接收和解释命令。
|
||||
|
||||
**会话(session)**<br/>
|
||||
自动化始终在一个会话的上下文中执行,这些客户端程序库以各自的方式发起与服务器的会话,但都以发给服务器一个 `POST /session` 请求结束,请求中包含一个被称作 'desired capabilities' 的 JSON 对象。这时服务器就会开启这个自动化会话,并返回一个用于发送后续命令的会话 ID。
|
||||
|
||||
**Desired Capabilities**<br/>
|
||||
Desired capabilities 是一些发送给 Appium 服务器的键值对集合 (比如 map 或 hash),告诉服务器我们想要启动什么类型的自动化会话。也有各种可以在自动化运行时修改服务器行为的 capabilities。例如,我们可以把 `platformName` capability 设置为 `iOS`,告诉 Appium 我们想要 iOS 会话,而不是 Android 或者 Windows 会话。我们也可以设置 `safariAllowPopups` capability 为 `true` ,确保我们在 Safari 自动化会话中可以使用 javascript 打开新窗口。有关 Appium capabilities 的完整列表,请参阅 [capabilities doc](/docs/cn/writing-running-appium/caps.md) 。
|
||||
|
||||
**Appium 服务器**<br/>
|
||||
Appium 是用 Node.js 写的服务器。它可以从[源码](https://github.com/appium/appium/blob/master/docs/en/contributing-to-appium/appium-from-source.md)构建安装或者从 NPM 直接安装:
|
||||
```
|
||||
$ npm install -g appium
|
||||
$ appium
|
||||
```
|
||||
|
||||
**Appium 客户端**<br/>
|
||||
有多个客户端程序库(Java、Ruby、Python、PHP,、JavaScript 和 C# 的)支持 Appium 对 WebDriver 协议的扩展,你需要用这些客户端程序库代替通常的 WebDriver 客户端。在[这里](appium-clients.md)浏览所有程序库的列表。
|
||||
|
||||
**[Appium.app](https://github.com/appium/appium-dot-app), [Appium.exe](https://github.com/appium/appium-dot-exe)**<br/>
|
||||
有 Appium 服务器的图形界面包装器可以下载。它们打包了 Appium 服务器运行需要的所有东西,所以你不需要为 Node 而烦恼。它们还提供一个 Inspector 使你可以查看你应用的层级结构,这在写测试时很方便。
|
||||
|
||||
### 入门指南
|
||||
|
||||
恭喜!你现在有足够的知识来使用 Appium 了。 为什么不前往 [入门指南](/docs/cn/README.md) 了解更多详细的要求和指南呢?
|
||||
|
||||
由 @黑水 翻译,TesterHome 社区 id:sanlengjingvv
|
||||
|
||||
@lihuazhang 校验
|
||||
77
docs/cn/advanced-concepts/chromedriver.md
Normal file
@@ -0,0 +1,77 @@
|
||||
## Chromedriver
|
||||
|
||||
Appium 支持对基于 Chrome 内核的 H5 应用(混合应用)或者网页(Chrome 中的网页或者内建的浏览器中的网页)进行自动化。Appium 管理维护着一个 [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/) 实例,当需要的时候,使用代理模式,将命令传递给这个实例。这和[最新版本的 Chromedriver](https://chromedriver.storage.googleapis.com/LATEST_RELEASE)是绑定的。我们可以通过 npm 包来安装[appium-chromedriver](https://www.npmjs.com/package/appium-chromedriver)。(Github: [appium-chromedriver](https://github.com/appium/appium-chromedriver))
|
||||
|
||||
不幸的是,每次 Chromedriver 升级,支持的 Chrome 的最小版本都会升级,这就导致了老设备上经常无法在绑定的版本上自动化。在 Appium 的服务端就会有这样的错误日志:
|
||||
```
|
||||
An unknown server-side error occurred while processing the command.
|
||||
Original error: unknown error: Chrome version must be >= 55.0.2883.0
|
||||
```
|
||||
|
||||
为了解决这个问题,Appium 可以指定特定的 Chromedriver 版本。或者在安装的时候指定版本,比如 `npm install appium --chromedriver_version="2.16"`
|
||||
或者 `CHROMEDRIVER_VERSION=2.20 npm install appium`,也可以使用 `LATEST` 作为 `CHROMEDRIVER_VERSION` 的版本号,表示使用最新的 Chromedriver。或者可以在 Appium 运行的时候指定 `--chromedriver-executable` 为你自己下载的版本的路径,比如 `appium --chromedriver-executable /path/to/my/chromedriver`。
|
||||
|
||||
以下就是 Chromedriver 版本和支持的 Chrome 的最小版本的信息:
|
||||
|
||||
|
||||
| Version | Minimum Chrome Version | Link to Chromedriver |
|
||||
|---------|------------------------|---------------------------------------------------------------------------|
|
||||
| 2.29 | 57.0.2987.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.29/) |
|
||||
| 2.28 | 55.0.2883.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.28/) |
|
||||
| 2.27 | 54.0.2840.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.27/) |
|
||||
| 2.26 | 53.0.2785.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.26/) |
|
||||
| 2.25 | 53.0.2785.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.25/) |
|
||||
| 2.24 | 52.0.2743.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.24/) |
|
||||
| 2.23 | 51.0.2704.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.23/) |
|
||||
| 2.22 | 49.0.2623.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.22/) |
|
||||
| 2.21 | 46.0.2490.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.21/) |
|
||||
| 2.20 | 43.0.2357.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.20/) |
|
||||
| 2.19 | 43.0.2357.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.19/) |
|
||||
| 2.18 | 43.0.2357.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.18/) |
|
||||
| 2.17 | 42.0.2311.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.17/) |
|
||||
| 2.16 | 42.0.2311.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.16/) |
|
||||
| 2.15 | 40.0.2214.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.15/) |
|
||||
| 2.14 | 39.0.2171.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.14/) |
|
||||
| 2.13 | 38.0.2125.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.13/) |
|
||||
| 2.12 | 36.0.1985.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.12/) |
|
||||
| 2.11 | 36.0.1985.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.11/) |
|
||||
| 2.10 | 33.0.1751.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.10/) |
|
||||
| 2.9 | 31.0.1650.59 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.9/) |
|
||||
| 2.8 | 30.0.1573.2 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.8/) |
|
||||
| 2.7 | 30.0.1573.2 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.7/) |
|
||||
| 2.6 | | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.6/) |
|
||||
| 2.5 | | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.5/) |
|
||||
| 2.4 | 29.0.1545.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.4/) |
|
||||
| 2.3 | 28.0.1500.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.3/) |
|
||||
| 2.2 | 27.0.1453.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.2/) |
|
||||
| 2.1 | 27.0.1453.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.1/) |
|
||||
| 2.0 | 27.0.1453.0 | [link](https://chromedriver.storage.googleapis.com/index.html?path=2.0/) |
|
||||
|
||||
|
||||
我们可以在[这里](https://chromedriver.storage.googleapis.com/index.html) 可以找到完整的 Chromedriver release 列表。任何一个 Chromedriver 支持的 Chrome 最小版本都可以在 [Chromium](https://www.chromium.org/Home) 项目的[源码](https://chromium.googlesource.com/chromium/src/+/master/docs/get_the_code.md)中找到。把发布那个提交给拉出来,然后在 `src/chrome/test/chromedriver/chrome/version.cc` 里找到 `kMinimumSupportedChromeVersion` 这个变量。
|
||||
|
||||
### 安装遇到的网络问题
|
||||
|
||||
Appium 安装的时候需要下载 Chromedriver,所以经常会遇到网络问题,尤其在有长城防火墙的中国。
|
||||
|
||||
Chromedriver 默认是从 `https://chromedriver.storage.googleapis.com/` 下载。如果要使用镜像的话,需要配置npm的参数 `chromedriver_cdnurl`
|
||||
|
||||
```bash
|
||||
npm install appium-chromedriver --chromedriver_cdnurl=http://npm.taobao.org/mirrors/chromedriver
|
||||
```
|
||||
|
||||
或者把这个参数加到你的 [`.npmrc`](https://docs.npmjs.com/files/npmrc) 文件中去.
|
||||
|
||||
```bash
|
||||
chromedriver_cdnurl=http://npm.taobao.org/mirrors/chromedriver
|
||||
```
|
||||
|
||||
也可以使用环境变量 `CHROMEDRIVER_CDNURL`.
|
||||
|
||||
```bash
|
||||
CHROMEDRIVER_CDNURL=http://npm.taobao.org/mirrors/chromedriver npm install appium-chromedriver
|
||||
```
|
||||
|
||||
当然最好开着代理或者vpn来下载更好。
|
||||
|
||||
本文由 [lihuazhang](https://github.com/lihuazhang) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
36
docs/cn/advanced-concepts/cross-domain-iframes.md
Normal file
@@ -0,0 +1,36 @@
|
||||
## 跨域 iFrame 的自动化
|
||||
|
||||
[同源策略](https://en.wikipedia.org/wiki/Same-origin_policy) 会阻止 Appium 对和父页面不同域的 iFrame 进行自动化测试。
|
||||
|
||||
### 子域名的解决方案
|
||||
如果父页面和 iFrame 使用同一个 domain (比如 `site.com` 和 `shop.site.com`),你可以在父页面和 iFrame 里将 `document.domain` 设置为一个共同的domain。这就解决了同源问题。
|
||||
|
||||
父页面:
|
||||
```
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
document.domain = 'site.com';
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="http://shop.site.com" width="200" height="200"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
子 iFrame:
|
||||
```
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
document.domain = 'site.com';
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>This is an iFrame!</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
本文由 [lihuazhang](https://github.com/lihuazhang) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
45
docs/cn/advanced-concepts/event-timings.md
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
## Appium 事件计时
|
||||
|
||||
Appium 提供了一个能力,可以获取关于启动信息和命令执行时间的计时信息。这是由 `eventTimings` 这个初始化参数控制的高级功能(把这个参数设置为 `true` 来记录事件的计时信息)
|
||||
|
||||
打开这个参数,`GET /session/:id` 这个接口的响应结果(也就是,`driver.getSessionDetails()` 的响应结果,或者类似的,取决于客户端实现)中会包含 `events` 属性。下面是 `events` 属性的结构
|
||||
|
||||
```json
|
||||
{
|
||||
"<event_type>": [<occurence_timestamp_1>, ...],
|
||||
"commands": [
|
||||
{
|
||||
"cmd": "<command_name>",
|
||||
"startTime": <js_timestamp>,
|
||||
"endTime": <js_timestamp>
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
换句话说,`events` 属性包含两种类别的属性。
|
||||
|
||||
* 事件类型的名字属性
|
||||
* `commands` 属性
|
||||
|
||||
事件类型的名字属性对应的是事件发生时的时间戳列表。因为在一个会话周期内,事件可能发生多次,所以时间戳是个列表。事件的类型包含:
|
||||
|
||||
* `newSessionRequested`
|
||||
* `newSessionStarted`
|
||||
|
||||
(个别 driver 会定义属于它们自己的事件类型,所以在这里我们没法列出一个完整的事件列表。最好是从一个会话得到响应结果之后去检查各种可能的事件类型。)
|
||||
|
||||
`commands` 属性是一个对象列表。每个对象都包括一个 appium 的内部命令的名字(例如 `click`),也包括这个命令执行的开始时间和结束时间。
|
||||
|
||||
通过这些数据,你可以计算出时间之间的间隔,或者事件的精确时间轴,或者某个事件的平均时间的统计信息等等。
|
||||
|
||||
你只能获得调用 `/session/:id` 这个接口期间发生的事件数据,所以获取会话周期数据的最佳时间是在你正好要退出会话之前。
|
||||
|
||||
Appium团队维护了一个事件计时解析工具,这个工具可以解析事件计时的输出,然后生成各种报告:
|
||||
[appium/appium-event-parser](https://github.com/appium/appium-event-parser).
|
||||
|
||||
|
||||
|
||||
本文由 yanqiang@douban.com 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,47 +0,0 @@
|
||||
# Selenium Grid
|
||||
|
||||
使用 <b>"--nodeconfig"</b> 服务器参数,你可以在本地 selenium grid 里注册你的 appium 服务器。
|
||||
|
||||
```bash
|
||||
> node . -V --nodeconfig /path/to/nodeconfig.json
|
||||
```
|
||||
|
||||
在 node 的配置文件里,你需要定义 <b>"browserName"</b>,<b>"version"</b> 和 <b>"platform"</b>。
|
||||
基于这些参数,selenium grid 会将你的测试定向到正确的设备上去。你还需要配置你的 <b>host</b> 详细信息和
|
||||
<b>selenium grid</b> 的详细信息。你可以在 <a href="http://code.google.com/p/selenium/source/browse/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties">这里</a> 找到详细的参数列表和描述信息。
|
||||
|
||||
一旦你启动了 appium 服务器并且在 grid 里注册了信息,你会在 grid 控制台发现你的设备:
|
||||
|
||||
"http://<b>\<grid-ip-adress\></b>:<b>\<grid-port\></b>/grid/console"
|
||||
|
||||
## Grid 配置文件例子
|
||||
|
||||
```xml
|
||||
{
|
||||
"capabilities":
|
||||
[
|
||||
{
|
||||
"browserName": "<e.g._iPhone5_or_iPad4>",
|
||||
"version":"<version_of_iOS_e.g._6.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",
|
||||
"maxSession": 1,
|
||||
"register": true,
|
||||
"registerCycle": 5000,
|
||||
"hubPort": <grid_port>,
|
||||
"hubHost": "<Grid_host_name_or_grid_ip-address>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
可以在 <a href="http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/Platform.html">这里</a>查看有效的 platform 参数。
|
||||
如果没有给出url、host和 port,配置会自动指向本地:whatever-port-Appium-started-on。
|
||||
如果你的Appium服务和Selenium Grid服务没有运行在同一台机器上,为确保Selenium Grid连接正常,请在你的host & url docs上使用外部其它名称或IP地址,而非localhost 和 127.0.0.1
|
||||
55
docs/cn/advanced-concepts/grid.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Selenium Grid
|
||||
|
||||
通过 `--nodeconfig` 这个服务端参数,可以将 appium server 注册到本地的 [Selenium grid](https://code.google.com/p/selenium/wiki/Grid2) ([Grid 的配置文档](http://docs.seleniumhq.org/docs/07_selenium_grid.jsp))
|
||||
|
||||
```center
|
||||
> appium --nodeconfig /path/to/nodeconfig.json
|
||||
# 或者使用源文件执行
|
||||
> node . --nodeconfig /path/to/nodeconfig.json
|
||||
```
|
||||
|
||||
在 node 的配置文件里,你需要定义 `browserName`,`version` 和 `platform`。
|
||||
通过这些参数,selenium grid 会将你的测试定向到正确的设备上去。你还需要配置你的 `host` 详细信息和
|
||||
`selenium grid` 的详细信息。你可以在 <a href="http://code.google.com/p/selenium/source/browse/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties">这里</a> 找到详细的参数列表和描述信息。
|
||||
|
||||
一旦你启动了 appium 服务器并且在 grid 里注册了信息,就可以在 grid 控制台发现你的设备:
|
||||
|
||||
"http://**\<grid-ip-adress\>**:**\<grid-port\>**/grid/console"
|
||||
|
||||
### Grid node的配置文件例子
|
||||
|
||||
```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>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
可以在 <a href="http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/Platform.html">这里</a>查看有效的 platform 参数。
|
||||
|
||||
如果没有给出 `url`、`host` 和 `port`,配置会自动指向 `localhost:whatever-port-Appium-started-on`。
|
||||
|
||||
如果你的 Appium Server 和 Selenium Grid 没有运行在同一台机器上,为确保 Selenium Grid 连接正常,请在你的 `host` & `url` 上使用外部域名或 IP 地址,而不是 localhost 和 127.0.0.1
|
||||
|
||||
本文由 [tobecrazy](https://github.com/tobecrazy) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,202 +0,0 @@
|
||||
# 自动化混合应用
|
||||
|
||||
Appium 其中一个理念就是你不能为了测试应用而修改应用。为了符合这个方法学,我们可以使用 Selenium 测试传统 web 应用的方法来测试混合 web 应用 (比如,iOS 应用里的元素 "UIWebView" ),这是有可能的。这里会有一些技术性的复杂,Appium 需要知道你是想测试原生部分呢还是web部分。幸运的是,我们还能遵守 WebDriver 的协议。
|
||||
|
||||
* [混合 iOS 应用](hybrid.cn.md)
|
||||
* [混合 Android 应用](hybrid.cn.md)
|
||||
|
||||
## 自动化混合 iOS 应用
|
||||
|
||||
在你的 Appium 测试里,你需要以下几步来和 web 页面交涉:
|
||||
|
||||
1. 前往到应用里 web 视图激活的部分。
|
||||
1. 调用 [GET session/:sessionId/window_handles](http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/window_handles)
|
||||
1. 这会返回一个我们能访问的 web 视图的 id 的列表。
|
||||
1. 使用你想访问的这个 web 视图的 id 作为参数,调用 [POST session/:sessionId/window](http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/window)
|
||||
1. (这会将你的 Appium session 放入一个模式, 在这个模式下,所有的命令都会被解释成自动化web视图而不是原生的部分。比如,当你运行 getElementByTagName,它会在 web 视图的 DOM 上操作,而不是返回 UIAElements。当然,一个 Webdriver 的方法只能在一个上下文中有意义,所以如果在错误的上下文,你会收到错误信息。)
|
||||
1. 如果你想停止 web 视图的自动化,回到原生部分,你可以简单地使用 `execute_script` 调用 `"mobile: leaveWebView"` 方法来离开 web 层。
|
||||
|
||||
## 在 iOS 真机上运行
|
||||
|
||||
appium 使用一个远程调试器建立连接来实现和 web 视图的交互。当在模拟器上执行下面例子的时候,我们可以直接建立连接,因为模拟器和 appium 服务器在同一台机器上。
|
||||
|
||||
当在真机上运行用例时,appium 无法直接访问 web 视图,所以我们需要通过 USB 线缆来建立连接。我们使用 [ios-webkit-debugger-proxy](https://github.com/google/ios-webkit-debug-proxy)建立连接。
|
||||
|
||||
使用 brew 安装最新的 ios-webkit-debug-proxy。在终端运行一下命令:
|
||||
|
||||
``` bash
|
||||
# 如果你没有安装 brew 的话,先安装 brew。
|
||||
> ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go/install)"
|
||||
> brew update
|
||||
> brew install ios-webkit-debug-proxy
|
||||
```
|
||||
|
||||
你也可以通过 git 克隆项目来自己安装最新版本:
|
||||
|
||||
``` bash
|
||||
# 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
|
||||
```
|
||||
|
||||
一旦安装好了, 你就可以启动代理:
|
||||
|
||||
``` bash
|
||||
# 将udid替换成你的设备的udid。确保端口 27753 没有被占用
|
||||
# remote-debugger 将会使用这个端口。
|
||||
> ios_webkit_debug_proxy -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d
|
||||
```
|
||||
|
||||
<b>注意:</b> 这个 ios-webkit-debug-proxy 需要 <b>"web inspector"</b> 打开着以便建立连接。在 <b> settings > safari > advanced </b> 里打开它。请注意 web inspector <b>在 iOS6 时候加入的</b> 以前的版本没有。
|
||||
|
||||
## Wd.js Code example
|
||||
|
||||
```js
|
||||
// 假设我们已经有一个初始化好了的 `driver` 对象。
|
||||
driver.elementByName('Web, Use of UIWebView', function(err, el) { // 找到按钮,打开 web 视图
|
||||
el.click(function(err) { // 引导到 UIWebView
|
||||
driver.windowHandles(function(err, handles) { // 得到能访问的视图列表。
|
||||
driver.window(handles[0], function(err) { // 因为只有一个,所以选择第一个。
|
||||
driver.elementsByCss('.some-class', function(err, els) { // 通过 css 拿到元素。
|
||||
els.length.should.be.above(0); // 肯定有元素。
|
||||
els[0].text(function(elText) { // 得到第一个元素的文本。
|
||||
elText.should.eql("My very own text"); // 比较匹配文本。
|
||||
driver.execute("mobile: leaveWebView", function(err) { // 离开web视图上下文。
|
||||
// 如果你想的话,做一些原生应用的操作。
|
||||
driver.quit(); // 退出。
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
* 想看到具体的上下文,请看[该node 的例子](/sample-code/examples/node/hybrid.js)
|
||||
* *我们正在完善 web 视图下面的方法。[加入我们!](http://appium.io/get-involved.html)
|
||||
|
||||
## Wd.java 代码例子
|
||||
|
||||
```java
|
||||
//配置 webdriver 并启动 webview 应用。
|
||||
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
|
||||
desiredCapabilities.setCapability("device", "iPhone Simulator");
|
||||
desiredCapabilities.setCapability("app", "http://appium.s3.amazonaws.com/WebViewApp6.0.app.zip");
|
||||
URL url = new URL("http://127.0.0.1:4723/wd/hub");
|
||||
RemoteWebDriver remoteWebDriver = new RemoteWebDriver(url, desiredCapabilities);
|
||||
|
||||
// 切换到最新的web视图
|
||||
for(String winHandle : remoteWebDriver.getWindowHandles()){
|
||||
remoteWebDriver.switchTo().window(winHandle);
|
||||
}
|
||||
|
||||
//在 guinea-pig 页面用 id 和 元素交互。
|
||||
WebElement div = remoteWebDriver.findElement(By.id("i_am_an_id"));
|
||||
Assert.assertEquals("I am a div", div.getText()); //验证得到的文本是否正确。
|
||||
remoteWebDriver.findElement(By.id("comments")).sendKeys("My comment"); //填写评论。
|
||||
|
||||
//离开 webview,回到原生应用。
|
||||
remoteWebDriver.executeScript("mobile: leaveWebView");
|
||||
|
||||
//关闭应用。
|
||||
remoteWebDriver.quit();
|
||||
```
|
||||
|
||||
## Wd.rb cucumber 的例子
|
||||
|
||||
```ruby
|
||||
TEST_NAME = "Example Ruby Test"
|
||||
SERVER_URL = "http://127.0.0.1:4723/wd/hub"
|
||||
APP_PATH = "https://dl.dropboxusercontent.com/s/123456789101112/ts_ios.zip"
|
||||
capabilities =
|
||||
{
|
||||
'browserName' => 'iOS 6.0',
|
||||
'platform' => 'Mac 10.8',
|
||||
'device' => 'iPhone Simulator',
|
||||
'app' => APP_PATH,
|
||||
'name' => TEST_NAME
|
||||
}
|
||||
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => SERVER_URL)
|
||||
|
||||
## 这里切换到最近一个窗口是因为在我们的例子里这个窗口一直是 webview。其他的用例里,你需要自己指定。
|
||||
## 运行 @driver.window_handles,查看 appium 的日志,找出到底哪个窗口是你要的,然后找出相关的数字。
|
||||
## 然后用 @driver.switch_to_window(number),切换过去。
|
||||
|
||||
Given(/^I switch to webview$/) do
|
||||
webview = @driver.window_handles.last
|
||||
@driver.switch_to.window(webview)
|
||||
end
|
||||
|
||||
Given(/^I switch out of webview$/) do
|
||||
@driver.execute_script("mobile: leaveWebView")
|
||||
end
|
||||
|
||||
# 你可以使用 CSS 选择器在你的 webview 里来选择元素
|
||||
|
||||
And(/^I click a webview button $/) do
|
||||
@driver.find_element(:css, ".green_button").click
|
||||
end
|
||||
```
|
||||
### 用 ruby 调试 web 视图:
|
||||
我在我的帮助类里创建了一个快速方法来定位web元素,无论它在哪一个窗口视图。
|
||||
(这非常有帮助,特别是你的 webview 的 id 变化或者你用同一份代码来测试 Android 和 iOS。)
|
||||
https://gist.github.com/feelobot/7309729
|
||||
|
||||
## 自动化混合 Android 应用
|
||||
|
||||
Appium 通过 Chromedriver 内建混合应用支持。Appium 也可以使用 Selendroid 做为 4.4 之前的设备对 webview 支持的背部引擎。(你需要在 desired capability 里指定 `"device": "selendroid"`)。然后:
|
||||
|
||||
1. 前往你应用里 web 视图激活的部分。
|
||||
1. 用 "WEBVIEW" 做窗口句柄调用 [POST session/:sessionId/window](http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/window) , 比如 `driver.window("WEBVIEW")`。
|
||||
1. (这会将你的 Appium session 放入一个模式, 在这个模式下,所有的命令都会被解释成自动化web视图而不是原生的部分。比如,当你运行 getElementByTagName,它会在 web 视图的 DOM 上操作,而不是返回 UIAElements。当然,一个 Webdriver 的方法只能在一个上下文中有意义,所以如果在错误的上下文,你会收到错误信息。)
|
||||
1. 如果要停止web上下文里的自动化,回到原生部分的自动化,简单地使用 "NATIVE_APP" 调用 `window` 方法。比如 `driver.window("NATIVE_APP")`。
|
||||
|
||||
注意:我们可以像上面说的,使用同样的策略。然而,Selendroid 使用 `WEBVIEW`/`NATIVE_APP` 窗口设置策略。 Appium 常规的混合支持也使用这种策略。
|
||||
|
||||
## Wd.js 代码例子
|
||||
|
||||
```js
|
||||
// 假设我们已经初始化了一个 `driver` 实例。
|
||||
driver.window("WEBVIEW", function(err) { // 选择唯一的 WebView
|
||||
driver.elementsByCss('.some-class', function(err, els) { // 通过 CSS 取得元素
|
||||
els.length.should.be.above(0); // 验证元素存在
|
||||
els[0].text(function(elText) { // 得到第一个元素的文本
|
||||
elText.should.eql("My very own text"); // 验证文本内容
|
||||
driver.window("NATIVE_APP", function(err) { // 离开 webview 上下文
|
||||
// 可以做些原生应用的测试
|
||||
driver.quit(); // 关闭 webdriver
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Wd.java 代码例子
|
||||
|
||||
```java
|
||||
//配置 webdriver 并启动 webview 应用。
|
||||
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
|
||||
desiredCapabilities.setCapability("device", "Selendroid");
|
||||
desiredCapabilities.setCapability("app", "/path/to/some.apk");
|
||||
URL url = new URL("http://127.0.0.1:4723/wd/hub");
|
||||
RemoteWebDriver remoteWebDriver = new RemoteWebDriver(url, desiredCapabilities);
|
||||
|
||||
// 切换到最新的web视图
|
||||
remoteWebDriver.switchTo().window("WEBVIEW");
|
||||
|
||||
//在 guinea-pig 页面用 id 和 元素交互。
|
||||
WebElement div = remoteWebDriver.findElement(By.id("i_am_an_id"));
|
||||
Assert.assertEquals("I am a div", div.getText()); //验证得到的文本是否正确。
|
||||
remoteWebDriver.findElement(By.id("comments")).sendKeys("My comment"); //填写评论。
|
||||
|
||||
//离开 webview,回到原生应用。
|
||||
remoteWebDriver.switchTo().window("NATIVE_APP");
|
||||
|
||||
//关闭应用。
|
||||
remoteWebDriver.quit();
|
||||
```
|
||||
143
docs/cn/advanced-concepts/hybrid.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 自动化混合应用
|
||||
|
||||
Appium 其中一个理念就是你不能为了测试应用而修改应用。为了符合这个方法学,我们可以使用 Selenium 测试传统 web 应用的方法来测试混合 web 应用 (比如,iOS 应用里的元素 "[UIAWebView](https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAWebViewClassReference/)") ,这是有可能的。这里会有一些技术性的复杂,Appium 需要知道你是想测试原生部分呢还是web部分。幸运的是,我们还能遵守 WebDriver 的协议。
|
||||
|
||||
在 Appium 测试里,你需要以下几步来和 web 页面交涉:
|
||||
|
||||
1. 切到 webview 部分
|
||||
1. 调用 [GET session/:sessionId/contexts](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)
|
||||
1. 这会返回一个我们能访问的 context 的列表,比如 'NATIVE_APP' 或者 'WEBVIEW_1'
|
||||
1. 用 context 的 id 作为参数,调用[POST session/:sessionId/context](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)方法,切换到 webview 中去。
|
||||
1. (这会将你的 Appium session 放入一个模式, 在这个模式下,所有的命令都会被解释成自动化 web 视图而不是原生的部分。比如,当你运行 getElementByTagName,它会在 web 视图的 DOM 上操作,而不是返回 UIAElements。当然,一个 Webdriver 的方法只能在一个上下文中有意义,所以如果在错误的上下文,你会收到错误信息。)
|
||||
1. 如果你想停止 web 视图的自动化,回到原生部分,你可以简单地用 `context` 调用来离开 web 层,参数传原生 context id 即可。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
// 假定你已经初始化driver
|
||||
driver
|
||||
.contexts().then(function (contexts) { // 获取view列表,返回数组格式: ["NATIVE_APP","WEBVIEW_1"]
|
||||
return driver.context(contexts[1]); // 选择 webview context
|
||||
})
|
||||
|
||||
// 执行web测试
|
||||
.elementsByCss('.green_button').click()
|
||||
|
||||
.context('NATIVE_APP') // leave webview context
|
||||
|
||||
//把native操作放这里
|
||||
|
||||
.quit() // 退出driver
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
// 假定我们设置了capabilities
|
||||
driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
|
||||
|
||||
Set<String> contextNames = driver.getContextHandles();
|
||||
for (String contextName : contextNames) {
|
||||
System.out.println(contextNames); //输出 NATIVE_APP \n WEBVIEW_1
|
||||
}
|
||||
driver.context(contextNames.toArray()[1]); // 设置当前 context 为 WEBVIEW_1
|
||||
|
||||
//执行web测试
|
||||
String myText = driver.findElement(By.cssSelector(".green_button")).click();
|
||||
|
||||
driver.context("NATIVE_APP");
|
||||
|
||||
//如果需要此次放置native测试脚本
|
||||
|
||||
driver.quit();
|
||||
```
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
# 假定我们设置了capabilities
|
||||
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => SERVER_URL)
|
||||
|
||||
# I switch to the last context because its always the webview in our case, in other cases you may need to specify a context
|
||||
# View the appium logs while running @driver.contexts to figure out which context is the one you want and find the associated ID
|
||||
# Then switch to it using @driver.switch_to.context("WEBVIEW_6")
|
||||
|
||||
Given(/^I switch to webview$/) do
|
||||
webview = @driver.contexts.last
|
||||
@driver.switch_to.context(webview)
|
||||
end
|
||||
|
||||
Given(/^I switch out of webview$/) do
|
||||
@driver.switch_to.context(@driver.contexts.first)
|
||||
end
|
||||
|
||||
# Now you can use CSS to select an element inside your webview
|
||||
|
||||
And(/^I click a webview button $/) do
|
||||
@driver.find_element(:css, ".green_button").click
|
||||
end
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
# assuming we have an initialized `driver` object for an app
|
||||
|
||||
# switch to webview
|
||||
webview = driver.contexts.last
|
||||
driver.switch_to.context(webview)
|
||||
|
||||
# do some webby stuff
|
||||
driver.find_element(:css, ".green_button").click
|
||||
|
||||
# switch back to native view
|
||||
driver.switch_to.context(driver.contexts.first)
|
||||
|
||||
# do more native testing if we want
|
||||
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
// assuming we have an initialized `driver` object in an AppiumTestCase
|
||||
|
||||
public function testThings()
|
||||
{
|
||||
$expected_contexts = array(
|
||||
0 => 'NATIVE_APP',
|
||||
1 => 'WEBVIEW_1'
|
||||
);
|
||||
|
||||
$contexts = $this->contexts();
|
||||
$this->assertEquals($expected_contexts, $contexts);
|
||||
|
||||
$this->context($contexts[1]);
|
||||
$context = $this->context();
|
||||
$this->assertEquals('WEBVIEW_1', $context);
|
||||
|
||||
// do webby stuff
|
||||
|
||||
$this->context('NATIVE_APP');
|
||||
|
||||
// do mobile stuff
|
||||
}
|
||||
```
|
||||
## 自动化 Android 的混合应用
|
||||
|
||||
Appium 通过 Chromedriver 内建混合应用支持。Appium 也可以使用 Selendroid 支持 4.4 之前的设备的 webview 测试。(你需要在 desired capability 里指定 `"device": "selendroid"`)。
|
||||
|
||||
请确保
|
||||
[setWebContentsDebuggingEnabled](http://developer.android.com/reference/android/webkit/WebView.html#setWebContentsDebuggingEnabled(boolean)) 设置为 true。具体见[remote debugging docs](https://developer.chrome.com/devtools/docs/remote-debugging#configure-webview).
|
||||
|
||||
一旦你设置了 desired capabilities,开始一个 appium 会话,遵循上面的教程。
|
||||
|
||||
## 自动化 iOS 混合应用
|
||||
|
||||
Appium 使用 remote debugger 创建和 webview 的交互连接。当在模拟器上执行下面例子的时候,我们可以直接建立连接,因为模拟器和 appium 服务器在同一台机器上。
|
||||
|
||||
一旦你设置了 desired capabilities,开始一个 appium 会话,遵循上面的教程。
|
||||
|
||||
## 在 iOS 真机上运行
|
||||
|
||||
当在真机上运行用例时,appium 无法直接访问 web 视图,所以我们需要通过 USB 线缆来建立连接。我们使用 [ios-webkit-debugger-proxy](https://github.com/google/ios-webkit-debug-proxy)建立连接。
|
||||
|
||||
如何安装和使用 iOS webkit debug proxy,请参考 [iOS webkit debug proxy](/docs/cn/advanced-concepts/ios-webkit-debug-proxy.md)
|
||||
|
||||
本文由 [tobecrazy](https://github.com/tobecrazy) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
73
docs/cn/advanced-concepts/ios-webkit-debug-proxy.md
Normal file
@@ -0,0 +1,73 @@
|
||||
## iOS WebKit 调试代理
|
||||
|
||||
借助 [ios_webkit_debug_proxy](https://github.com/google/ios-webkit-debug-proxy),Appium 可以在 iOS 真机上访问 webview。
|
||||
|
||||
### 安装
|
||||
|
||||
#### 使用 Homebrew
|
||||
|
||||
在终端执行以下命令使用 Homebrew 安装最新版本的 ios-webkit-debug-proxy:
|
||||
|
||||
``` center
|
||||
# 没有安装 brew 时才需要第一条命令。
|
||||
> ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
> brew update
|
||||
> brew install ios-webkit-debug-proxy
|
||||
```
|
||||
|
||||
#### 从源码构建 ios-webkit-debug-proxy
|
||||
|
||||
在你的 mac 上打开终端。你可以通过喜欢的搜索引擎查找如何打开终端的操作指南。打开后确认你已经安装了 [Homebew](http://brew.sh/):
|
||||
|
||||
```shell
|
||||
$ brew -v
|
||||
```
|
||||
|
||||
确认 Homebrew 已安装后,按下面的做( $ 是命令行提示符,不用输入):
|
||||
|
||||
```shell
|
||||
$ cd ~
|
||||
$ sudo apt-get install autoconf automake libusb-dev libusb-1.0-0-dev libplist-dev libplist++-dev usbmuxd libtool libimobiledevice-dev
|
||||
$ git clone https://github.com/google/ios-webkit-debug-proxy.git
|
||||
$ cd ios-webkit-debug-proxy
|
||||
$ ./autogen.sh
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
#### 运行 ios-webkit-debug-proxy
|
||||
|
||||
安装后使用以下命令启动代理:
|
||||
|
||||
``` center
|
||||
# 修改 udid 为目标设备的 udid 并确认 remote-debugger 使用 27753 端口。
|
||||
# 你可以从苹果开发者资源平台学习如何获取 UDID 。
|
||||
> ios_webkit_debug_proxy -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d
|
||||
```
|
||||
|
||||
你也可以设置 'startIWDP' desired capability 为 true (https://github.com/appium/appium/blob/master/docs/cn/writing-running-appium/caps.md)。Appium 会开启一个子进程运行上述命令并设置 udid,所以你不再需要自己运行 ios_webkit_debug_proxy 。Appium 会监控 ios-webkit-debug-proxy,一旦崩溃就会重启。
|
||||
|
||||
``` center
|
||||
// desired capabilities 示例
|
||||
{
|
||||
"browserName": "Safari",
|
||||
"platformName": "iOS",
|
||||
"deviceName": "iPhone 7",
|
||||
"automationName": "XCUITest",
|
||||
"startIWDP": true,
|
||||
"udid": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
你也可以使用 `ios-webkit-debug-proxy-launcher` —— Appium 代码库中的一个小脚本 —— 来启动代理。它会监控日志中的错误,并在需要时重启代理。
|
||||
|
||||
``` center
|
||||
# 修改 udid
|
||||
# 注意,在 Appium 仓库中运行
|
||||
> ./bin/ios-webkit-debug-proxy-launcher.js -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d
|
||||
```
|
||||
|
||||
**注意:** 为了允许建立连接,设备上需要打开 **"Web 检查器"**。在 **设置 >
|
||||
safari > 高级** 中打开。Web 检查器作为 iOS6 的一部分被添加,不在之前的版本中提供,请知悉。
|
||||
|
||||
本文由 [sanlengjingvv](https://testerhome.com/sanlengjingvv) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
17
docs/cn/advanced-concepts/iwd_xcode7.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## 为 xcode 7 和 iOS >= 9.0 配置无延迟 instruments(iwd)
|
||||
|
||||
iOS >= 9.0 时,需要手动通过命令行传递二进制文件来配置无延迟的 instruments (在 xcode < 7 时 appium 会自动加上 ),参阅 [iwd](https://github.com/lawrencelomax/instruments-without-delay/tree/xcode7-quirks#xcode-7--ios-9-support)
|
||||
|
||||
在 xcode >= 7 时启用 iwd :
|
||||
- 下载 [appium-instruments](https://github.com/appium/appium-instruments)
|
||||
- 在 `<appium-instruments>/bin/` 下根据以下指示的参数运行 `xcode-iwd.sh` :
|
||||
|
||||
```
|
||||
sh <appium-instruments>/bin/xcode-iwd.sh <path to xcode> <path to appium-instruments>
|
||||
```
|
||||
比如: `sh ./bin/xcode-iwd.sh /Applications/Xcode.app /Users/xyz/appium-instruments/`
|
||||
|
||||
注意:Xcode 7 的 iwd 只在 iOS >= 9.0 时有效,你可以在 iOS < 9.0 时切换一个旧版本的 Xcode
|
||||
|
||||
由 @黑水 翻译,TesterHome 社区 id:sanlengjingvv
|
||||
由 [@chenhengjie123](https://github.com/chenhengjie123) 校验
|
||||
@@ -1,109 +0,0 @@
|
||||
# 把appium 0.18.x上的测试用例集迁移到appium1.x上
|
||||
|
||||
Appium 1.0 已经从先前的版本中移除了一部分过时的特性, 这个指导文档会帮助你了解使用Appium 1.0需要做的具体改变.
|
||||
|
||||
## 新的客户端库
|
||||
|
||||
你需要关注的最大的改变是利用新的appium的client libraries来替换原生的WebDriver ciients. 访问[Appium client list](appium-clients.md) 去寻找符合你自己编程语言的客户端库吧. 在每个客户端的网站上都可以找到用于集成到你代码中的依赖库相关介绍和下载
|
||||
|
||||
基本上, 你需要做如下的改变(以Python作为例子)
|
||||
|
||||
用
|
||||
```
|
||||
from appium import webdriver
|
||||
```
|
||||
|
||||
替换原来的:
|
||||
|
||||
```
|
||||
from selenium import webdriver
|
||||
```
|
||||
|
||||
## 新的适配参数
|
||||
|
||||
下面的适配参数将不再使用
|
||||
* `device`
|
||||
* `version`
|
||||
|
||||
取而代之的是利用下面的配置参数
|
||||
|
||||
* `platformName` ("iOS" 或者 "Android")
|
||||
* `platformVersion` (你希望测试的os版本)
|
||||
* `deviceName` (你想用的设备, 比如 "iPhone Simulator")
|
||||
* `automationName` ("Selendroid" 如果你想使用Selendroid的话, 否则可以省略)
|
||||
|
||||
|
||||
`app` 配置参数保持不变, 但是特指非浏览器的app, 如果你想使用类似Safari或者Chrome这样的浏览器, 你需要设置`browserName`. 这代表`app`和`browserName`是互斥的.
|
||||
|
||||
我们把appium的配置参数都规范为驼峰拼写法(camelCase), 这代表着原来的`app-package`或者`app-wait-activity`现在会变成`appPackage`和`appWaitActivity`. 当然目前android的app package和activity都已经是自动探测了, 大部分情况下你可以省略这两个配置项.
|
||||
|
||||
## 新的定位方式
|
||||
|
||||
我们已经移除了下面的定位方式
|
||||
|
||||
* `name`
|
||||
* `tag name`
|
||||
|
||||
我们增加了`accessibility_id`定位方法去做过去`name`做的事情. 具体的细节还得跟你使用的Appium客户端库有关.
|
||||
|
||||
`tag name`已经被替换为`class name`. 所以想通过UI的类型来定位某个元素, 你需要使用class name定位方式
|
||||
|
||||
关于`class name`和`xpath`的定位方式: 现在需要使用完整的全类名, 这意味着如果你有一个如下的定位用的xpath
|
||||
|
||||
```
|
||||
//table/cell/button
|
||||
```
|
||||
现在需要改成
|
||||
|
||||
```
|
||||
//UIATableView/UIATableCell/UIAButton
|
||||
```
|
||||
|
||||
如果是android的话, `button`需要改变成`android.widget.Button`
|
||||
|
||||
我们也增加了如下的定位方式
|
||||
|
||||
* `-ios uiautomation`
|
||||
* `-android uiautomator`
|
||||
|
||||
根据你使用的客户端去相应的使用新的定位方式
|
||||
|
||||
## 使用xml, 不再是json了
|
||||
|
||||
App source方法先前返回JSON, 现在修改成返回XML. 所以如果你有代码是依赖解析app source的, 那么就需要更新
|
||||
|
||||
## 通过context支持混合应用, 不再是window了
|
||||
|
||||
以前混合app的切换支持是通过"windows"
|
||||
|
||||
* `window_handles`
|
||||
* `window`
|
||||
* `switch_to.window`
|
||||
|
||||
现在Appium支持"context" 概念了, 要获得当前环境下所有的上下文(contexts), 或者特定的context, 你可以用
|
||||
|
||||
```python
|
||||
driver.contexts
|
||||
current = driver.context
|
||||
```
|
||||
|
||||
在这些context之间切换, 可以使用
|
||||
|
||||
```python
|
||||
driver.switch_to.context("WEBVIEW")
|
||||
```
|
||||
|
||||
## 没有了`execute_script("mobile: xxx")`
|
||||
|
||||
所有的`mobile:`方法都已经被移除, 并且被替换为appium client libraries的原生方法. 这意味着如果一个方法调用原来的方式是
|
||||
`driver.execute("mobile: lock", [5])`
|
||||
现在需要更新为
|
||||
`driver.lock(5)`
|
||||
在这个地方`lock`已经变成了原生的客户端方法. 当然具体的调用细节在不同的客户端库中的实现可能会有所差别.
|
||||
|
||||
特别需要注意的是, 手势(gesture)方法已经被替换为TouchAction / MultiAction API, 它允许更强大通用的组合手势的自动化. 可以参考你的客户端库的具体用法.
|
||||
|
||||
这就是全部啦, 祝迁移愉快
|
||||
|
||||
(文档由testerhome.com翻译, 欢迎更多热爱技术的同学加入到翻译中来, We Love Appium)
|
||||
|
||||
168
docs/cn/advanced-concepts/migrating-to-1-0.md
Normal file
@@ -0,0 +1,168 @@
|
||||
*这是一个旧文档,只有从早期版本迁移到 Appium 1.x 的用户才有兴趣。*
|
||||
|
||||
## 将您的测试从 Appium 0.18.x 迁移到 Appium 1.x
|
||||
|
||||
Appium 1.0 中删除了许多之前版本就不推荐使用的功能。 本指南将帮助您了解在测试套件中需要做哪些修改才可以很好利用Appium 1.0。
|
||||
|
||||
### 新的客户端库
|
||||
|
||||
The biggest thing you need to worry about is using the new Appium client libraries instead of the vanilla WebDriver clients you are currently using. Visit the [Appium client list](/docs/cn/about-appium/appium-clients.md) to find the client for your language. Downloads and instructions for integrating into your code are available on the individual client websites.
|
||||
|
||||
您最需要担心的是使用新的 Appium 客户端库,而不是您正在使用的普通 WebDriver 客户端。 访问[Appium客户端列表](/docs/cn/about-appium/appium-clients.md)以找到匹配您的语言的客户端。 你可以在各个客户端网站上找到下载地址和如何集成到你的测试代码的教程。
|
||||
|
||||
最终,你会做以下一些事情(以Python为例):
|
||||
|
||||
```center
|
||||
from appium import webdriver
|
||||
```
|
||||
|
||||
代替:
|
||||
|
||||
```center
|
||||
from selenium import webdriver
|
||||
```
|
||||
|
||||
### 新的 desired capabilities
|
||||
|
||||
不再使用以下的 capabilities:
|
||||
|
||||
* `device`
|
||||
* `version`
|
||||
|
||||
使用这些功能替换:
|
||||
|
||||
* `platformName`(“iOS”或“Android”)
|
||||
* `platformVersion`(你想要的手机操作系统版本)
|
||||
* `deviceName`(你想要的那种设备,就像“iPhone模拟器”)
|
||||
* `automationName`(“Selendroid”如果你想使用,可以使用Selendroid,除此之外,可以省略这一点)
|
||||
|
||||
`app` capability 保持不变,但现在专指非浏览器 app。 要使用 Safari 或 Chrome 等浏览器,请使用标准的 `browserName` capability。这意味着 `app` 和 `browserName` 是互斥的。
|
||||
|
||||
针对 Appium 服务端的 capability,我们统一了驼峰式风格。这意味着像 `app-package` 或 `app-wait-activity` 这样的上限现在分别是 `appPackage` 和 `appWaitActivity`。当然,由于 Android 应用的包名和 activity 现在已被自动检测到,在大多数情况下,您应该可以完全省略它们。
|
||||
|
||||
### 新的定位策略
|
||||
|
||||
我们删除了以下定位器策略:
|
||||
|
||||
* `name`
|
||||
* `tag name`
|
||||
|
||||
我们添加了 `accessibility_id` 策略来替代 `name` 曾经的作用。具体细节将与您的 Appium 客户端相关。
|
||||
|
||||
`tag name` 已被 `class name`替换。 所以要通过 UI 类型找到一个元素,在你的客户脚本里使用类名定位器策略。
|
||||
|
||||
Note about `class name` and `xpath` strategies: these now require the fully-qualified class name for your element. This means that if you had an xpath selector that looked like this:
|
||||
|
||||
关于 `class name` 和 `xpath` 策略的注意事项:这些策略现在需要元素完全限定类名。 这意味着如果你有一个如下所示的 xpath 选择器:
|
||||
|
||||
```center
|
||||
//table/cell/button
|
||||
```
|
||||
|
||||
现在需要:
|
||||
|
||||
```center
|
||||
//UIATableView/UIATableCell/UIAButton
|
||||
```
|
||||
|
||||
(同样对于Android:`button` 现在需要是 `android.widget.Button`)
|
||||
|
||||
我们还添加了以下定位器策略:
|
||||
|
||||
* `-ios uiautomation`
|
||||
* `-android uiautomator`
|
||||
|
||||
参考你的客户端了解如何使用这些新的定位策略。
|
||||
|
||||
### XML, not JSON
|
||||
|
||||
App source methods, which previously returned JSON, now return XML, so if you have code that relies on parsing the app source, it will need to be updated.
|
||||
|
||||
以前返回 JSON 的 app source 方法现在返回 XML,因此如果您有代码依赖于解析 app source,则需要更新。
|
||||
|
||||
### Hybrid 通过 context 支持,而不是 window
|
||||
|
||||
以前通过在 "windows" 之间切换支持 hybrid app
|
||||
|
||||
* `window_handles`
|
||||
* `window`
|
||||
* `switch_to.window`
|
||||
|
||||
现在 Appium 使用概念上更加贴切的 "context"。要获得所有可用的 context,或应用程序特定的 context,您可以使用以下方法
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.contexts
|
||||
current = driver.context
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.contexts().then(function (contexts) { /*...*/ })
|
||||
```
|
||||
|
||||
```c#
|
||||
// c#
|
||||
driver.GetContexts ()
|
||||
driver.GetContext ()
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
Set<String> contextNames = driver.getContextHandles();
|
||||
String context = driver.getContext();
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
$contexts = $this->contexts();
|
||||
$context = $this->context();
|
||||
```
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
contexts = available_contexts
|
||||
context = current_context
|
||||
```
|
||||
|
||||
在他们之间切换,你使用以下方法
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.switch_to.context("WEBVIEW")
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.currentContext().then(function (context) { /*...*/ })
|
||||
```
|
||||
|
||||
```c#
|
||||
// c#
|
||||
driver.SetContext ("WEBVIEW");
|
||||
```
|
||||
|
||||
```java
|
||||
java
|
||||
driver.context(contextName);
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
$this->context('WEBVIEW');
|
||||
```
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
set_context "WEBVIEW"
|
||||
```
|
||||
|
||||
### 不再有 `execute_script("mobile: xxx")`
|
||||
|
||||
所有 `mobile: ` 方法已被删除,并已被 Appium 客户端库中的原生方法所替代。这意味着像 `driver.execute("mobile: lock", [5])` 的方法调用,现在可能会是 `driver.lock(5)`(其中 `lock` 已经变成原生的客户端方法)。 当然,调用这些方法的细节会因客户端而异。
|
||||
|
||||
特别值得注意的是,手势方法已被新的 TouchAction / MultiAction API 所取代,该 API 允许一种更强大更普遍的方法将手势自动化放在一起。有关TouchAction / MultiAction 的使用说明,请参考您的Appium客户端。
|
||||
|
||||
就是这样!快乐的迁移!
|
||||
|
||||
本文由 [高鹏](https://testerhome.com/026) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
126
docs/cn/advanced-concepts/migrating-to-xcuitest.md
Normal file
@@ -0,0 +1,126 @@
|
||||
## 将你的iOS测试从UIAutomation(iOS 9.3及更低版本)迁移到XCUITest(iOS 9.3及更高版本)
|
||||
|
||||
对于 iOS 自动化,Appium 依赖苹果提供的系统框架。对于 iOS 9.2 及更低版本,苹果唯一的自动化技术被称为UIAutomation,它运行在 “Instruments” 中。从 iOS 10 开始,苹果已经完全删除了 UIAutomation 工具,因此 Appium 不可能按照以前的方式进行测试。同时,苹果推出了一款名为 XCUITest 的新型自动化技术,从 iOS 9.3 到 iOS 10 及以上版本,这将是苹果唯一支持的自动化框架。
|
||||
|
||||
Appium 从 Appium 1.6 开始支持 XCUITest。在大多数情况下,XCUITest 的功能与 UIAutomation 的功能相匹配,因此,Appium 团队能够确保测试行为保持不变。这是使用 Appium 的好处之一!即使苹果完全改变了测试使用的技术,你的脚本可以保持大致相同!话虽如此,如果您想在 XCUITest 运行它们,还是存在些许差异,您需要关注测试脚本中需要修改的部分。本文将帮助您解决这些差异。
|
||||
|
||||
### 元素类名称模式
|
||||
|
||||
在 XCUITest 中,苹果已经为构成视图层次结构的 UI 元素提供了不同的类名。例如,`UIAButton` 现在为`XCUIElementTypeButton`。在很多情况下,这两个类之间有直接映射。如果您使用 `class name` 定位器策略来查找元素,Appium 1.6 将为您重写选择器。同样,如果你使用xpath定位器策略,Appium 1.6 将在 XPath 字符串中找到所有 `UIA*` 元素,并适当地重写它们。
|
||||
|
||||
但是,这并不能保证你的测试可以完全相同地运行,原因有两个:
|
||||
|
||||
1. Appium 通过 XCUITest 和 UIAutomation 看到的应用的层次结构不一定是相同的。如果你有基于路径的 XPath 选择器,则可能需要进行调整。
|
||||
|
||||
2. 类名列表也不完全一样。许多由 XCUITest 返回的元素属于`XCUIElementTypeOther类`,这是一种全新的容器。
|
||||
|
||||
### 页面源码
|
||||
|
||||
如上述,如果你依赖 `page source` 命令返回的 app 源 XML,那么这个输出的 XML 会与基于 UIAutomation 的结果会有显著不同。
|
||||
|
||||
### `-ios uiautomation` 定位策略
|
||||
|
||||
此定位器策略专门用于 UIAutomation,因此它不包括在 XCUITest 中。 在即将发布的版本中,我们将致力于类似的 “native” 型定位策略。
|
||||
|
||||
### `xpath` 定位策略
|
||||
|
||||
1. 尽量不要使用 XPath 定位器,除非你完全没有其他选择。 通常,xpath 定位器可能比其他类型的定位器慢,比如accessibility id,类名和谓词(在某些特殊情况下可减缓100倍)。 它们太慢了,因为 xpath 的位置不是苹果的XCTest 框架本身所支持的。
|
||||
|
||||
2. 使用
|
||||
|
||||
```
|
||||
driver.findElement(x)
|
||||
```
|
||||
|
||||
而不是使用
|
||||
|
||||
```
|
||||
driver.findElements(x)[0]
|
||||
```
|
||||
|
||||
通过xpath查找单个元素。 您的定位器匹配的UI元素越多,你的脚本越慢。
|
||||
|
||||
3. 在通过 xpath 定位元素时,一定要使用非常具体的xpath。 像这样的定位器
|
||||
|
||||
```
|
||||
//*
|
||||
```
|
||||
|
||||
可能需要几分钟才能完成,具体取决于您的应用程序有多少用户界面元素(例如,
|
||||
|
||||
```
|
||||
driver.findElement(By.xpath("//XCUIElementTypeButton[@value='blabla']"))
|
||||
```
|
||||
|
||||
比
|
||||
|
||||
```
|
||||
driver.findElement(By.xpath("//*[@value='blabla']"))
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```
|
||||
driver.findElement(By.xpath("//XCUIElementTypeButton")))
|
||||
```
|
||||
|
||||
要快很多。
|
||||
|
||||
4. 在大多数情况下,执行多个嵌套的 findElement 调用比执行 xpath 单个调用更快(例如,
|
||||
|
||||
```
|
||||
driver.findElement(x).findElement(y)
|
||||
```
|
||||
通常比
|
||||
|
||||
```
|
||||
driver.findElement(z)
|
||||
```
|
||||
|
||||
要快
|
||||
|
||||
其中x和y不是xpath定位符,z是xpath定位符)。
|
||||
|
||||
### 系统依赖
|
||||
|
||||
除了升级 XCode 会带来(与Appium无关)许多问题之外,Appium 对 XCUITest 的支持还需要一个新的系统依赖:[Carthage](https://github.com/Carthage/Carthage)。Appium Doctor 现已更新,以确保`carthage`二进制在你的系统路径里。
|
||||
|
||||
### API差异
|
||||
|
||||
Unfortunately, the XCUITest API and the UIAutomation API are not equivalent. In many cases (like with `tap/click`), the behavior is identical. But some features that were available in the UIAutomation backend are not yet available in the new XCUITest backend. These known lacking features include:
|
||||
|
||||
不幸的是,XCUITest API 和 UIAutomation API 还是有差别的。在许多情况下(比如 tap/click),行为是相同的,但在 UIAutomation 作为底层驱动时,可用的某些功能在新的 XCUITest 时尚不可用。下面是已知的缺乏的功能:
|
||||
|
||||
* 地理位置支持(例如: `driver.location`)
|
||||
* 振动设备
|
||||
* 锁定设备
|
||||
* 旋转设备(device _orientation_ 是支持的)
|
||||
|
||||
|
||||
We will endeavor to add these features back in future releases of Appium.
|
||||
|
||||
我们在努力把这些功能加到 Appium 的未来版本里。
|
||||
|
||||
#### 滚动和点击
|
||||
|
||||
在之前基于 UIAutomation 的驱动中,如果您尝试单击不在视图中的元素,UIAutomation 将自动滚动到该元素,然后点击它。 使用 XCUITest,不是这样。 点击之前,你需要确保元素可见(与用户看到才能点击的行为一致)。
|
||||
|
||||
### 其他已知问题
|
||||
|
||||
Finally, a list of known issues with the initial 1.6 release (we'll strike through issues which have been resolved):
|
||||
|
||||
最后,列出了初始 1.6 版本的已知问题(已解决的问题会被横线划去):
|
||||
|
||||
* ~~无法以横向模式与设备上的元素进行交互(https://github.com/appium/appium/issues/6994)~~
|
||||
* `shake` 苹果不支持所以我们没有实现
|
||||
* `lock` 苹果不支持所以我们没有实现
|
||||
* 设置地理位置不被苹果支持,我们也不支持
|
||||
* 通过TouchAction / MultiAction API,`zoom` 手势支持,因为苹果的一个bug,`pinch` 手势不支持。
|
||||
* ~~通过TouchAction / MultiAction API,`swipe`手势目前不受支持,应该很快解决(https://github.com/appium/appium/issues/7573)~~
|
||||
* `autoAcceptAlerts`, `autoDismissAlerts`目前还不能工作,而且我们是否能够在将来实施这些,存在争议。
|
||||
* iOS SDK 有一个问题,因此使用某些 API 方法构建的 PickerWheels 不能由 XCUITest 自动执行。有关解决方法,请参阅https://github.com/appium/appium/issues/6962,以确保您的 PickerWheels 正确构建。
|
||||
|
||||
我们将尽可能添加缺失的功能,并在以后的 Appium 版本中修复其他已知问题。
|
||||
|
||||
|
||||
本文由 [校长](https://testerhome.com/xushizhao) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,40 +0,0 @@
|
||||
## Settings
|
||||
|
||||
Settings 是 Appium 引入的一个新的概念。 它目前还没有被纳入 Mobile JSON Wire Protocol 及 Webdriver 标准之中。
|
||||
|
||||
Settings 是一种用来配置 Appium 服务器的方式。
|
||||
|
||||
Settings 有以下特点:
|
||||
- 可变的,它在同一会话中是可以被修改的。
|
||||
- 唯一的,它在被测应用会话中是唯一的。 它在每创建一个新会话时会被重置。
|
||||
- 可控的,它在自动化测试过程中控制着 Appium 服务器的运行。 它们不会被用来控制被测应用或被测终端。
|
||||
|
||||
在 Android 环境中 以 `ignoreUnimportantViews` 设置举例,该参数在 Android 环境中可以被设置成忽略所有与当前视图无关的元素,它将使测试过程更加有效率。 然而当我们希望能够访问被忽略的元素时,我们必须在将 `ignoreUnimportantViews` 设置成 *true* 后,重新修改成 *false* 。
|
||||
|
||||
另外也可以通过 Settings 配置让 Appium 忽略所有当前不可见的元素。
|
||||
|
||||
Settings 可以通过以下 API 方法进行配置:
|
||||
|
||||
**POST** /session/:sessionId/appium/settings
|
||||
|
||||
>以 JSON 格式提交 key:value 键值对形式的Settings配置。
|
||||
```
|
||||
{
|
||||
settings: {
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**GET** /session/:sessionId/appium/settings
|
||||
|
||||
>以 JSON 格式返回当前所有 Settings 配置。
|
||||
```
|
||||
{
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
```
|
||||
|
||||
### 其它 Settings 配置参考
|
||||
|
||||
**"ignoreUnimportantViews"** -该参数值为 *true* 或 *false*。 如果你希望能够尽量减少测试过程的交互确认过程,或希望测试脚本能更快的执行,可以在 Android 终端环境下使用 `setCompressedLayoutHeirarchy()` 参数。它将忽略所有被标记为 IMPORTANT_FOR_ACCESSIBILITY_NO 或 IMPORTANT_FOR_ACCESSIBILITY_AUTO(以及那些被认为不是很重要的系统元素)的元素。
|
||||
58
docs/cn/advanced-concepts/settings.md
Normal file
@@ -0,0 +1,58 @@
|
||||
## Settings
|
||||
Settings是appium引入的一个新概念。 它们目前不是Mobile JSON Wire协议或Webdriver规范的一部分。
|
||||
|
||||
Settings是用来指定appium server的工作方式。
|
||||
|
||||
Settings有以下特点:
|
||||
- 可变性,Settings在一个会话中是可以被修改的。
|
||||
- 临时性,Settings只对当前会话生效,新建立的会话会被重置。
|
||||
- 局限性,Settings只用来控制appium server,不能用于控制被测应用或设备。
|
||||
|
||||
以Android的`ignoreUnimportantViews`为例。Android中可以设置`ignoreUnimportantViews`用来忽略所有与当前视图无关的元素,这样可以让用例执行的更快。注意,当用户需要访问这些被忽略的元素时,需要禁用`ignoreUnimportantViews`后并重新启用。
|
||||
|
||||
另外一个例子是Settings让appium忽略当前不可见的元素。
|
||||
|
||||
Settings通过下面的API实现:
|
||||
|
||||
**POST** /session/:sessionId/appium/settings
|
||||
|
||||
>Settings使用键值对(name:value)的JSON格式,name为setting的名字,value是setting的取值。
|
||||
```
|
||||
{
|
||||
settings: {
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**GET** /session/:sessionId/appium/settings
|
||||
|
||||
>以JSON格式返回当前所有配置。
|
||||
```
|
||||
{
|
||||
ignoreUnimportantViews : true
|
||||
}
|
||||
```
|
||||
|
||||
注意,实际的命令因您的脚本所使用的语言而异; 请参阅具体的Appium客户端文档以获取更多信息。
|
||||
|
||||
### 支持的Settings
|
||||
|
||||
**"ignoreUnimportantViews"** - 布尔类型。设置为false时,Android设备不会忽略任何视图;被设置为true时,会使用`setCompressedLayoutHeirarchy()`忽略标记了IMPORTANT_FOR_ACCESSIBILITY_NO或IMPORTANT_FOR_ACCESSIBILITY_AUTO(以及被系统认为不重要的)的视图,从而尽量让脚本变得简单或执行的更快。
|
||||
|
||||
#### Android UiAutomator Configurator
|
||||
|
||||
设置[UiAutomator Configurator](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html) 的超时时间和延迟. 只支持Android API 18 及以上版本。
|
||||
|
||||
**"actionAcknowledgmentTimeout"** - Int类型,与[setActionAcknowledgmentTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setActionAcknowledgmentTimeout(long))相同。被设置为负数时将取默认值(3 * 1000 毫秒)
|
||||
|
||||
**"keyInjectionDelay"** - Int类型,与[setKeyInjectionDelay](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setKeyInjectionDelay(long))相同。被设置为负数时将取默认值(0 毫秒)
|
||||
|
||||
**"scrollAcknowledgmentTimeout"** - Int类型,与[setScrollAcknowledgmentTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setScrollAcknowledgmentTimeout(long))相同。被设置为负数时将取默认值(200 毫秒)
|
||||
|
||||
**"waitForIdleTimeout"** - Int类型,与[setWaitForIdleTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setWaitForIdleTimeout(long))相同。被设置为负数时将取默认值(10 * 1000 毫秒)
|
||||
|
||||
**"waitForSelectorTimeout"** - Int类型,与[setWaitForSelectorTimeout](https://developer.android.com/reference/android/support/test/uiautomator/Configurator.html#setWaitForSelectorTimeout(long))相同。被设置为负数时将取默认值(10 * 1000 毫秒)
|
||||
|
||||
|
||||
本文由 [ghost62184](https://github.com/ghost62184) 翻译, 由 [chenhengjie123](https://github.com/chenhengjie123) 校验
|
||||
286
docs/cn/advanced-concepts/wda-custom-server.md
Normal file
@@ -0,0 +1,286 @@
|
||||
## 如何搭建并定制 WebDriverAgent Server
|
||||
|
||||
Appium 的 iOS 版本的后端用的是[Facebook's WebDriverAgent](https://github.com/facebook/WebDriverAgent)。该后端是基于苹果公司的 XCTest 框架,所以也有所有XCTest 框架已知的问题。其中有些问题我们正在设法解决,有一些在现阶段可能无法解决。本文中描述的方法已经能够使您完全掌握在设备上如何构建、管理和运行WDA。通过这种方式,您可以在CI环境中对您的自动化测试进行微调,并使其在长期运行的情况下更加稳定。
|
||||
|
||||
重点:
|
||||
* 如果使用了Appium的默认设置,则不需要如下的步骤。服务器将为您搞定一切,当然你也不能对WDA做太多控制。
|
||||
* 对连接的被测设备必须有SSH或物理访问权限。
|
||||
|
||||
### 安装WDA
|
||||
|
||||
Appium 会自动下载 WebDriverAgent 源码。如果使用 npm 命令(`npm install -g appium`) 安装Appium的话,通常情况下会保存在/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent 目录下。
|
||||
如果是首次安装的话,还需要下载一些第三方依赖("carthage"工具就是为此准备的: `brew install carthage`):
|
||||
|
||||
```bash
|
||||
cd /usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent
|
||||
./Scripts/bootstrap.sh -d
|
||||
```
|
||||
|
||||
不需要进一步的配置步骤,你就可以在iOS模拟器上执行自动化测试。
|
||||
|
||||
如果是在真机上进行测试的话,则需要做更多的设置。参考[real device configuration documentation](https://github.com/appium/appium-xcuitest-driver/blob/master/docs/real-device-config.md) 设置代码签名。另外,你还需要安装iproxy工具。
|
||||
|
||||
```bash
|
||||
npm install -g iproxy
|
||||
```
|
||||
|
||||
为了确保 WDA 源代码配置正确,请执行以下操作:
|
||||
|
||||
* 用Xcode打开/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/WebDriverAgent.xcodeproj
|
||||
* 选择 "WebDriverAgentRunner" 工程
|
||||
* 选择要运行自动化测试的真机/模拟器作为构建目标机
|
||||
* 在主菜单中选择 Product -> Test
|
||||
|
||||
Xcode 会成功构建项目并安装到真机/模拟器上,所以您将在苹果系统的桌面上看到 WebDriverAgentRunner 应用程序的图标。
|
||||
|
||||
### 启动WDA
|
||||
|
||||
WebDriverAgent 应用程序扮演一个 REST 服务的角色,接收外部 API 请求,然后传递给被测应用的原生 XCTest 调用。如果在模拟器上运行你的测试,REST 服务的地址将是localhost,如果在有实际的 IP 地址的真实设备上运行,REST 服务的地址将是实际的 ip 地址。我们使用 iproxy 将网络请求路由到通过 USB 连接的真实设备上,这意味着可以使用这个工具将模拟器和真实设备上的 WDA 网络地址统一。
|
||||
|
||||
这个用Java编写的助手类说明了主要的实现细节:
|
||||
|
||||
```java
|
||||
public class WDAServer {
|
||||
private static final Logger log = ZLogger.getLog(WDAServer.class.getSimpleName());
|
||||
|
||||
private static final int MAX_REAL_DEVICE_RESTART_RETRIES = 1;
|
||||
private static final Timedelta REAL_DEVICE_RUNNING_TIMEOUT = Timedelta.ofMinutes(4);
|
||||
private static final Timedelta RESTART_TIMEOUT = Timedelta.ofMinutes(1);
|
||||
|
||||
// These settings are needed to properly sign WDA for real device tests
|
||||
// See https://github.com/appium/appium-xcuitest-driver for more details
|
||||
private static final File KEYCHAIN = new File(String.format("%s/%s",
|
||||
System.getProperty("user.home"), "/Library/Keychains/MyKeychain.keychain"));
|
||||
private static final String KEYCHAIN_PASSWORD = "******";
|
||||
|
||||
private static final File IPROXY_EXECUTABLE = new File("/usr/local/bin/iproxy");
|
||||
private static final File XCODEBUILD_EXECUTABLE = new File("/usr/bin/xcodebuild");
|
||||
private static final File WDA_PROJECT =
|
||||
new File("/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/" +
|
||||
"WebDriverAgent/WebDriverAgent.xcodeproj");
|
||||
private static final String WDA_SCHEME = "WebDriverAgentRunner";
|
||||
private static final String WDA_CONFIGURATION = "Debug";
|
||||
private static final File XCODEBUILD_LOG = new File("/usr/local/var/log/appium/build.log");
|
||||
private static final File IPROXY_LOG = new File("/usr/local/var/log/appium/iproxy.log");
|
||||
|
||||
private static final int PORT = 8100;
|
||||
public static final String SERVER_URL = String.format("http://127.0.0.1:%d", PORT);
|
||||
|
||||
private static final String[] IPROXY_CMDLINE = new String[]{
|
||||
IPROXY_EXECUTABLE.getAbsolutePath(),
|
||||
Integer.toString(PORT),
|
||||
Integer.toString(PORT),
|
||||
String.format("> %s 2>&1 &", IPROXY_LOG.getAbsolutePath())
|
||||
};
|
||||
|
||||
private static WDAServer instance = null;
|
||||
private final boolean isRealDevice;
|
||||
private final String deviceId;
|
||||
private final String platformVersion;
|
||||
private int failedRestartRetriesCount = 0;
|
||||
|
||||
private WDAServer() {
|
||||
try {
|
||||
this.isRealDevice = !getIsSimulatorFromConfig(getClass());
|
||||
final String udid;
|
||||
if (isRealDevice) {
|
||||
udid = IOSRealDeviceHelpers.getUDID();
|
||||
} else {
|
||||
udid = IOSSimulatorHelpers.getId();
|
||||
}
|
||||
this.deviceId = udid;
|
||||
this.platformVersion = getPlatformVersionFromConfig(getClass());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ensureToolsExistence();
|
||||
ensureParentDirExistence();
|
||||
}
|
||||
|
||||
public synchronized static WDAServer getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new WDAServer();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private boolean waitUntilIsRunning(Timedelta timeout) throws Exception {
|
||||
final URL status = new URL(SERVER_URL + "/status");
|
||||
try {
|
||||
if (timeout.asSeconds() > 5) {
|
||||
log.debug(String.format("Waiting max %s until WDA server starts responding...", timeout));
|
||||
}
|
||||
new UrlChecker().waitUntilAvailable(timeout.asMillis(), TimeUnit.MILLISECONDS, status);
|
||||
return true;
|
||||
} catch (UrlChecker.TimeoutException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureParentDirExistence() {
|
||||
if (!XCODEBUILD_LOG.getParentFile().exists()) {
|
||||
if (!XCODEBUILD_LOG.getParentFile().mkdirs()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"The script has failed to create '%s' folder for Appium logs. " +
|
||||
"Please make sure your account has correct access permissions on the parent folder(s)",
|
||||
XCODEBUILD_LOG.getParentFile().getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureToolsExistence() {
|
||||
if (isRealDevice && !IPROXY_EXECUTABLE.exists()) {
|
||||
throw new IllegalStateException(String.format("%s tool is expected to be installed (`npm install -g iproxy`)",
|
||||
IPROXY_EXECUTABLE.getAbsolutePath()));
|
||||
}
|
||||
if (!XCODEBUILD_EXECUTABLE.exists()) {
|
||||
throw new IllegalStateException(String.format("xcodebuild tool is not detected on the current system at %s",
|
||||
XCODEBUILD_EXECUTABLE.getAbsolutePath()));
|
||||
}
|
||||
if (!WDA_PROJECT.exists()) {
|
||||
throw new IllegalStateException(String.format("WDA project is expected to exist at %s",
|
||||
WDA_PROJECT.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> generateXcodebuildCmdline() {
|
||||
final List<String> result = new ArrayList<>();
|
||||
result.add(XCODEBUILD_EXECUTABLE.getAbsolutePath());
|
||||
result.add("clean build test");
|
||||
result.add(String.format("-project %s", WDA_PROJECT.getAbsolutePath()));
|
||||
result.add(String.format("-scheme %s", WDA_SCHEME));
|
||||
result.add(String.format("-destination id=%s", deviceId));
|
||||
result.add(String.format("-configuration %s", WDA_CONFIGURATION));
|
||||
result.add(String.format("IPHONEOS_DEPLOYMENT_TARGET=%s", platformVersion));
|
||||
result.add(String.format("> %s 2>&1 &", XCODEBUILD_LOG.getAbsolutePath()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<String> generateKeychainUnlockCmdlines() throws Exception {
|
||||
final List<String> result = new ArrayList<>();
|
||||
result.add(String.format("/usr/bin/security -v list-keychains -s %s", KEYCHAIN.getAbsolutePath()));
|
||||
result.add(String.format("/usr/bin/security -v unlock-keychain -p %s %s",
|
||||
KEYCHAIN_PASSWORD, KEYCHAIN.getAbsolutePath()));
|
||||
result.add(String.format("/usr/bin/security set-keychain-settings -t 3600 %s", KEYCHAIN.getAbsolutePath()));
|
||||
return result;
|
||||
}
|
||||
|
||||
public synchronized void restart() throws Exception {
|
||||
if (isRealDevice && failedRestartRetriesCount >= MAX_REAL_DEVICE_RESTART_RETRIES) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"WDA server cannot start on the connected device with udid %s after %s retries. " +
|
||||
"Reboot the device manually and try again", deviceId, MAX_REAL_DEVICE_RESTART_RETRIES));
|
||||
}
|
||||
|
||||
final String hostname = InetAddress.getLocalHost().getHostName();
|
||||
log.info(String.format("Trying to (re)start WDA server on %s:%s...", hostname, PORT));
|
||||
UnixProcessHelpers.killProcessesGracefully(IPROXY_EXECUTABLE.getName(), XCODEBUILD_EXECUTABLE.getName());
|
||||
|
||||
final File scriptFile = File.createTempFile("script", ".sh");
|
||||
try {
|
||||
final List<String> scriptContent = new ArrayList<>();
|
||||
scriptContent.add("#!/bin/bash");
|
||||
if (isRealDevice && isRunningInJenkinsNetwork()) {
|
||||
scriptContent.add(String.join("\n", generateKeychainUnlockCmdlines()));
|
||||
}
|
||||
if (isRealDevice) {
|
||||
scriptContent.add(String.join(" ", IPROXY_CMDLINE));
|
||||
}
|
||||
final String wdaBuildCmdline = String.join(" ", generateXcodebuildCmdline());
|
||||
log.debug(String.format("Building WDA with command line:\n%s\n", wdaBuildCmdline));
|
||||
scriptContent.add(wdaBuildCmdline);
|
||||
try (Writer output = new BufferedWriter(new FileWriter(scriptFile))) {
|
||||
output.write(String.join("\n", scriptContent));
|
||||
}
|
||||
new ProcessBuilder("/bin/chmod", "u+x", scriptFile.getCanonicalPath())
|
||||
.redirectErrorStream(true).start().waitFor(5, TimeUnit.SECONDS);
|
||||
final ProcessBuilder pb = new ProcessBuilder("/bin/bash", scriptFile.getCanonicalPath());
|
||||
final Map<String, String> env = pb.environment();
|
||||
// This is needed for Jenkins
|
||||
env.put("BUILD_ID", "dontKillMe");
|
||||
log.info(String.format("Waiting max %s for WDA to be (re)started on %s:%s...", RESTART_TIMEOUT.toString(),
|
||||
hostname, PORT));
|
||||
final Timedelta started = Timedelta.now();
|
||||
pb.redirectErrorStream(true).start().waitFor(RESTART_TIMEOUT.asMillis(), TimeUnit.MILLISECONDS);
|
||||
if (!waitUntilIsRunning(RESTART_TIMEOUT)) {
|
||||
++failedRestartRetriesCount;
|
||||
throw new IllegalStateException(
|
||||
String.format("WDA server has failed to start after %s timeout on server '%s'.\n"
|
||||
+ "Please make sure that iDevice is properly connected and you can build "
|
||||
+ "WDA manually from XCode.\n"
|
||||
+ "Xcodebuild logs:\n\n%s\n\n\niproxy logs:\n\n%s\n\n\n",
|
||||
RESTART_TIMEOUT, hostname,
|
||||
getLog(XCODEBUILD_LOG).orElse("EMPTY"), getLog(IPROXY_LOG).orElse("EMPTY"))
|
||||
);
|
||||
}
|
||||
|
||||
log.info(String.format("WDA server has been successfully (re)started after %s " +
|
||||
"and now is listening on %s:%s", Timedelta.now().diff(started).toString(), hostname, PORT));
|
||||
} finally {
|
||||
scriptFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRunning() throws Exception {
|
||||
if (!isProcessRunning(XCODEBUILD_EXECUTABLE.getName())
|
||||
|| (isRealDevice && !isProcessRunning(IPROXY_EXECUTABLE.getName()))) {
|
||||
return false;
|
||||
}
|
||||
return waitUntilIsRunning(isRealDevice ? REAL_DEVICE_RUNNING_TIMEOUT : Timedelta.ofSeconds(3));
|
||||
}
|
||||
|
||||
public Optional<String> getLog(File logFile) {
|
||||
if (logFile.exists()) {
|
||||
try {
|
||||
return Optional.of(new String(Files.readAllBytes(logFile.toPath()), Charset.forName("UTF-8")));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void resetLogs() {
|
||||
for (File logFile : new File[]{XCODEBUILD_LOG, IPROXY_LOG}) {
|
||||
if (logFile.exists()) {
|
||||
try {
|
||||
final PrintWriter writer = new PrintWriter(logFile);
|
||||
writer.print("");
|
||||
writer.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
之前应该调用这段代码来启动 Appium iOS 驱动,例如,在 setUp 方法中:
|
||||
|
||||
```java
|
||||
if (!WDAServer.getInstance().isRunning()) {
|
||||
WDAServer.getInstance().restart();
|
||||
}
|
||||
```
|
||||
|
||||
为 Appium 驱动程序设置 webDriverAgentUrl 非常重要,让它知道我们的 WDA 驱动程序可以使用:
|
||||
|
||||
```java
|
||||
capabilities.setCapability("webDriverAgentUrl", WDAServer.SERVER_URL);
|
||||
```
|
||||
|
||||
### 重要注释
|
||||
|
||||
* 如果是 jenkins agent 执行的,该进程不能直接访问钥匙串(Keychain),所以我们需要在为真实设备编译 WDA 之前准备钥匙串,否则编码将失败。
|
||||
* 如果 xcodebuild 和 iproxy 进程已经被冻结,我们在重新启动之前杀死这些进程,以确保编译成功,
|
||||
* 我们准备一个单独的 bash 脚本并独立于 iproxy / xcodebuild 进程,所以即使在实际的代码执行完成后,它们也可以在后台继续运行。如果在自动化实验室中的同一机器/节点上执行多个测试/套件,最少的人工干预是非常重要的。
|
||||
* 更改 BUILD_ID 环境变量的值以避免在作业完成后由 Jenkins agent 程序杀死后台进程。
|
||||
* isRunning 检查是通过验证实际的网络终端来完成的.
|
||||
* 守护进程的输出会存入日志,因此可以跟踪错误和意外的故障。如果服务器无法启动/重启,日志文件的内容会自动添加到实际的错误消息中。
|
||||
* 真机设备ID可以从 `system_profiler SPUSBDataType` 输出中解析
|
||||
* 模拟器ID可以从 `xcrun simctl list` 输出中解析
|
||||
* UrlChecker 类是从 org.openqa.selenium.net 包导入的
|
||||
|
||||
|
||||
本文由 [simple](https://testerhome.com/simple) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,11 +0,0 @@
|
||||
# Intel® 硬件加速器管理
|
||||
|
||||
如果你发现android模拟器太慢, 并且你的系统运行在Intel® 的cpu上. 那么你可以尝试下HAXM, HAXM能够让你充分利用硬件虚拟化技术来加速android模拟器。
|
||||
|
||||
* 要安装HAXM, 你可以打开Android SDK Manager, 你可以在Extras中发现这个安装选项;
|
||||
* 你可以在[Intel官方网站][1]找到所有相关的文档;
|
||||
* 这将需要x86的模拟镜像;
|
||||
* 利用Intel的包来安装HAXM; Android SDK Manager有时候会安装不成功,这主要取决于你安装的版本是否兼容。
|
||||
|
||||
[1]: http://software.intel.com/en-us/articles/intel-hardware-accelerated-execution-manager/ "Hax"
|
||||
[2]: http://software.intel.com/en-us/search/site/language/en?query=Intel%20Hardware%20Accelerated%20Execution%20Manager%20%28HAXM%29 "Hax all"
|
||||
13
docs/cn/appium-setup/android-hax-emulator.md
Normal file
@@ -0,0 +1,13 @@
|
||||
## Intel® 硬件加速执行管理器
|
||||
|
||||
如果你发现你的 android 模拟器运行速度太缓慢,而你的系统又运行在 Intel® 的 cpu 下,你可以试试 HAXM。 HAXM 可以让你利用你的硬件虚拟化技术,为你的模拟器加速。
|
||||
|
||||
* 使用 Android SDK Manager 安装 HAXM ,你会在 Extras 文件夹里找到这个包;
|
||||
* 你可以在 [Intel® 的网站][1] 找到所有相关的文档;
|
||||
* 这需要 x86 架构的模拟器镜像;
|
||||
* 使用 Intel 的安装包去安装 HAXM; 根据你已经安装过的版本不同,Android SDK Manager 可能会安装不成功(译者注:如果原来已经有一个旧版本,此时有可能会自动安装失败。建议在 [Intel® 的网站][1] 安装官方安装包手动安装)。
|
||||
|
||||
[1]: http://software.intel.com/en-us/articles/intel-hardware-accelerated-execution-manager/
|
||||
|
||||
|
||||
翻译 by [thanksdanny](https://github.com/thanksdanny) ,由 [chenhengjie123](https://github.com/chenhengjie123) 校验
|
||||
@@ -1,38 +0,0 @@
|
||||
## Android Setup
|
||||
|
||||
使用前,你需要安装node.js(版本大于等于0.10)。 请参照 [instructions for your flavor of linux](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager)。
|
||||
|
||||
当node.js安装成功后,请安装 [Android SDK](http://developer.android.com/sdk/index.html)。
|
||||
运行'android' tool(位于SDK,tool文件目录下)。
|
||||
|
||||
运行'android' tool 来安装大于等于Level 17的API。
|
||||
|
||||
(如果你想从Appium的源码来运行,可在真机或者模拟器上用 [Apache Ant](http://ant.apache.org/) 来编译bootstrap jar包)。
|
||||
|
||||
最后,将环境变量`$ANDROID_HOME`设置为 Android SDK 的路径。例如,如果你将Android SDK 解压到 /usr/local/adt/,你需要把这个路径加到你的shell环境变量中去:
|
||||
|
||||
export ANDROID_HOME="/usr/local/adt/sdk"
|
||||
|
||||
现在就可以启动Appium了!如果你在源码中运行Appium请运行
|
||||
`./reset.sh --android` 版本从Appium checkout会安装所有的依赖。
|
||||
|
||||
### 老版本的额外安装
|
||||
|
||||
当android的版本是2.3到4.1的时候,appium用的是selendroid。 当它检测到时低版本时,它会自动应用Selendroid。但是需要配置一些额外的设置如果从source运行。
|
||||
|
||||
* 已经安装 [Maven 3.1.1](http://maven.apache.org/download.cgi) 或更新 (`mvn`)
|
||||
* 运行 `./reset.sh --selendroid` 从checkout的Appium源码
|
||||
|
||||
### (运行Appium Android 测试)
|
||||
|
||||
在Linux上运行,启动一个API大于等于level17的AVD。 在源文件目录下运行 (`appium`) 在安装好 NPM, 或者 `node`。如果你选择的是从源代码方式运行。
|
||||
参照 [server documentation](/docs/cn/writing-running-appium/server-args.cn.md) 来了解所有命令和参数。
|
||||
|
||||
### 注意
|
||||
|
||||
* Android 加速模拟器需要存在,它有自己的局限性,如果想了解更多,请看这里
|
||||
[page](/docs/cn/appium-setup/android-hax-emulator.cn.md)。
|
||||
* 如果你想运行任何Appium的测试,或者任何强大的命令,确保你的 `hw.battery=yes` 在 AVD's `config.ini`文件中。
|
||||
* Selendroid 需要你APP中的如下权限:
|
||||
`<uses-permission android:name="android.**permission.INTERNET"/>`,
|
||||
如果你在使用selendroid或者低版本的android(如版本2.3到4.1),请确保你的App已设置internet权限。
|
||||
43
docs/cn/appium-setup/android-setup.md
Normal file
@@ -0,0 +1,43 @@
|
||||
## Android 配置
|
||||
|
||||
开始配置之前,你需要安装 Node.js(v4 或更高版本)。具体请参考 [instructions for your flavor of linux](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager)。
|
||||
|
||||
在你安装完 Node.js 后,下一步就是安装 [Android SDK](http://developer.android.com/sdk/index.html).
|
||||
因为你需要运行 `android` tool(包含 SDK, 在 'tools' 目录下)。
|
||||
|
||||
|
||||
运行 `android` tool,并使用他来安装 Level 17 或更高级的 API。
|
||||
|
||||
(如果想通过源码运行 Appium,需要先用 [Apache Ant](http://ant.apache.org/) 去构建出 bootstrap jar包,Appium 会在 Android 模拟器或真机上运行该 jar 包。)
|
||||
|
||||
|
||||
最后,将环境变量 `$ANDROID_HOME` 配置为你的 Android SDK 路径。举个例子,假如你解压了 Android SDK 到 /usr/local/adt/,你应该在添加这行命令到你的 shell 环境变量中:
|
||||
|
||||
export ANDROID_HOME="/usr/local/adt/sdk"
|
||||
|
||||
|
||||
现在你已经配置好可以运行 Appium 的环境了!(如果你是通过源码运行的 Appium,应该确保你已经在 Appium 的代码目录下,运行过 `npm install` 安装所有的依赖。)
|
||||
|
||||
|
||||
### 对于 Android 老版本的一些额外配置
|
||||
|
||||
Appium 是用 [Selendroid](https://selendroid.io) 去运行Android 2.3到4.1版本。当 Appium 检测到当前正在运行旧版本,它就会自动地切换 Selendroid 去运行(这里不太对,如果要使用 Selendroid 需要指定),但假如你是使用源码去运行,你还需要一些额外的配置。
|
||||
|
||||
* 确保你已经安装 [Maven 3.1.1](http://maven.apache.org/download.cgi) 或已更新到 `mvn` 的最新版本
|
||||
|
||||
|
||||
### 运行 Appium Android 测试
|
||||
|
||||
在 Linux 环境上运行测试,你需要启动并运行一个 API 为 Level 17 或更高版本的 AVD。如果你是通过 NPM 安装的话,则直接在命令行输入 `appium` 去运行 Appium。如果是通过源码运行,在目录底下运行 `node .`。
|
||||
|
||||
阅读 [server documentation](/docs/cn/writing-running-appium/server-args.md) 你能查看所有命令行参数。
|
||||
|
||||
|
||||
### 注意
|
||||
|
||||
* 现在有一些 android 的硬件加速模拟器,他有自己的一些局限性。更多的信息你可以查看这份 [page](/docs/cn/appium-setup/android-hax-emulator.md).
|
||||
* 如果你想运行任何 Appium 的测试或使用任何电量相关的命令,需要确保在你的 AVD 的 `config.ini` 里 `hw.battery=yes` 。若为 Android 5.0, 则这是默认的
|
||||
* Selendroid 需要检测你的应用是否拥有以下权限:
|
||||
`<uses-permission android:name="android.**permission.INTERNET"/>`,假如你在使用 selendroid 或者更老的Android版本(也就是2.3到4.1)时,你应确保你的应用设置了 internet 权限。
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,72 +0,0 @@
|
||||
# 部署iOS app 到手机上
|
||||
|
||||
准备在真机上执行appium测试, 需要如下准备:
|
||||
|
||||
1. 用特殊的设备参数来构建app
|
||||
1. 使用 [fruitstrap](https://github.com/ghughes/fruitstrap), 这是一个第三方程序,可以用来部署你构建的app到手机上
|
||||
|
||||
## Xcodebuild 命令的参数:
|
||||
新的参数运行指定设置. 参考 [developer.apple.com](https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html):
|
||||
|
||||
```
|
||||
xcodebuild [-project projectname] [-target targetname ...]
|
||||
[-configuration configurationname] [-sdk [sdkfullpath | sdkname]]
|
||||
[buildaction ...] [setting=value ...] [-userdefault=value ...]
|
||||
```
|
||||
|
||||
这有一个资料来参考可用的[设置](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)
|
||||
|
||||
```
|
||||
CODE_SIGN_IDENTITY (Code Signing Identity)
|
||||
介绍: 标识符,指定一个签名。
|
||||
例如: iPhone Developer
|
||||
```
|
||||
|
||||
PROVISIONING_PROFILE 已经从可用的的命令中消失了,但还是有必要设置的。
|
||||
|
||||
在xcodebuild命令中设置 "CODE_SIGN_IDENTITY" & "PROVISIONING_PROFILE":
|
||||
|
||||
```
|
||||
xcodebuild -sdk <iphoneos> -target <target_name> -configuration <Debug> CODE_SIGN_IDENTITY="iPhone Developer: Mister Smith" PROVISIONING_PROFILE="XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"
|
||||
```
|
||||
|
||||
成功的话, app会构建到如下目录 ```<app_dir>/build/<configuration>-iphoneos/<app_name>.app```
|
||||
|
||||
## 用Fruitstrap进行部署
|
||||
clone一个fruitstrap的fork版本在[ghughes version](https://github.com/ghughes/fruitstrap) ,这个已经不再维护. 已确认该fork可用[unprompted fork](https://github.com/unprompted/fruitstrap), 但是其它的据说也可用。
|
||||
|
||||
clone成功的话, 执行 ``make fruitstrap``
|
||||
然后, 然后复制生成的 ``fruitstrap``到app的所在的目录或上级目录下。
|
||||
|
||||
运行fruitstrap 通过输入以下命令 (命令是否可用依赖于你fork的 fruitstrap):
|
||||
|
||||
```
|
||||
./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID>
|
||||
```
|
||||
|
||||
如果是为了持续集成,你可以发现很有用的方法来记录fruitstrap命令行和日志文件中的记录, 像这样:
|
||||
|
||||
```
|
||||
./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID> 2>&1 | tee fruit.out
|
||||
```
|
||||
|
||||
在node服务启动前fruitstrap进行需要被结束, 一个方法是扫描fruitstrap的输出来得知app完成启动。 有一个有效的方法是通过一个Rakefile 和一个 ``go_device.sh`` 脚本:
|
||||
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
一旦fruitstrap的进程被结束, node 服务就可以启动并且appium测试可以被执行!
|
||||
|
||||
下一步:
|
||||
[在真机上运行appium](real-devices.cn.md)
|
||||
51
docs/cn/appium-setup/ios-deploy.md
Normal file
@@ -0,0 +1,51 @@
|
||||
## 在真机上部署 iOS 应用
|
||||
|
||||
准备在真机上运行 Appium 之前,你需要做好以下几件事:
|
||||
|
||||
1. 使用特定设备相关的参数去构建你的 app
|
||||
2. 使用第三方工具 [ideviceinstaller](https://github.com/libimobiledevice/ideviceinstaller) 将你构建的包部署到你的设备上
|
||||
|
||||
### Xcodebuild 的参数:
|
||||
|
||||
现在新版的 xcodebuild 允许使用的指定设置。请参考[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 ...]
|
||||
```
|
||||
|
||||
在这资料中你会发现一些有用的 [设置](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 (代码签名标识)
|
||||
描述: 指定代码签名标识的名称.
|
||||
示例值: iPhone Developer
|
||||
|
||||
```
|
||||
|
||||
PROVISIONING_PROFILE 虽然在可用的命令列表中移除了,但还是有必要设置的。
|
||||
|
||||
在 xcodebuild 命令中指定 "CODE_SIGN_IDENTITY" 与 "PROVISIONING_PROFILE" 的设置:
|
||||
|
||||
```center
|
||||
xcodebuild -sdk <iphoneos> -target <target_name> -configuration <Debug> CODE_SIGN_IDENTITY="iPhone Developer: Mister Smith" PROVISIONING_PROFILE="XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"
|
||||
```
|
||||
|
||||
一旦成功,app 就会被构建到 `<app_dir>/build/<configuration>-iphoneos/<app_name>.app` 目录下。
|
||||
|
||||
### 使用 ideviceinstaller 部署
|
||||
|
||||
使用 Homebrew 去安装被标记为最新版本的 ideviceinstaller 工具,在终端运行以下命令:
|
||||
|
||||
``` center
|
||||
# 第一行命令只是在你没有安装好 brew 的情况下才需要执行
|
||||
> ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
> brew update
|
||||
> brew install ideviceinstaller
|
||||
> ideviceinstaller -u <UDID of device> -i <path of .app/.ipa>
|
||||
```
|
||||
|
||||
下一部分:[在真机上运行 Appium](real-devices.md)
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,31 +0,0 @@
|
||||
## Android并发测试
|
||||
|
||||
Appium提供了在一台设备上启动多个Android会话的方案,而这个方案需要你输入不同的指令来启动多个Appium服务来实现。
|
||||
|
||||
启动多个Android会话的重要指令包括:
|
||||
|
||||
- `-p` Appium的主要端口
|
||||
- `-U` 设备id
|
||||
- `-bp` Appium bootstrap端口
|
||||
- `--chromedriver-port` chromedriver端口(当使用了webviews或者chrome)
|
||||
- `--selendroid-port` selendroid端口(当使用了selendroid)
|
||||
|
||||
|
||||
更多参数的解释详见 [here](../writing-running-appium/caps.cn.md)。
|
||||
|
||||
|
||||
如果我们有两台设备,设备ID分别为43364和32456,我们应该用下面的命令启动来两个不同的Appium服务:
|
||||
|
||||
`node . -p 4492 -bp 2251 -U 32456`
|
||||
|
||||
`node . -p 4491 -bp 2252 -U 43364`
|
||||
|
||||
只要你的Appium和Appium bootstrap端口介于0和65536即可,并且保证是两个不同的端口以便两个Appium服务不会监听相同的端口。确认你的-u参数绑定正确的设备ID。这可以让Appium知道连接哪台设备,所以参数一定要准确。
|
||||
|
||||
如果你用了chromedriver或selendroid,不同的服务要设置不同的端口。
|
||||
|
||||
### iOS并发测试
|
||||
|
||||
不幸的是,IOS不能进行本地并发测试。跟Android不一样,IOS在同一时间只能启动一个版本的模拟器来运行多个测试。
|
||||
如果你想在IOS上进行并发测试,你需要用到Sauce。只需上传你的Appium测试脚本到Sauce,它就可以按照你的设置执行多个IOS或Android的并发测试。在Sauce上执行测试的更多信息,详见[here](https://docs.saucelabs.com/tutorials/appium/)。
|
||||
|
||||
35
docs/cn/appium-setup/parallel_tests.md
Normal file
@@ -0,0 +1,35 @@
|
||||
## Android 并发测试
|
||||
|
||||
Appium 给用户提供了在一个机器上启动多个 Android sessions 的方案。该方案只需要通过不同参数来启动的多个 Appium 服务。
|
||||
|
||||
以下是启动多个 Android 会话的一些重要参数:
|
||||
|
||||
- `-p` Appium 主要端口
|
||||
- `-U` 设备 id
|
||||
- `-bp` Appium bootstrap 端口
|
||||
- `--chromedriver-port` chromedriver 端口 (若是在使用 webviews 或 chrome)
|
||||
- `--selendroid-port` selendroid 端口 (若是在使用 selendroid)
|
||||
|
||||
更多相关参数的信息可以参考 [这里](../writing-running-appium/caps.md) 。
|
||||
|
||||
如果我们有两台设备,且他们的设备 id 分别为 43364 和 32456,我们可以通过以下命令启动两个不同的 Appium 服务器:
|
||||
|
||||
`node . -p 4492 -bp 2251 -U 32456`
|
||||
|
||||
`node . -p 4491 -bp 2252 -U 43364`
|
||||
|
||||
只要你的 Appium 与 Appium bootstrap 的端口在 0 到 65536 之间,且端口号并不相同,这样两个 Appium 服务器就不会去监听同一个端口。确保通过 -u 参数标志的 id 与对应的设备 id 是一致的。这就是 Appium 能知道设备之间是如何通信的原因,因此必须保证参数准确无误。
|
||||
|
||||
如果你使用 chromedriver 或 selendroid,记得确保服务器的端口号是独一无二的。
|
||||
|
||||
如果你使用 [appium-uiautomator2-driver](https://github.com/appium/appium-uiautomator2-driver),
|
||||
需要给 systemPort 这个 capability 配置为不同的系统端口。因为有时候如果没有使用不同的端口,会出现冲突,比如[这个问题](https://github.com/appium/appium/issues/7745).
|
||||
|
||||
### iOS 并发测试
|
||||
|
||||
十分不幸,目前并不能在本地运行 iOS 的并发测试。iOS 同一时间只能启动一个模拟器,不像 Andoid 可以同时多个模拟器去运行测试。
|
||||
|
||||
如果你想运行 iOS 的并发测试,你需要使用 Sauce 上传你的 Appium 测试脚本,然后就可以运行多台 iOS 和 Android 的并发测试,只要你的账号允许。查看更多相关信息可以查看 [这里](https://docs.saucelabs.com/tutorials/appium/)。
|
||||
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,36 +0,0 @@
|
||||
# Appium支持的平台
|
||||
|
||||
Appium支持很多的运行平台和测试方式(包括原生、混合应用、内嵌浏览器、真机、模拟器等)。这篇文档主要用来让大家明确在使用
|
||||
Appimu的时候支持的平台版本和上述测试方式的必备条件。
|
||||
|
||||
## iOS平台支持
|
||||
|
||||
请移步到[Running on OS X: iOS](running-on-osx.cn.md) 。这里介绍了在iOS系统下使用Appium的必备条件和安装说明。
|
||||
|
||||
* 版本号:6.1,7.0,以及7.1。
|
||||
* 支持设备:iPhone模拟器,iPad模拟器以及iPhones和iPads真机。
|
||||
* 是否支持原生应用:支持。同时支持模拟器中调试应用版本和正确签名的真机ipa。其他相关支持由苹果的[UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)框架提供。
|
||||
* 是否支持内置移动浏览器:支持。Safari浏览器已经通过测试。对于真机,则需要安装调试工具ios-webkit-remote-debugger。很遗憾,对于Safari的原生界面的自动化是不支持的。更多信息请移步至[mobile web doc](/docs/cn/writing-running-appium/mobile-web.cn.md) 。
|
||||
* 是否支持混合应用:支持。同样对于真机需要安装调试工具ios-webkit-remote-debugger,更多详情请移步至[hybrid doc](/docs/cn/advanced-concepts/hybrid.cn.md) 查看详情。
|
||||
* 是否支持在同一个session中执行多个应用的自动化:不支持。
|
||||
* 是否支持同时再多个设备上执行自动化:不支持。
|
||||
* 是否支持第三方提供应用:只支持在模拟器上有限的第三方应用(例如:喜好设置、地图等)。
|
||||
* 是否支持自定义的、非标准UI控件的自动化:仅支持很少一部分。最好对控件添加可识别信息,以方便对元素进行一些基础的自动化操作。
|
||||
|
||||
## Android平台支持
|
||||
|
||||
请移步至 [Running on OS X: Android](running-on-osx.cn.md),[Running on Windows](running-on-windows.cn.md),或者[Running on Linux](running-on-linux.cn.md) 获得在不同操作系统下android平台对appium的支持和安装配置文档。
|
||||
|
||||
* 支持版本:android 2.3平台及以上。
|
||||
* android 4.2平台及以上通过Appium自有的[UiAutomator](http://developer.android.com/tools/help/uiautomator/index.html)类库支持。默认在自动化后台。
|
||||
* 从android 2.3到4.3平台,Appium是通过绑定[Selendroid](http://selendroid.io),实现自动化测试的,你可以到android开发社区的[Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html)。(仪表盘)中查看相关介绍。Selendroid拥有一套不同的命令行和不同的profile文件(这部分差距正在逐步缩小)。要获得在后台运行自动化的权限,需要配置`automationName` 组件的值为 `Selendroid`。
|
||||
* 支持的设备:Android模拟器和Android真机。
|
||||
* 是否支持原生应用:支持。
|
||||
* 是否支持内置移动浏览器:支持(除了使用Selendroid后台运行的情况)。通过代理方式绑定到[Chromedriver](https://code.google.com/p/selenium/wiki/ChromeDriver)来运行自动化测试。在android4.2和4.3版本中,只有在官方版本的谷歌浏览器或者Chromium下才能运行自动化测试。伴随着android 4.4+版本的出现。自动化测试则可以运行在内置浏览器的应用程序。但是需要在测试设备环境下安装Chrome/Chromium/浏览器。请移步至[mobile web doc](/docs/cn/writing-running-appium/mobile-web.cn.md) 获取更多详情。
|
||||
* 是否支持混合应用: 支持。请移步至[hybrid doc](/docs/cn/advanced-concepts/hybrid.cn.md)参考相关文档。
|
||||
* 通过默认的Appium的后台支持android 4.4以上的版本。
|
||||
* 通过Selendroid的后台支持android 2.3以上的版本。
|
||||
* 是否支持在同一个session中执行多个应用的自动化:支持(但是不支持使用Selendroid后台的场景)。
|
||||
* 是否支持同时再多个设备上执行自动化:支持,。尽管Appium必须要启动另一个端口即通过添加参数的方式运行命令行,例如`--port`,`--bootstrap-port`(或者`--selendroid-port`)或者`--chromedriver-port`。更多详情请移步至[server args doc](/docs/cn/writing-running-appium/server-args.cn.md)。
|
||||
* 是否支持第三方应用自动化:支持(但是不支持Selendroid后台运行的场景)。
|
||||
* 是否支持自定义的、非标准UI控件的自动化:不支持。
|
||||
45
docs/cn/appium-setup/platform-support.md
Normal file
@@ -0,0 +1,45 @@
|
||||
## Appium 支持的平台
|
||||
|
||||
Appium 支持多种平台以及各种测试方式(native,hybrid,web,真机,模拟器,等等...)。这份文档的设计初衷就是为了搞清楚所支持平台的版本,以及所需的条件。
|
||||
|
||||
### iOS 平台支持
|
||||
|
||||
获取 iOS 平台下所需的必备条件和安装说明,请查阅 [Running on OS X: iOS](running-on-osx.md)
|
||||
|
||||
* 版本:7.1 及以上版本
|
||||
* 设备:iPhone 模拟器,iPad 模拟器,以及 iPhone 和 iPad 的真机
|
||||
* 是否支持 Native 应用:支持。如在模拟器执行,需要 debug 版本的 .app 包,在真机上运行则需要已签名的 .ipa 包。底层的框架是由苹果的 [XCUITest](https://developer.apple.com/reference/xctest) (或 [UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/) 支持更旧的版本) 所提供支持
|
||||
* 是否支持移动端浏览器:支持。我们通过移动端的 Safari 进行自动化测试。对于真机,`ios-webkit-remote-debugger` 工具是必须的。可惜的是对于 Safari 的 native 部分的自动化目前还不支持。更多介绍请查看 [mobile web doc](/docs/cn/writing-running-appium/mobile-web.md)。
|
||||
* 是否支持 Hybrid 应用:支持。如使用真机,ios-webkit-remote-debugger 工具也是必须的。更多介绍请查看 [hybrid doc](/docs/cn/advanced-concepts/hybrid.md)。
|
||||
* 是否支持在一个 session 中多个应用的自动化:不支持
|
||||
* 是否支持多设备同时执行自动化:不支持
|
||||
* 是否支持第三方应用的自动化:仅支持在模拟器上仅有的第三方应用(设置,地图,等等...)。若在 iOS 10 及以上的版本,你同样可以在 home 界面做自动化。
|
||||
* 是否支持自定义的、非标准的 UI 控件的自动化:只支持小部分。你需要在控件设置可识别的信息,从而对一些元素进行一些基础的自动化操作。
|
||||
|
||||
### Android 平台支持
|
||||
|
||||
查阅[Running on OS X: Android](running-on-osx.md),[Running on Windows](running-on-windows.md) 或者 [Running on Linux](running-on-linux.md) 查看更多的设备信息以及安装说明。
|
||||
|
||||
* 版本:2.3 及以上版本
|
||||
* 2.3 至 4.2 版本是通过 Appium 绑定的基于 [Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html)框架的 [Selendroid](http://selendroid.io)实现的自动化。Selendroid 的命令设置与默认的 Appium 有点不同, 支持的配置文件也同样不同。要获得在后台运行自动化的权限,需要环境配置中将 `automationName` 的值为 `Selendroid`。
|
||||
* 4.2 以及更高的版本是通过 Appium 自己的 [UiAutomator](http://developer.android.com/tools/testing-support-library/index.html#UIAutomator) 库实现。这是默认的自动化后台。
|
||||
* 设备:Android 模拟器以及 Android 真机
|
||||
* 是否支持 Native 应用:支持
|
||||
* 是否支持移动端浏览器:支持(除了使用 Selendroid 后台的时候)。Appium 绑定了一个 [Chromedriver](https://code.google.com/p/selenium/wiki/ChromeDriver) 服务,使用这个代理服务进行自动化测试。在 4.2 和 4.3 版本,只能在官方的 Chrome 浏览器或者 Chromium 执行自动化测试。在 4.4 及更高版本,可以在内置的 “浏览器” 应用上进行自动化了。更多介绍请查看 [mobile web doc](/docs/cn/writing-running-appium/mobile-web.md)。
|
||||
* 是否支持 Hybrid 应用:支持。更多介绍请查阅 [hybrid doc](/docs/cn/advanced-concepts/hybrid.md)。
|
||||
* 默认的 Appium 自动化后台:支持 4.4 以及更高版本
|
||||
* Selendroid 自动化后台:支持 2.3 以及更高版本
|
||||
* 是否支持多个 app 在同一个 session 中自动化:支持(除了使用 Selendroid 后台的时候)
|
||||
* 是否支持多个设备同时进行自动化:支持,即使 Appium 在开始的时候,使用不同的端口号作为服务器参数,`--port`, `--bootstrap-port` (或者 `--selendroid-port`) 还有 `--chromedriver-port`. 更多介绍请查看 [server args doc](/docs/cn/writing-running-appium/server-args.md)。
|
||||
* 支持第三方引用:支持(除了使用 Selendroid 后台的时候)
|
||||
* 支持自定义的、非标准的 UI 控件的自动化:不支持
|
||||
|
||||
### Windows 桌面支持
|
||||
|
||||
查看以下文档获取更多信息:
|
||||
|
||||
* [Running on Windows](running-on-windows.md)
|
||||
* [Windows App Testing](/docs/cn/writing-running-appium/windows-app-testing.md)
|
||||
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
7
docs/cn/appium-setup/real-devices-android.md
Normal file
@@ -0,0 +1,7 @@
|
||||
### 在 Android 真机上运行 Appium
|
||||
|
||||
谢天谢地!在 Android 真机上运行是没有额外需要注意的地方:在模拟器上能运行的测试同样适用在真机上。确保你的设备可以连接 ADB 和开启开发者模式。在真机上测试 Chrome,你只需负责确认 Chrome 已安装上一个合适的版本。
|
||||
|
||||
同样,你需要在手机上关闭“验证应用”,否则他会阻止 Appium 的辅助应用启动和正常运行。
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
BIN
docs/cn/appium-setup/real-devices-img/check-prov-prof.png
Normal file
|
After Width: | Height: | Size: 832 KiB |
BIN
docs/cn/appium-setup/real-devices-img/create-new-project.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
docs/cn/appium-setup/real-devices-img/create-single-page.png
Normal file
|
After Width: | Height: | Size: 765 KiB |
BIN
docs/cn/appium-setup/real-devices-img/no-prov-prof.png
Normal file
|
After Width: | Height: | Size: 928 KiB |
BIN
docs/cn/appium-setup/real-devices-img/project-prov-prof.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
docs/cn/appium-setup/real-devices-img/set-up-bundle.png
Normal file
|
After Width: | Height: | Size: 650 KiB |
BIN
docs/cn/appium-setup/real-devices-img/untrusted-dev.png
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
docs/cn/appium-setup/real-devices-img/xcode-bundle-id.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
docs/cn/appium-setup/real-devices-img/xcode-config.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
docs/cn/appium-setup/real-devices-img/xcode-facebook-fail.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
docs/cn/appium-setup/real-devices-img/xcode-facebook-succeed.png
Normal file
|
After Width: | Height: | Size: 849 KiB |
207
docs/cn/appium-setup/real-devices-ios.md
Normal file
@@ -0,0 +1,207 @@
|
||||
## 在 iOS 真机上运行 Appium
|
||||
|
||||
Appium 已支持真机的测试。
|
||||
|
||||
### 使用 Appium 运行你的测试
|
||||
|
||||
把设备的 udid 传给 `udid` 这个 capability。把应用的 bundle ID 传给 `app` 这个 capability,如果你的应用已经在手机上安装好了。如果应用未安装,那么需要将 `.ipa` 或者 `.app` 文件的路径传给 `app` 这个 capability。一旦你的设备和应用已经配置好,你就可以在那个设备上运行测试了。
|
||||
|
||||
### Desired Capabilities
|
||||
|
||||
通过在测试里使用以下的 capability,你可以在某个设备加载这个应用:
|
||||
|
||||
* `app` 或者 `bundleId` - 指定应用,或者如果应用已经安装到手机上了,只需简单地指定应用的 bundleID。这样 Appium 就可以加载该应用了。
|
||||
* `udid` - 被测设备的 id。如果只有一台设备连接的时候,可以设置为 `auto`,Appium 能自动识别设备 id 并使用它。
|
||||
|
||||
更多的细节参考 [Appium server capabilities](/docs/cn/writing-running-appium/caps.md)
|
||||
|
||||
### 必备的软件
|
||||
|
||||
Appium iOS 真机支持依赖一个重要的第三方软件套件 [libimobiledevice](http://www.libimobiledevice.org/),使用 [Homebrew](http://brew.sh/) 可以轻易地安装好。
|
||||
```
|
||||
brew install libimobiledevice
|
||||
```
|
||||
|
||||
## 在 Xcode 7 和 iOS 9.3 或者以下,配置 iOS 真机设备测试
|
||||
|
||||
在 iOS 9.3 或者以下,使用 Xcode 7.3 或者以下对真机进行自动化 (比如,基于 Instruments 的测试) 需要相对较少的配置。主要就是需要你的应用是使用开发者证书签名的。 不幸的是,苹果移除了所有使用老版本 Xcode 的文档,不过你可以从[这里](https://medium.com/ios-os-x-development/ios-code-signing-provisioning-in-a-nutshell-d5b247760bef#.5hirl92tn),[这里](https://engineering.nodesagency.com/articles/iOS/Understanding-code-signing-for-iOS-apps/)找到如何操作。
|
||||
|
||||
更详细地说, 在真机上开始测试, 你需要如下步骤:
|
||||
|
||||
* 一个 [Apple Developer ID](https://developer.apple.com/programs/ios/) 和一个有效的配置好开发者证书和 provisioning profile 的开发者账号。
|
||||
* 要在真机上测试,一个有效的 iOS 开发证书和 Provisioning Profile 是必须的。被测应用也必须被签名。更多信息可以在 [Apple documentation](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/TestingYouriOSApp/TestingYouriOSApp.html) 找到。
|
||||
* 一个苹果设备: iPad 或者 iPhone 都可以。确保已经在 Xcode 里已经配置好了开发机。
|
||||
* 一个已经签名的 `.app` 或则 `.ipa` 文件,或者使用源码编一个。
|
||||
* 一台 Mac 电脑,装好了 [Xcode](https://developer.apple.com/xcode/) 和 Xcode Command
|
||||
Line Developer Tools。
|
||||
|
||||
Appium 使用 `ideviceinstaller` (`libimobiledevice` 套件的一部分)来处理应用安装问题。但是有时候使用 Xcode 提前安装好应用确保没有问题更加容易。(更多参考 [iOS deploy](ios-deploy.md))。
|
||||
|
||||
### 排障思路
|
||||
|
||||
0. 确保 UDID 是无误的,可以通过 Xcode Organizer 或者 iTunew 查看。留意 UDID 是很长的字符串(20+ 字符)。
|
||||
0. 确保你可以在模拟器运行你的测试。
|
||||
0. 重复确认通过 Instrumens 是否可以启动你的自动化。
|
||||
0. 确保 Instruments 不在运行状态中。
|
||||
0. 确保 UI Automation 在你的设备已经打开。设置 -> 开发者 -> 使用 UI Automation。
|
||||
|
||||
## 在 Xcode 8 和 iOS 9.3 以上配置 iOS 真机设备测试
|
||||
|
||||
作为对 `libimobiledevice` 依赖的补充,Appium 对 iOS 9.3 及以上和 Xcode 8 及以上的支持依赖 `ios-deploy`,
|
||||
通过 [npm](https://www.npmjs.com/package/ios-deploy) 可以方便地安装:
|
||||
```
|
||||
npm install -g ios-deploy
|
||||
```
|
||||
|
||||
不幸地是,苹果改变了以往的测试方法。新的方法需要安装一个帮助应用到设备上去,通过这个应用,自动化测试才能进行。说起来挺简单,但是代码签名和生成供开发和测试的应用,让人有一点头疼。
|
||||
|
||||
Appium 安装的应用叫 `WebDriverAgent-Runner` (可以在[这里](https://github.com/facebook/WebDriverAgent/))找到,要想安装这个应用,Appium需要能配置这个构建。
|
||||
|
||||
### 基本 (自动化) 配置
|
||||
|
||||
在 iOS 真机上设置和运行 Appium XCUItest,最方便的方法是使用自动化配置策略。有两种方式:
|
||||
|
||||
* 使用 `xcodeOrgId` 和 `xcodeSigningId` desired capabilities:
|
||||
```json
|
||||
{
|
||||
"xcodeOrgId": "<Team ID>",
|
||||
"xcodeSigningId": "iPhone Developer"
|
||||
}
|
||||
```
|
||||
* 在你的文件系统里创建一个 `.xcconfig` 文件,内容是:
|
||||
```
|
||||
DEVELOPMENT_TEAM = <Team ID>
|
||||
CODE_SIGN_IDENTITY = iPhone Developer
|
||||
```
|
||||
以上任何一个方式,Team ID 是一个 10 个字符长的字符串,苹果生成这个字符串,分配给你的团队。你可以在你的开发者账号里找到你的 Team ID。登录 [developer.apple.com/account](http://developer.apple.com/account),然后点击边栏上的 Membership。你的 Team ID 在 Membership
|
||||
Information 部分的团队名字下面。你也可以在 keychain 里的 iPhone 开发者证书里的 "Organizational Unit" 属性找到你的 Team ID。
|
||||
|
||||
注意这是互斥的策略;要么用 `xcodeConfigFile` capability, 要么用 `xcodeOrgId` and `xcodeSigningId` 的组合。
|
||||
|
||||
当以上的配置搞定后,只需再指定 `udid` capability 就可以在真机上开始测试了。
|
||||
|
||||
如果还是不工作的话,通常会在 Appium server 的日志里显示一些错误如:`info XCUITest xcodebuild exited with code '65' and signal 'null'`。这通常表示必要的代码签名没配置正确。 去看下 [Basic (manual) configuration](https://github.com/imurchie/appium-xcuitest-driver/blob/isaac-rs/docs/real-device-config.md#basic-manual-configuration)
|
||||
这个文档,参试修复下。
|
||||
|
||||
如果 `WebDriverAgentRunner` 成功的在设备上安装好,但是在 Appium server 日志里还是有如下错误信息:
|
||||
```
|
||||
2017-01-24 09:02:18.358 xcodebuild[30385:339674] Error Domain=com.apple.platform.iphoneos Code=-12 "Unable to launch com.apple.test.WebDriverAgentRunner-Runner" UserInfo={NSLocalizedDescription=Unable to launch com.apple.test.WebDriverAgentRunner-Runner, NSUnderlyingError=0x7fa839cadc60 {Error Domain=DTXMessage Code=1 "(null)" UserInfo={DTXExceptionKey=The operation couldn’t be completed. Unable to launch com.apple.test.WebDriverAgentRunner-Runner because it has an invalid code signature, inadequate entitlements or its profile has not been explicitly trusted by the user. : Failed to launch process with bundle identifier 'com.apple.test.WebDriverAgentRunner-Runner'}}}
|
||||
2017-01-24 09:02:18.358 xcodebuild[30385:339674] Error Domain=IDETestOperationsObserverErrorDomain Code=5 "Early unexpected exit, operation never finished bootstrapping - no restart will be attempted" UserInfo={NSLocalizedDescription=Early unexpected exit, operation never finished bootstrapping - no restart will be attempted}
|
||||
|
||||
Testing failed:
|
||||
Test target WebDriverAgentRunner encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted)
|
||||
```
|
||||
这个问题是因为开发者在这台设备上不被信任。如果你在设备上手动运行 `WebDriverAgentRunner`,你会看到一个错误页面弹出来:
|
||||
|
||||

|
||||
|
||||
你可以去设备中的 Settings => General => Device Management 信任这个开发者,允许 `WebDriverAgentRunner` 运行 (参考 [Apple
|
||||
documentation for more information](https://support.apple.com/en-us/HT204460)).
|
||||
|
||||
|
||||
### 基本 (手动) 配置
|
||||
|
||||
很多情况,基本的自动配置满足不了需求。这通常和真机运行上的代码签名和项目配置有关。这常常发生在免费的开发者账号上,免费的开发者账号不能创建 wildcard provisioning profile,也不能为应用创建默认的配置文件。
|
||||
|
||||
Xcode **创建 provisioning profile 失败** 的错误如下:
|
||||
|
||||

|
||||
|
||||
最容易的解决方案就是打开 [Xcode](https://developer.apple.com/xcode/)创建一个新工程:
|
||||
|
||||

|
||||
|
||||
类型不重要,只要是 "iOS"。用最简单的 "Single View Application" 即可:
|
||||
|
||||

|
||||
|
||||
重要的地方是要用唯一的 "Product Name" 和 "Organization Name". 然后,在这里,指定你的 "Team"。
|
||||
|
||||

|
||||
|
||||
你可以在 "Project" tab 确认 provisioning profile 是否创建成功。
|
||||
|
||||

|
||||
|
||||
或者去你的账号首选项里看看 provisioning profile:
|
||||
|
||||

|
||||
|
||||
现在你就有了一个有效的 provisioning profile。 记住你关联这个 profile 的 bundle id,然后放到 `updatedWDABundleId` 这个 desired capability 里。然后跟着[前面的自动配置教程](#basic-automatic-configuration)操作即可。
|
||||
|
||||
|
||||
### 全部手动配置
|
||||
|
||||
另外,可以手动把 provisioning profile 和项目关联在一起。 (记住如果使用这个方法,每次 WebDriverAgent 更新,都要做一次。所以我们不推荐这个方法):
|
||||
|
||||
* 找到你的 Appium 的安装目录
|
||||
```
|
||||
$ which appium
|
||||
/path/where/installed/bin/appium
|
||||
```
|
||||
* 假设安装目录是: `/path/where/installed/bin/appium`,那么 `WebDriverAgent`
|
||||
在 `/path/where/installed/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent`。
|
||||
打开终端到那个目录,然后按以下命令操作:
|
||||
```
|
||||
mkdir -p Resources/WebDriverAgent.bundle
|
||||
./Scripts/bootstrap.sh -d
|
||||
```
|
||||
* 在 Xcode 里打开 `WebDriverAgent.xcodeproj`。 对于 `WebDriverAgentLib`
|
||||
和 `WebDriverAgentRunner` 两个 target,都选择 "General" tab 里的 "Automatically manage signing"
|
||||
然后选择你的 `Development Team`。这也会自动选择 `Signing Ceritificate`。大概的样子如下:
|
||||
|
||||

|
||||
|
||||
* Xcode 可能会创建不了 `WebDriverAgentRunner` 的 provisioning profile:
|
||||
|
||||

|
||||
|
||||
* 这时候需要在 "Build Settings" tab 里手动改 bundle id。把 "Product Bundle Identifier"
|
||||
从 `com.facebook.WebDriverAgentRunner` 改成 Xcode 能采用的:
|
||||
|
||||

|
||||
|
||||
* 在回到 "General" tab 里的 `WebDriverAgentRunner` target,现在你可以看到一个 provisioning profile 创建成果了:
|
||||
|
||||

|
||||
|
||||
* 最后,你可以验证一切都 OK 了。 构建这个项目:
|
||||
```
|
||||
xcodebuild -project WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=<udid>' test
|
||||
```
|
||||
如果成果了,最后的输出会像下面这样:
|
||||
```
|
||||
Test Suite 'All tests' started at 2017-01-23 15:49:12.585
|
||||
Test Suite 'WebDriverAgentRunner.xctest' started at 2017-01-23 15:49:12.586
|
||||
Test Suite 'UITestingUITests' started at 2017-01-23 15:49:12.587
|
||||
Test Case '-[UITestingUITests testRunner]' started.
|
||||
t = 0.00s Start Test at 2017-01-23 15:49:12.588
|
||||
t = 0.00s Set Up
|
||||
```
|
||||
* 要完整验证的话,你可以试试看访问 WebDriverAgent server 的状态 (**注意:** 你必须和手机设备同一个网段,你可以从 Settings => Wi-Fi => Current Network 找到手机当前的 IP。):
|
||||
```
|
||||
export DEVICE_URL='http://<device IP>:8100'
|
||||
export JSON_HEADER='-H "Content-Type: application/json;charset=UTF-8, accept: application/json"'
|
||||
curl -X GET $JSON_HEADER $DEVICE_URL/status
|
||||
```
|
||||
你会得到如下输出:
|
||||
```
|
||||
{
|
||||
"value" : {
|
||||
"state" : "success",
|
||||
"os" : {
|
||||
"name" : "iOS",
|
||||
"version" : "10.2"
|
||||
},
|
||||
"ios" : {
|
||||
"simulatorVersion" : "10.2",
|
||||
"ip" : "192.168.0.7"
|
||||
},
|
||||
"build" : {
|
||||
"time" : "Jan 23 2017 14:59:57"
|
||||
}
|
||||
},
|
||||
"sessionId" : "8951A6DD-F3AD-410E-A5DB-D042F42F68A7",
|
||||
"status" : 0
|
||||
}
|
||||
```
|
||||
@@ -1,38 +0,0 @@
|
||||
# Appium在真机上
|
||||
|
||||
Appium已经初步支持真机测试。
|
||||
|
||||
如果要在真机上执行测试,你将要做如下准备:
|
||||
|
||||
1.一个苹果的开发者ID和有效的开发者对应的配置文件和签名文件
|
||||
|
||||
2.一台iPad或者iPhone
|
||||
|
||||
3. 你要测试的应用的源码
|
||||
|
||||
4. 一台安装了XCode和XCode Command Line Developer Tools的Mac机器
|
||||
|
||||
## Provisioning Profile
|
||||
|
||||
要在真机上测试就需要一个有效的iOS开发者的Distribution Certificate and Provisioning Profile。你可以在这个上面找到配置这些的相关信息[Apple documentation](http://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/YourFirstAppStoreSubmission/TestYourApponManyDevicesandiOSVersions/TestYourApponManyDevicesandiOSVersions.html)
|
||||
|
||||
同样的,你还需要对你的应用签名,更多的信息可以查看[sign your app](http://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/YourFirstAppStoreSubmission/ProvisionYourDevicesforDevelopment/ProvisionYourDevicesforDevelopment.html#//apple_ref/doc/uid/TP40011375-CH4-SW1).
|
||||
|
||||
你必须使用Xcode的执行按钮来安装你的应用
|
||||
|
||||
## 使用Appium运行你的测试
|
||||
|
||||
一旦你的设备和应用设置好了之后,你就能够用如下的命令在你的机器上执行测试:
|
||||
|
||||
```
|
||||
node . -U <UDID> --app <bundle_id>
|
||||
```
|
||||
|
||||
这将会启动Appium并且开始在真机上测试应用。
|
||||
|
||||
## 疑问解答思路
|
||||
|
||||
0. 确认UDID已经正确的在xcode organizar或itunes中设置了。很长的字符串(20多个字符串)
|
||||
0.确认你测试代码中的测试对象设备的设置
|
||||
0. 再次确认你从instruments启动你的自动化测试
|
||||
0. 确认instruments已经关闭
|
||||
6
docs/cn/appium-setup/real-devices.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## Appium 上对真机测试的支持
|
||||
|
||||
Appium 已支持真机的测试。
|
||||
|
||||
* **Android** 测试, 参考 [android real device documentation](real-devices-android.md)
|
||||
* **iOS** 测试, 参考 [iOS real device documentation](real-devices-ios.md)
|
||||
@@ -1,32 +0,0 @@
|
||||
# 在 Linux 上运行 Appium
|
||||
|
||||
### 限制
|
||||
|
||||
如果你在 Linux 上使用 Appium, 那么你没法使用已经构建好的 '.app',那是为 OS X 准备的。 另外由于 Appium 在测试 iOS 应用时 依赖 OS X 特有的库, 所以你也没有办法测试在 Linux 上测试 iOS 应用。
|
||||
|
||||
## 配置
|
||||
|
||||
首先,安装版本高于或等于 0.8 的 nodejs。可以根据 [instructions for your flavor of linux](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager) 进行安装。
|
||||
|
||||
安装好了 node.js 之后,安装 [Android SDK](http://developer.android.com/sdk/index.html)。 你会需要运行 `android` `adb` 等工具,这些工具都在 SDK 里包含了, 你要做的是配置环境变量。当然你要确保你的 API level 大于等于 17。 你也需要使用 Ant 来构建 bootstrap jar 以便 Appium 使用它来测试 Android 应用。
|
||||
|
||||
最后, 设置 `$ANDROID_HOME` 为你的 Android SDK 的路径。比如, 你将 Android SDK 解压在 `/usr/local/adt/`, 那你就要将如下添加到你的 `.bashrc` 或 `.zshrc` 或 `.bash_profile` 等 shell 配置文件中去:
|
||||
|
||||
export ANDROID_HOME="/usr/local/adt/sdk
|
||||
|
||||
现在你可以运行 Appium 了, 在你 checkout 出来的 Appium 目录里, 运行 `.reset.sh --android`, 它会帮助你安装好所有的依赖。
|
||||
|
||||
## 运行 Appium
|
||||
|
||||
运行测试前, 你需要启动一个 API Level 大于等于 17 的 Android 模拟器或者连接一个系统是 4.1 以上的 Android 真机。然后在 Appium 目录运行
|
||||
|
||||
node .
|
||||
|
||||
你可以在 [server documentation](server-args.cn.md) 找到所有的命令行参数。
|
||||
|
||||
|
||||
## 备注
|
||||
* There exists a hardware accelerated emulator for android, it has it's own
|
||||
limitations. For more information you can check out this
|
||||
Android 有一些硬件加速的模拟器,这些模拟器有自己的限制。你可以在 [page](android-hax-emulator.cn.md) 找到更多的信息。
|
||||
* 确保你使用的 AVD 里面的 `config.ini` 有这条指令 `hw.battery=yes`。
|
||||
11
docs/cn/appium-setup/running-on-linux.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## 在 Linux 上运行 Appium
|
||||
|
||||
### 局限性
|
||||
|
||||
如果你要在 Linux 上运行 Appium,是不能使用 '.app' 的预构建包的,因为它只能在 OS X 上进行构建。其次,iOS 的应用测试也是无法进行,因为 Appium 也是依赖在 OS X 上特有的库才能支持 iOS 的测试。
|
||||
|
||||
### 配置(Android)
|
||||
|
||||
Android 上的一些设置,与在 linux 上运行测试的方式,都是跟 Mac OS X 上的操作方式是相同的。 请查阅 [Android 设置文档](/docs/cn/appium-setup/android-setup.md).
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,28 +0,0 @@
|
||||
# 在 Mac OS X 上使用 Appium
|
||||
|
||||
在 OS X 上, Appium 支持 iOS 和 Android 测试
|
||||
|
||||
## 系统配置 (iOS)
|
||||
|
||||
* Appium 需要 Mac OS X 10.7, 推荐 10.8。 (经过测试, 10.9 也能工作。)
|
||||
* 确保 Xcode 和 iOS SDK 都已经安装好了。 (当前 Appium 支持 Xcode 4.6.3/iOS 6.1 和 Xcode 5/iOS 7.0。 注意不推荐在基于 Xcode 5 下且低于 7.0 的 iOS 版本进行测试。 参照下篇可以获取更多信息)
|
||||
* 你需要授权 iOS 模拟器的使用。如果你是通过 NPM 安装的 Appium,那么你可以运行 `sudo authorize_ios` (`authorize_ios`)是来自 Appium npm 包里的一个二进制执行文件。如果你是从源代码运行 Appium,那么你可以简单的使用 `sudo grunt authorize`。如果你使用[Appium.app](https://github.com/appium/appium-dot-app), 那你只要用界面来操作。
|
||||
* 如果你使用的是Xcode 6,在启动Appium之前,你需要打开模拟器,并且在你需要进行输入文字的操作之前,必须先将输入法提前调出。你可以通过点击输入区域或通过快捷键`command-K`来将软键盘唤出。
|
||||
* Xcode 6中,有一个Devices的模块(command-shift-2可唤出)。你必须确保Appium 的capabilities参数中,所使用到的deviceName要存在于Devices里。换句话说,如果capabilities中的deviceName为"iPhone 5s",platformVersion为"8.0",那么你必须确保Devices中要存在那么一个设备是"iOS8系统的iPhone5s",否则Appium将不知道使用哪一个设备进行测试。
|
||||
* 在iOS8设置中的开发者选项里面,你可以打开或关闭UIAutomation。如果你的是iOS8设备,请在运行Appium之前,确保UIAutomation是打开状态的。
|
||||
|
||||
## 使用多种 iOS SDK 进行测试
|
||||
|
||||
Appium 使用苹果提供的 `instruments` 来启动 iOS 模拟器,默认它会使用当前安装的 Xcode 和该 Xcode 下安装好的最高版本的 iOS SDK。这就意味着如果你想测试 iOS 6.1, 但是你安装了 iOS 7.0, 那么 Appium 会强制使用 7.0 的模拟器。 唯一的方法就是安装多个Xcode,然后在安装不同的 SDK。然后在启动 Appium 前,切换到你要测试的特定的版本。
|
||||
|
||||
另外,我们发现 Xcode 5 上的 iOS 6.1 测试,会很慢而且不稳定。所以我们推荐,如果要在 6.1 及 6.1 以下版本的 iOS 上进行测试,请使用 Xcode 4.6.3。如果要在 iOS 7.0 上测试,请使用 Xcode 5。假设我们的 Xcode 5 在 `/Applications/Xcode.app`, Xcode 4.6 在 `/Applications/Xcode-4.6.app`,我们就可以用下面的命令来切换到 Xcode 4.6 来为 iOS 6.1 测试做准备。
|
||||
|
||||
sudo xcode-select -switch /Applications/Xcode-4.6.app/Contents/Developer/
|
||||
|
||||
如果要回到 Xcode 5 的话,我们再运行一次:
|
||||
|
||||
sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer/
|
||||
|
||||
## 系统配置 (Android)
|
||||
|
||||
* 在Mac OSX 上运行Android项目所需要的配置,与Linux的配置方法是一致的,请参考 [Android setup docs](/docs/cn/appium-setup/android-setup.cn.md)。
|
||||
150
docs/cn/appium-setup/running-on-osx.md
Normal file
@@ -0,0 +1,150 @@
|
||||
## 在 Mac OS Xcode 上运行 Appium
|
||||
|
||||
在 OS X 上,Appium 支持 iOS 与 Android 测试。
|
||||
|
||||
### 系统配置(iOS)
|
||||
|
||||
* Appium 要求 Mac OS X 10.10 或更高的系统版本。
|
||||
* 确保你已经安装 Xcode 与 iOS 的 SDK。推荐使用 Xcode 7.1版本,因为早期版本的 Xcode 的版本对于可测试的 iOS 版本是受限的。查看下面的章节了解更多信息。
|
||||
* 你需要给 iOS 模拟器授权使用。请查看[下面章节](#authorizing-ios-on-the-computer)。
|
||||
* 如果你使用 Xcode 7.x 及以上版本,Instruments Without Delay(IWD) 已经失效了。你通过[这个方法](/docs/cn/advanced-concepts/iwd_xcode7.md)去使用 IWD (它会使你的测试速度显著提升)。
|
||||
* 如果你使用 Xcode 6,使用 Appium 前你得提前启动模拟器。假如你想发送文本信息,你得改变他的默认设置,去开启虚拟键盘。开启键盘后,你就可以通过点击输入框,或使用快捷键(comand + K)去调出键盘。
|
||||
* 如果你使用 Xcode 6,Xcode 上有个模块叫 Devices(快捷键:comand-shift-2)。使用 Appium 的时候,你只需要在 capabilities 中的 devicesName 参数填上你的设备名字,每一个 sdk 版本都会对应一个设备。换句话说,如果你在 capabilities 里设置了 devicesName 为 "iPhone 5s" 以及 platformVersion 为 "8.0",你就得保证在设备列表里,这是唯一一个使用 8.0 sdk 且名为"iPhone 5s"的设备。否则,Appium 就不会知道你想用的哪台设备。
|
||||
* 在 iOS 8,可以在`设置`里开启或者关闭 UIAutomation。该设置就在手机的设置里一个叫"Developer"页面。在使用模拟器或者真机去做自动化前,你需要去该页面确保 UIautomation 开关已经开启。
|
||||
|
||||
### 授权 iOS 设备给你的电脑
|
||||
|
||||
你要运行 `authorize-ios` 工具进行授权,可以通过 `npm` 去安装该工具,运行以下命令进行安装
|
||||
|
||||
```
|
||||
npm install -g authorize-ios
|
||||
```
|
||||
|
||||
然后运行以下命令去调起该工具
|
||||
|
||||
```
|
||||
sudo authorize-ios
|
||||
```
|
||||
|
||||
如果你是使用 [Appium.app](https://github.com/appium/appium-dot-app),你可以在 GUI 界面进行授权。
|
||||
|
||||
每次更新 Xcode 版本的时候,你都需要重复以上步骤哦!
|
||||
|
||||
### 使用多种 iOS SDK 测试
|
||||
|
||||
Xcode 7.1 版本允许使用 iOS 7.1 以及更高级的系统版本去做自动化测试。
|
||||
|
||||
如果你使用多个 Xcode 版本,你使用以下命令去切换版本:
|
||||
|
||||
sudo xcode-select --switch <path to required xcode>
|
||||
|
||||
### 在 Xcode 8(包括 iOS 10)下使用 XCUITest 进行测试
|
||||
|
||||
为了在 Xcode 8(其中包括所有 iOS 10+ 的测试)使用 iOS 真机做自动化,你要安装 [Carthage](https://github.com/Carthage/Carthage) 去做依赖管理:
|
||||
```
|
||||
brew install carthage
|
||||
```
|
||||
|
||||
### 测试 Mac 应用
|
||||
|
||||
目前为止,Mac 对应的 appium driver 在 AppiumForMac 的二进制文件还没发布,也就是说如果你想进行 Mac 应用的自动化,你就得手动去安装 AppiumForMac 应用,并且对 OS X 授予可访问权限。
|
||||
|
||||
|
||||
如何安装 Appium for Mac:
|
||||
1. [下载该发布版本](https://github.com/appium/appium-for-mac/releases/tag/0.2.0),将他解压缩到 `/Applications` 文件夹中
|
||||
2. 查看 [简要补充安装说明](https://github.com/appium/appium-for-mac#installation),确保 appium 放访问到 OS X 的 Accessibility APIs
|
||||
|
||||
更多相关如何使用 Appium for mac 的相关信息,请查阅该[文档](https://github.com/appium/appium-for-mac#appium-for-mac)。
|
||||
|
||||
|
||||
### 系统配置(Android)
|
||||
|
||||
Android 的设置操作指南与在 Mac OS X 上的设置,大致与 Linux 上的设置相似,可以参考 [Android 设置文档](/docs/en/appium-setup/android-setup.md)。
|
||||
|
||||
### 使用 Jenkins 在 OS X 上运行 iOS 测试
|
||||
|
||||
第一步就是下载 jenkins-cli.jar,以及验证你的 Mac 是否成功的连接上 Jenkins 主机。确保已经运行了 `authorize-ios` 等相关的命令。
|
||||
|
||||
`wget https://jenkins.ci.cloudbees.com/jnlpJars/jenkins-cli.jar`
|
||||
|
||||
```
|
||||
java -jar jenkins-cli.jar \
|
||||
-s https://team-appium.ci.cloudbees.com \
|
||||
-i ~/.ssh/id_rsa \
|
||||
on-premise-executor \
|
||||
-fsroot ~/jenkins \
|
||||
-labels osx \
|
||||
-name mac_appium
|
||||
```
|
||||
|
||||
接下来为了在登录的时候可以自动启动,定义一个 Jenkins 的 LaunchAgent。LaunchDaemon 将会停止工作,因为 deamons 没有获取 GUI 的访问权限。确保 plist 文件不会包含`SessionCreate` 或 `User` 这两个键值,就防止测试在运行时启动。如果漏了配置,你会看到该报错: `Failed to authorize rights`。
|
||||
|
||||
|
||||
```
|
||||
$ sudo nano /Library/LaunchAgents/com.jenkins.ci.plist
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.jenkins.ci</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>java</string>
|
||||
<string>-Djava.awt.headless=true</string>
|
||||
<string>-jar</string>
|
||||
<string>/Users/appium/jenkins/jenkins-cli.jar</string>
|
||||
<string>-s</string>
|
||||
<string>https://instructure.ci.cloudbees.com</string>
|
||||
<string>on-premise-executor</string>
|
||||
<string>-fsroot</string>
|
||||
<string>/Users/appium/jenkins</string>
|
||||
<string>-executors</string>
|
||||
<string>1</string>
|
||||
<string>-labels</string>
|
||||
<string>mac</string>
|
||||
<string>-name</string>
|
||||
<string>mac_appium</string>
|
||||
<string>-persistent</string>
|
||||
</array>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/appium/jenkins/stdout.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/appium/jenkins/error.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
最后设置 owner,权限,再开启代理。
|
||||
|
||||
```
|
||||
sudo chown root:wheel /Library/LaunchAgents/com.jenkins.ci.plist
|
||||
sudo chmod 644 /Library/LaunchAgents/com.jenkins.ci.plist
|
||||
|
||||
launchctl load /Library/LaunchAgents/com.jenkins.ci.plist
|
||||
launchctl start com.jenkins.ci
|
||||
```
|
||||
|
||||
### 运行 iOS 测试时生成的文件
|
||||
|
||||
测试 iOS 的过程中生成的文件有时可能会过大。这些文件包含日志,临时文件,还有 Xcode 运行时产生的数据。一般来说,下面的这些地址都是这些文件保存的地方,可以删除他们节省空间:
|
||||
|
||||
```
|
||||
$HOME/Library/Logs/CoreSimulator/*
|
||||
```
|
||||
|
||||
基于 Instruments 的测试 (iOS 不是使用 `XCUITest` 作为 `automationName`):
|
||||
|
||||
```
|
||||
/Library/Caches/com.apple.dt.instruments/*
|
||||
```
|
||||
|
||||
基于 XCUITest 的测试:
|
||||
|
||||
```
|
||||
$HOME/Library/Developer/Xcode/DerivedData/*
|
||||
```
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,58 +0,0 @@
|
||||
# 在Windows上运行Appium
|
||||
|
||||
### 局限性
|
||||
|
||||
如果你在windows上安装appium,你没法使用预编译专用于OS X的.app文件,你也将不能测试IOS apps,因为appium依赖OS X专用的库来支持IOS测试。这意味着你只能通过在mac上来运行IOS的app测试。这点限制挺大。
|
||||
|
||||
## 开始安装
|
||||
|
||||
1. 安装[nodejs](http://nodejs.org/download/) 0.8版本及以上, 通过官方的安装程序来安装。
|
||||
|
||||
2. 安装android的sdk包,(http://developer.android.com/sdk/index.html), 运行依赖sdk中的'android'工具。并确保你安装了Level17或以上的版本api。设置`ANDROID_HOME`系统变量为你的Android SDK路径,并把tools platform-tools两个目录加入到系统的Path路径里。因为这里面包含有一些执行命令
|
||||
|
||||
3. 安装java的JDK,并设置`JAVA_HOME` 变量为你的JDK目录。
|
||||
|
||||
4. 安装[Apache Ant](http://ant.apache.org/bindownload.cgi)
|
||||
或者直接使用Android Windows SDK自带的ant,地址在eclipse\plugins目录,你需要把这个目录加到你的系统PATH变量中
|
||||
|
||||
5. 安装[Apache Maven](http://maven.apache.org/download.cgi). 并且设置M2HOME和M2环境变量,把M2环境变量添加到你的系统PATH变量中。
|
||||
|
||||
6. 安装[Git](http://git-scm.com/download/win). 确保你安装了windows下的Git,以便可以运行常用的command命令
|
||||
|
||||
|
||||
现在,你已经下载安装了所有的依赖,开始运行
|
||||
reset.bat
|
||||
|
||||
### 运行Appium
|
||||
|
||||
要在windows上运行测试用例,你需要先启动Android模拟器或者连接上一个API Level17以上的android真机。然后在命令行运行`appium`。
|
||||
如果你是使用源码运行Appium的,请在你所安装的appium目录下执行node.js命令:
|
||||
```center
|
||||
node .
|
||||
```
|
||||
|
||||
### 备注
|
||||
* 在windows系统下运行appium.app时,需要使用管理员权限;当你通过源码的形式运行Appium时,也需要使用管理员权限启动CMD。
|
||||
* 在windows系统下运行Android项目时,启动Appium时请带上`--no-reset`或`--full-reset`命令。
|
||||
* 有一个硬件加速模拟器用于android,但是它有自己的一些限制,如果你想了解更多,请参考[页面](android-hax-emulator.cn.md)
|
||||
* 确保在你的AVD的`config.ini`中有一个配置项为`hw.battery=yes`
|
||||
|
||||
|
||||
|
||||
### 最简略的安装方式
|
||||
出于对官方文档的尊重,我按照原文翻译,如下介绍我的安装心得。官方提到的一些工具,其实并不需要安装。
|
||||
下面介绍我已经测试过的安装和使用过程
|
||||
|
||||
### 安装appium
|
||||
|
||||
1. 安装nodejs
|
||||
|
||||
2. 使用npm安装appium,npm install -g appium
|
||||
|
||||
### 运行appium
|
||||
启动appium,直接运行appium 即可。
|
||||
|
||||
### 更新appium
|
||||
通过`npm install -g appium` 来更新appium即可
|
||||
|
||||
如果有任何疑问,欢迎到testerhome.com来交流
|
||||
43
docs/cn/appium-setup/running-on-windows.md
Normal file
@@ -0,0 +1,43 @@
|
||||
#Windows 设置
|
||||
|
||||
在 Windows 上,Appium 支持 Windows 与 Android 应用的自动化测试!
|
||||
|
||||
获取更多信息请查阅 [Windows 应用测试](/docs/cn/writing-running-appium/windows-app-testing.md)。
|
||||
|
||||
## 在 Windows 上运行 Appium
|
||||
|
||||
## 配置
|
||||
|
||||
开始安装:
|
||||
|
||||
1. 下载最新版本的 [node 与 npm 工具](https://nodejs.org/download/release/v6.3.0/node-v6.3.0-x64.msi) 的 MSI (版本 >= 6.0) `npm` 和 `nodejs` 两个命令应该在你的 PATH 系统变量里。
|
||||
2. 打开你的 cmd 终端
|
||||
3. 运行 `npm install -g appium` 这条命令后,就会通过 NPM 去安装 Appium。
|
||||
4. 在命令行简单地输入 `appium` 就可以快速开启 Appium。
|
||||
5. 按照下面的只是去设置 Android 或者 Windows 应用的测试。
|
||||
6. 使用任意 Appium 客户端去运行一个测试。
|
||||
|
||||
## Android 应用测试的一些额外配置
|
||||
|
||||
1. 下载最新版的 Java JDK[这里](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)(记得先接受协议的许可)。设置 'JAVA_HOME' 为你的 JDK 路径。目录下的 `bin` 文件夹应该添加到你的 PATH 变量中。
|
||||
2. 安装 [Android SDK](http://developer.android.com/sdk/index.html)。将环境变量`ANDROID_HOME`设置为你的 Android SDK 路径,并且将 `tools` 和 `platform-tools` 这两个文件夹添加到你的 PATH 变量中去。
|
||||
3. 安装 [Apache Ant](http://ant.apache.org/bindownload.cgi) 或使用 eclipse 插件目录中的 Android Windows SDK。确保添加的文件夹包含 Ant 在你的 PATH 变量中。
|
||||
4. 安装 [Apache Maven](http://maven.apache.org/download.cgi) ,并设置 M2HOME 与 M2 的环境变量。设置 `M2_HOME` 为 maven 所在的安装路径,设置 `M2` 为 `bin` 目录的路径。将 `M2` 路径添加到你的 PATH 变量中。
|
||||
5. 在 Windows 上运行测试,你需要启动 Android 的虚拟机或者一台已经连接电脑的 Android 真机,并且 AVD 要求 API Level 17 或更高版本,才能在命令行中运行 Appium(通过 `appium` 命令)
|
||||
6. 你的测试脚本应该确保 `platformVersion` 参数是与你的模拟器或者模拟器的版本是一一对应的,以及`app`参数是你的需要测试的应用的绝对路径。
|
||||
|
||||
## Windows 应用测试的额外配置
|
||||
|
||||
1. 测试 Windows 应用,最基本的要求就是要打开 [开发者模式](https://msdn.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)。
|
||||
|
||||
(查看[Windows app testing](/docs/cn/writing-running-appium/windows-app-testing.md),了解更多测试 Windows 应用测试的说明)
|
||||
|
||||
## 运行 Appium
|
||||
|
||||
查看 [server documentation](/docs/cn/writing-running-appium/server-args.md) 可以查看所有的命令参数。
|
||||
|
||||
* 在 Windows 上运行 Appium.exe 需要管理员权限,或者当你以源码方式运行,你要在 cmd 运行时有管理员权限。
|
||||
* 在 Windows 上运行 Andoid 测试时,务必记得添加上`--no-reset` 或 `--full-reset` 参数。
|
||||
* Android 有硬件加速仿真器;但他也是有限制的,更多信息请查阅该[文章](/docs/cn/appium-setup/android-hax-emulator.md).
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,96 +0,0 @@
|
||||
## Appium 故障排除
|
||||
|
||||
当你遇到问题时,请不要急着将问题提交到Github,也不用急着发到[appium-discuss discussion group](https://discuss.appium.io),也许你可以在本文中找到答案。
|
||||
|
||||
### 常见问题解决办法
|
||||
|
||||
* 确保你的每一个步骤都是遵循 [入门指南](/docs/cn/README.cn.md) 来做的。
|
||||
* 确保你的系统配置正确。(例如:Xcode是否升级到了最新版本,Android SDK是否有设置到环境变量`ANDROID_HOME`中去。)
|
||||
* 确保你的应用存放路径没有错误。
|
||||
|
||||
### Appium.app运行出现问题的解决办法
|
||||
|
||||
* 升级Appium.app后重新打开即可解决。如果提示你不能升级,则需要重新下载Appium.app,下载地址:[appium.io](http://appium.io)
|
||||
|
||||
|
||||
### 通过源码启用Appium出现问题的解决办法
|
||||
|
||||
* 使用`git pull`拉取最新源码,确保运行的代码是当前最新版本。
|
||||
* 针对你所自动化的平台,运行`reset.sh`命令:
|
||||
|
||||
|命令 | 说明 |
|
||||
|-------------------------|-------------|
|
||||
|./reset.sh | # all |
|
||||
|./reset.sh --ios | # ios-only |
|
||||
|./reset.sh --android | # android-only |
|
||||
|./reset.sh --selendroid | # selendroid-only |
|
||||
|
||||
* 当你需要下载以及构建测试应用时,运行`reset.sh`时你需要用到`--dev`指令。
|
||||
* 你也可以使用`appium-doctor`来自动检测你的环境依赖都是否正常。如果你是使用源码运行,则需要使用到`bin/appium-doctor.js`或`node bin/appium-doctor.js`。
|
||||
* 当你将Android SDK升级到22后,可能出现如下错误:
|
||||
`{ANDROID_HOME}/tools/ant/uibuild.xml:155: SDK does not have any Build Tools installed.`
|
||||
这是因为在Android SDK 22中,platform 和 build 工具被分拆到他们各自的SDK管理包中去了。你需要确保你的机器上正确安装了build-tools 和 platform-tools。
|
||||
|
||||
### Android常见问题解决办法
|
||||
|
||||
* 确保 Android 模拟器启动并运行着。
|
||||
* 出现设备连接问题时,运行`adb kill-server && adb devices`是非常有效的。它能够帮助重置和连接Android设备。
|
||||
* 请确保环境变量 ANDROID_HOME 指向的是正确的Android SDK的路径。
|
||||
|
||||
### IOS常见问题解决方案
|
||||
|
||||
* 确保Instruments.app是关闭的。
|
||||
* 如果你是使用模拟器运行的,请不要将真机设备连接电脑。
|
||||
* 确保模拟器或真机中,设置里面的accessibility辅助功能是关闭状态的。
|
||||
* 确保App是编译在当前运行的模拟器上。
|
||||
* 确保App是编译在合适的模拟器(或真机)上,不然会出现`posix spawn`的报错。(比如:运行在debug模式下的模拟器)
|
||||
* 如果你曾经用 sudo 运行过 Appium, 你需要先删除/tmp/instruments_sock, 执行`sudo rm /tmp/instruments_sock`。然后在不适用SUDO的情况下再次启动Appium即可。
|
||||
* 第一次运行Appium时,需要对Instruments进行授权。不然的话会经常弹出对话框要求你输入密码。如果你从源代码运行 Appium,你只需在主分支上运行`sudo grunt authorize`来回避该弹窗。如果用 npm 安装的话,运行 `sudo authorize_ios` 即可。注意,当你每次安装了新版本的xcode,你都需要重复以上操作。
|
||||
* 如果检查路径正确,但仍然报 `iOS Simulator failed to install the application.`的错误的时候,请尝试重启你的电脑。
|
||||
|
||||
### Webview/Hybrid/Safari 应用支持
|
||||
|
||||
* 确保真机上的'Web Inspector'为打开状态。
|
||||
* 确保打开了Safari的开发模式。(Safari - Advance Preferences- Developer menu for
|
||||
simulators)
|
||||
* 确保由client library提供的Appium命令-`context`能够正常得对contexts进行切换。
|
||||
* 当你尝试打开代理的时候,出现如下错误:select_port() failed,请参考[discussion](https://groups.google.com/forum/#!topic/appium-discuss/tw2GaSN8WX0)
|
||||
|
||||
### FirefoxOS常见问题解决办法
|
||||
|
||||
* 确保 Boot-to-Gecko 模拟器启动并运行着。
|
||||
* 确保模拟器的屏幕是亮着并无锁屏的(可能需要重启 B2G).
|
||||
|
||||
### 到社区寻求帮助
|
||||
|
||||
若通过上述方法你的问题依然没有得到解决,你可以:
|
||||
|
||||
如果你的 Appium 无法正常工作,然后错误信息不够清晰,欢迎加入 [discussion group](https://discuss.appium.io)中发表你的问题,你的问题需要包括以下内容:
|
||||
|
||||
* 你是如何运行Appium的?(Appium.app, npm, source)
|
||||
* 你使用的是什么操作系统?
|
||||
* 你使用的是什么设备?版本是什么? (i.e. Android 4.4, or iOS 7.1)
|
||||
* 你使用的是真机还是模拟器?
|
||||
* 给出你得到的客户端和服务端的出错日志 (比如,"我的Python代码中报了如下错误:balabala,在Appium server中的输出内容如链接中所示")
|
||||
* 除了上述, 贴出 Appium 服务器端的输出也非常重要,特别是运行在 verbose 模式。这样我们可以分析诊断问题在哪里。
|
||||
|
||||
如果你确信你发现的是一个BUG,请到[issue tracker](https://github.com/appium/appium/issues)中提交一个issue,并将BUG的内容描述清楚。
|
||||
|
||||
### 已知问题
|
||||
|
||||
* 如果你从 Node 官网安装的 Node,那需要你使用 sudo 运行 `npm`。 但这么做并不是非常理想。请尝试从
|
||||
[n](https://github.com/visionmedia/n) 获取node 或运行`brew install node`来安装 。
|
||||
* Webview通过代理可以支持iOS真机设备,请参考[discussion](https://groups.google.com/d/msg/appium-discuss/u1ropm4OEbY/uJ3y422a5_kJ)
|
||||
* 有时候, iOS 的 UI 元素在定位到之后几毫秒会突然变得无效。这会导致一个类似(null) cannot be tapped的错误。唯一的解决方法就是把finding-and-acting的代码放到 retry 块里。
|
||||
* 如果你是通过MacPorts安装了Node和Npm,你必须确保MacPorts的bin文件夹已经被添加到环境变量`PATH`中去,不然Appium会出现难以找到可执行`node`的情况。
|
||||
|
||||
|
||||
### 特定的错误
|
||||
|
||||
|Action|Error|Resolution|
|
||||
|------|-----|----------|
|
||||
|Running reset.sh|xcodebuild: error: SDK "iphonesimulator6.1" cannot be located|安装 iPhone 6.1 SDK 或者 使用单独的 SDK 构建 待测应用 比如: `grunt buildApp:UICatalog:iphonesimulator5.1`|
|
||||
|Running reset.sh|Warning: Task "setGitRev" not found. Use --force to continue.|使用`git submodule update --init`更新模块并再次运行`reset.sh`|
|
||||
|Running reset.sh|`[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project selendroid-server: Compilation failure [ERROR] Failure executing javac, but could not parse the error: [ERROR] [ERROR] [ERROR] The system is out of resources. [ERROR] Consult the following stack trace for details. [ERROR] java.lang.StackOverflowError `|`export MAVEN_OPTS="-Xms1024m -Xmx2048m -Xss2048k"`|
|
||||
|Running ios test|`[INST STDERR] posix spawn failure; aborting launch`|你的应用没有正确编译在模拟器或真机上。|
|
||||
|Running mobile safari test|`error: Could not prepare mobile safari with version '7.1'`|你可能需要在此运行授权脚本以保证使iOS SDK文件为可写状态。 E.g., `sudo authorize_ios`|
|
||||
150
docs/cn/appium-setup/troubleshooting.md
Normal file
@@ -0,0 +1,150 @@
|
||||
## Appium 的故障排查
|
||||
|
||||
当你在使用过程中遇到了问题,先别急着到 github 上提交反馈,或者到 [appium-discuss discussion group](https://discuss.appium.io) 提问。可以先试试在本文中能否找到解决的办法。
|
||||
|
||||
### 常见问题
|
||||
|
||||
* 确保你是跟着 [README](/README.md) 中的每一步来做。
|
||||
* 确保你的系统已经配置好所需环境(例如. Xcode 已更至最新,Android SDK 已经安装好,而且`ANDROID_HOME`也设置无误)。
|
||||
* 确保你应用的存放路径是正确的。
|
||||
* 在 windows 上运行 appium.app 要使用管理员权限,假如你在 cmd 中运行,也得确保是在管理员权限下。
|
||||
|
||||
### 如果你是通过 Appium.app 运行
|
||||
|
||||
* 升级应用并重启。如果你被告知应用无法升级,请到 [appium.io](http://appium.io) 重新下载。
|
||||
|
||||
### 如果你是通过 Appium 的源码运行
|
||||
|
||||
* 通过 `git pull` 命令拉取代码,确保当前的代码是最新的
|
||||
* 移除旧的依赖:`rm -rf node_modules`
|
||||
* 重新安装依赖:`npm install`
|
||||
* 代码 Re-transpile: `gulp transpile`
|
||||
|
||||
* 你可以使用 [Appium Doctor](https://github.com/appium/appium-doctor) 去检测 Appium 环境是否已经配置好了。
|
||||
* 如果你升级到 Android SDK 22 后出现如下报错:
|
||||
`{ANDROID_HOME}/tools/ant/uibuild.xml:155: SDK does not have any Build Tools installed.`
|
||||
在 Android SDK 22 中,platform 与 build tools 分别被拆分到各自的 SDK 管理包中去了。你需要确保已经正确安装了 build-tools 与 platform-tools。
|
||||
|
||||
### Android
|
||||
|
||||
* 确保 Android 模拟器已经开启并在运行中。
|
||||
* 出现设备连接问题时, `adb kill-server && adb devices` 这行命令非常有用。它可以重置你的 Android 设备的连接。
|
||||
* 确保你已经设置了 ANDROID_HOME 已经指向了 Android SDK 路径
|
||||
|
||||
|
||||
### Windows
|
||||
|
||||
* 确保已经开启了开发者模式。
|
||||
* 确保 command prompt 已经是管理员权限。
|
||||
* 检查 Appium 服务器正在监听的 URL 是否与你测试脚本中的 URL 匹配的上。
|
||||
|
||||
### IOS
|
||||
|
||||
* 确保 Instruments.app 没有被开启。
|
||||
* 如果你使用模拟器时,记得不要让真机连上你的电脑。
|
||||
* 确保在手机的设置中的 accessibility 辅助功能是关闭的。
|
||||
* 确保应用是变异在当前运行的模拟器上。
|
||||
* 确保应用已编译在合适的模拟器(或真机)上(例如. 在模拟器上运行需要 debug 模式的包),否则你会出现`posix spawn`报错。
|
||||
* 如果你曾经用 sudo 运行过 Appium,你可能需要运行 `sudo rm /tmp/instruments_sock` 该命令,而且记住以后尽量别带上 sudo。
|
||||
* 如果你是第一次运行 Appium,记得对 Instruments 进行授权。 查阅 [running on OSX documentation](./running-on-osx.md#authorizing-ios-on-the-computer) 了解更多。
|
||||
* 如果在真机上运行 Instruments 出现了崩溃("exited with code 253"),确保 Xcode 已经下载了设备的符号文件。到 Window -> Devices,然后他就会自动的开始下载。每次 iOS 版本升级后都需要做这步。
|
||||
* 如果你看到 `iOS Simulator failed to install the application.` 这样的报错,并且确定路径没有设置错误的话,那你可以尝试去重启你的电脑。
|
||||
* 确保你的 macOS 上的 keychain 已经保存了用于构建你的应用的证书,并且 WebDeriverAgent 是已签名的。特别是你在使用 ssh 的情况下。通常失败的话会显示`签名`报错。
|
||||
* 如果你的应用中还有自定义的元素,他们或许不能通过默认的方式去使用 UIAutomaion(and therefore Appuim)进行自动化。你需要将 accessibility status 设置为'enabled'。在代码中设置的方式如下:
|
||||
|
||||
```center
|
||||
[myCustomView setAccessibilityEnabled:YES];
|
||||
```
|
||||
|
||||
* 在 iOS 上测试可能会出现类似内存泄露(包括性能不佳、程序挂起)的状况。如果你出现了类似的问题,这很可能是由于一个 NSLog 的已知问题所导致的。其中的一个解决办法就是将所有的 NSLog 代码移除。然而,还是有一些巧妙的处理方法,可以不重构就能解决。
|
||||
|
||||
### 解决办法 1
|
||||
NSLog 是一个宏且可以被定义的。例如:
|
||||
```objectivec
|
||||
// *You'll need to define TEST or TEST2 and then recompile.*
|
||||
|
||||
#ifdef TEST
|
||||
#define NSLog(...) _BlackHoleTestLogger(__VA_ARGS__);
|
||||
#endif // TEST
|
||||
#ifdef TEST2
|
||||
#define NSLog(...) _StdoutTestLogger(__VA_ARGS__);
|
||||
#endif // TEST2
|
||||
|
||||
void _BlackHoleTestLogger(NSString *format, ...) {
|
||||
//
|
||||
}
|
||||
|
||||
void _StdoutTestLogger(NSString *format, ...) {
|
||||
va_list argumentList;
|
||||
va_start(argumentList, format);
|
||||
NSMutableString * message = [[NSMutableString alloc] initWithFormat:format
|
||||
arguments:argumentList];
|
||||
|
||||
printf(message);
|
||||
|
||||
va_end(argumentList);
|
||||
[message release];
|
||||
}
|
||||
```
|
||||
|
||||
### 解决办法 2
|
||||
手动去替换掉 NSLog 封装的底层功能。该方法被 [Apple in a similar context.](https://support.apple.com/kb/TA45403?locale=en_US&viewlocale=en_US) 所推荐
|
||||
```objectivec
|
||||
extern void _NSSetLogCStringFunction(void(*)(const char *, unsigned, BOOL));
|
||||
|
||||
static void _GarbageFreeLogCString(const char *message, unsigned length, BOOL withSyslogBanner) {
|
||||
fprintf(stderr, "%s\\n", message);
|
||||
}
|
||||
|
||||
int main (int argc, const char *argv[]) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
int exitCode;
|
||||
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
_NSSetLogCStringFunction(_GarbageFreeLogCString);
|
||||
exitCode = WOApplicationMain(@"Application", argc, argv);
|
||||
[pool release];
|
||||
return exitCode;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Webview/Hybrid/Safari 应用的支持
|
||||
|
||||
* 确保真机上的 'Web Inspector' 为打开状态。
|
||||
* 确保你已经打开 Safari 的开发者模式(Safari - Advance Preferences- Developer menu for simulators)。
|
||||
* 确保你客户端的库提供的 appium 命令 `context` 可以让你正确地切换 contexts。
|
||||
* 当你尝试打开代理的时候,出现了这个报错:select_port() failed,请查阅该[文档](https://groups.google.com/forum/#!topic/appium-discuss/tw2GaSN8WX0)。
|
||||
* 在 Safari session 中,如果日志记录到不能输入初始 url 的问题,先确保你的软键盘是否已被开启,详情请查阅该[文档](https://github.com/appium/appium/issues/6440)。
|
||||
|
||||
### 到社区寻求帮助
|
||||
|
||||
如果上述步骤还没解决你的问题,那你可以通过以下方式获得帮助:
|
||||
|
||||
当你在使用 Appium 的过程中有任何问题,而且 Appium 提供的报错信息不够清晰的话,欢迎加入[讨论组](https://discuss.appium.io)与大家进行讨论。提问时请附带上如下信息:
|
||||
|
||||
* 你是通过什么方式运行 Appium(Appium.app, npm, source)。
|
||||
* 你使用什么操作系统。
|
||||
* 你是针对什么设备和版本去做测试的(例如. Android 4.4, 或者 iOS 7.1)。
|
||||
* 你是使用真机还是模拟器去做测试。
|
||||
* 提供客户端和服务端给出的的错误(例如. “在运行我的 Python 测试脚本时候出现了异常,Appium 服务器的报错信息如链接中所示”)。
|
||||
* 除了上述,在提问的时候希望可以附带上 Appium 服务器输出的内容(特别是在 verbose 模式下),这样我们就可以更好地分析并跟进问题。
|
||||
|
||||
如果你确信你发现的是一个 bug,请直接到 [issue tracker](https://github.com/appium/appium/issues) 去提交一个 issue 去描述 bug 的信息以及重现步骤。
|
||||
|
||||
### 已知问题
|
||||
|
||||
* 如果你已在官网下载并安装 Node,你需要使用 sudo 去运行 `npm`。可这么做这并不理想。可以尝试通过 [nvm](https://github.com/creationix/nvm), [n](https://github.com/visionmedia/n) 或者 `brew install node` 这几种方式去安装!
|
||||
* 通过设置代理,iOS 真机可以支持 Webview 了,详情可查看[讨论](https://groups.google.com/d/msg/appium-discuss/u1ropm4OEbY/uJ3y422a5_kJ)。
|
||||
* 有时候 iOS 的 UI 元素在被定位到后的几毫秒间会失效,这会导致一个类似 `(null) cannot be tapped` 的报错。唯一的解决办法就是把 finding-and-clicking 的代码放进一个 retry block 中。
|
||||
* 如果你是通过 MacPorts 去安装 Node 与 npm,Appium 可能很难找到可执行的 `node`。你必须确保 MacoPorts 的 bin 文件夹(默认是 `/opt/local/bin`)已经添加到你的 `~/.profile`, `~/.bash_profile` 或者 `~/.bashrc` 中的 `PATH` 环境变量中。
|
||||
|
||||
### 特定的错误
|
||||
|
||||
|Action|Error|Resolution|
|
||||
|------|-----|----------|
|
||||
|Running ios test|`[INST STDERR] posix spawn failure; aborting launch`|你的应用没有分别对应模拟器或者真机去编译对应版本.|
|
||||
|Running mobile safari test|`error: Could not prepare mobile safari with version '7.1'`|你可能需要再次运行授权的脚本以确保 iOS SDK 文件是可写状态。详情请查阅 [running on OSX documentation](./running-on-osx.md#authorizing-ios-on-the-computer)|
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,179 +0,0 @@
|
||||
##从源码运行Appium
|
||||
|
||||
你想要从源码运行 Appium 并帮助修复 bug 和添加新的特性么?很好! fork 这个项目,做一点更改,并且发送一个请求吧!
|
||||
另外,在工作之前请先看下我们的[代码风格指南](style-guide.cn.md)。请在发送请求前,确保单元测试与功能测试都测试通过;
|
||||
关于如何运行测试的更多信息,请继续阅读!
|
||||
首先确保你阅读并遵循 README 中的安装说明。
|
||||
|
||||
###从源码配置Appium
|
||||
|
||||
Appium 的安装,包含在你的测试代码与设备/模拟器之间来回发送消息的 Appium 服务端,和一个用任何存在且兼容Appium的语言编写的测试脚本。
|
||||
运行一个 Appium 服务器实例,然后进行你的测试。
|
||||
|
||||
快速开始的方式:
|
||||
|
||||
```center
|
||||
$ git clone https://github.com/appium/appium.git
|
||||
$ cd appium
|
||||
$ ./reset.sh
|
||||
$ sudo ./bin/authorize-ios.js # for ios only
|
||||
$ node .
|
||||
```
|
||||
|
||||
### Appium 开发环境搭建
|
||||
|
||||
确保你安装了 ant,maven,adb 并且将他们加入到了系统环境变量 PATH 中,与此同时你还需要安装 android-16 sdk(Selendroid) 和android-19 sdk。
|
||||
从你本地仓库的命令行提示,使用下边的命令安装如下包(如果你没有使用homebrew包管理器安装 `node`,则你可能不得不使用 sudo 权限运行npm):
|
||||
|
||||
```center
|
||||
npm install -g mocha
|
||||
npm install -g grunt-cli
|
||||
node bin/appium-doctor.js --dev
|
||||
./reset.sh --dev
|
||||
```
|
||||
|
||||
前两个命令安装测试和构建工具(如果你已经通过 Homebrew 包管理器安装了 node.js 就不需要 `sudo` 了)。
|
||||
第三个命令验证所有的依赖关系是否设置正确(由于依赖关系构建 Appium 不同于简单的运行 Appium ),
|
||||
第四个命令安装所有程序依赖关系和构建支持二进制文件和测试应用程序。
|
||||
`reset.sh` 也是建议先从 master 上 pull 下改变后的内容再执行命令。
|
||||
运行 `reset.sh` 加上 `--dev` 标志同时安装 git hooks 以确保代码质量在提交时是被保存过的。
|
||||
此时,你可以启动 Appium 服务:
|
||||
|
||||
```center
|
||||
node .
|
||||
```
|
||||
|
||||
查看完整的服务文档参数列表[the server documentation](/docs/cn/writing-running-appium/server-args.cn.md)
|
||||
|
||||
想要实现任务自动化,请检出[Appium Grunt tasks](/docs/cn/contributing-to-appium/grunt.cn.md)来构建应用程序,安装程序,生成文档,等等。
|
||||
|
||||
|
||||
#### 搭建iOS运行环境
|
||||
|
||||
为了避免启动 iOS apps 时弹出安全警告,你可以通过以下两种方法修改 /etc/authorization 文件:
|
||||
|
||||
1. 手动将 `/etc/authorization` 文件中 `<key>system.privilege.taskport<key/>` 下紧跟 `<allow-root>` 的元素改成 `<true/>`。
|
||||
|
||||
|
||||
2. 运行以下grunt命令来自动修改 `/etc/authorization` 文件:
|
||||
|
||||
```center
|
||||
sudo ./bin/authorize-ios.js
|
||||
```
|
||||
|
||||
然后再运行以下命令:
|
||||
|
||||
```center
|
||||
./reset.sh --ios --dev
|
||||
```
|
||||
|
||||
现在你的 appium 实例已经准备就绪,运行 `node .` 来启动 appium server.
|
||||
|
||||
#### 搭建android运行环境
|
||||
|
||||
Bootstrap 通过运行以下命令来启动 android:
|
||||
|
||||
```center
|
||||
./reset.sh --android --dev
|
||||
```
|
||||
|
||||
如果你想运行[Selendroid](http://github.com/DominikDary/selendroid) 来支持2.3这样的旧的android平台,运行以下命令:
|
||||
|
||||
```center
|
||||
./reset.sh --selendroid --dev
|
||||
```
|
||||
|
||||
确保你有且只有一个 Android 模拟器或者真机在运行,举个例子,在其它的设备上运行此命令(假设 `emulator` 命令已经在你的 path 中了)需执行:
|
||||
|
||||
|
||||
```center
|
||||
emulator -avd <MyAvdName>
|
||||
```
|
||||
|
||||
现在你可以通过 `node .` 启动 Appium server 了。
|
||||
|
||||
#### 确保更新到最新版本
|
||||
|
||||
由于 Appium 使用一些包的开发版本,所以经常安装新的 `npm` 包和升级不同的包是很有必要的。以下命令可以将所有平台上的包进行更新( `--dev` 标志会获取 npm dev 依赖和 Appium 测试套件中用到的应用程序)。当Appium提示版本更新时,你也可以用以下命令来更新:
|
||||
|
||||
|
||||
```center
|
||||
./reset.sh --dev
|
||||
```
|
||||
|
||||
或者你可以只更新指定的平台:
|
||||
|
||||
```center
|
||||
./reset.sh --ios --dev
|
||||
./reset.sh --android --dev
|
||||
./reset.sh --selendroid --dev
|
||||
```
|
||||
|
||||
### 运行测试集
|
||||
首先,看看我们的文档[普通情况下执行测试](/docs/cn/writing-running-appium/running-tests.cn.md) ,
|
||||
然后确保你的环境在对应的平台上已经搭建好了且与你所期望的那样。
|
||||
|
||||
当你的环境搭建好了之后并且你的代码是最新的,你可以通过以下的方式来运行单元测试:
|
||||
|
||||
```center
|
||||
grunt unit
|
||||
```
|
||||
你可以在所支持的平台上运行一些功能测试(确保后 Appium 用 `node .` 在另外一个窗口中运行):
|
||||
|
||||
```center
|
||||
bin/test.sh
|
||||
```
|
||||
|
||||
或者你可以通过运行 `test.sh` 来对指定的平台环境进行测试:
|
||||
|
||||
```center
|
||||
bin/test.sh --android
|
||||
bin/test.sh --ios
|
||||
bin/test.sh --ios7
|
||||
bin/test.sh --ios71
|
||||
```
|
||||
在提交代码时,请运行 `grunt` 执行一些基本的测试和核对代码质量标准的更改,请注意,这可能会自动发生的,
|
||||
如果你已经运行 `reset.sh --dev` ,这于你预先提交代码的操作所关联起来的。
|
||||
|
||||
```center
|
||||
grunt lint
|
||||
> Running "newer:jshint" (newer) task
|
||||
>
|
||||
> Running "newer:jshint:files" (newer) task
|
||||
> No newer files to process.
|
||||
>
|
||||
> Running "newer:jshint:test" (newer) task
|
||||
> No newer files to process.
|
||||
>
|
||||
> Running "newer:jshint:examples" (newer) task
|
||||
> No newer files to process.
|
||||
>
|
||||
> Running "jscs:files" (jscs) task
|
||||
> >> 303 files without code style errors.
|
||||
```
|
||||
|
||||
#### 运行单独的测试
|
||||
如果你有一个 Appium 服务监听,你可以通过 Mocha 来运行单独的测试文件,例如:
|
||||
|
||||
```center
|
||||
DEVICE=ios71 mocha -t 60000 -R spec test/functional/ios/testapp/simple.js
|
||||
```
|
||||
或者单独的测试集(例如,测试名称中的单词 "alert" )
|
||||
|
||||
|
||||
```center
|
||||
DEVICE=ios6 mocha -t 60000 -R spec --grep "alert" test/functional/ios/uicatalog
|
||||
```
|
||||
|
||||
对于 windows 操作系统,你可以用 `set DEVICE=android` 在 cmd 命令行的方式中运行以上所有测试集,例如:
|
||||
|
||||
|
||||
```center
|
||||
set DEVICE=android
|
||||
mocha -t 60000 -R spec test/functional/android/apidemos/alerts-specs.js
|
||||
```
|
||||
|
||||
注意:对于安卓系统,你将需要一个屏幕大小为4.0(400x800)的模拟器/设备(emulator/device),有些测试集在不同的屏幕大小下可能会失败。
|
||||
|
||||
`DEVICE` 必须设置为一个有效的值:`ios71`, `ios6`, `android`, `selendroid`
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
##从源码运行Appium
|
||||
|
||||
你想要从源码运行 Appium 并帮助修复 bug 和添加新的特性么?很好! fork 这个项目,做一点更改,并且发送一个请求吧!
|
||||
另外,在工作之前请先看下我们的[代码风格指南](style-guide.cn.md)。请在发送请求前,确保单元测试与功能测试都测试通过;
|
||||
关于如何运行测试的更多信息,请继续阅读!
|
||||
首先确保你阅读并遵循 README 中的安装说明。
|
||||
|
||||
###从源码配置Appium
|
||||
|
||||
Appium 的安装,包含在你的测试代码与设备/模拟器之间来回发送消息的 Appium 服务端,和一个用任何存在且兼容Appium的语言编写的测试脚本。
|
||||
运行一个 Appium 服务器实例,然后进行你的测试。
|
||||
|
||||
快速开始的方式:
|
||||
|
||||
```center
|
||||
$ git clone https://github.com/appium/appium.git
|
||||
$ cd appium
|
||||
$ ./reset.sh
|
||||
$ sudo ./bin/authorize-ios.js # for ios only
|
||||
$ node .
|
||||
```
|
||||
|
||||
### Appium 开发环境搭建
|
||||
|
||||
确保你安装了 ant,maven,adb 并且将他们加入到了系统环境变量 PATH 中,与此同时你还需要安装 android-16 sdk(Selendroid) 和android-19 sdk。
|
||||
从你本地仓库的命令行提示,使用下边的命令安装如下包(如果你没有使用homebrew包管理器安装 `node`,则你可能不得不使用 sudo 权限运行npm):
|
||||
|
||||
```center
|
||||
npm install -g mocha
|
||||
npm install -g grunt-cli
|
||||
node bin/appium-doctor.js --dev
|
||||
./reset.sh --dev
|
||||
```
|
||||
|
||||
前两个命令安装测试和构建工具(如果你已经通过 Homebrew 包管理器安装了 node.js 就不需要 `sudo` 了)。
|
||||
第三个命令验证所有的依赖关系是否设置正确(由于依赖关系构建 Appium 不同于简单的运行 Appium ),
|
||||
第四个命令安装所有程序依赖关系和构建支持二进制文件和测试应用程序。
|
||||
`reset.sh` 也是建议先从 master 上 pull 下改变后的内容再执行命令。
|
||||
运行 `reset.sh` 加上 `--dev` 标志同时安装 git hooks 以确保代码质量在提交时是被保存过的。
|
||||
此时,你可以启动 Appium 服务:
|
||||
|
||||
```center
|
||||
node .
|
||||
```
|
||||
|
||||
查看完整的服务文档参数列表[the server documentation](/docs/cn/writing-running-appium/server-args.cn.md)
|
||||
|
||||
想要实现任务自动化,请检出[Appium Grunt tasks](/docs/cn/contributing-to-appium/grunt.cn.md)来构建应用程序,安装程序,生成文档,等等。
|
||||
|
||||
|
||||
#### 搭建iOS运行环境
|
||||
|
||||
为了避免启动 iOS apps 时弹出安全警告,你可以通过以下两种方法修改 /etc/authorization 文件:
|
||||
|
||||
1. 手动将 `/etc/authorization` 文件中 `<key>system.privilege.taskport<key/>` 下紧跟 `<allow-root>` 的元素改成 `<true/>`。
|
||||
|
||||
|
||||
2. 运行以下grunt命令来自动修改 `/etc/authorization` 文件:
|
||||
|
||||
```center
|
||||
sudo ./bin/authorize-ios.js
|
||||
```
|
||||
|
||||
然后再运行以下命令:
|
||||
|
||||
```center
|
||||
./reset.sh --ios --dev
|
||||
```
|
||||
|
||||
现在你的 appium 实例已经准备就绪,运行 `node .` 来启动 appium server.
|
||||
|
||||
#### 搭建android运行环境
|
||||
|
||||
Bootstrap 通过运行以下命令来启动 android:
|
||||
|
||||
```center
|
||||
./reset.sh --android --dev
|
||||
```
|
||||
|
||||
如果你想运行[Selendroid](http://github.com/DominikDary/selendroid) 来支持2.3这样的旧的android平台,运行以下命令:
|
||||
|
||||
```center
|
||||
./reset.sh --selendroid --dev
|
||||
```
|
||||
|
||||
确保你有且只有一个 Android 模拟器或者真机在运行,举个例子,在其它的设备上运行此命令(假设 `emulator` 命令已经在你的 path 中了)需执行:
|
||||
|
||||
|
||||
```center
|
||||
emulator -avd <MyAvdName>
|
||||
```
|
||||
|
||||
现在你可以通过 `node .` 启动 Appium server 了。
|
||||
|
||||
#### 确保更新到最新版本
|
||||
|
||||
由于 Appium 使用一些包的开发版本,所以经常安装新的 `npm` 包和升级不同的包是很有必要的。以下命令可以将所有平台上的包进行更新( `--dev` 标志会获取 npm dev 依赖和 Appium 测试套件中用到的应用程序)。当Appium提示版本更新时,你也可以用以下命令来更新:
|
||||
|
||||
|
||||
```center
|
||||
./reset.sh --dev
|
||||
```
|
||||
|
||||
或者你可以只更新指定的平台:
|
||||
|
||||
```center
|
||||
./reset.sh --ios --dev
|
||||
./reset.sh --android --dev
|
||||
./reset.sh --selendroid --dev
|
||||
```
|
||||
|
||||
### 运行测试集
|
||||
首先,看看我们的文档[普通情况下执行测试](/docs/cn/writing-running-appium/running-tests.cn.md) ,
|
||||
然后确保你的环境在对应的平台上已经搭建好了且与你所期望的那样。
|
||||
|
||||
当你的环境搭建好了之后并且你的代码是最新的,你可以通过以下的方式来运行单元测试:
|
||||
|
||||
```center
|
||||
grunt unit
|
||||
```
|
||||
你可以在所支持的平台上运行一些功能测试(确保后 Appium 用 `node .` 在另外一个窗口中运行):
|
||||
|
||||
```center
|
||||
bin/test.sh
|
||||
```
|
||||
|
||||
或者你可以通过运行 `test.sh` 来对指定的平台环境进行测试:
|
||||
|
||||
```center
|
||||
bin/test.sh --android
|
||||
bin/test.sh --ios
|
||||
bin/test.sh --ios7
|
||||
bin/test.sh --ios71
|
||||
```
|
||||
在提交代码时,请运行 `grunt` 执行一些基本的测试和核对代码质量标准的更改,请注意,这可能会自动发生的,
|
||||
如果你已经运行 `reset.sh --dev` ,这于你预先提交代码的操作所关联起来的。
|
||||
|
||||
```center
|
||||
grunt lint
|
||||
> Running "newer:jshint" (newer) task
|
||||
>
|
||||
> Running "newer:jshint:files" (newer) task
|
||||
> No newer files to process.
|
||||
>
|
||||
> Running "newer:jshint:test" (newer) task
|
||||
> No newer files to process.
|
||||
>
|
||||
> Running "newer:jshint:examples" (newer) task
|
||||
> No newer files to process.
|
||||
>
|
||||
> Running "jscs:files" (jscs) task
|
||||
> >> 303 files without code style errors.
|
||||
```
|
||||
|
||||
#### 运行单独的测试
|
||||
如果你有一个 Appium 服务监听,你可以通过 Mocha 来运行单独的测试文件,例如:
|
||||
|
||||
```center
|
||||
DEVICE=ios71 mocha -t 60000 -R spec test/functional/ios/testapp/simple.js
|
||||
```
|
||||
或者单独的测试集(例如,测试名称中的单词 "alert" )
|
||||
|
||||
|
||||
```center
|
||||
DEVICE=ios6 mocha -t 60000 -R spec --grep "alert" test/functional/ios/uicatalog
|
||||
```
|
||||
|
||||
对于 windows 操作系统,你可以用 `set DEVICE=android` 在 cmd 命令行的方式中运行以上所有测试集,例如:
|
||||
|
||||
|
||||
```center
|
||||
set DEVICE=android
|
||||
mocha -t 60000 -R spec test/functional/android/apidemos/alerts-specs.js
|
||||
```
|
||||
|
||||
注意:对于安卓系统,你将需要一个屏幕大小为4.0(400x800)的模拟器/设备(emulator/device),有些测试集在不同的屏幕大小下可能会失败。
|
||||
|
||||
`DEVICE` 必须设置为一个有效的值:`ios71`, `ios6`, `android`, `selendroid`
|
||||
|
||||
155
docs/cn/contributing-to-appium/appium-from-source.md
Normal file
@@ -0,0 +1,155 @@
|
||||
## 从源码运行Appium
|
||||
|
||||
你想从源码运行Appium并帮助修复BUG和添加功能吗?
|
||||
真棒!只需要fork工程,添加一个修改,然后发送pull请求即可!
|
||||
在开始之前请阅读我们的代码风格指南([Style Guide](style-guide-2.0.md)。
|
||||
在发送pull请求前请确保通过单元和功能测试;关于如何运行测试等更多信息,请继续阅读!
|
||||
|
||||
首先,确保你阅读README文件且按照设置说明走。
|
||||
|
||||
### 从源码配置 Appium
|
||||
|
||||
Appium 的配置涉及:
|
||||
|
||||
1. Appium Server —— 在你的测试代码和设备或模拟器之间通过 Appium Server 来回发送消息
|
||||
2. 测试脚本 —— 任何客户端语言都可以,只要和 Appium 兼容
|
||||
|
||||
运行 Appium Server,然后运行你的测试。
|
||||
|
||||
快速开始:
|
||||
|
||||
```center
|
||||
git clone https://github.com/appium/appium.git
|
||||
cd appium
|
||||
npm install
|
||||
gulp transpile # requires gulp, see below
|
||||
npm install -g authorize-ios # for ios only
|
||||
authorize-ios # for ios only
|
||||
node .
|
||||
```
|
||||
```center
|
||||
git clone https://github.com/appium/appium.git
|
||||
cd appium
|
||||
npm install
|
||||
gulp transpile # 需要gulp,往下看
|
||||
npm install -g authorize-ios # 仅iOS
|
||||
authorize-ios # 仅iOS
|
||||
node .
|
||||
```
|
||||
|
||||
### 捣鼓改造 Appium
|
||||
|
||||
Make sure you have `ant`, `maven`, `adb` installed and added to system `PATH`, also you
|
||||
would need the android-16 sdk (for Selendroid) and android-19 sdk installed.
|
||||
From your local repo's command prompt, install the following packages using the
|
||||
following commands (if you didn't install `node` using Homebrew, you might have
|
||||
to run `npm` with sudo privileges):
|
||||
|
||||
|
||||
确保已安装 `ant`、 `maven`、 `adb` 且已添加到 `PATH` 环境变量,还需要安装 android-16 的 sdk(Selendroid需要使用)和 android-19 的 sdk。在 Appium 本地仓库打开命令行,使用以下命令安装以下包(如果你没有使用Homebrew安装过 node,可能需要使用 sudo 运行 npm):
|
||||
|
||||
```center
|
||||
npm install -g mocha
|
||||
npm install -g gulp
|
||||
npm install -g gulp-cli
|
||||
npm install -g appium-doctor && appium-doctor --dev
|
||||
npm install
|
||||
gulp transpile
|
||||
```
|
||||
|
||||
前两个命令安装测试和构建工具(如果您通过 Homebrew 安装了 nodejs,则 `sudo` 可能不是必需的)。 第三个命令验证所有依赖关系是否正确设置(因为构建 Appium 的依赖关系不同于简单运行 Appium 的依赖项),而第四个命令将安装所有应用程序依赖关系并构建支持二进制文件和测试应用程序。 最终的命令将转换所有代码,以便 nodejs 可以运行它。
|
||||
|
||||
|
||||
When pulling new code from GitHub, if there are changes to `package.json` it
|
||||
is necessary to remove the old dependencies and re-run `npm install`:
|
||||
|
||||
当从 GitHub 中拉出新的代码时,如果 `package.json` 有更改,需要删除旧的依赖关系并重新运行 `npm install`:
|
||||
|
||||
```center
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
gulp transpile
|
||||
```
|
||||
|
||||
此时,您将可以启动 Appium Server:
|
||||
|
||||
```center
|
||||
node .
|
||||
```
|
||||
|
||||
完整的参数列表,请参考[the server documentation](/docs/cn/writing-running-appium/server-args.md)
|
||||
|
||||
|
||||
#### Hacking with Appium for iOS
|
||||
|
||||
#### 鼓捣 iOS 上的Appium
|
||||
|
||||
为了避免启动iOS应用程序时可能出现的安全对话框,您必须通过以下两种方式之一修改 `/etc/authorization` 文件:
|
||||
|
||||
1. 手动修改 `/etc/authorization` 文件中的 `<key>system.privilege.taskport</key>` 下的 `<allow-root>`的值为 `<true/>`。
|
||||
2. 运行以下命令,为您自动修改 `/etc/authorization` 文件:
|
||||
|
||||
```center
|
||||
npm install -g authorize-ios
|
||||
sudo authorize-ios
|
||||
```
|
||||
|
||||
|
||||
此时,运行:
|
||||
|
||||
```center
|
||||
rm -rf node-modules
|
||||
npm install
|
||||
gulp transpile
|
||||
```
|
||||
|
||||
现在你的 Appium 实例已经准备好了。运行 `node .` 以启动Appium服务器。
|
||||
|
||||
#### 鼓捣 Android 上的Appium
|
||||
|
||||
通过运行以下命令配置Appium:
|
||||
|
||||
```center
|
||||
rm -rf node-modules
|
||||
npm install
|
||||
gulp transpile
|
||||
```
|
||||
|
||||
确保您只有一个 Android 模拟器或设备运行,例如,通过在另一个进程中运行此命令(假设 `emulator` 命令在您的路径上):
|
||||
|
||||
```center
|
||||
emulator -avd <MyAvdName>
|
||||
```
|
||||
|
||||
现在,您可以通过 `node .` 运行Appium服务器了。
|
||||
|
||||
#### 确保你的代码是最新的
|
||||
|
||||
由于Appium使用某些软件包的开发版本,因此通常需要安装新 `npm` 软件包或更新各种软件。运行 `npm install` 将更新所需的一切。当 Appium 升级版本时,您还需要执行此操作。在运行 `npm install` 之前,建议先删除 `node_modules` 目录中的所有旧依赖项:
|
||||
|
||||
```center
|
||||
rm -rf node-modules
|
||||
npm install
|
||||
gulp transpile
|
||||
```
|
||||
|
||||
### 运行测试
|
||||
|
||||
首先,请查看我们关于[running tests in
|
||||
general](/docs/cn/writing-running-appium/running-tests.md) 的文档,确保您的系统正确设置为您希望测试的平台。
|
||||
|
||||
一旦您的系统配置完毕,您的代码是最新的,您可以运行单元测试:
|
||||
|
||||
```center
|
||||
gulp once
|
||||
```
|
||||
|
||||
您可以对所有受支持的平台运行功能测试(确保在另一个窗口中运行Appium `node .`)与:
|
||||
|
||||
```center
|
||||
gulp e2e-test
|
||||
```
|
||||
|
||||
在提交代码之前,请运行 `gulp once` 一些基本测试,并根据代码质量标准检查您的更改。
|
||||
|
||||
本文由 [校长](https://testerhome.com/xushizhao) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
262
docs/cn/contributing-to-appium/appium-packages.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# Appium 简述
|
||||
|
||||

|
||||
|
||||
## appium
|
||||
- 运行时的基本检查
|
||||
- 节点版本(>= 4)
|
||||
- CLI 参数检查
|
||||
- 包含所有可用和支持的CLI参数
|
||||
- 检是否有冲突和弃用
|
||||
- 统一存放日志
|
||||
- 统一存放npmlog, winston和appium-logger
|
||||
- 启动AppiumDriver(继承Basedriver)
|
||||
- 为iOS/Android/Selendroid/Fake Driver 建立会话
|
||||
- 创建/删除Appium会话
|
||||
- 启动baseServer (appium-express)
|
||||
- 通过驱动给出的路径
|
||||
|
||||
## appium-express (部分appium basedriver)
|
||||
- 启动express server(允许x-domain-origin)
|
||||
- 从AppiumDriver初始化
|
||||
- 超时处理
|
||||
- 提供一个用于测试的静态页面
|
||||
- 将req/res事件记入日志
|
||||
|
||||
## mobile-json-wire-protocol (部分appium basedriver)
|
||||
- 提供了Appium命令列表
|
||||
- 通过协议的驱动子类
|
||||
-客户端和驱动程序之间的中间件
|
||||
- 处理驱动程序的jwp代理
|
||||
- 包含所有类型错误的错误类
|
||||
- 消除错误响应
|
||||
- 将参数封装/解封到命令中
|
||||
- 检查所需参数,验证参数
|
||||
|
||||
## appium basedriver
|
||||
- 每个实例化都有一个单独的测试会话
|
||||
- 包含对caps的约束 (platformName必须存在等)
|
||||
- 验证功能
|
||||
- 运行具有单个并发性的命令
|
||||
- 处理会话重启
|
||||
- 处理滑动选项
|
||||
- DeviceSettings负责设备的get/update管理
|
||||
- 包含基本命令
|
||||
- 找到元素
|
||||
- 创建/删除会话
|
||||
- 处理超时
|
||||
- 设备的set/update设置
|
||||
- 为命令提供帮助方法
|
||||
|
||||
## appiium iosdriver
|
||||
- 也可以作为独立服务器运行(从appium-express继承了小部分服务)
|
||||
- 支持的策略:“name”,“xpath”,“id”,“-ios uiautomation”,“class name”,“accessibility id”
|
||||
- 可以启动一个模拟器或一个真实的设备(需要标明udid)
|
||||
- 每个类型的说明
|
||||
- removeInstrumentsSocket
|
||||
- setBundleIdFromApp
|
||||
- createInstruments
|
||||
- runSimReset, isolateSimDevice, setLocale || runRealDeviceReset
|
||||
- setPreferences || runRealDeviceReset
|
||||
- startLogCapture
|
||||
- prelaunchSimulator || (noop)
|
||||
- startInstruments
|
||||
- onInstrumentsLaunch
|
||||
- configureBootstrap
|
||||
- setBundleId
|
||||
- setInitialOrientation
|
||||
- initAutoWebview
|
||||
- waitForAppLaunched
|
||||
- 所有帮助说明都在driver.js中
|
||||
- 包含一组更具体的功能约束
|
||||
- 有使用appium-xcode构建和运行Safari(safari-launcher)的逻辑
|
||||
- 实现iOSdriver的命令
|
||||
- Selenium命令被编译为ui-automator命令
|
||||
- 命令将会发送到uiAutoClient(appium-uiauto)
|
||||
- 连接到appium远程调试器
|
||||
|
||||
## appium-xcode
|
||||
- 运行shell命令从Xcode返回有用的数据,比如
|
||||
- getPath
|
||||
- getVersion
|
||||
- getAutomationTraceTemplatePath
|
||||
- getMaxIOSSDK
|
||||
- …
|
||||
- 内置自动重试
|
||||
|
||||
## appium-uiauto
|
||||
- 封装 iOS UI Automation 框架的
|
||||
- 通过socket连接进行通信
|
||||
- 运行由sendCommand函数填充的命令队列
|
||||
- 处理来自ui-automation的响应(作为缓冲区)
|
||||
- 使用osascript旋转屏幕截图
|
||||
- 提供bootstrap simulator/realdevice (dynamic-bootstrap)的方法
|
||||
- 在iOS UI自动化上下文(非节点)中运行的JavaScript文件
|
||||
- 负责执行实际的iOS UI Automation命令
|
||||
- 参考 [UIAutomation docs](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
|
||||
- 命令流程就像
|
||||
- Webdriver 命令-> iOS driver 命令 -> uiauto-命令
|
||||
|
||||
## appium-instruments
|
||||
- 封装运行instruments的命令
|
||||
- 很多exec调用与instruments二进制义互
|
||||
- 所有这些都采取回调来获取结果
|
||||
- 必须使用“iwd”包编译软件包
|
||||
- 特殊的Instruments包不存在命令延迟
|
||||
- 还包含较旧版本的iwd instrument(v4 - v7)
|
||||
|
||||
## appium-ios日志
|
||||
- 捕获iOS模拟器或实际设备的控制台,性能和崩溃日志
|
||||
- 通过调用tail来从系统路径获取日志(模拟器设备)
|
||||
- 或通过调用deviceconsole(实际设备)
|
||||
- 使用远程调试器来抓取性能日志
|
||||
- 崩溃日志保留在系统上的“.crash”文件中
|
||||
|
||||
## appium-iOS-模拟器
|
||||
- 封装iOS模拟器应用程序
|
||||
- 启动和关闭(杀死所有)模拟器
|
||||
- 更新设置和本地
|
||||
- 更新/清除 safari
|
||||
- 获取有关模拟器设备的元数据
|
||||
- 使用simctl与模拟器通信
|
||||
- 适用于Xcode 6和7
|
||||
|
||||
## authorize-iOS
|
||||
- 程序预先授权Instruments针对iOS设备运行UIAutomation脚本
|
||||
- 通过调用“DevToolsSecurity -enable”来启用开发人员工具
|
||||
- 授权用户作为开发人员调用“authorizationdb”
|
||||
- 改变模拟器目录的所有权
|
||||
|
||||
## node-simctl
|
||||
- 封装simctl二进制(cli实用程序来控制iOS模拟器)
|
||||
- 作为xcrun的子命令执行(从命令行查找或调用开发人员工具)
|
||||
- 包含功能
|
||||
- 安装/删除应用程序
|
||||
- 启动和关闭模拟器
|
||||
- 创建/清除/删除设备
|
||||
- 获取设备列表
|
||||
|
||||
## appium-cookies
|
||||
- 简单的包来创建和接收cookie
|
||||
- 在appium-iosdriver中使用,以在Web上下文中实现jswonwire cookie命令
|
||||
|
||||
## appium-chromedriver
|
||||
- 封装 chromedriver
|
||||
- 下载并安装chromedriver二进制文件
|
||||
- 启动,重新启动并停止(或杀死所有)chrome实例
|
||||
- 使用appium-jsonwp-proxy向驱动程序发送json wire protocol命令
|
||||
|
||||
## jsonwp-proxy (部分appium basedriver)
|
||||
- 允许将json wire协议命令发送到了解它的服务器(浏览器驱动程序)
|
||||
- 解析json的响应
|
||||
- 允许代理服务器的请求
|
||||
- 用于在Chromium-Chromedriver和appium-selendroiddriver中进行通信
|
||||
|
||||
## appium-androiddriver
|
||||
- 类似于appium-iosdriver,它可以作为独立服务运行
|
||||
- 自动化模拟器和实际设备上的本地,混合和移动Web应用程序
|
||||
- 负责安装Android软件包到设备
|
||||
- 如果需要,运行chromedriver会话
|
||||
- 包含一组更具体的功能约束
|
||||
- 使用appium-adb与emulator/simulator/realdevice进行交互
|
||||
- 和appium-android-bootstrap来执行实际的命令
|
||||
- 包含帮忙找出哪个网页视图属于哪个应用程序包,反之亦然
|
||||
|
||||
|
||||
## appium-adb
|
||||
- 封装 Android Debug Bridge(adb)
|
||||
- 包含一些基本的rpc到adb二进制的命令
|
||||
- 容纳jar文件来运行特殊用例,例如签名,验证应用程序或移动清单
|
||||
- 允许与webdriver协议无关的特殊(移动专用)模拟器命令
|
||||
- 锁定屏幕
|
||||
- 按返回按钮
|
||||
- 按home按钮
|
||||
- 设置/获取飞行模式
|
||||
- 设置/获取wifi状态
|
||||
- 捕获logcat
|
||||
- 处理模拟器/模拟器动作(例如重启)
|
||||
|
||||
## appium-androidbootstrap
|
||||
- JavaScript界面和Java代码,用于与Android UI Automator进行交互
|
||||
- 构建包含执行命令的逻辑的AppiumBootstrap.jar
|
||||
- 对应的 iOS 上的 appium-uiauto
|
||||
- 一旦启动,就会创建一个到设备的web scoket连接
|
||||
- 应用程序提供启动/关闭/发送命令接口
|
||||
- 命令流程如下:
|
||||
- Selenium 命令 - > appium-adb - > appium-androidbootstrap - > 使用Android UI Automator 框架的 Java 代码
|
||||
|
||||
|
||||
## appium-uiautomator
|
||||
- 启动和关闭uiautomator服务器由appium-android-bootstrap jar建立
|
||||
- 命令流程就像
|
||||
- appium-android-bootstrap:start -> appium-uiautomator:start -> appium-adb:install bootstrap
|
||||
|
||||
## appium-selendroiddriver
|
||||
- 类似于appium-androiddriver,它可以作为独立服务运行
|
||||
- 使用appium-selendroid-installer下载并安装Selendroid
|
||||
- 包含几个Selendroid特定的逻辑,以确保无缝集成
|
||||
- 包含一组更具体的功能约束
|
||||
- 使用jsonwp-proxy与服务器交互
|
||||
- 使用appium-adb启用在Selendroid中未实现的命令
|
||||
|
||||
## appium-selendroid 安装程序
|
||||
- 包含并导出设置逻辑
|
||||
- 下载Selendroid
|
||||
- 确定AndroidManifest的位置
|
||||
- 确定Server APK的位置
|
||||
- 提取这两个文件
|
||||
- 复制和清理文件
|
||||
|
||||
## appium-android-ime
|
||||
- 允许从 Android 设备发送和接收 unicode 字符
|
||||
- 将文本编码为UTF-7将其发送到设备并将其重新编码为 Unicode
|
||||
- 由 appium-androiddriver 和 appium-selendroiddriver 使用
|
||||
|
||||
## appium-doctor
|
||||
- 在启动Appium之前诊断,报告和修复常见的Node,iOS和Android配置问题
|
||||
- 暴露cli命令“appium-doctor”
|
||||
- 它检查
|
||||
- Android:
|
||||
- android sdk存在并正确配置
|
||||
- env变量和路径检查
|
||||
- iOS:
|
||||
- 安装了xcode(使用命令行工具)
|
||||
- 开发工具安全检查
|
||||
- auth检查
|
||||
- nodejs 检查
|
||||
|
||||
## appium-gulp-plugins
|
||||
- 具有定制插件的开发包使用交叉应用模块(仅适用于Appium开发)
|
||||
- 包含任务
|
||||
- e2e和单元测试(覆盖率报告)
|
||||
- 将ES2016 转换成 ES5
|
||||
- 静态代码分析(jshint)
|
||||
- 开发人员的任务
|
||||
|
||||
## appium-remote-debugger
|
||||
- RPC客户端将Appium连接到iOS网页浏览
|
||||
- 可以连接到WebKit devtools
|
||||
- 仅适用于iOS
|
||||
- 有两个rpc客户端类
|
||||
- remote-debugger-rpc-client:使用连接到localhost的tcp6:27753
|
||||
- webkit-rpc-client:使用WebSockets连接到ws:// localhost:27753 / devtools / page / $ {pageId}
|
||||
|
||||
## node-teen_process
|
||||
- 助手模块暴露:
|
||||
- exec:在引擎盖下使用spawn的exec的ES7(async / await)实现
|
||||
- SubProcess:在使用spawn时减少样板(特别是在async / await上下文中使用时)
|
||||
|
||||
## appium 日志
|
||||
- 运行时,日志器默认为 npmlog,
|
||||
- 暴露了几乎所有的Appium软件包使用的getLogger函数
|
||||
- 如果有一个已经运行的记录器,那么所有的东西都会记录
|
||||
|
||||
## appium-support
|
||||
- 用于支持跨应用程序包的库的实用程序函数。
|
||||
- 为一些常见的操作提供封装,如
|
||||
- 系统方法(isWindows,isLinux ...)
|
||||
- 实用程序方法,如hasValue,escapeSpace
|
||||
- 一堆fs方法
|
||||
- plist帮助解析和更新plist文件
|
||||
|
||||
本文由 [校长](https://testerhome.com/xushizhao) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
BIN
docs/cn/contributing-to-appium/appium-packages.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
@@ -1,8 +1,8 @@
|
||||
# 名单
|
||||
## 鸣谢
|
||||
|
||||
### 以下这些项目,鼓舞了我们,成就了 Appium。
|
||||
### 以下是在Appium的开发过程中予我们以启示,或是为Appium锦上添花的项目
|
||||
|
||||
* [Apple UIAutomation](http://developer.apple.com/library/ios/#documentation/DeveloperTools/Reference/UIAutomationRef/_index.html)
|
||||
* [Apple UIAutomation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)
|
||||
* [GhostDriver](https://github.com/detro/ghostdriver)
|
||||
* [IOS Auto](https://github.com/penguinho/applecart)
|
||||
* [IOS Driver](https://github.com/ios-driver/ios-driver)
|
||||
@@ -12,4 +12,8 @@
|
||||
* [Selenium Project](http://code.google.com/p/selenium/)
|
||||
* [ios-webkit-debug-proxy](https://github.com/google/ios-webkit-debug-proxy)
|
||||
* [instruments-without-delay](https://github.com/facebook/instruments-without-delay)
|
||||
* [deviceconsole](https://github.com/rpetrich/deviceconsole)
|
||||
* [deviceconsole](https://github.com/rpetrich/deviceconsole)
|
||||
* [WinAppDriver](http://github.com/Microsoft/WinAppDriver)
|
||||
* [WebDriverAgent](https://github.com/facebook/webdriveragent)
|
||||
|
||||
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
|
||||
140
docs/cn/contributing-to-appium/developers-overview.md
Normal file
@@ -0,0 +1,140 @@
|
||||
## 一个开发人员对于Appium的概述
|
||||
|
||||
在阅读这个此文档之前,请确保你已经阅读并理解了关于[Appium的基本概念](/docs/cn/about-appium/intro.md),
|
||||
以及关于如何参与[Appium贡献说明](/CONTRIBUTING.md)
|
||||
|
||||
### 技术愿景
|
||||
|
||||
Appium致力于成为一个移动JSONWP前端,实现最佳的应用自动化技术。仅此而已。我们想要采用所有不同的
|
||||
但自带亮点的自动化引擎,通过制作Appium驱动程序来平滑它们的差异和瑕疵,同时将它们纳入Appium。这与
|
||||
Selenium项目有异曲同工之妙。对于我们而言,我们想要每一个驱动都是一个独立的实体(单独的repo, 测试,
|
||||
等等)即便它们使用共享库,这一举措会使Appium驱动程序的开发变得尽可能简单,而且不拘泥于样板。我们之所以
|
||||
使用现今流行的JavaScript,因为它们无处不在,而且对于很多开发人员而言容易理解并易于贡献。
|
||||
|
||||
### 开发者社区
|
||||
|
||||
欢迎任何人成为Appium开发人员,你仅需要阅读此指南并把你的一些代码合并进来,那么你就成为了我们一员。
|
||||
如果你坚持不懈并且广施善缘,我们将会把你升级为一名提交者,这样你能继续帮助社区发展而且省去很多纷繁复杂。
|
||||
如果你在开发Appium的时候遇到疑问,请前往我们的开发人员社区`appium-developers@googlegroups.com`.
|
||||
请注意,这是一个为_开发_疑问而设的邮件列表,而不是关于_使用_疑问或bug提交。 有关使用问题请前往[discuss.appium.io](https://discuss.appium.io)
|
||||
Github问题跟踪只是用于bug提交和功能需求。
|
||||
|
||||
### 敏捷开发工作流程
|
||||
|
||||
Appium团队根据轻量化的scrum版本来运行开发。每两个星期我们开始一个新的“sprint”,或者每一段时间,我们
|
||||
会决定团队下一阶段需要完成的事情。我们欢迎任何熟悉Appium代码库的人参加我们的sprint计划,并将视作SCRUM参与团队成员。
|
||||
参与者无需是代码长期提交者。sprint期间,我们将在[Appium slack 团队](https://appium.slack.com)的
|
||||
`#standup` 聊天室更新我们每个人的进程(没有实时的每天站立会议)。sprint结束时,我们将举行“回顾”活动,以此来
|
||||
庆祝我们取得的成就并总结活动进展如何,这可能会生成一个关于如何进行不同尝试又或者如何做的更好的总结列表。
|
||||
|
||||
最终,我们的目标是在每一个sprint结束时发布一个Appium版本,也就是说每两个星期一个周期。我们还没有实现这个目标,但希望
|
||||
我们能很快达成。
|
||||
|
||||
当前会议时间:
|
||||
* sprint计划: 每两个周一 10:00 AM - 10:45 AM (太平洋时间)
|
||||
* sprint回顾: 每三个周五 1:00 PM - 1:30 PM(太平洋时间)
|
||||
|
||||
我们使用[Zoom](https://zoom.us)视讯来举行会议
|
||||
|
||||
关于项目管理,我们使用[ZenHub](http://zenhub.com) 浏览器插件,它向GitHub接口提供了例如
|
||||
Kanban boards 和 Epics 这些功能。要完全参与到Appium SCRUM,你需要安装上述的这些浏览器插件。
|
||||
|
||||
如果你有意参加sprint,你可以在Appium Slack群组里联系`@jlipps` 或者 `@isaac`,又或者直接在推特
|
||||
上联系`@jlipps`,我们将会在下一次sprint里分享如何加入视频聊天。
|
||||
|
||||
### 构造
|
||||
|
||||
Appium主要是一个[node.js](http://nodejs.org)包的集合,以此组合形成一个运行的node.js服务器。
|
||||
这些包都被单独维护并拥有各自的GitHub repo, CI和发布流程。一些软件包(比如 `appium-ios-driver`)
|
||||
很大,并且给Appinum添加了很重要的功能。相比而言,其他软件包则扮演着一个辅助的角色,而且高度曝光其某个
|
||||
特定并被反复使用的功能。
|
||||
|
||||
有关软件包的层次结构和每一个包所起的作用,请前往我们[包的概述](/docs/cn/contributing-to-appium/appium-packages.md)文档。
|
||||
|
||||
### 转化
|
||||
|
||||
Appium是用JavaScript的新形式编写的,称为ES6(或现在的ES2015)。因为这个版本的语言尚未被老版本
|
||||
node.js的原生支持,Appium代码是_被移植_到ES5(JS更为广泛支持的版本)。这个转化过程必须发生在所有
|
||||
代码运行之前。除了ES6的新语言特性,我们也从JS的_后续_版本中采用了很重要的关键词,`async` 和 `await`,
|
||||
这有助于编写整洁的异步代码。因为这个代换的步骤,Appium软件包囊括了观察代码变化和重新编排代码的工具。
|
||||
通常而言,同样的工具会自动运行单元测试,同时确保没有任何小的纰漏。大多Appium软件包在运行`gulp`的时候
|
||||
把上述过程当做默认行为。
|
||||
|
||||
### 排查和代码风格
|
||||
|
||||
对于所有Appium的JS而言,代码外观和使用感觉同样重要。这包括样式常规,编码模式以及我们解决各种问题时使用的
|
||||
库。你应该熟悉我们新的[ES2015 风格指南](/docs/cn/contributing-to-appium/style-guide-2.0.md)。
|
||||
当转化时,Appium包将自动运行JSHint或其他lint工具,并在代码不符合我们规范的时候提供警告或错误反馈。
|
||||
这些工具不一定能顾全我们关心的种种风格问题,所以我们在review代码的时候也应该注意代码规范问题。这不是
|
||||
吹毛求疵,而是为了有一个整洁,一致并且可读的代码库。
|
||||
|
||||
### 提交代码
|
||||
|
||||
将你的代码提交到Appium很容易:你只需要提交一个pull请求到我们的repos并在代码review的过程中与我们的
|
||||
维护者进行互动。我们对代码提交有一系列的要求(但是不用担心!如果下面所列的太过繁复,我们将会为你一一道来)。
|
||||
那我们就从你提交PR的那一步开始吧:
|
||||
|
||||
* 参考其他代码的样式和我们的样式指南
|
||||
* Atomic 提交 -- 每个逻辑变化进行一次提交(例如:确保你的提交不用进入组论即可以正常运行,而且它在任何指定提交下都应该正常运行)这通常意味着每个PR一个提交。你将想要非常熟悉的`git rebase -i` 和压缩。
|
||||
* 没有合并提交:在提交你的PR之前,通常在最新的master之上进行rebase(或者其它你想要merge进去的branch)。
|
||||
* 几乎所有的更改都应该有测试。关于漏洞修复,至少应该有单元测试以证明这个bug已被修复。新功能应该有单元测试,并且在大多数情况下进行e2e测试,以证明该功能正常工作。我们将乐意带你浏览测试的创建过程。阅读其他的测试代码会是一个很好的开始。我们的CI系统通常运行测试覆盖率统计,而且我们不大可能去合并那些会降低测试覆盖率的代码。
|
||||
|
||||
如果你在提交之前做了所有这些事情,你的代码将可能很快被接受。当然,如果你打算对Appium进行大量的改造工作,你可以联系开发人员,以确保这些改变符合我们的理念,这样在你开动之前确保我们会接受这些改动。
|
||||
|
||||
### 测试
|
||||
|
||||
始终确保你的更改已经被测试过! 除了单测试和e2e测试,请确保在你开始进行更改和提交review之前,所有现有测试都被运行。
|
||||
我们有为每一个Appium repo设置CI作为安全网,这样便于审阅者知晓代码是否已经通过测试。在任何Appium包运行测试都很容易!
|
||||
以下是你可以做的事情(除非README另有说明):
|
||||
|
||||
```
|
||||
gulp # 监测目录下重编译代码更改,以及运行单元测试
|
||||
gulp once # 同上,当不提供监测
|
||||
gulp unit-test # 转化和运行单元测试
|
||||
gulp e2e-test # 转化以及运行端到端/功能测试
|
||||
_FORCE_LOGS=1 <command> # 显示测试运行期间的模块日志输出
|
||||
```
|
||||
|
||||
请注意,单元测试的文件后缀通常为 `-specs.js` ,而e2e测试文件后缀则为`-e2e-specs.js`.
|
||||
|
||||
### 发布
|
||||
|
||||
任何非Appium主包的发布流程都是非常简洁明了的(请注意:如果你想要发布它,你需要成为一个NPM的所有者。
|
||||
所有权由Appium提交者管理; 如果你对所有者有任何疑问,请联系@jlipps 或者 @imurchie)。
|
||||
|
||||
0. `rm -rf node_modules && npm install` 并运行测试以确保全新安装正常工作
|
||||
0. 根据[SemVer](http://semver.org/) 规则决定我们是否需要发布一个补丁(漏洞修复),微调(功能)或者是主要(迭代)(请参考 [how SemVer works with NPM](https://docs.npmjs.com/getting-started/semantic-versioning).
|
||||
0. 通过任何适当的更改和提交来更新CHANGELOG以README文件。大多数子包没有CHANGELOG。
|
||||
0. 通过适当的版本类型运行 `npm version <version-type>`
|
||||
0. 将适当的分支推送到GitHub, 不要忘记加入`--tags` 来标记刚由 `npm version`创建的标志.
|
||||
0. 运行 `npm publish` (如果不是正式版, 请使用`--tag beta`).
|
||||
|
||||
对于Appium的主包发布,上述步骤必须执行,但有以下改变。一个原因是对于主包,我们使用NPM收缩包装
|
||||
以确保依赖在安装的时候不更改。另一个原因是我们在master上开发和各种分支上发布。它的工作方式
|
||||
如下:我们经常在master上开发和增加新的代码。 当我们准备好了做一个新的次要或主要版本(例如`1.5.0`
|
||||
或`2.0.0`),我们创建一个发布分支(分别为`1.5`或`2.0`)。然后我们发布该分支。 一旦我们认为需要修复补丁,
|
||||
我们首先将补丁拉到master中,然后将单个补丁挑选到发布分支(甚至是多个发布分支)。 然后我们再次
|
||||
从这些分支发布更新的补丁版本(例如`1.5.1`或`2.0.1`)。
|
||||
|
||||
**关于 `npm shrinkwrap`的注释:** 我们使用[npm shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap)是为了在发布时锁定依赖关系。
|
||||
没有它,任何依赖包上的开发将在安装Appium时反应出来,这可能会导致问题。 由于配置文件`npm-shrinkwrap.json`仅存在于发布分支上,
|
||||
因此有必要在发布过程中手动管理它。 它需要与对`package.json`的更改一起提交到GitHub。
|
||||
|
||||
0. 如果 NPM shrinkwrap JSON 文件存在,请移除.
|
||||
0. `rm -rf node_modules && npm install` 并运行测试以确保全新安装正常工作
|
||||
0. `rm -rf node_modules && npm install --production` 以获取仅production部分.
|
||||
0. `npm shrinkwrap` 来编写新的 NPM shrinkwrap JSON 文件.
|
||||
0. 根据SemVer来决定我们是否需要发布一个补丁(漏洞修复),微调(功能)或者是主要(迭代)
|
||||
0. 用合适的新版本信息来更新`package.json`
|
||||
0. 对CHANGELOG/README进行合适的更改,同shrinkwrap 和 `package.json`的改变一起以PR的形式进行提交审核。待它被合并之后,把它`pull`进`release`分支。
|
||||
0. 在发布分支(通常是一个小分支,如`1.5`或`1.4`)上创建一个形式为`v <version>`的标签:`git tag -av <version>`,例如`git tag -a 1.5.0`。 这对测试版本不是必需的。
|
||||
0. 把标签推送到上游分支: `git push --tags <remote> <branch>`
|
||||
0. 安装dev依赖 (或者至少`gulp` 和 `appium-gulp-plugins`)
|
||||
0. 运行`npm publish`(如果这不是正式版本,请使用`--tag beta` )。
|
||||
0. 在appium.io更新文档。 从github的check out appium.io repo,check out`gh-pages`分支和并更新到最新版本。 然后运行`rake publish`。
|
||||
0. 在GitHub上创建一个新版本:转到`https://github.com/appium/appium/releases/tag/v <VERSION>`并点击“编辑标签”。 输入发布名称为`<VERSION>`(例如,`2.0.5`),然后粘贴到更改日志(但不是此版本的changelog标题)。 如果是试用版,请标记为预发布。
|
||||
0. 在 discuss.appium.io 创建新的帖子来宣布release. 请创建于 "News"类别. 粘贴在changelog和任何可选的评论。 置顶当前帖子并取消置顶上一个release帖子。
|
||||
0. 开始发布`appium-desktop`。
|
||||
0. 请告知 @jlipps,以便他可以发布一个链接到讨论帖子。
|
||||
|
||||
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
|
||||
@@ -1,35 +0,0 @@
|
||||
# Appium grunt 命令
|
||||
|
||||
[Grunt](http://gruntjs.com) 是 Node.js 的 Make! 我们用它来自动化所有的 appium 开发任务。 下面就是你能做的:
|
||||
|
||||
|任务|描述|
|
||||
|----|-----------|
|
||||
|grunt lint|运行 JSLint|
|
||||
|grunt test|运行所有的测试|
|
||||
|grunt functional|运行整个功能测试集|
|
||||
|grunt ios|运行 iOS 功能测试集|
|
||||
|grunt android|运行 Android 功能测试集|
|
||||
|grunt selendroid|运行 selendroid 功能测试集|
|
||||
|grunt firefoxos|运行 firefoxos 功能测试集|
|
||||
|grunt unit|运行所有的单元测试|
|
||||
|grunt getSampleCode|下载示例代码和示例app. 接受`:hardcore` 参数
|
||||
|grunt buildApp:<AppName>:<SDK>|构建一个用于 iPhone 模拟器的 iOS 应用。 我们预计这个应用的路径是 `sample-code/apps/<AppName>/build/Release-iphonesimulator/<AppName>.app`. 默认的 SDK 是 'iphonesimulator7.1'|
|
||||
|grunt signApp:<certName>|使用开发证书的绝对路径,签名测试应用。|
|
||||
|grunt authorize|授权模拟器,使它不需要弹框请求权限。|
|
||||
|grunt log|打印 appium.log (运行测试的时候很有用)|
|
||||
|grunt configAndroidBootstrap|配置使用 ant 构建 Android 的 bootstrap.jar|
|
||||
|grunt buildAndroidBootstrap|使用 ant 构建 bootstrap.jar|
|
||||
|grunt buildSelendroidServer|构建 selendroid 服务器|
|
||||
|grunt configAndroidApp:<AppName>|配置使用 ant 构建 android 测试应用。 我们期待有一个 `sample-code/apps/<AppName>` 的 Android 项目|
|
||||
|grunt buildAndroidApp:<AppName>|使用 ant 构建项目. 会在 `sample-code/apps/<AppName>` 下生成应用。|
|
||||
|grunt installAndroidApp:<AppName>|将安卓应用安装到模拟器和设备中去|
|
||||
|grunt docs|生成文档|
|
||||
|grunt generateAppiumIo|将 README.md 转成 appium.io 的 getting-started.html|
|
||||
|grunt setConfigVer:<device>|将 package.json 里面 appium 的版本号和对应设备写入 `.appiumconfig.json` 文件|
|
||||
|
||||
## 其他
|
||||
|
||||
`grunt buildApp` 默认使用 iPhone 6.1 模拟器的 SDK 来构建应用。你可以传其他的 SDK 给 grunt 命令。
|
||||
(用 `xcodebuild -showsdks` 找出你所有的 sdk):
|
||||
|
||||
> grunt buildApp:UICatalog:iphonesimulator6.0
|
||||
17
docs/cn/contributing-to-appium/gulp.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## Appium gulp命令
|
||||
|
||||
[Gulp](http://gulpjs.com)就像Node.js的`make`一样!我们使用它来自动化各种应用开发任务。
|
||||
以下是你可以执行的操作:
|
||||
|
||||
|任务|说明|
|
||||
| ---- | ----------- |
|
||||
| gulp once |清理,验错,转译以及运行单元测试|
|
||||
| gulp watch |当代码更改时,自动运行`gulp once`|
|
||||
| gulp lint |运行 JSLint |
|
||||
| gulp jshint |运行 JSHint |
|
||||
| gulp transpile |将我们的ES7/ES2015代码转译为ES5,生成`/build`目录+内容|
|
||||
| gulp unit-test |运行单元测试|
|
||||
| gulp e2e-test |运行e2e 测试 |
|
||||
| gulp docs |生成 docs/en/writing-running-appium/server-args.md 文档|
|
||||
|
||||
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
|
||||
@@ -1,58 +0,0 @@
|
||||
## 如何去写文档
|
||||
|
||||
`##` 被用于写第二级标题。每个文档必须以第二级标题开头。
|
||||
这是为了支持appium.io文档的生成,不要使用下划线`---`的方式来创建标题。
|
||||
不要使用第一级标题或者 `===` 底线方式来创建标题(其中文件夹名字被用于第一级标题)
|
||||
|
||||
### 小标题
|
||||
|
||||
`###` 用于小标题。
|
||||
|
||||
### 普通标题
|
||||
|
||||
`####` 用于不会出现在目录中的标题。
|
||||
不要使用第五级标题 `#####`, 或者第六级标题 `######`。
|
||||
|
||||
### 分隔线
|
||||
|
||||
不要使用分隔线例如 `--` 或者 `---`。 这会使 Slate 混乱。
|
||||
|
||||
### 链接
|
||||
|
||||
链接到 readme:
|
||||
|
||||
`[readme](../../README.md)`
|
||||
|
||||
链接到 contributing:
|
||||
|
||||
`[contributing](../../CONTRIBUTING.md)`
|
||||
|
||||
链接到其他文档:
|
||||
|
||||
`[link text](filename.md)`
|
||||
|
||||
链接到文档的内部, 使用 `#` 来标记 Slate 链接。
|
||||
|
||||
`[go direct to json](filename.md#json-wire-protocol-server-extensions)`
|
||||
|
||||
需要注意的是当标题改变时,哈希链接会损坏。所以链接到文档的开头是最好的( `other.md` 替换 `other.md#something` )。
|
||||
|
||||
### appium.io兼容性
|
||||
|
||||
#### 在appium.io中心对齐代码
|
||||
|
||||
Appium.io中文档使用 [slate](https://github.com/tripit/slate) 来作为文档标准
|
||||
如果在文件中的代码段不是特定语言或如果你想要代码片段保持与文本中心对齐在 appium.io 文档中,请把代码块放在中心位置
|
||||
例子:
|
||||
```中心
|
||||
代码片段放在这里
|
||||
```
|
||||
#### 发布
|
||||
发布文档请在appium.io中查看 [api-docs](https://github.com/appium/api-docs) 和
|
||||
在 [appium.io](https://github.com/appium/appium.io) 中查看。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
56
docs/cn/contributing-to-appium/how-to-write-docs.md
Normal file
@@ -0,0 +1,56 @@
|
||||
## 如何编写文档
|
||||
|
||||
`##`用于写一个h2头。 每个文档必须以h2开头。这是为了支持appium.io文档生成。不要使用`---`下划线方法创建标题。
|
||||
不要对标题使用h1`#`或`===`,因为它不支持目录(文件夹名称用作h1)。
|
||||
|
||||
### 副标题
|
||||
|
||||
`###` 用于编写副标题
|
||||
|
||||
### 常规标题
|
||||
|
||||
`####` 用于不出现在目录里的标题。
|
||||
不要使用h5 `#####`或者h6`######`
|
||||
|
||||
### 换行符
|
||||
|
||||
不要使用 `--` 或者 `---`这样的换行符。 这样会混淆版面。
|
||||
|
||||
### 链接
|
||||
|
||||
链接到 readme :
|
||||
|
||||
`[readme](../../README.md)`
|
||||
|
||||
链接到贡献榜:
|
||||
|
||||
`[contributing](../../CONTRIBUTING.md)`
|
||||
|
||||
链接到另一个文件
|
||||
|
||||
`[link text](filename.md)`
|
||||
|
||||
如果想链接文件内部,请使用`#` 作为版面URL
|
||||
|
||||
`[go direct to json](filename.md#json-wire-protocol-server-extensions)`
|
||||
|
||||
请注意,当标题改变时,哈希链接会被破坏掉。所以更好的选择是链接到文件的开头(用`other.md` 取代 `other.md#something`)
|
||||
|
||||
### 与appium.io的兼容性
|
||||
|
||||
### 在appium.io里中居对齐代码
|
||||
|
||||
Appium.io文档使用[slate](https://github.com/tripit/slate)获取文档。
|
||||
如果文档中的代码段不是特定的语言,或者你希望代码段保留在appium.io文档的居中部分,请使用`center`作为代码区的后缀。
|
||||
|
||||
例如:
|
||||
|
||||
```center
|
||||
代码段放置于此。
|
||||
```
|
||||
|
||||
#### 出版
|
||||
|
||||
要在appium.io上发布文档,请参阅[api-docs](https://github.com/appium/api-docs) 和 [appium.io](https://github.com/appium/appium.io).
|
||||
|
||||
本文由 [ZhaoC](https://github.com/ZhaoC) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
|
||||
257
docs/cn/contributing-to-appium/style-guide-2.0.md
Normal file
@@ -0,0 +1,257 @@
|
||||
## 给贡献者的风格指南
|
||||
|
||||
感谢您对Appium的贡献!以下是我们编写javascript代码时需要遵守的准则,请确认你的提交能符合这些规范,这有利于我们合并你的代码时能保持良好的编码风格。其中最核心的准则是:*使你的代码与其他代码的编码风格保持一致*。
|
||||
|
||||
### 衍合(Rebasing)
|
||||
|
||||
每个 pull 请求中的提交(commits)都应该包含[逻辑变更(logical changes)](https://github.com/appium/appium/pull/920#issuecomment-21588553)。
|
||||
如果有多位贡献者,请确保他们各自都有自己的提交记录,修改作者信息不是一个好主意。合并(merge)提交必须从 pull 请求中 rebase 。
|
||||
|
||||
### 检错(Linting)
|
||||
|
||||
所有的代码(除了使用了 Apple 私有方法的`bootstrap.js`代码)必须通过 JSLint 的检错测试。你可以在 Appium 存储目录下,运行`grunt lint`来检查你的代码。如果你已创建一个新的 .js 文件,请确认它在`grunt.js`中被通配符覆盖,或者被专门添加。
|
||||
|
||||
编辑器的即时检错集成很简单,并且这会使得整个编码过程更加顺利。 我们喜欢 [jshint](http://www.jshint.com), 因为它已经与许多源代码编辑器集成了。将文件`.jshintrc`加入到仓库中,当通过添加jshint到你的编辑器时,你将大受即时检错的裨益。
|
||||
|
||||
因为jshint不再强制检查代码风格,我们也使用 [jscs](https://github.com/mdevils/node-jscs),它也集成在一些源代码编辑器中。
|
||||
|
||||
这些配置文件定义了哪些警告类型将会出现在你的编辑器中。 查看 [this page for jshint](http://www.jshint.com/platforms/) 和 [this page for jscs](https://github.com/mdevils/node-jscs#friendly-packages) ,找到它们各自支持的编辑器和平台的列表,以及如何设置你的编辑器使之能自动化检错。
|
||||
|
||||
### 风格注释(Style notes)
|
||||
|
||||
我们使用前沿版本的 JavaScript,并利用Babel将其渲染到支持当前版本的 Node.js。我们使用 [ES2015](https://babeljs.io/)(以前称为ES6)中的一些非标准特性,如[`async / await`](http://babeljs.io/docs/plugins/syntax-async-functions/)。在所有Appium的贡献中必须严格遵循如下编码风格!
|
||||
|
||||
* 使用两个空格来缩进, *不要使用 tabs*
|
||||
* 在运算符两边,分别添加一个空格:
|
||||
|
||||
```javascript
|
||||
var x = 1;
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
var x=1;
|
||||
```
|
||||
|
||||
* 在列表(lists),对象(objects),函数调用(function calls)等语句块中,逗号和冒号后面需要添加一个空格:
|
||||
|
||||
```javascript
|
||||
var x = myFunc("lol", {foo: bar, baz: boo});
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
var x = myFunc("lol",{foo:bar,baz:boo});
|
||||
```
|
||||
|
||||
* 代码始终以分号结尾
|
||||
* 以逗号开头
|
||||
|
||||
```javascript
|
||||
var x = {
|
||||
foo: 'bar'
|
||||
, baz: 'boo'
|
||||
, wuz: 'foz'
|
||||
};
|
||||
```
|
||||
|
||||
* 左花括号应该和`function`,`if`等写在同一行,`else`应该被夹在两个花括号中间:
|
||||
|
||||
|
||||
```javascript
|
||||
if (foo === bar) {
|
||||
// do something
|
||||
} else {
|
||||
// do something else
|
||||
}
|
||||
```
|
||||
|
||||
* `if`,`for`, 和`function`之后需要添加空格:
|
||||
|
||||
```javascript
|
||||
if (foo === bar) {
|
||||
```
|
||||
```javascript
|
||||
for (var i = 0; i < 10; i ++) {
|
||||
```
|
||||
```javascript
|
||||
var lol = function (foo) {
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
if(foo === bar) {
|
||||
```
|
||||
```javascript
|
||||
for(var i = 0; i < 10; i ++) {
|
||||
```
|
||||
```javascript
|
||||
var lol = function(foo) {
|
||||
```
|
||||
|
||||
* 只有一行代码时,`if`语句块的花括号也应该添加上:
|
||||
|
||||
```javascript
|
||||
if (foo === bar) {
|
||||
foo++;
|
||||
}
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
if (foo === bar)
|
||||
foo++;
|
||||
```
|
||||
|
||||
除了出错后直接调用回调函数(callback)处理错误(error)的语句
|
||||
|
||||
```javascript
|
||||
if (err) return cb(err);
|
||||
```
|
||||
|
||||
* 一般情况下,使用`===`, 而不是`==`;使用`!==`, 而不是`!=`;
|
||||
* 单行长度不应超过79个字符;
|
||||
* 截断长字符串使用如下方法:
|
||||
|
||||
```javascript
|
||||
myFunc("This is a really long string that's longer " +
|
||||
"than 79 characters so I broke it up, woo");
|
||||
```
|
||||
|
||||
* 注释需要和上一行代码左对齐:
|
||||
|
||||
```javascript
|
||||
if (foo === 5) {
|
||||
myFunc(foo);
|
||||
// foo++;
|
||||
}
|
||||
```
|
||||
|
||||
not
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
if (foo === 5) {
|
||||
myFunc(foo);
|
||||
//foo++;
|
||||
}
|
||||
```
|
||||
|
||||
* 通过拓展原型,来创建子类:
|
||||
|
||||
```javascript
|
||||
var _ = require('underscore');
|
||||
|
||||
var SuperClass = function () {
|
||||
this.init();
|
||||
};
|
||||
|
||||
SuperClass.prototype.init = function () {
|
||||
// initialize
|
||||
};
|
||||
|
||||
// Create a subclass
|
||||
|
||||
var SubClass = function () {
|
||||
this.init();
|
||||
};
|
||||
|
||||
_.extend(SubClass.prototype, SuperClass.prototype);
|
||||
```
|
||||
|
||||
* 函数定义中,最后使用回调函数:
|
||||
|
||||
```javascript
|
||||
var foo = function (arg1, arg2, cb) {
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
* 使用变量来定义函数:
|
||||
|
||||
```javascript
|
||||
var myFunc = function (a, b, c) {};
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
function myFunc (a, b, c) {}
|
||||
```
|
||||
|
||||
* 变量名应该是驼峰式大小写风格:
|
||||
|
||||
```javascript
|
||||
var myVariable = 42;
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
var my_variable = 42;
|
||||
```
|
||||
|
||||
* 检查是否有未定义的变量:
|
||||
|
||||
```javascript
|
||||
typeof myVariable === "undefined"
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
myVariable === undefined
|
||||
```
|
||||
|
||||
* 给变量定义默认值:
|
||||
|
||||
```javascript
|
||||
var x = y || z;
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
var x = y ? y : z;
|
||||
```
|
||||
|
||||
### 测试代码风格(Test Style):
|
||||
|
||||
在代码语义通顺和长度许可下,可以保持在同一行:
|
||||
|
||||
样例:
|
||||
|
||||
```javascript
|
||||
driver.elementByTagName('el1').should.become("123")
|
||||
.nodeify(done);
|
||||
|
||||
driver
|
||||
.elementsByTagName('el1').should.eventually.have.length(0)
|
||||
.nodeify(done);
|
||||
```
|
||||
|
||||
或者使用缩进来提高代码的可读性:
|
||||
|
||||
```javascript
|
||||
h.driver
|
||||
.elementById('comments')
|
||||
.clear()
|
||||
.click()
|
||||
.keys("hello world")
|
||||
.getValue()
|
||||
.should.become("hello world")
|
||||
.elementById('comments')
|
||||
.getValue().should.become("hello world")
|
||||
.nodeify(done);
|
||||
|
||||
h.driver
|
||||
.execute("'nan'--")
|
||||
.should.be.rejectedWith("status: 13")
|
||||
.nodeify(done);
|
||||
```
|
||||
|
||||
本文由 [wanyukang](https://github.com/wanyukang) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
|
||||
@@ -1,24 +1,18 @@
|
||||
# 贡献者的代码风格指南
|
||||
## 给贡献者的风格指南
|
||||
|
||||
感谢你们对 Appium 的贡献! 这些是我们书写 javascript 代码时使用的基本原则。
|
||||
请遵守这些,避免风格的来回修改,以便我们可以合并你的 pull 请求。
|
||||
基本原则就是:*让你的代码看起来和周围的代码一致*。
|
||||
感谢您对Appium的贡献!以下是我们编写javascript代码时需要遵守的准则,请确认你的提交能符合这些规范,这有利于我们合并你的代码时能保持良好的编码风格。其中最核心的准则是:*使你的代码与其他代码的编码风格保持一致*。
|
||||
|
||||
## 衍合(Rebasing)
|
||||
|
||||
每个 pull 请求中的提交(commits)必须包括 [logical changes](https://github.com/appium/appium/pull/920#issuecomment-21588553)。
|
||||
如果有多个作者,确认每个作者有自己的提交。最好不要修改作者信息。
|
||||
合并(merge)提交必须从 pull 请求中 rebase 。
|
||||
### 衍合(Rebasing)
|
||||
|
||||
## 检错(Linting)
|
||||
每个 pull 请求中的提交(commits)都应该包含[逻辑变更(logical changes)](https://github.com/appium/appium/pull/920#issuecomment-21588553)。
|
||||
如果有多位贡献者,请确保他们各自都有自己的提交记录,修改作者信息不是一个好主意。合并(merge)提交必须从 pull 请求中 rebase 。
|
||||
|
||||
所有的代码 (除了 `bootstrap.js` 的代码,它使用了 Apple 的私有方法) 必须通过 JSLint。
|
||||
为了检查你的代码,你可以在 Appium 存储目录下,简单地运行 `grunt lint`。
|
||||
如果你已创建一个新的 .js 文件,请确认它在 `grunt.js` 中被通配符覆盖,或者被专门添加。
|
||||
### 检错(Linting)
|
||||
|
||||
边输入边检错你的代码是容易实现的,使得整个进程更加顺利。
|
||||
我们喜欢 [jshint](http://www.jshint.com), 因为它有与许多源代码编辑器的集成。
|
||||
文件 `.jshintrc` 加入到仓库中,它的内容是:
|
||||
所有的代码(除了使用了 Apple 私有方法的`bootstrap.js`代码)必须通过 JSLint 的检错测试。你可以在 Appium 存储目录下,运行`grunt lint`来检查你的代码。如果你已创建一个新的 .js 文件,请确认它在`grunt.js`中被通配符覆盖,或者被专门添加。
|
||||
|
||||
编辑器的即时检错集成很简单,并且这会使得整个编码过程更加顺利。 我们喜欢 [jshint](http://www.jshint.com), 因为它已经与许多源代码编辑器集成了。将文件`.jshintrc`加入到仓库中,它的内容是:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -26,15 +20,14 @@
|
||||
"strict": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"trailing": true,
|
||||
"node": true,
|
||||
"es5": true,
|
||||
"white": true,
|
||||
"eqeqeq": true,
|
||||
"trailing": true,
|
||||
"indent": 2
|
||||
}
|
||||
```
|
||||
|
||||
因为jshint不再执行代码风格,我们也使用 [jscs](https://github.com/mdevils/node-jscs),它其中也存在许多源代码编辑器的集成。配置文件是:
|
||||
因为jshint不再强制检查代码风格,我们也使用 [jscs](https://github.com/mdevils/node-jscs),它也集成在一些源代码编辑器中。配置文件为:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -53,36 +46,39 @@
|
||||
}
|
||||
```
|
||||
|
||||
你将在你喜欢的编辑器中看到这些在配置文件中定义的警告类型,查看[this page for jshint](http://www.jshint.com/platforms/) 和
|
||||
[this page for jscs](https://github.com/mdevils/node-jscs#friendly-packages),编辑器和平台列表,找到使你的编辑器自动化检错的设置方法。
|
||||
这些配置文件定义了哪些警告类型将会出现在你的编辑器中。 查看 [this page for jshint](http://www.jshint.com/platforms/) 和 [this page for jscs](https://github.com/mdevils/node-jscs#friendly-packages) ,找到它们各自支持的编辑器和平台的列表,以及如何设置你的编辑器使之能自动化检错。
|
||||
|
||||
## 风格注意点
|
||||
### 风格注释(Style notes)
|
||||
|
||||
* 使用两个空格来缩进, *不要使用 tabs*
|
||||
* 在运算符两边,分别添加一个空格:
|
||||
|
||||
```js
|
||||
var x = 1;
|
||||
```javascript
|
||||
var x = 1;
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
var x=1;
|
||||
```
|
||||
|
||||
* 在 lists, objects, function calls 等中,逗号和冒号后面需要添加一个空格:
|
||||
* 在列表(lists),对象(objects),函数调用(function calls)等语句块中,逗号和冒号后面需要添加一个空格:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
var x = myFunc("lol", {foo: bar, baz: boo});
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
var x = myFunc("lol",{foo:bar,baz:boo});
|
||||
```
|
||||
|
||||
* 代码语句一般以分号结尾
|
||||
* 以逗号开头:
|
||||
* 代码始终以分号结尾
|
||||
× 以逗号开头
|
||||
|
||||
```js
|
||||
```javascript
|
||||
var x = {
|
||||
foo: 'bar'
|
||||
, baz: 'boo'
|
||||
@@ -90,10 +86,9 @@
|
||||
};
|
||||
```
|
||||
|
||||
* 左花括号应该和`function`,`if`等写在同一行,`else`应该被夹在两个花括号中间:
|
||||
|
||||
* 左花括号应该和 `function`, `if` 等 写在同一行, `else` 被夹在两个花括号中间:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
if (foo === bar) {
|
||||
// do something
|
||||
} else {
|
||||
@@ -101,75 +96,81 @@
|
||||
}
|
||||
```
|
||||
|
||||
* `if`, `for`, 和 `function` 之后需要添加空格:
|
||||
* `if`,`for`, 和`function`之后需要添加空格:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
if (foo === bar) {
|
||||
```
|
||||
```js
|
||||
```javascript
|
||||
for (var i = 0; i < 10; i ++) {
|
||||
```
|
||||
```js
|
||||
```javascript
|
||||
var lol = function (foo) {
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
if(foo === bar) {
|
||||
```
|
||||
```js
|
||||
```javascript
|
||||
for(var i = 0; i < 10; i ++) {
|
||||
```
|
||||
```js
|
||||
```javascript
|
||||
var lol = function(foo) {
|
||||
```
|
||||
|
||||
* 只有一行代码时,花括号也应该添加上:
|
||||
* 只有一行代码时,`if`语句块的花括号也应该添加上:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
if (foo === bar) {
|
||||
foo++;
|
||||
}
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
if (foo === bar)
|
||||
foo++;
|
||||
```
|
||||
|
||||
除了出错后直接调用回调函数(callback)处理错误(error)的语句
|
||||
|
||||
```javascript
|
||||
if (err) return cb(err);
|
||||
```
|
||||
|
||||
* 一般情况下,使用 `===`, 而不是 `==`; 使用 `!==`, 而不是 `!=`
|
||||
* 单行长度不应超过79个字符
|
||||
* 截断长字符串,方法如下:
|
||||
* 一般情况下,使用`===`, 而不是`==`;使用`!==`, 而不是`!=`;
|
||||
* 单行长度不应超过79个字符;
|
||||
* 截断长字符串使用如下方法:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
myFunc("This is a really long string that's longer " +
|
||||
"than 79 characters so I broke it up, woo");
|
||||
```
|
||||
|
||||
* 注释需要和上一行代码左对齐:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
if (foo === 5) {
|
||||
myFunc(foo);
|
||||
// foo++;
|
||||
}
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
if (foo === 5) {
|
||||
myFunc(foo);
|
||||
//foo++;
|
||||
}
|
||||
```
|
||||
|
||||
除了出错后直接调用回调函数(callback)处理错误(error)的语句
|
||||
|
||||
```javascript
|
||||
if (err) return cb(err);
|
||||
```
|
||||
|
||||
* 通过拓展原型,来创建子类:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
var _ = require('underscore');
|
||||
|
||||
var SuperClass = function () {
|
||||
@@ -191,7 +192,7 @@
|
||||
|
||||
* 函数定义中,最后使用回调函数:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
var foo = function (arg1, arg2, cb) {
|
||||
...
|
||||
};
|
||||
@@ -199,41 +200,59 @@
|
||||
|
||||
* 使用变量来定义函数:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
var myFunc = function (a, b, c) {};
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
function myFunc (a, b, c) {}
|
||||
```
|
||||
|
||||
* 变量名应该是驼峰式大小写风格:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
var myVariable = 42;
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
var my_variable = 42;
|
||||
```
|
||||
|
||||
* 检查是否有未定义的变量:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
typeof myVariable === "undefined"
|
||||
```
|
||||
|
||||
而不是
|
||||
```js
|
||||
|
||||
```javascript
|
||||
myVariable === undefined
|
||||
```
|
||||
|
||||
## 试验风格:
|
||||
* 给变量定义默认值:
|
||||
|
||||
```javascript
|
||||
var x = y || z;
|
||||
```
|
||||
|
||||
而不是
|
||||
|
||||
```javascript
|
||||
var x = y ? y : z;
|
||||
```
|
||||
|
||||
### 测试代码风格(Test Style):
|
||||
|
||||
在代码语义通顺和长度许可下,可以保持在同一行:
|
||||
|
||||
样例:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
driver.elementByTagName('el1').should.become("123")
|
||||
.nodeify(done);
|
||||
|
||||
@@ -244,7 +263,7 @@
|
||||
|
||||
或者使用缩进来提高代码的可读性:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
h.driver
|
||||
.elementById('comments')
|
||||
.clear()
|
||||
@@ -259,5 +278,7 @@ h.driver
|
||||
h.driver
|
||||
.execute("'nan'--")
|
||||
.should.be.rejectedWith("status: 13")
|
||||
.nodeify(done);
|
||||
.nodeify(done);
|
||||
```
|
||||
|
||||
本文由 [wanyukang](https://github.com/wanyukang) 翻译,由 [oscarxie](https://github.com/oscarxie) 校验。
|
||||
55
docs/cn/contributing-to-appium/version-branch-release.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Appium 版本, 分支和发布模式
|
||||
|
||||
## 版本控制
|
||||
|
||||
1.3.6版本之后, Appium 使用语义版本控制: `major | minor | patch | [-beta{N}]`. 例如, `1.4.1` or `2.4.0-Beta4`.
|
||||
* Major: API 突破性变化;新功能
|
||||
* Minor: 向后兼容的变化; 可能包含或不包括新功能
|
||||
* Patch: 快速修复工程; 没有新功能
|
||||
|
||||
这使得 Appium 的版本与 NPM 生态系统中的其他主要项目一致。它也适用于下面描述的基于主干的开发模式。
|
||||
|
||||
## 分支和发布模式
|
||||
|
||||
Appium 使用 [Trunk Based Development](http://paulhammant.com/2013/04/05/what-is-trunk-based-development/)。正如 Paul Hammant 所说,
|
||||
|
||||
>Trunk Based Development (TBD) 是所有开发人员(针对特定可部署单元)在源控制下提交到一个共享分支。那个分支俗称为 trunk。
|
||||
>
|
||||
>⋯ 分支是为了发布而创建的。开发人员不得在共享的地方建立分支。只有发布工程师才能对这些分支进行 commit,并且实际上得去创建这些分支。如果有必要的话,发布工程师可能会 cherry-pick 一些提交到发布分支。
|
||||
>
|
||||
>⋯ 发布分支将在短时间内被另一个发布分支替代,每个发布分支在创建时要从 trunk 中获取所有内容。在合并方面,只支持从主干到发布分支的 cherry-pick。
|
||||
|
||||
## 里程碑
|
||||
|
||||
我们根据版本控制和发布模式来设定 Appium 的里程碑. 下一个里程碑一直会是 Major.Minor 的发布。 与接下来要发布的 Major.Minor 版本不相干的产品缺陷修复和新功能,将会被积压到下一个以修复 BUG 或者新功能的命名分支上发布(即 Bugs 和 Features)。一般来说,我们每次的 minor 发布周期为 8 到 10 周一次。这包括大约一周的 Beta 测试和另外一周的修复和最终更改。 修补程序在 Major.Minor 版本之间根据需要发布(Major.Minor.Patch)。这样我们可以快速解决问题,同时最大限度地减少回归的风险。
|
||||
|
||||
## Workflow
|
||||
|
||||
对于Appium,基本流程如下所示:
|
||||
|
||||
1. 所有 PRs 都提交到 `master` (aka `trunk`).
|
||||
2. 由发布工程师(Release engineer,简称RE)来主导发布行为。 当发布分支已经准备好共享(“Beta”状态或更好)时,RE将创建一个新的分支v[Major].[Minor].[Patch]-branch。
|
||||
3. PRs 持续提交到 `master`.
|
||||
4. 如果有修复相关的发布提交到 `master`, RE将这些提交到发布分支。
|
||||
5. 发布分支可以修改与后续补丁修补程序发布。 这使得团队可以小心地将小型变更集放在一起,以便快速发布。修复也可以在需要时被并入以前的分支。
|
||||
6. 冲洗,重复。
|
||||
|
||||
开发人员可以随他们的意愿维护他们开发中的分支,这些仅是个人使用。但所有“官方”分支机构均应符合上述规定。
|
||||
|
||||
### 例如
|
||||
|
||||
1. 今天 6 月 1 日, Appium 团队计划于7月15日发布 20.1-beta,8 月 1 日发布全面的 20.1 版本。
|
||||
2. 在接下来的六个星期里,这个团队将他们的代码提交到 `master`.
|
||||
3. 7月15日,执行 RE 创建 20.1-branch。第一个节点被标记为 “20.1.0 Beta”。
|
||||
4. 一个团队成员开始修复测试版中的错误。这些修复会被提交到 `master`.
|
||||
5. 其他贡献者开始按计划提交代码到 `20.2` 中去。这些内容也会被提交到 `master`。
|
||||
6. RE把修复的内容cherry picks到 `20.1-branch`, 并保留 `master` 的其他变更。
|
||||
7. 该团队庆祝 8 月 1 日发布的所有测试版本都已修复。
|
||||
8. RE 标签的 HEAD 20.1-branch 为 20.1.0 发布版本。
|
||||
9. 几周后,发现 20.1.0 存在崩溃,用户现在需要修复。
|
||||
10. 执行 RE 将主机的崩溃修复程序拉入 20.1-branch,将 HEAD 标记为 20.1.1 并发布修补程序。
|
||||
11. 一旦 20.2 发布完毕,循环就会重复。
|
||||
|
||||
本文由 [大东](https://testerhome.com/Anikikun) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
|
||||
|
||||
3
docs/cn/ios-touch-id.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## Touch ID
|
||||
|
||||
(参考 https://github.com/appium/appium-xcuitest-driver/blob/master/docs/touch-id.md)
|
||||
@@ -1,17 +1,16 @@
|
||||
## Appium 客户端库
|
||||
## Appium 客户端类库
|
||||
|
||||
Appium 有对应以下语言的客户端库:
|
||||
|
||||
语言 | 代码
|
||||
:--|--:
|
||||
[Ruby][rubygems] | [GitHub](https://github.com/appium/ruby_lib)
|
||||
[Python][pypi] | [GitHub](https://github.com/appium/python-client)
|
||||
[Java][maven] | [GitHub](https://github.com/appium/java-client)
|
||||
[JavaScript][npm] | [GitHub](https://github.com/admc/wd)
|
||||
[PHP][php] | [GitHub](https://github.com/appium/php-client)
|
||||
[C#][nuget] | [GitHub](https://github.com/appium/appium-dotnet-driver)
|
||||
[Objective-C][cocoapods] | [GitHub](https://github.com/appium/selenium-objective-c)
|
||||
Appium 支持以下语言的客户端类库:
|
||||
|
||||
|语言 | 源码|
|
||||
|:---|---:|
|
||||
| [Ruby][rubygems] | [GitHub](https://github.com/appium/ruby_lib) |
|
||||
| [Python][pypi] | [GitHub](https://github.com/appium/python-client) |
|
||||
| [Java][maven] | [GitHub](https://github.com/appium/java-client) |
|
||||
| [JavaScript][npm] | [GitHub](https://github.com/admc/wd) |
|
||||
| [PHP][php] | [GitHub](https://github.com/appium/php-client) |
|
||||
| [C#][nuget] | [GitHub](https://github.com/appium/appium-dotnet-driver) |
|
||||
| [Objective-C][cocoapods] | [GitHub](https://github.com/appium/selenium-objective-c) |
|
||||
|
||||
[rubygems]: http://rubygems.org/gems/appium_lib
|
||||
[pypi]: https://pypi.python.org/pypi/Appium-Python-Client
|
||||
@@ -21,14 +20,12 @@ Appium 有对应以下语言的客户端库:
|
||||
[nuget]: http://www.nuget.org/packages/Appium.WebDriver/
|
||||
[cocoapods]: https://github.com/appium/selenium-objective-c
|
||||
|
||||
请注意:有些方法,比如 `endTestCoverage()` 目前不能提供完整支持。
|
||||
只有[这个问题](https://github.com/appium/appium/issues/2448)修复, 完整的覆盖率支持才会被添加。
|
||||
如果你一定要用这些方法,请先查看 Github 上关于 bindings 的文档。
|
||||
|
||||
注意,一些方法类似 `endTestCoverage()` 目前并不能完全支持。当[这个问题](https://github.com/appium/appium/issues/2448)被解决后,覆盖率支持才会被添加。如果你仍然想使用这些方法,请参考 GitHub 上关于 bindings 的文档。
|
||||
|
||||
### 锁定
|
||||
|
||||
锁定屏幕
|
||||
|
||||
锁定屏幕。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -65,48 +62,64 @@ driver.LockDevice(3);
|
||||
[driver lockDeviceScreen:3];
|
||||
```
|
||||
|
||||
### 将 app 置于后台
|
||||
### 将应用切换至后台
|
||||
|
||||
把当前应用放到后台去
|
||||
将当前的应用切换到后台,然后可以让其在指定时间内回到前台,或者让它一直留在后台。
|
||||
|
||||
传递给这个方法的参数有两种类型:
|
||||
|
||||
1. 一个整型(秒):表示后台状态维持多久。-1 表示持续置于后台。这种风格的参数已经被废弃。
|
||||
2. 一个看起来像 `{"timeout": secs}` 的对象。里面的 `secs` 是含义和第一个类型一样的整型数字(即表示置于后台多少秒),或者为 `null` (表示持续置于后台)。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
background_app 5
|
||||
background_app 5 # 置于后台,持续5秒
|
||||
background_app -1 # 持续置于后台
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.background_app(5)
|
||||
driver.background_app(5) # 置于后台,持续5秒
|
||||
driver.background_app(-1) # 持续置于后台
|
||||
driver.background_app({'timeout': None}) # 持续置于后台
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
driver.runAppInBackground(5);
|
||||
driver.runAppInBackground(5); // 置于后台,持续5秒
|
||||
driver.runAppInBackground(-1); // 持续置于后台
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.backgroundApp(5)
|
||||
driver.backgroundApp(5); // 置于后台,持续5秒
|
||||
driver.backgroundApp(-1); // 持续置于后台
|
||||
driver.backgroundApp({timeout: null}); // 持续置于后台
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
$this->backgroundApp(5);
|
||||
$this->backgroundApp(-1);
|
||||
```
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
driver.BackgroundApp(5);
|
||||
driver.BackgroundApp(-1);
|
||||
```
|
||||
|
||||
```objectivec
|
||||
// objective c
|
||||
[driver runAppInBackground:3];
|
||||
[driver runAppInBackground:-1];
|
||||
```
|
||||
|
||||
|
||||
### 收起键盘
|
||||
|
||||
收起键盘
|
||||
收起键盘。
|
||||
*注意*: 在 iOS,这辅助功能并不能保证一定有效。因为没有用于隐藏键盘的自动化钩子方法(译者注:可以理解为 iOS 没有提供隐藏键盘的 API),而且应用是允许用户去使用各种策略去收起键盘的,无论是点击键盘以外的区域,还是向下滑动诸如此类...相比于使用该方法,我们更加鼓励你去思考 _用户_ 在应用中是如何收起键盘(如滑动,点击一个固定的坐标,等等...),并让 Appium 去执行这些方法,而不是调用这个 API 。话虽如此,但这里默认的行为还是可能帮助到你的。
|
||||
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -144,9 +157,10 @@ driver.HideKeyboard("Done");
|
||||
[driver hideKeyboard];
|
||||
```
|
||||
|
||||
|
||||
### 启动 Activity
|
||||
|
||||
在当前应用中打开一个 activity 或者启动一个新应用并打开一个 activity 。 *只能在 Android 上使用*
|
||||
在当前 app 打开一个 activity,或者新打开一个应用并启动一个 acticity, *仅支持 Android*。
|
||||
|
||||
```java
|
||||
// java
|
||||
@@ -184,9 +198,10 @@ $this->startActivity(array("appPackage" => "com.example.android.apis",
|
||||
[driver startActivity:@"com.example.android.apis" package:@".Foo"];
|
||||
```
|
||||
|
||||
### 打开通知栏 (Notifications)
|
||||
|
||||
打开下拉通知栏 *只能在 Android 上使用*
|
||||
### 打开通知栏
|
||||
|
||||
打开通知栏,*仅支持 Android*。
|
||||
|
||||
```java
|
||||
// java
|
||||
@@ -205,7 +220,7 @@ driver.open_notifications()
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
openNotifications
|
||||
open_notifications
|
||||
```
|
||||
|
||||
```csharp
|
||||
@@ -223,9 +238,9 @@ $this->openNotifications();
|
||||
[driver openNotifications];
|
||||
```
|
||||
|
||||
### 是否已经安装
|
||||
### 应用是否已安装
|
||||
|
||||
检查应用是否已经安装
|
||||
检测应用是否已被安装。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -265,7 +280,7 @@ driver.IsAppInstalled("com.example.android.apis-");
|
||||
|
||||
### 安装应用
|
||||
|
||||
安装应用到设备中去
|
||||
在设备上安装应用。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -302,9 +317,10 @@ driver.InstallApp("path/to/my.apk");
|
||||
[driver installAppAtPath:@"path/to/my.apk"];
|
||||
```
|
||||
|
||||
### 删除应用
|
||||
|
||||
从设备中删除一个应用
|
||||
### 卸载应用
|
||||
|
||||
卸载设备上的应用。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -341,9 +357,9 @@ driver.RemoveApp("com.example.android.apis");
|
||||
[driver removeApp:@"com.example.android.apis"];
|
||||
```
|
||||
|
||||
### 摇晃 (Shake)
|
||||
### 摇一摇
|
||||
|
||||
模拟设备摇晃
|
||||
模拟摇晃设备的操作。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -382,7 +398,7 @@ driver.ShakeDevice();
|
||||
|
||||
### 关闭应用
|
||||
|
||||
关闭应用
|
||||
关闭应用。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -419,13 +435,13 @@ driver.CloseApp();
|
||||
[driver closeApp];
|
||||
```
|
||||
|
||||
### 启动 (Launch)
|
||||
### 启动(Launch)
|
||||
|
||||
根据服务关键字 (desired capabilities) 启动会话 (session) 。请注意这必须在设定 `autoLaunch=false` 关键字时才能生效。这不是用于启动指定的 app/activities ————你可以使用 `start_activity` 做到这个效果————这是用来继续进行使用了 `autoLaunch=false` 关键字时的初始化 (Launch) 流程的。
|
||||
为 desired capabilities 启动一个 session。请注意只有设置了 autoLaunch=false 关键字时才会生效。这不是为了随意启动一个应用或 activities ——如果你想这么做,请使用 `start_activity` 这个 desired capability 的参数。这个方法的使用场景是在你设置了 autoLaunch=false 后,用来继续执行初始化("launch")流程的。(译者注:举个例子,国产系统经常会在应用安装时弹出提示窗阻碍安装,此时可以通过 autoLaunch=false 来让应用安装后先执行你的脚本来关掉弹窗,然后再用这个函数来继续启动应用。)
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
launch
|
||||
launch_app
|
||||
```
|
||||
|
||||
```python
|
||||
@@ -458,15 +474,13 @@ driver.LaunchApp();
|
||||
[driver launchApp];
|
||||
```
|
||||
|
||||
### 重置 (Reset)
|
||||
### 重置
|
||||
|
||||
应用重置
|
||||
|
||||
(翻译者注:相当于卸载重装应用)
|
||||
重置应用。(译者注:类似于清除缓存)
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
reset
|
||||
driver.reset
|
||||
```
|
||||
|
||||
```python
|
||||
@@ -499,11 +513,9 @@ driver.ResetApp();
|
||||
[driver resetApp];
|
||||
```
|
||||
|
||||
### 可用上下文 (context)
|
||||
### 可用的上下文(Contexts)
|
||||
|
||||
列出所有的可用上下文
|
||||
|
||||
翻译备注:context可以理解为 可进入的窗口 。例如,对于原生应用,可用的context和默认context均为`NATIVE_APP`。详情可查看[对混合应用进行自动化测试](http://appium.io/slate/en/v1.3.4/?ruby#automating-hybrid-apps)
|
||||
列出所有可用的上下文(contexts)。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -540,9 +552,9 @@ driver.GetContexts()
|
||||
NSArray *contexts = driver.allContexts;
|
||||
```
|
||||
|
||||
### 当前上下文 (context)
|
||||
### 当前上下文(context)
|
||||
|
||||
列出当前上下文
|
||||
列出当前的上下文(context)。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -579,9 +591,9 @@ driver.GetContext()
|
||||
NSString *context = driver.context;
|
||||
```
|
||||
|
||||
### 切换到默认的上下文 (context)
|
||||
### 切换至默认的上下文(context)
|
||||
|
||||
将上下文切换到默认上下文
|
||||
切换回默认的上下文(context)。(译者注:一般就是原生上下文 “NATIVE_APP”)
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -618,13 +630,13 @@ driver.SetContext();
|
||||
[driver setContext:nil];
|
||||
```
|
||||
|
||||
### 应用的字符串 (App Strings)
|
||||
### 应用的字符串
|
||||
|
||||
获取应用的字符串
|
||||
获得应用的字符串。(译者注:这里实际指的是返回应用的多语言文本,即每个 string 变量及在指定语言上的显示内容。例如 `{"action_forgot_password":"Forgot your password?"}` 。在 android 上对应的是项目中的 `strings.xml` 多语言配置文件)
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
strings = app_strings
|
||||
app_strings
|
||||
```
|
||||
|
||||
```python
|
||||
@@ -659,9 +671,9 @@ driver.GetAppStrings();
|
||||
[driver appStringsForLanguage:"@ru"];
|
||||
```
|
||||
|
||||
### 按键事件 (Key Event)
|
||||
### 按键事件
|
||||
|
||||
给设备发送一个按键事件
|
||||
给设备发送按键事件。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -701,7 +713,7 @@ NSError *err;
|
||||
|
||||
### 当前 Activity
|
||||
|
||||
获取当前 activity。只能在 Android 上使用
|
||||
获取当前的 Acticity。仅支持 Android。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -739,9 +751,45 @@ NSError *err;
|
||||
[driver currentActivity];
|
||||
```
|
||||
|
||||
### 触摸动作(TouchAction) / 多点触摸动作(MultiTouchAction)
|
||||
### 当前包名(package)
|
||||
|
||||
获取当前包名(package)。仅支持 Android 。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
current_package
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.current_package
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
driver.getCurrentPackage();
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.getCurrentPackage().then(function (package) { /*...*/ })
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
$this->currentPackage();
|
||||
```
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
driver.GetCurrentPackage();
|
||||
```
|
||||
|
||||
|
||||
### 点击操作 / 多点触控操作
|
||||
|
||||
用于生成点击操作的 API。这部分文档的内容将会很快被补充进来。
|
||||
|
||||
生成触摸动作的接口。这部分文档很快将会补充更多的内容进来。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -807,9 +855,9 @@ action.Press(el, 10, 10).Release();
|
||||
action.Perform ();
|
||||
```
|
||||
|
||||
### 滑动(Swipe)
|
||||
### 滑动屏幕
|
||||
|
||||
模拟用户滑动
|
||||
模拟用户滑动屏幕的操作。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -818,7 +866,7 @@ swipe start_x: 75, start_y: 500, end_x: 75, end_y: 0, duration: 0.8
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.swipe(start=75, starty=500, endx=75, endy=0, duration=800)
|
||||
driver.swipe(start_x=75, start_y=500, end_x=75, end_y=0, duration=800)
|
||||
```
|
||||
|
||||
```java
|
||||
@@ -853,9 +901,9 @@ $this->swipe(75, 500, 75, 0, 800);
|
||||
todo: c#
|
||||
```
|
||||
|
||||
### 捏 (Pinch)
|
||||
### 捏(Pinch)手势
|
||||
|
||||
捏屏幕 (双指往内移动来缩小屏幕)
|
||||
在屏幕上使用捏(Pinch)手势。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -913,9 +961,9 @@ $this->pinch($el);
|
||||
driver.Pinch(25, 25)
|
||||
```
|
||||
|
||||
### 放大 (Zoom)
|
||||
### 放大屏幕(Zoom)
|
||||
|
||||
放大屏幕 (双指往外移动来放大屏幕)
|
||||
在屏幕上使用放大手势。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -974,33 +1022,35 @@ $this->zoom($el);
|
||||
driver.Zoom(100, 200);
|
||||
```
|
||||
|
||||
### 滑动到 (Scroll To)
|
||||
|
||||
滑动到某个元素。
|
||||
### 滚动到
|
||||
|
||||
滚动到指定的元素。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
element = find_element :accessibility_id, 'Element ID'
|
||||
execute_script "mobile: scrollTo", :element => element.ref
|
||||
element = find_element :accessibility_id, "Element ID"
|
||||
execute_script "mobile: scroll", direction: "down", element: element.ref
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
todo: python
|
||||
driver.execute_script("mobile: scroll", {"direction": "down", "element": element.id})
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
WebElement element = driver.findElementByAccessibilityId("Element ID");
|
||||
HashMap<String, String> arguments = new HashMap<String, String>();
|
||||
arguments.put("element", element.getId());
|
||||
(JavascriptExecutor)driver.executeScript("mobile: scrollTo", arguments);
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, String> scrollObject = new HashMap<String, String>();
|
||||
scrollObject.put("direction", "down");
|
||||
scrollObject.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: scroll", scrollObject);
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
return driver.elementByAccessibilityId().then(function (el) {
|
||||
return driver.execute('mobile: scrollTo', {element: el.value});
|
||||
driver.execute("mobile: scroll", [{direction: "down", element: el.value}]);
|
||||
});
|
||||
```
|
||||
|
||||
@@ -1012,12 +1062,15 @@ $this->scroll($els[count($els) - 1], $els[0]);
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
todo: csharp
|
||||
Dictionary<string, string> scrollObject = new Dictionary<string, string>();
|
||||
scrollObject.Add("direction", "down");
|
||||
scrollObject.Add("element", <element_id>);
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: scroll", scrollObject));
|
||||
```
|
||||
|
||||
### 拉出文件 (Pull File)
|
||||
### 拉取(pull)文件
|
||||
|
||||
从设备中拉出文件
|
||||
从设备上拉取文件。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -1050,9 +1103,9 @@ $this->pullFile('Library/AddressBook/AddressBook.sqlitedb');
|
||||
driver.PullFile("Library/AddressBook/AddressBook.sqlitedb");
|
||||
```
|
||||
|
||||
### 推送文件(Push file)
|
||||
### 推送(push)文件
|
||||
|
||||
推送文件到设备中去
|
||||
推送文件到设备。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
@@ -1094,49 +1147,53 @@ driver.PushFile("/data/local/tmp/file.txt", "some data for the file");
|
||||
|
||||
### 设置
|
||||
|
||||
|
||||
从这里你可以获取/设置 appium 的服务器设置。
|
||||
想知道它如何工作,以及它支持哪些设置,请查看[关于设置的文档](/docs/en/advanced-concepts/settings.cn.md)
|
||||
在这你会找到关于获取或设置 appium 服务器设置的示例代码。如果想了解工作原理,以及支持哪些设置,请查看[设置文档](/docs/en/advanced-concepts/settings.md)
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
current_settings = get_settings
|
||||
update_settings someSetting: true
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
current_settings = driver.get_settings()
|
||||
driver.update_settings({"someSetting": true})
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
JsonObject settings = driver.getSettings()
|
||||
// java-client doesn't support setting arbitrary settings, just settings which are already provided by appium.
|
||||
// So for the 'ignoreUnimportantViews' setting, the following method exists:
|
||||
// java 客户端不支持设置任意的设置项,只能设置 appium 当前支持的部分。
|
||||
// 所以对于 `ignoreUnimportantViews`(译者注:忽略不重要的视图,即 android uiautomator 上的压缩后 xml )这个设置项,对应存在下面这个设置方法:
|
||||
driver.ignoreUnimportantViews(true);
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var settings = driver.settings();
|
||||
browser.updateSettings({'someSetting': true});
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
$settings = $this->getSettings();
|
||||
$this->updateSettings(array('cyberdelia' => "open"));
|
||||
```
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
Dictionary<String, Object>settings = driver.GetSettings();
|
||||
// dotnet-driver doesn't support setting arbitrary settings, just settings which are already provided by appium.
|
||||
// So for the 'ignoreUnimportantViews' setting, the following method exists:
|
||||
// .net 客户端不支持设置任意的设置项,只能设置 appium 当前支持的部分。
|
||||
// 所以对于 `ignoreUnimportantViews`(译者注:忽略不重要的视图,即 android uiautomator 上的压缩后 xml )这个设置项,对应存在下面这个设置方法:
|
||||
driver.IgnoreUnimportantViews(true);
|
||||
```
|
||||
|
||||
### Appium 桌面应用
|
||||
|
||||
Appium 的桌面应用支持 OS X 和 Windows.
|
||||
Appium 的桌面应用支持 OS X, Windows 及 Linux.
|
||||
|
||||
- [Appium.app for OS X][bitbucket]
|
||||
- [Appium.exe for Windows][bitbucket]
|
||||
- [Appium Desktop](https://www.github.com/appium/appium-desktop/releases/latest)
|
||||
|
||||
[bitbucket]: https://bitbucket.org/appium/appium.app/downloads/
|
||||
|
||||
本文由 [thanksdanny](https://github.com/thanksdanny) 翻译,由 [chenhengjie123](https://github.com/chenhengjie123) 校验。
|
||||
@@ -1,85 +0,0 @@
|
||||
## Appium 服务关键字
|
||||
|
||||
<expand_table>
|
||||
|
||||
|关键字|描述|实例|
|
||||
|----|-----------|-------|
|
||||
|`automationName`|你想使用的自动化测试引擎|`Appium` (默认) 或 `Selendroid`|
|
||||
|`platformName`|你要测试的手机操作系统|`iOS`, `Android`, 或 `FirefoxOS`|
|
||||
|`platformVersion`|手机操作系统版本|例如: `7.1`, `4.4`|
|
||||
|`deviceName`|使用的手机类型或模拟器类型|`iPhone Simulator`, `iPad Simulator`, `iPhone Retina 4-inch`, `Android Emulator`, `Galaxy S4`, 等。在 iOS 上,这个关键字的值必须是使用 `instruments -s devices` 得到的可使用的设备名称之一。在 Android 上,这个关键字目前不起作用。|
|
||||
|`app`|`.ipa` or `.apk`文件所在的本地绝对路径或者远程路径,也可以是一个包括两者之一的`.zip`。 Appium会先尝试安装路径对应的应用在适当的真机或模拟器上。针对Android系统,如果你指定`app-package`和`app-activity`(具体见下面)的话,那么就可以不指定`app`。 **会与 `browserName` 冲突** |比如`/abs/path/to/my.apk`或`http://myapp.com/app.ipa`|
|
||||
|`browserName`|需要进行自动化测试的手机 web 浏览器名称。如果是对应用进行自动化测试,这个关键字的值应为空。|iOS 系统上可以用 'Safari' ,Android 系统上可以用 'Chrome', 'Chromium', 或 'Browser'。|
|
||||
|`newCommandTimeout`|设置命令超时时间,单位:秒。达到超时时间仍未接收到新的命令时 Appium 会假设客户端退出然后自动结束会话。|比如 `60`
|
||||
|`autoLaunch`|Appium是否需要自动安装和启动应用。默认值`true`|`true`, `false`|
|
||||
|`language`| (Sim/Emu-only) 设定模拟器 ( simulator / emulator ) 的语言。|如: `fr`|
|
||||
|`locale`| (Sim/Emu-only) 设定模拟器 ( simulator / emulator ) 的区域设置。|如: `fr_CA`|
|
||||
|`udid`| 连接的物理设备的唯一设备标识|如: `1ae203187fc012g`|
|
||||
|`orientation`| (Sim/Emu-only) 在一个设定的方向模式中开始测试|`LANDSCAPE` (横向) 或 `PORTRAIT` (纵向) |
|
||||
|`autoWebview`| 直接转换到 WebView 上下文。 默认值 `false`、|`true`, `false`|
|
||||
|`noReset`|不要在会话前重置应用状态。默认值`false`。|`true`, `false`|
|
||||
|`fullReset`|(iOS) 删除整个模拟器目录。(Android) 通过卸载——而不是清空数据——来重置应用状态。在 Android 上,这也会在会话结束后自动清除被测应用。默认值 `false`|`true`, `false`|
|
||||
|
||||
### Android特有
|
||||
|
||||
<expand_table>
|
||||
|
||||
|关键字|描述|实例|
|
||||
|----|-----------|-------|
|
||||
|`appActivity`| 你要从你的应用包中启动的 Android Activity 名称。它通常需要在前面添加 `.` (如:使用`.MainActivity` 而不是 `MainActivity`) |`MainActivity`, `.Settings`|
|
||||
|`appPackage`| 你想运行的Android应用的包名|比如`com.example.android.myApp`, `com.android.settings`|
|
||||
|`appWaitActivity`| 你想要等待启动的 Android Activity 名称|`SplashActivity`|
|
||||
|`deviceReadyTimeout`| 设置等待一个模拟器或真机准备就绪的超时时间|`5`|
|
||||
|`androidCoverage`| 用于执行测试的 instrumentation 类。作为命令 `adb shell am instrument -e coverage true -w` 的 `-w` 参数。| `com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation`|
|
||||
|`enablePerformanceLogging`| (仅适用于 Chrome 和 webview) 开启 Chromedriver 的性能日志。 (默认 `false`) | `true`, `false`|
|
||||
|`androidDeviceReadyTimeout`|等待设备在启动应用后准备就绪的超时时间。以秒为单位。|如 `30`|
|
||||
|`androidDeviceSocket`|开发工具的 socket 名称。只有在被测应用是一个使用 Chromium 内核的浏览器时需要。 socket 会被浏览器打开,然后 Chromedriver 把它作为开发者工具来进行连接。|如 `chrome_devtools_remote`|
|
||||
|`avd`| 需要启动的 AVD (安卓虚拟设备) 名称。|如 `api19`|
|
||||
|`avdLaunchTimeout`| 以毫秒为单位,等待 AVD 启动并连接到 ADB 的超时时间。(默认值 `120000`)| `300000`|
|
||||
|`avdReadyTimeout`| 以毫秒为单位,等待 AVD 完成启动动画的超时时间。(默认值 `120000`)| `300000`|
|
||||
|`avdArgs`| 启动 AVD 时需要加入的额外的参数。|如 `-netfast`|
|
||||
|`useKeystore`| 使用一个自定义的 keystore 来对 apk 进行重签名。默认值 `false`|`true` or `false`|
|
||||
|`keystorePath`| 自定义 keystore 的路径。默认: ~/.android/debug.keystore|如 `/path/to.keystore`|
|
||||
|`keystorePassword`| 自定义 keystore 的密码。|如 `foo`|
|
||||
|`keyAlias`| key 的别名 |如 `androiddebugkey`|
|
||||
|`keyPassword`| key 的密码 |如 `foo`|
|
||||
|`chromedriverExecutable`| webdriver 可执行文件的绝对路径 (如果 Chromium 核心提供了对应的 webdriver, 应该用它代替 Appium 自带的 webdriver) |`/abs/path/to/webdriver`|
|
||||
|`autoWebviewTimeout`| 以毫秒为单位,等待 Webview 上下文激活的时间。默认值 `2000`| 如 `4`|
|
||||
|`intentAction`| 用于启动 activity 的 intent action。 (默认值 `android.intent.action.MAIN`)| 如 `android.intent.action.MAIN`, `android.intent.action.VIEW`|
|
||||
|`intentCategory`| 用于启动 activity 的 intent category。 (默认值 `android.intent.category.LAUNCHER`) | 如 `android.intent.category.LAUNCHER`, `android.intent.category.APP_CONTACTS`
|
||||
|`intentFlags`| 用于启动 activity 的标识 ( flags ) (默认值 `0x10200000`) | 如 `0x10200000`
|
||||
|`optionalIntentArguments`| 用于启动 activity 的额外 intent 参数。请查看 [Intent 参数](http://developer.android.com/tools/help/adb.html#IntentSpec) | 如 `--esn <EXTRA_KEY>`, `--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>`
|
||||
|`stopAppOnReset`| 在使用 adb 启动应用前停止被测应用的进程 ( process ) 。如果被测应用是被另一个应用创建的,当这个参数被设定为 false 时,允许另一个应用的进程在使用 adb 启动被测应用时继续存活。默认值 `true`| `true` 或 `false`|
|
||||
|`unicodeKeyboard`| 使用 Unicode 输入法。默认值 `false`| `true` 或 `false`|
|
||||
|`resetKeyboard`| 在设定了 `unicodeKeyboard` 关键字的 Unicode 测试结束后,重置输入法到原有状态。如果单独使用,将会被忽略。默认值 `false`| `true` 或 `false`|
|
||||
|`noSign`| 跳过检查和对应用进行 debug 签名的步骤。只能在使用 UiAutomator 时使用,使用 selendroid 是不行。默认值 `false` | `true` 或 `false`|
|
||||
|`ignoreUnimportantViews`| 调用 uiautomator 的函数 `setCompressedLayoutHierarchy()`。由于 Accessibility 命令在忽略部分元素的情况下执行速度会加快,这个关键字能加快测试执行的速度。被忽略的元素将不能够被找到,因此这个关键字同时也被实现成可以随时改变的 *设置 ( settings ) * 。默认值 `false` | `true` 或 `false`
|
||||
|
||||
### iOS特有
|
||||
|
||||
<expand_table>
|
||||
|
||||
|关键字|描述|实例|
|
||||
|----|-----------|-------|
|
||||
|`calendarFormat`| (Sim-only) 为iOS的模拟器设置日历格式|如 `gregorian` (公历) |
|
||||
|`bundleId`| 被测应用的 bundle ID 。用于在真实设备中启动测试,也用于使用其他需要 bundle ID 的关键字启动测试。在使用 bundle ID 在真实设备上执行测试时,你可以不提供 `app` 关键字,但你必须提供 `udid` 。|如 `io.appium.TestApp`|
|
||||
|`udid`| 连接的真实设备的唯一设备编号 ( Unique device identifier ) |如 `1ae203187fc012g`|
|
||||
|`launchTimeout`| 以毫秒为单位,在 Appium 运行失败之前设置一个等待 instruments 的时间 |比如: `20000`|
|
||||
|`locationServicesEnabled`| (Sim-only) 强制打开或关闭定位服务。默认值是保持当前模拟器的设定|`true` 或 `false`|
|
||||
|`locationServicesAuthorized`| (Sim-only) 通过修改 plist 文件设定是否允许应用使用定位服务,从而避免定位服务的警告出现。默认值是保持当前模拟器的设定。请注意在使用这个关键字时,你同时需要使用 `bundleId` 关键字来发送你的应用的 bundle ID。|`true` 或者 `false`|
|
||||
|`autoAcceptAlerts`| 当 iOS 的个人信息访问警告 (如 位置、联系人、图片) 出现时,自动选择接受( Accept )。默认值 `false`。|`true` 或者 `false`|
|
||||
|`autoDismissAlerts`| 当 iOS 的个人信息访问警告 (如 位置、联系人、图片) 出现时,自动选择不接受( Dismiss )。默认值 `false`。|`true` 或者 `false`|
|
||||
|`nativeInstrumentsLib`| 使用原生 intruments 库 (即关闭 instruments-without-delay ) |`true` 或者 `false`|
|
||||
|`nativeWebTap`| (Sim-only) 在Safari中允许"真实的",非基于 javascript 的 web 点击 (tap) 。 默认值: `false`。注意:取决于 viewport 大小/比例, 点击操作不一定能精确地点中对应的元素。|`true` 或者 `false`|
|
||||
|`safariInitialUrl`| (Sim-only) (>= 8.1) 初始化 safari 的时使用的地址。默认是一个本地的欢迎页面 | 如 `https://www.github.com` |
|
||||
|`safariAllowPopups`| (Sim-only) 允许 javascript 在 Safari 中创建新窗口。默认保持模拟器当前设置。|`true` 或者 `false`|
|
||||
|`safariIgnoreFraudWarning`| (Sim-only) 阻止 Safari 显示此网站可能存在风险的警告。默认保持浏览器当前设置。|`true` 或者 `false`|
|
||||
|`safariOpenLinksInBackground`| (Sim-only) Safari 是否允许链接在新窗口打开。默认保持浏览器当前设置。|`true` 或者 `false`|
|
||||
|`keepKeyChains`| (Sim-only) 当 Appium 会话开始/结束时是否保留存放密码存放记录 (keychains) (库(Library)/钥匙串(Keychains)) |`true` 或者 `false`|
|
||||
|`localizableStringsDir`| 从哪里查找本地化字符串。默认值 `en.lproj`|`en.lproj`|
|
||||
|`processArguments`| 通过 instruments 传递到 AUT 的参数 |如 `-myflag`|
|
||||
|`interKeyDelay`| 以毫秒为单位,按下每一个按键之间的延迟时间。|如 `100`|
|
||||
|`showIOSLog`| 是否在 Appium 的日志中显示设备的日志。默认值 `false`|`true` 或者 `false`|
|
||||
|`sendKeyStrategy`| 输入文字到文字框的策略。模拟器默认值:`oneByOne` (一个接着一个) 。真实设备默认值:`grouped` (分组输入) |`oneByOne`, `grouped` 或 `setValue`|
|
||||
|`screenshotWaitTimeout`| 以秒为单位,生成屏幕截图的最长等待时间。默认值: 10。 |如 `5`|
|
||||
|`waitForAppScript`| 用于判断 "应用是否被启动” 的 iOS 自动化脚本代码。默认情况下系统等待直到页面内容非空。结果必须是布尔类型。 |例如 `true;`, `target.elements().length > 0;`, `$.delay(5000); true;` |
|
||||
144
docs/cn/writing-running-appium/caps.md
Normal file
@@ -0,0 +1,144 @@
|
||||
## Appium 服务器初始化参数(Capability)
|
||||
|
||||
<expand_table>
|
||||
|
||||
|键|描述|值|
|
||||
|----|-----------|-------|
|
||||
|`automationName`| 自动化测试的引擎 |`Appium` (默认)或者 `Selendroid`|
|
||||
|`platformName`| 使用的手机操作系统 |`iOS`, `Android`, 或者 `FirefoxOS`|
|
||||
|`platformVersion`| 手机操作系统的版本 |例如 `7.1`, `4.4`|
|
||||
|`deviceName`| 使用的手机或模拟器类型 |`iPhone Simulator`, `iPad Simulator`, `iPhone Retina 4-inch`, `Android Emulator`, `Galaxy S4`, 等等.... 在 iOS 上,使用 Instruments 的 `instruments -s devices` 命令可返回一个有效的设备的列表。在 Andorid 上虽然这个参数目前已被忽略,但仍然需要添加上该参数 |
|
||||
|`app`|本地绝对路径_或_远程 http URL 所指向的一个安装包(`.ipa`,`.apk`,或 `.zip` 文件)。Appium 将其安装到合适的设备上。请注意,如果您指定了 `appPackage` 和 `appActivity` 参数(见下文),Android 则不需要此参数了。该参数也与 `browserName` 不兼容。|`/abs/path/to/my.apk` 或 `http://myapp.com/app.ipa`|
|
||||
|`browserName`|做自动化时使用的浏览器名字。如果是一个应用则只需填写个空的字符串|'Safari' 对应 iOS,'Chrome', 'Chromium', 或 'Browser' 则对应 Android|
|
||||
|`newCommandTimeout`|用于客户端在退出或者结束 session 之前,Appium 等待客户端发送一条新命令所花费的时间(秒为单位)|例如 `60`|
|
||||
|`language`| (Sim/Emu-only) 为模拟器设置语言 |例如 `fr`|
|
||||
|`locale`| (Sim/Emu-only) 为模拟器设置所在区域 |例如 `fr_CA`|
|
||||
|`udid`| 连接真机的唯一设备号|例如 `1ae203187fc012g`|
|
||||
|`orientation`| (Sim/Emu-only) 模拟器当前的方向|`竖屏` 或 `横屏`|
|
||||
|`autoWebview`| 直接转换到 Webview 上下文(context)。默认值为 `false`|`true`, `false`|
|
||||
|`noReset`|在当前 session 下不会重置应用的状态。默认值为 `false`|`true`, `false`|
|
||||
|`fullReset`|(iOS)删除所有的模拟器文件夹。(Android) 要清除 app 里的数据,请将应用卸载才能达到重置应用的效果。在 Android, 在 session 完成之后也会将应用卸载掉。默认值为 `false`|`true`, `false`|
|
||||
|
||||
|
||||
|
||||
### Android 独有
|
||||
|
||||
<expand_table>
|
||||
|
||||
|键|描述|值|
|
||||
|----|-----------|-------|
|
||||
|`appActivity`|Activity 的名字是指从你的包中所要启动的 Android acticity。他通常需要再前面添加`.` (例如 使用 `.MainActivity` 代替 `MainActivity`) |`MainActivity`, `.Settings`|
|
||||
|`appPackage`| 运行的 Android 应用的包名|`com.example.android.myApp`, `com.android.settings`|
|
||||
|`appWaitActivity`| 用于等待启动的 Android Activity 名称 |`SplashActivity`|
|
||||
|`appWaitPackage`| 用于等待启动的 Android 应用的包|`com.example.android.myApp`, `com.android.settings`|
|
||||
|`appWaitDuration`| 用于等待 appWaitActivity 启动的超时时间(以毫秒为单位)(默认值为 `20000`)| `30000`|
|
||||
|`deviceReadyTimeout`| 用于等待模拟器或真机准备就绪的超时时间 |`5`|
|
||||
|`androidCoverage`| 用于执行测试的 instrumentation 类。 传送 `-w` 参数到如下命令 `adb shell am instrument -e coverage true -w `| `com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation`|
|
||||
|`enablePerformanceLogging`| (仅适用于 Chrome 与 webview)开启 Chromedriver 的性能日志。(默认值为 `false`)| `true`, `false`|
|
||||
|`androidDeviceReadyTimeout`| 用于等待设备在启动应用后准备就绪的超时时间。以秒为单位。 |例如 `30`|
|
||||
|`androidInstallTimeout`| 用于等待在设备中安装 apk 所花费的时间(以毫秒为单位)。默认值为 `90000` |例如 `90000`|
|
||||
|`adbPort`| 用来连接 ADB 服务器的端口(默认值为 `5037`)|`5037`|
|
||||
|`androidDeviceSocket`|开发工具的 socket 名称。只有在被测应用是一个使用 Chromium 内核的浏览器时才需要。socket 会被浏览器打开,然后 Chromedriver 把它作为开发者工具来进行连接。|例如 `chrome_devtools_remote`|
|
||||
|`avd`| 被启动 avd 的名字|例如 `api19`|
|
||||
|`avdLaunchTimeout`| 用于等待 avd 启动并连接 ADB 的超时时间(以毫秒为单位),默认值为 `120000`。| `300000`|
|
||||
|`avdReadyTimeout`| 用于等待 avd 完成启动动画的超时时间(以毫秒为单位),默认值为 `120000`。| `300000`|
|
||||
|`avdArgs`| 启动 avd 时使用的额外参数|例如 `-netfast`|
|
||||
|`useKeystore`| 使用自定义的 keystore 给 apk 签名,默认值为 `false`|`true`或`false`|
|
||||
|`keystorePath`| 自定义 keystore 的路径, 默认路径为 ~/.android/debug.keystore|例如 `/path/to.keystore`|
|
||||
|`keystorePassword`| 自定义 keystore 的密码|例如 `foo`|
|
||||
|`keyAlias`| key 的别名|例如 `androiddebugkey`|
|
||||
|`keyPassword`| key 的密码 |例如 `foo`|
|
||||
|`chromedriverExecutable`| webdriver 可执行文件的绝对路径(如果 Chromium 内嵌一个自己提供的 webdriver,则应使用他去替换掉 Appium 自带的 chromedriver)|`/abs/path/to/webdriver`|
|
||||
|`autoWebviewTimeout`| 用于等待 Webview 上下文(context)激活的时间(以毫秒为单位)。默认值为 `2000`| 例如 `4`|
|
||||
|`intentAction`| 用于启动 activity 的 intent action(默认值为 `android.intent.action.MAIN`)| 例如 `android.intent.action.MAIN`, `android.intent.action.VIEW`|
|
||||
|`intentCategory`| 用于启动 activity 的 intent category。(默认值为 `android.intent.category.LAUNCHER`)| 例如 `android.intent.category.LAUNCHER`, `android.intent.category.APP_CONTACTS`
|
||||
|`intentFlags`| 用于启动 activity 的标识(flags)(默认值为 `0x10200000`)| 例如 `0x10200000`
|
||||
|`optionalIntentArguments`| 用于启动 activity 的额外 intent 参数。请查看 [Intent 参数](http://developer.android.com/reference/android/content/Intent.html) | 例如 `--esn <EXTRA_KEY>`, `--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>`, 等等。
|
||||
|`dontStopAppOnReset`| 在使用 adb 启动应用之前,不要终止被测应用的进程。如果被测应用是被其他钩子(anchor)应用所创建的,设置该参数为 false 后,就允许钩子(anchor)应用的进程在使用 adb 启动被测应用期间仍然存在。换而言之,设置 `dontStopAppOnReset` 为 `true` 后,我们在 `adb shell am start` 的调用中不需要包含 `-S`标识(flag)。忽略该 capability 或 设置为 `false` 的话,就需要包含 `-S` 标识(flag)。默认值为 `false`| `true`或`false`|
|
||||
|`unicodeKeyboard`| 使用 Unicode 输入法。 默认值为 `false`| `true`或`false`|
|
||||
|`resetKeyboard`| 在设定了 `unicodeKeyboard` 关键字的 Unicode 测试结束后,重置输入法到原有状态。如果单独使用,将会被忽略。默认值为 `false` | `true`或`false`|
|
||||
|`noSign`| 跳过检查和对应用进行 debug 签名的步骤。仅适用于 UiAutomator,不适用于 selendroid。 默认值为 `false`| `true`或`false`|
|
||||
|`ignoreUnimportantViews`|调用 uiautomator 的函数 `setCompressedLayoutHierarchy()`。由于 Accessibility 命令在忽略部分元素的情况下执行速度会加快,这个关键字能加快测试执行的速度。被忽略的元素将不能够被找到,因此这个关键字同时也被实现成可以随时改变的 *设置 ( settings )*。 默认值为 `false` | `true` 或 `false`
|
||||
|`disableAndroidWatchers`| 禁用 android 监视器(watchers)。监视器用于见识应用程序的无响应状态(anr)和崩溃(crash),禁用会降低 Android 设备或模拟器的 CPU 使用率。该 capability 仅在使用 UiAutomator 时有效,不适用于 selendroid,默认设置为 `false`。 | `true` 或 `false`|
|
||||
|`chromeOptions`| 允许对 ChromeDriver 传 chromeOptions 的参数。了解更多信息请查阅 [chromeOptions](https://sites.google.com/a/chromium.org/chromedriver/capabilities)| `chromeOptions: {args: ['--disable-popup-blocking']}` |
|
||||
|`recreateChromeDriverSessions`| 当移除非 ChromeDriver webview时,终止掉 ChromeDriver 的 session。默认设置为 `false` | `true`或`false`|
|
||||
|`nativeWebScreenshot`| 在 web 的上下文(context),使用原生(native)的方法去截图,而不是用过代理的 ChromeDriver。默认值为 `false` | `true`或`false`|
|
||||
|`androidScreenshotPath`| 在设备中截图被保存的目录名。默认值为 `/data/local/tmp` |例如 `/sdcard/screenshots/`|
|
||||
|`autoGrantPermissions`|让Appium自动确定您的应用需要哪些权限,并在安装时将其授予应用。默认设置为 `false`|`true`或`false`|
|
||||
|
||||
### iOS 独有
|
||||
|
||||
<expand_table>
|
||||
|
||||
|键|描述|值|
|
||||
|----|-----------|-------|
|
||||
|`calendarFormat`| (仅支持模拟器) 为iOS的模拟器设置日历格式|例如 `gregorian`|
|
||||
|`bundleId`| 被测应用的 bundle ID 。用于在真实设备中启动测试,也用于使用其他需要 bundle ID 的关键字启动测试。在使用 bundle ID 在真实设备上执行测试时,你可以不提供 `app` 关键字,但你必须提供 `udid` 。|例如 `io.appium.TestApp`|
|
||||
|`udid`|连接的真实设备的唯一设备编号 (Unique device identifier) |例如 `1ae203187fc012g`|
|
||||
|`launchTimeout`| 以毫秒为单位,在 Appium 运行失败之前设置一个等待 instruments 的时间 |例如 `20000`|
|
||||
|`locationServicesEnabled`| (仅支持模拟器)强制打开或关闭定位服务。默认值是保持当前模拟器的设定.|`true`或`false`|
|
||||
|`locationServicesAuthorized`| (仅支持模拟器)通过修改 plist 文件设定是否允许应用使用定位服务,从而避免定位服务的警告出现。默认值是保持当前模拟器的设定。请注意在使用这个关键字时,你同时需要使用 `bundleId` 关键字来发送你的应用的 bundle ID。|`true`或`false`|
|
||||
|`autoAcceptAlerts`| 当警告弹出的时候,都会自动去点接受。包括隐私访问权限的警告(例如 定位,联系人,照片)。默认值为 false。不支持基于 `XCUITest` 的测试。|`true`或`false`|
|
||||
|`autoDismissAlerts`|当警告弹出的时候,都会自动去点取消。包括隐私访问权限的警告(例如 定位,联系人,照片)。默认值为 false。不支持基于 `XCUITest` 的测试。|`true`或`false`|
|
||||
|`nativeInstrumentsLib`| 使用原生 intruments 库(即关闭 instruments-without-delay)。|`true`或`false`|
|
||||
|`nativeWebTap`|(仅支持模拟器)在Safari中允许“真实的",非基于 javascript 的 web 点击 (tap) 。 默认值:`false`。注意:取决于 viewport 大小/比例, 点击操作不一定能精确地点中对应的元素。|`true`或`false`|
|
||||
|`safariInitialUrl`|(仅支持模拟器) (>= 8.1) 初始化 safari 的时使用的地址。默认是一个本地的欢迎页面 | 例如 `https://www.github.com` |
|
||||
|`safariAllowPopups`|(仅支持模拟器)允许 javascript 在 Safari 中创建新窗口。默认保持模拟器当前设置。|`true`或`false`|
|
||||
|`safariIgnoreFraudWarning`| (仅支持模拟器)阻止 Safari 显示此网站可能存在风险的警告。默认保持浏览器当前设置。|`true`或`false`|
|
||||
|`safariOpenLinksInBackground`| (仅支持模拟器)Safari 是否允许链接在新窗口打开。默认保持浏览器当前设置。|`true`或`false`|
|
||||
|`keepKeyChains`| (仅支持模拟器)当 Appium 会话开始/结束时是否保留存放密码存放记录 (keychains) 库(Library)/钥匙串(Keychains))|`true`或`false`|
|
||||
|`localizableStringsDir`| 从哪里查找本地化字符串。默认值为 `en.lproj`|`en.lproj`|
|
||||
|`processArguments`| 通过 instruments 传递到 AUT 的参数|例如 `-myflag`|
|
||||
|`interKeyDelay`| 以毫秒为单位,按下每一个按键之间的延迟时间|例如 `100`|
|
||||
|`showIOSLog`| 是否在 Appium 的日志中显示设备的日志。默认值为 `false`|`true`或`false`|
|
||||
|`sendKeyStrategy`| 输入文字到文字框的策略。模拟器默认值:`oneByOne`(一个接着一个)。真实设备默认值:`grouped` (分组输入)|`oneByOne`, `grouped`或`setValue`|
|
||||
|`screenshotWaitTimeout`| 以秒为单位,生成屏幕截图的最长等待时间。默认值为:10 |例如 `5`|
|
||||
|`waitForAppScript`| 用于判断 "应用是否被启动” 的 iOS 自动化脚本代码。默认情况下系统等待直到页面内容非空。结果必须是布尔类型。 |例如 `true;`, `target.elements().length > 0;`, `$.delay(5000); true;` |
|
||||
|`webviewConnectRetries`| 用于获取 webview 失败时,发送连接信息到远程调试器的次数。默认次数为: `8` |例如 `12`|
|
||||
|`appName`| 被测应用的名字。 用于支持 iOS 9 以上系统的应用的自动化。 |例如 `UICatalog`|
|
||||
|`customSSLCert`|(Sim/Emu-only) 给模拟器添加一个 SSL 证书。 | 例如 <br/>`-----BEGIN CERTIFICATE-----MIIFWjCCBEKg...`<br/>`-----END CERTIFICATE-----`|
|
||||
|
||||
|
||||
### 使用 XCUITest(iOS 独有)
|
||||
|
||||
<expand_table>
|
||||
|
||||
|键|描述|值|
|
||||
|----------|-----------|------|
|
||||
|`processArguments`|将会传送到 WebDriverAgent 的进程参数与环境|`{ args: ["a", "b", "c"] , env: { "a": "b", "c": "d" } }` 或 `'{"args": ["a", "b", "c"], "env": { "a": "b", "c": "d" }}'`|
|
||||
|`wdaLocalPort`|如果这个值被指定了,Mac 主机就会使用这个端口,通过 USB 发送数据到 iOS 设备中。默认的端口与 iOS 设备中 WDA 的端口号是一致的。|例如 `8100`|
|
||||
|`showXcodeLog`| 是否显示运行测试时 Xcode 的输出日志,如果值设置为 `true` ,则会在启动的时候产生**大量**的额外日志。默认设置为 `false`。|例如 `true`|
|
||||
|`iosInstallPause`| 安装应用程序与启动 WebDriverAgent 之间停止的间隔时间(以毫秒为单位),特别适用于体积较大的包。默认是设置为 `0`。|例如 `8000`|
|
||||
|`xcodeConfigFile`|一个可选的 Xcode 可配置文件的完整路径,用于指定在真机上运行 WebDriverAgent 的个人身份或者团队身份的代码签名。|例如 `/path/to/myconfig.xcconfig`|
|
||||
|`keychainPath`| 从系统的 keychain 中导出私有开发秘钥的完整路径。在真机测试时与 `keychainPassword` 配合使用。|例如 `/path/to/MyPrivateKey.p12`|
|
||||
|`keychainPassword`|在 `keychainPath` 中指定 keychain 的解锁密码。|例如 `super awesome password`|
|
||||
|`scaleFactor`|模拟器缩放因子。这对于默认分辨率是大于实际分辨的模拟器来说非常有用。因此,你不用上下滑动模拟器的屏幕就能看到所有模拟器显示的内容了。|可接受的值为: `'1.0', '0.75', '0.5', '0.33' 和 '0.25'`。 这些值都应该是一个字符串|
|
||||
|`preventWDAAttachments`|设置 WebDriverAgent 项目中的 DerivedData 文件夹的权限为`仅可读`。为了防止 XCTest 框架产生大量无用的截屏与日志,该设置是非常必要的,因为这是不可能通过 Apple 提供的接口去关闭的。|设置 capabilitity 为 `true` 将会设置 Posix 的文件夹的权限为 `555`,设置为 `false` 则会将权限重置回 `755`|
|
||||
|`webDriverAgentUrl`|若提供了 URL,Appium 将在这 URL 上连接现有的 WebDriverAgent 实例,而不是重新启动一个。|例如 `http://localhost:8100`|
|
||||
|`useNewWDA`|若设置为 `true`,则直接卸载设备上现存的所有 WebDriverAgent 客户端。在某些情况,该做法可以提高稳定性。默认设置为 `false`。|例如 `true`|
|
||||
|`wdaLaunchTimeout`|等待 WebDriverAgent 可 ping 同的时间(以毫秒为单位)。默认设置为 60000ms。|例如 `30000`|
|
||||
|`calendarAccessAuthorized`|若设置为 `true`,则允许在 iOS 模拟器上访问日历。若设置为 `false`,则不被允许。否则,日历的 authorizationStatus 会保持不变。 | - |
|
||||
|
||||
|
||||
|
||||
### You.i 引擎独有
|
||||
|
||||
<expand_table>
|
||||
|
||||
|键|描述|值|
|
||||
|----|-----------|-------|
|
||||
|`youiEngineAppAddress`| 正在运行的应用的设备的 IP 地址。使用 `localhost` 作为模拟地址。使用 `localhost` 作为模拟器地址。使用设备的 IP 地址作为真机的 IP。|例如 `localhost` 或 `192.168.1.203`|
|
||||
|
||||
|
||||
|
||||
### WinAppDriver 独有
|
||||
|
||||
<expand_table>
|
||||
|
||||
|键|描述|值|
|
||||
|----|-----------|-------|
|
||||
|`platformName`| 运行测试时所在的平台 |例如 `Windows`|
|
||||
|`deviceName`| 运行测试时所使用设备的名字 | 例如 `WindowsPC`|
|
||||
|`app`| 被测 windows 应用的 appID 或被测的 .exe 文件的路径。 查阅[该文档](/docs/cn/writing-running-appium/windows-app-testing.md)可了解更多查找 appID 的详细方法。 | 例如 `c24c8163-548e-4b84-a466-530178fc0580_scyf5npe3hv32!App`|
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译。由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
57
docs/cn/writing-running-appium/default-capabilities-arg.md
Normal file
@@ -0,0 +1,57 @@
|
||||
## --default-capabilities 标识
|
||||
|
||||
Appium 1.5 移除了大部分旧版本遗留的 CLI 标识;其余部分可转换成 JSON 并成为 `--default-capabilities` 标识的一部分。
|
||||
举个例子:
|
||||
|
||||
```
|
||||
# 未处理的 JSON 作为一个参数
|
||||
--default-capabilities '{"app": "myapp.app", "deviceName": "iPhone Simulator"}'
|
||||
# 或一个 JSON 文件的名字
|
||||
--default-capabilities /path/to/file.json
|
||||
```
|
||||
|
||||
**Windows 用户**在命令行传递 JSON 时记得去掉引号:`--default-capabilities "{\"app\": \"myapp.app\"}"`
|
||||
|
||||
|
||||
| Flag | JSON key |
|
||||
|---------------------------|-------------------------|
|
||||
| --keep-artifacts | keepArtifacts |
|
||||
| --platform-name | platformName |
|
||||
| --platform-version | platformVersion |
|
||||
| --automation-name | automationName |
|
||||
| --device-name | deviceName |
|
||||
| --browser-name | browserName |
|
||||
| --app | app |
|
||||
| --launch-timeout | launchTimeout |
|
||||
| --language | language |
|
||||
| --locale | locale |
|
||||
| --udid | udid |
|
||||
| --orientation | orientation |
|
||||
| --no-reset | noReset |
|
||||
| --full-reset | fullReset |
|
||||
| --app-pkg | appPackage |
|
||||
| --app-activity | appActivity |
|
||||
| --app-wait-package | appWaitPackage |
|
||||
| --app-wait-activity | appWaitActivity |
|
||||
| --device-ready-timeout | deviceReadyTimeout |
|
||||
| --android-coverage | androidCoverage |
|
||||
| --avd | avd |
|
||||
| --avd-args | avdArgs |
|
||||
| --use-keystore | useKeystore |
|
||||
| --keystore-path | keystorePath |
|
||||
| --keystore-password | keystorePassword |
|
||||
| --key-alias | keyAlias |
|
||||
| --key-password | keyPassword |
|
||||
| --intent-action | intentAction |
|
||||
| --intent-category | intentCategory |
|
||||
| --intent-flags | intentFlags |
|
||||
| --intent-args | optionalIntentArguments |
|
||||
| --dont-stop-app-on-reset | dontStopAppOnReset |
|
||||
| --calendar-format | calendarFormat |
|
||||
| --native-instruments-lib | nativeInstrumentsLib |
|
||||
| --keep-keychains | keepKeyChains |
|
||||
| --localizable-strings-dir | localizableStringsDir |
|
||||
| --show-ios-log | showIOSLog |
|
||||
| --reboot | reboot |
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译
|
||||
3
docs/cn/writing-running-appium/espresso.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Espresso
|
||||
|
||||
如果要使用 espresso 驱动,需要把 desired capabilities 中的 `automationName` 配置为 'espresso'。Espresso 驱动和 UIAutomator 的使用方式一致。 (警告:Appium 的 Espresso 驱动目前还在 beta 阶段,只能体验性的使用。它的 API 还不完整,也不能保证正常工作。如果有问题,请给我们报 bug).
|
||||
@@ -1,39 +0,0 @@
|
||||
## 元素定位与交互
|
||||
|
||||
Appium支持webdriver定位策略的子集
|
||||
|
||||
* 根据"class"定位(例如, UI组件类型)
|
||||
* 根据"xpath"定位 (例如,具有一定约束的路径抽象标示, 基于XPath方式)
|
||||
|
||||
另外, Appium 还支持部分 [Mobile JSON 连接协议](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) 的定位策略
|
||||
|
||||
* `ios uiautomation`: 一个递归地、对应使用 [UIAutomation library](ios_predicate.cn.md) 搜索元素的字符串(iOS-only)
|
||||
* `android uiautomator`: 一个递归地、对应使用 [UiAutomator Api](uiautomator_uiselector.cn.md)搜索元素的字符串 (Android-only)
|
||||
* `accessibility id`: 一个递归地、使用本地Accessibility选项实现的Id/Name进行元素搜索的字符串。
|
||||
|
||||
### 存在的问题
|
||||
|
||||
如果遇到定位元素变得无效请联系并告知我们。我们将会努力修复
|
||||
|
||||
### 使用Appium Inspector来定位元素
|
||||
|
||||
(翻译备注: 这个工具目前只有Mac版本, 如果你使用的是windows, 可以使用android sdk自带的 uiautomatorviewer 工具来获得元素的位置)
|
||||
|
||||
Appium提供了一个灵活的工具Appium Inspector, 允许你在app运行的时候, 直接定位你正在关注的元素. 通过Appium Inspector(靠近start test按钮的小"i"按钮), 你可以通过点击预览窗口上的控件来获得它的name属性, 或者直接在UI导航窗口中定位
|
||||
|
||||
#### 概述
|
||||
|
||||
Appium Inspector有一个简单的布局, 全部由如下窗口组成.
|
||||
UI导航器, 预览, 录制与刷新按钮, 和交互工具
|
||||
|
||||

|
||||
|
||||
#### 例子
|
||||
|
||||
启动Appium Inspector后(通过点击app右上的小"i"按钮), 你可以定位任何预览窗口中的元素. 作为测试, 我正在查找id为"show alert"的按钮
|
||||
|
||||

|
||||
|
||||
要找到这个按钮的id, 在定位预览窗口中我点击了"show alert"按钮, Appium Inspector在UI导航窗口中高亮显示了这个元素, 然后展示了刚被点击按钮的id和元素类型
|
||||
|
||||

|
||||
26
docs/cn/writing-running-appium/finding-elements.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## 元素的定位与交互
|
||||
|
||||
Appium 支持 WebDriver 定位策略的子集:
|
||||
|
||||
* 通过 "class" 查找 (例如: UI 组件的类型)
|
||||
* 通过 "xpath" 查找 (例如: 一个元素的路径以抽象的方式去表达,具有一定的约束)
|
||||
|
||||
|
||||
Appium 还额外支持部分 [Mobile JSON Wire Protocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) 的定位策略
|
||||
|
||||
|
||||
* `-ios uiautomation`: 该字符串相当于使用 [UIAutomation 库](ios_predicate.md) 去递归地搜索元素(仅支持iOS 9.3 及以下的版本)
|
||||
* `-android uiautomator`: 该字符串相当于使用 [UiAutomator Api](uiautomator_uiselector.md) 去递归地搜索元素(仅支持 Android)
|
||||
* `accessibility id`: 该字符串相当于利用原生的可访问性(Accessibility)选项,使用 Id/Name 去递归地搜索元素。
|
||||
|
||||
### 已知问题
|
||||
|
||||
在我们要与 table cell 元素进行交互之前,元素会变成无效。这是已知的问题,我们会尽快修复。
|
||||
|
||||
|
||||
### 使用 Appium Inspector 去定位元素
|
||||
|
||||
这里之前的文档都已经 deprecated 了。最新的请参见:[The Inspector](https://github.com/appium/appium-desktop#the-inspector)
|
||||
|
||||
|
||||
本文由 [thanksdanny](https://testerhome.com/thanksdanny) 翻译。由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
220
docs/cn/writing-running-appium/ios-xctest-mobile-gestures.md
Normal file
@@ -0,0 +1,220 @@
|
||||
## 使用 WebDriverAgent/XCTest Backend 进行iOS自动化手势操作
|
||||
|
||||
很可惜,苹果官方的 XCTest 框架本身并不支持 TouchAction 接口实现的 W3C 标准。尽管如此,XCTest 提供了非常丰富的手势操作,这些操作都是 iOS 平台独有的。你可以在 1.6.4-beta 版本的 Appium 中开始使用这些手势操作。
|
||||
|
||||
需要特别注意的是目前XCTest和WDA正在不断优化改变的阶段,这意味着所有 `mobile: *` 的命令可能会在没任何通知的情况下就被调整更改。
|
||||
|
||||
|
||||
### mobile: swipe
|
||||
|
||||
这个手势是在指定的屏幕上的控件或App的控件上执行“滑动”操作,一般是针对整个屏幕。这个方法不支持通过坐标来操作,并且仅仅是简单的模拟单个手指滑动。这个方法对于诸如相册分页、切换视图等情况可能会发挥比较大的作用。更复杂的场景可能需要用到`mobile:dragFromToForDuration`,这个方法支持传坐标(coordinates )和滑动持续时间(duration)。
|
||||
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _direction_: 'up', 'down', 'left' or 'right'. 这4个参数是固定的。
|
||||
* _element_: 需要滑动的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```java
|
||||
// Java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
scrollObject.put("direction", "down");
|
||||
scrollObject.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: swipe", params);
|
||||
```
|
||||
|
||||
|
||||
### mobile: scroll
|
||||
|
||||
滚动元素或整个屏幕。支持不同的滚动策略。该方法提供了4个可选择滑动策略:按照顺序有“name”,“direction”,“predicateString”或“toVisible”。所有的滑动策略都是排他性的,一次滑动只能选择一个策略。你可以使用`mobile:scroll`来对表格中或者集合视图中的某个已知控件进行精确的滚动操作。然而目前有一个已知的局限问题:如果需要在父容器上执行太多的滚动手势来达到必要的子元素(其中几十个),则方法调用可能会失败。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _element_: 需要滚动的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
|
||||
* _name_: 需要执行滚动的子控件的`accessibility id`。
|
||||
将`predicateString`参数设置为`“name == accessibilityId”`可以实现相同的结果。如果`element`不是容器,则不起作用。
|
||||
* _direction_: 'up', 'down', 'left' or 'right'. 该参数与`swipe`中的比,差别在于`scroll`会尝试将当前界面完全移动到下一页。(`page`一词表示单个设备屏幕中的所有内容)
|
||||
* _predicateString_: 需要被执行滚动操作的子控件的NSPredicate定位器。如果控件不是容器,则不起作用。
|
||||
* _toVisible_: 布尔类型的参数。如果设置为`true`,则表示要求滚动到父控件中的第一个可见到的子控件。如果`element`未设置,则不生效。
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```python
|
||||
# Python
|
||||
driver.execute_script('mobile: scroll', {'direction': 'down'});
|
||||
```
|
||||
|
||||
|
||||
### mobile: pinch
|
||||
|
||||
在给定的控件或应用程序控件上执行捏合手势。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _element_: 需要捏合的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
|
||||
* _scale_: 浮动型夹点尺度。使用0和1之间的比例来“捏紧”或缩小,大于1的比例“撑开”或放大。强制参数
|
||||
* _velocity_: 每秒缩放速度(浮点值)。强制参数
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```ruby
|
||||
# Ruby
|
||||
execute_script 'mobile: pinch', scale: 0.5, velocity: 1.1, element: element.ref
|
||||
```
|
||||
|
||||
|
||||
### mobile: doubleTap
|
||||
|
||||
在指定控件上或屏幕上执行双击手势。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _element_: 需要双击的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
|
||||
* _x_: 屏幕x轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
|
||||
* _y_: 屏幕y轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.execute('mobile: doubleTap', {element: element.value.ELEMENT});
|
||||
```
|
||||
|
||||
|
||||
### mobile: touchAndHold
|
||||
|
||||
在指定控件上或屏幕上长按的手势操作。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _element_: 需要长按的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
|
||||
* _duration_: 长按的持续时间(秒),浮点型。强制性参数
|
||||
* _x_: 屏幕x轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
|
||||
* _y_: 屏幕y轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
Dictionary<string, object> tfLongTap = new Dictionary<string, object>();
|
||||
tfLongTap.Add("element", element.Id);
|
||||
tfLongTap.Add("duration", 2.0);
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: touchAndHold", tfLongTap);
|
||||
```
|
||||
|
||||
|
||||
### mobile: twoFingerTap
|
||||
|
||||
在给定元素或应用程序元素上执行两个手指点击手势。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _element_: 需要两只手指操作的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
Dictionary<string, object> tfTap = new Dictionary<string, object>();
|
||||
tfTap.Add("element", element.Id);
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: twoFingerTap", tfTap);
|
||||
```
|
||||
|
||||
|
||||
### mobile: tap
|
||||
|
||||
在指定控件或屏幕上的坐标执行点击手势。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _element_: 控件ID(作为十六进制哈希字符串)。 如果设置 了`element`参数,则`x`、`y`代表的是以当前`element`为边界的xy轴。若未设置,则`x`,`y`代表的是以手机屏幕为边界。
|
||||
* _x_: x轴坐标,类型为float。强制参数
|
||||
* _y_: y轴坐标,类型为float。强制参数
|
||||
|
||||
#### 案例
|
||||
|
||||
```php
|
||||
// PHP
|
||||
$params = array(array('x' => 100.0, 'y' => 50.0, 'element' => element.GetAttribute("id")));
|
||||
$driver->executeScript("mobile: tap", $params);
|
||||
```
|
||||
|
||||
|
||||
### mobile: dragFromToForDuration
|
||||
|
||||
通过坐标点执行拖放手势。可以在控件上执行,也可以在屏幕上执行。
|
||||
|
||||
#### Supported arguments
|
||||
|
||||
* _element_: 控件ID(作为十六进制哈希字符串)。 如果设置 了`element`参数,则`x`、`y`代表的是以当前`element`为边界的xy轴。若未设置,则`x`,`y`代表的是以手机屏幕为边界。
|
||||
* _duration_: 浮点数范围[0.5,60]。表示开始拖动点之前的点击手势需要多长时间才能开始拖动。强制参数
|
||||
* _fromX_: 起始拖动点的x坐标(类型float)。强制参数
|
||||
* _fromY_: 起始拖动点的y坐标(类型float)。强制参数
|
||||
* _toX_: 结束拖曳点的x坐标(float类型)。强制参数
|
||||
* _toY_: 结束拖动点的y坐标(类型float)。强制参数
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```java
|
||||
// Java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("duration", 1.0);
|
||||
params.put("fromX", 100);
|
||||
params.put("fromY", 100);
|
||||
params.put("toX", 200);
|
||||
params.put("toY", 200);
|
||||
params.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: dragFromToForDuration", params);
|
||||
```
|
||||
|
||||
|
||||
### mobile: selectPickerWheelValue
|
||||
|
||||
选择下一个或上一个picker wheel的值。 如果这些值是动态的,那么这个方法是能起作用的。XCTest有一个BUG就是你并不能知道要选择哪一个或者当前的选择区域是否生效。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _element_: PickerWheel的内部元素id(作为十六进制哈希字符串)执行值选择。元素必须是XCUIElementTypePickerWheel类型。强制参数
|
||||
* _order_: `next` 选择下一个value,`previous`选择前面一个value。强制参数
|
||||
* _offset_: 区间值: [0.01, 0.5]。它定义了picker wheel的中心距离应该有多远。 通过将该值乘以实际的picker wheel高度来确定实际距离。太小的偏移值可能不会改变picker wheel的值,而过高的值可能会导致picker wheel同时切换两个或多个值。通常最优值位于范围[0.15,0.3]中。默认为0.2
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```java
|
||||
// Java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("order", "next");
|
||||
params.put("offset", 0.15);
|
||||
params.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: selectPickerWheelValue", params);
|
||||
```
|
||||
|
||||
|
||||
### mobile: alert
|
||||
|
||||
对NSAlert实例执行操作。
|
||||
|
||||
#### 支持参数
|
||||
|
||||
* _action_: 支持以下操作: `accept`, `dismiss` and `getButtons`。强制参数
|
||||
* _buttonLabel_: 点击已有警报按钮的标签文本。这是一个可选参数,只能与`accept`和`dismiss` 操作相结合才有效。
|
||||
|
||||
#### 用法示例
|
||||
|
||||
```python
|
||||
# Python
|
||||
driver.execute_script('mobile: alert', {'action': 'accept', 'buttonLabel': 'My Cool Alert Button'});
|
||||
```
|
||||
|
||||
|
||||
### 进阶主题
|
||||
|
||||
查看 [WDA Element Commands API](https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Commands/FBElementCommands.m)
|
||||
以获取有关在Facebook WebDriverAgent中实现的手势的信息。
|
||||
|
||||
本文由 [大东](https://testerhome.com/Anikikun) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -243,4 +243,4 @@ predicate = "name contains[c] '#{text}' || label contains[c] '#{text}' || value
|
||||
element = execute_script(%Q(au.mainApp().getFirstWithPredicate("#{predicate}");))
|
||||
|
||||
puts element.name # Buttons, Various uses of UIButton
|
||||
```
|
||||
```
|
||||
@@ -1,243 +0,0 @@
|
||||
## 自动化手机网页应用
|
||||
|
||||
如果你正对于如何在iOS的Safari或Android上的Chrome做网页应用的自动化感兴趣,
|
||||
那么Appium能够帮助你。基本上,你可以正常的写webdriver测试,只需要把Appium当
|
||||
成一个有特殊设置的selenium Server。
|
||||
|
||||
### iOS模拟器上的Safari浏览器
|
||||
|
||||
首先,要确保你的Safari浏览器参数中开启了开发者模式,这样Safari的远程调试端口也会被同时打开。
|
||||
|
||||
不管你使用模拟器还是真机,你必须使用Appium开始之前先开启Safari。
|
||||
|
||||
然后设置如下显示的这些信息以便于在设备中的Safari执行测试:
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'iOS'
|
||||
, platformVersion: '7.1'
|
||||
, browserName: 'Safari'
|
||||
, deviceName: 'iPhone Simulator'
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'iOS',
|
||||
'platformVersion': '7.1',
|
||||
'browserName': 'Safari',
|
||||
'deviceName': 'iPhone Simulator'
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'iOS',
|
||||
'platformVersion' => '7.1',
|
||||
'browserName' => 'Safari',
|
||||
'deviceName' => 'iPhone Simulator'
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
|
||||
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
|
||||
```
|
||||
|
||||
### iOS真机上的Safari浏览器
|
||||
|
||||
为了能够在真机上的Safari执行测试,我们使用了[SafariLauncher App](https://github.com/snevesbarros/SafariLauncher)来启动Safari。
|
||||
一旦Safari被启动,则使用[ios-webkit-webkit-proxy](https://github.com/google/ios-webkit-debug-proxy)来自动启动Safari的远程调试功能。
|
||||
|
||||
**提示:** 目前在ios-webkit-debug-proxy中有一个[问题](https://github.com/google/ios-webkit-debug-proxy/issues/38)。
|
||||
你必须添加信任才能开始运行ios-webkit-debug-proxy。
|
||||
|
||||
### 前期设置
|
||||
|
||||
当你要在真机上的Safari中执行你的测试脚本之前你需要先注意以下几点:
|
||||
|
||||
* 安装并运行 **ios-webkit-debug-proxy**,并监听27753端口 (具体可以参考([hybrid docs](../advanced-concepts/hybrid.cn.md))
|
||||
* 打开iOS真机中的 **web inspector**,可以在iOS6.0或更高版本中的 **设置 > safari > 高级**找到。
|
||||
* 创建一个 **provisioning profile** 能够帮助你配置safariLauncher。
|
||||
|
||||
你可以前往 **Apple Developers Member Center** 创建一个launcher profile:
|
||||
* **第一步:** 创建一个 **新的App Id** 同时设置WildCard App ID这个选项置为"*"
|
||||
* **第二步:** 为步骤1的App Id创建一个 **new Development Profile** 。
|
||||
* **第三步:** 选择你的 **certificate(s) and device(s)** 并选择下一步。
|
||||
* **第四步:** 设置profile的名称以及 **generate the profile**。
|
||||
* **第五步:** 下载profile并使用文本编辑器打开。
|
||||
* **第六步:** 寻找并牢记你的 **UUID**
|
||||
|
||||
现在你有了自己的profile文件,可以在终端中输入如下的命令:
|
||||
|
||||
```center
|
||||
$ git clone https://github.com/appium/appium.git
|
||||
$ cd appium
|
||||
|
||||
# 选项1:你可以不设置任何的参数。appium会把签名 (code signing identity) 设为'iPhone Developer'
|
||||
$ ./reset.sh --ios --real-safari
|
||||
|
||||
# 选项2:你需要定义code signing identity并且允许xcode选择profile identity code
|
||||
$ ./reset.sh --ios --real-safari --code-sign '<code signing idendity>'
|
||||
|
||||
# 选项3:你需要设置<code signing idendity>和<profile identity code>
|
||||
$ ./reset.sh --ios --real-safari --code-sign '<code signing idendity>' --profile '<retrieved profile identity code>'
|
||||
|
||||
# 设置成功之后,就可以像往常一样启动服务
|
||||
$ node /lib/server/main.js -U <UDID>
|
||||
```
|
||||
|
||||
### 执行测试
|
||||
如果要在safari下的运行你的测试, 只需要简单的配置**"browserName"**为safari即可
|
||||
|
||||
|
||||
### Java 范例
|
||||
|
||||
```java
|
||||
// java
|
||||
// 配置web driver并启动webview应用
|
||||
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
|
||||
desiredCapabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
|
||||
URL url = new URL("http://127.0.0.1:4723/wd/hub");
|
||||
AppiumDriver driver = new AppiumDriver(url, desiredCapabilities);
|
||||
|
||||
// 跳转到指定页面并在该页面所以用元素id进行交互
|
||||
driver.get("http://saucelabs.com/test/guinea-pig");
|
||||
WebElement div = driver.findElement(By.id("i_am_an_id"));
|
||||
Assert.assertEquals("I am a div", div.getText()); //跳转到指定页面并在该页面所以用元素id进行交互
|
||||
driver.findElement(By.id("comments")).sendKeys("My comment"); //通过id查找评论框并输入
|
||||
|
||||
// 关闭应用
|
||||
driver.quit();
|
||||
```
|
||||
|
||||
### Python 范例
|
||||
|
||||
```python
|
||||
# python
|
||||
# 配置web driver并启动webview应用
|
||||
capabilities = { 'browserName': 'Safari' }
|
||||
driver = webdriver.Remote('http://localhost:4723/wd/hub', capabilities)
|
||||
|
||||
# 跳转到指定页面并在该页面所以用元素id进行交互
|
||||
driver.get('http://saucelabs.com/test/guinea-pig');
|
||||
div = driver.find_element_by_id('i_am_an_id')
|
||||
# 检查文本是否符合预期
|
||||
assertEqual('I am a div', div.text)
|
||||
|
||||
# 通过id查找评论框并输入
|
||||
driver.find_element_by_id('comments').send_keys('My comment')
|
||||
|
||||
# 关闭应用
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
class ContextTests extends PHPUnit_Extensions_AppiumTestCase
|
||||
{
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'iOS',
|
||||
'platformVersion' => '7.1',
|
||||
'browserName' => 'Safari',
|
||||
'deviceName' => 'iPhone Simulator'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function testThings()
|
||||
{
|
||||
$this->get('http://saucelabs.com/test/guinea-pig');
|
||||
|
||||
$div = $this->byId('i_am_an_id');
|
||||
$this->assertEquals('I am a div', $div->text());
|
||||
|
||||
$this->byId('comments')->sendKeys('My comment');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 在真机或模拟器上的Chrome执行测试
|
||||
|
||||
需要做的准备:
|
||||
|
||||
* 确认Chrome已经安装在了你的真机或模拟器上 (应用的包名是`com.android.chrome`) 。在不编译Chromium的情况下, 不可能得到模拟器上的x86版本的chrome,你可以运行一个ARM的模拟器然后从真机上获取一个Chrome的APK安装在模拟器上。
|
||||
* 如果你是使用[NPM](https://www.npmjs.org/package/appium)下载的,
|
||||
或者是在[.app](https://github.com/appium/appium-dot-app)运行的话,那你不需要其他额外的工作。如果你是使用源码运行,`reset`会下载ChromeDriver并放在`build`。
|
||||
使用 `--chromedriver-version` 选项可以指定chromedriver的版本 (例如 `./reset.sh --android --chromedriver-version 2.8`),
|
||||
否则使用最新版。
|
||||
|
||||
接着,像这样设置就可以在Chrome上执行测试了:
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'Android'
|
||||
, platformVersion: '4.4'
|
||||
, deviceName: 'Android Emulator'
|
||||
, browserName: 'Chrome'
|
||||
};
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'Android',
|
||||
'platformVersion': '4.4',
|
||||
'deviceName': 'Android Emulator',
|
||||
'browserName': 'Chrome'
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'Android',
|
||||
'platformVersion' => '4.4',
|
||||
'browserName' => 'Chrome',
|
||||
'deviceName' => 'Android Emulator'
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
|
||||
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");
|
||||
```
|
||||
|
||||
在4.4以上的版本,你也可以用'Browser' `browserName` 来对内置浏览器进行自动化。
|
||||
在所有版本你都可以用'Chromium' `browserName`来对Chromium进行自动化。
|
||||
|
||||
|
||||
#### chromedriver故障排查
|
||||
|
||||
从Chrome 33开始,不再必须将设备root。在之前的版本,设备必须按要求进行root (ChromeDriver需要写 /data/local 目录来设定Chrome的命令行参数) 。
|
||||
|
||||
如果在版本33之前在Chrome上测试app,确保adb shell拥有设备中/data/local目录的读写权限:
|
||||
|
||||
```center
|
||||
$ adb shell su -c chmod 777 /data/local
|
||||
```
|
||||
|
||||
更多关于chromedriver的文档详见[ChromeDriver documentation](https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android)。
|
||||
|
||||
212
docs/cn/writing-running-appium/mobile-web.md
Normal file
@@ -0,0 +1,212 @@
|
||||
## 自动化测试移动网络应用
|
||||
|
||||
如果你有兴趣在 iOS 系统上的 Safari 浏览器或者 Android 系统上的 Chrome 浏览器进行网页自动化的话
|
||||
,Appium可以帮助你。你只要正常地写 WebDriver 测试,通过特别的设置,可以把 Appium 当成 Selenium 服务来运行。
|
||||
|
||||
### 模拟器上的移动端Safari浏览器
|
||||
|
||||
首先,确定你的 Safari 开发者模式开启,移动调试端口打开。
|
||||
|
||||
如果你需要用模拟器或真实设备,你必须在用 Appium 之前打开 Safari 浏览器。
|
||||
|
||||
然后,想在移动端 Safari 上运行你的测试,就需要按如下设置 desired capabilities:
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'iOS'
|
||||
, platformVersion: '7.1'
|
||||
, browserName: 'Safari'
|
||||
, deviceName: 'iPhone Simulator'
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'iOS',
|
||||
'platformVersion': '7.1',
|
||||
'browserName': 'Safari',
|
||||
'deviceName': 'iPhone Simulator'
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'iOS',
|
||||
'platformVersion' => '7.1',
|
||||
'browserName' => 'Safari',
|
||||
'deviceName' => 'iPhone Simulator'
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
|
||||
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
|
||||
```
|
||||
|
||||
### iOS 真机上的移动端 Safari
|
||||
|
||||
在iOS 9.3及以下(pre-XCUITest)版本系统,我们借助 SafariLauncher 应用在移动端Safari运行测试。
|
||||
这是因为Safari是苹果公司的应用,Instruments 不能在真机上拉起 Safari。SafariLuncher 可以帮助打开 Safari 浏览器,浏览器一旦打开,Remote Debugger 会通过 [ios-webkit-debug-proxy](https://github.com/google/ios-webkit-debug-proxy) 自动连接。在 `ios-webkit-debug-proxy` 运行时,
|
||||
必须在你的iOS设备测试前,信任这台设备
|
||||
|
||||
指导如何安装和运行 ios-webkit-debugger-proxy ,可以查阅 [iOS WebKit debug proxy](/docs/cn/advanced-concepts/ios-webkit-debug-proxy.md)
|
||||
|
||||
### 安装
|
||||
|
||||
在真实上运行测试前,你需要:
|
||||
|
||||
* 安装好 **ios-webkit-debug-proxy**,运行并在 27753 接口开启监听。(查阅 [hybrid 文档](/docs/cn/advanced-concepts/hybrid.md#execution-against-a-real-ios-device) 作为指导)
|
||||
* 在 iOS 设备上开启 **web inspector**(设置>safari>高级)
|
||||
* 确保 `SafariLauncher` 正常工作 (参考 [SafariLauncher docs](safari-launcher.md))
|
||||
|
||||
|
||||
### 运行你的测试
|
||||
|
||||
在 safari 运行你的测试,只需简单地设置 **"browserName"** 为 **"Safari"**
|
||||
|
||||
### Java示例
|
||||
|
||||
```java
|
||||
// java
|
||||
//setup the web driver and launch the webview app.
|
||||
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
|
||||
desiredCapabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
|
||||
URL url = new URL("http://127.0.0.1:4723/wd/hub");
|
||||
AppiumDriver driver = new AppiumDriver(url, desiredCapabilities);
|
||||
|
||||
// 浏览网页和定位页面元素取得id。
|
||||
driver.get("http://saucelabs.com/test/guinea-pig");
|
||||
WebElement div = driver.findElement(By.id("i_am_an_id"));
|
||||
Assert.assertEquals("I am a div", div.getText()); //check the text retrieved matches expected value
|
||||
driver.findElement(By.id("comments")).sendKeys("My comment"); //populate the comments field by id.
|
||||
|
||||
//关闭浏览器
|
||||
driver.quit();
|
||||
```
|
||||
|
||||
### Python Example
|
||||
|
||||
```python
|
||||
# python
|
||||
# 建立web driver,开启浏览器app。
|
||||
capabilities = { 'browserName': 'Safari' }
|
||||
driver = webdriver.Remote('http://localhost:4723/wd/hub', capabilities)
|
||||
|
||||
# 浏览网页和定位页面元素取得id。
|
||||
driver.get('http://saucelabs.com/test/guinea-pig');
|
||||
div = driver.find_element_by_id('i_am_an_id')
|
||||
# 检查文本是否匹配值
|
||||
assertEqual('I am a div', div.text)
|
||||
|
||||
# 通过元素id填值。
|
||||
driver.find_element_by_id('comments').send_keys('My comment')
|
||||
|
||||
# 关闭浏览器。
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
class ContextTests extends PHPUnit_Extensions_AppiumTestCase
|
||||
{
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'iOS',
|
||||
'platformVersion' => '7.1',
|
||||
'browserName' => 'Safari',
|
||||
'deviceName' => 'iPhone Simulator'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function testThings()
|
||||
{
|
||||
$this->get('http://saucelabs.com/test/guinea-pig');
|
||||
|
||||
$div = $this->byId('i_am_an_id');
|
||||
$this->assertEquals('I am a div', $div->text());
|
||||
|
||||
$this->byId('comments')->sendKeys('My comment');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 在模拟器和真机上的移动端 Chrome
|
||||
|
||||
前提设置:
|
||||
|
||||
* 确保 Chrome (应用包名 `com.android.chrome`) 在设备或者模拟器上安装好了。不编译 Chromium,在 x86 版本的模拟器上安装 Chrome 已经不可能了。所以你需要运行一个 ARM 版本的模拟器,然后从真机上复制一个 Chrome APK 到模拟器上。
|
||||
* 在特定版本的 Chrome 上进行自动化,需要安装和配置不同版本的 Chromedriver,更多信息参考[文档](/docs/cn/advanced-concepts/chromedriver.md)
|
||||
|
||||
然后,使用如下设置,在你的Chrome下运行你的测试:
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'Android'
|
||||
, platformVersion: '4.4'
|
||||
, deviceName: 'Android Emulator'
|
||||
, browserName: 'Chrome'
|
||||
};
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'Android',
|
||||
'platformVersion': '4.4',
|
||||
'deviceName': 'Android Emulator',
|
||||
'browserName': 'Chrome'
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'Android',
|
||||
'platformVersion' => '4.4',
|
||||
'browserName' => 'Chrome',
|
||||
'deviceName' => 'Android Emulator'
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
|
||||
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");
|
||||
```
|
||||
|
||||
注意:在 4.4+ 版本的设备上,你也可以将 `browserName` 设置为'Browser' 在内建的浏览器上运行自动化。设置浏览器为'Chromium'是在所有设备可以运行的。在所有设备上,你可以将 `browserName` 设置为 'Chromium' 来对Chromium的某个版本进行自动化。
|
||||
|
||||
#### Chromedriver 的障碍排除
|
||||
|
||||
截止 Chrome Version 33,设备不在需要被 root。在这之前,设备需要被 root,因为 ChromeDriver 设置启动Chrome的命令行参数需要在 /data/local 目录的写入权限。
|
||||
|
||||
如果在 Chrome 低于 33 版本上测试,请确保 adb shell 有设备读取/写入 /data/local 权限。
|
||||
|
||||
```center
|
||||
$ adb shell su -c chmod 777 /data/local
|
||||
```
|
||||
|
||||
更多chroomedriver文档参见(https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android)
|
||||
|
||||
本文由 [testly](https://github.com/testly) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,61 +0,0 @@
|
||||
## 调整网络设置
|
||||
|
||||
Selenium 的 [Mobile JSON Wire Protocol Specification](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) 支持一个获取和设置设备网络连接的 [API](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#104) 。这个 API 通过位掩码(bitmask)工作,把所有可能的状态用一个整型数据表示:
|
||||
|
||||
| 值 (别名) | 数据连接 | Wifi 连接 | 飞行模式 |
|
||||
| ------------------ | ---- | ---- | ------------- |
|
||||
| 0 (什么都没有) | 0 | 0 | 0 |
|
||||
| 1 (飞行模式) | 0 | 0 | 1 |
|
||||
| 2 (只有Wifi) | 0 | 1 | 0 |
|
||||
| 4 (只有数据连接) | 1 | 0 | 0 |
|
||||
| 6 (开启所有网络) | 1 | 1 | 0 |
|
||||
|
||||
翻译备注:数据链接即2g, 3g, 4g的网络连接。
|
||||
|
||||
### iOS
|
||||
|
||||
很不幸,目前 Appium 在 iOS 下不支持 Selenium 的网络连接 API。
|
||||
|
||||
### Android
|
||||
|
||||
选择你想使用的设置,然后根据上面的表格发送正确的位掩码(bitmask)。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
// 设置网络连接为飞行模式
|
||||
driver.setNetworkConnection(1)
|
||||
|
||||
// 设置网络连接为仅启用Wifi
|
||||
driver.setNetworkConnection(2)
|
||||
|
||||
// 设置网络连接为仅启用数据连接
|
||||
driver.setNetworkConnection(4)
|
||||
|
||||
// 设置网络连接为启用数据连接和Wifi
|
||||
driver.setNetworkConnection(6)
|
||||
```
|
||||
|
||||
获取网络连接设置会返回基于同样规则的位掩码,你可以将其解码来获得网络设置。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.getNetworkConnection().then(function (connectionType) {
|
||||
switch (connectionType) {
|
||||
case 0:
|
||||
// 无网络
|
||||
break;
|
||||
case 1:
|
||||
// 飞行模式
|
||||
break;
|
||||
case 2:
|
||||
// wifi
|
||||
break;
|
||||
case 4:
|
||||
// 数据连接
|
||||
break;
|
||||
case 6:
|
||||
// wifi和数据连接
|
||||
break;
|
||||
}
|
||||
});
|
||||
```
|
||||
77
docs/cn/writing-running-appium/network_connection.md
Normal file
@@ -0,0 +1,77 @@
|
||||
## 调整网络连接
|
||||
|
||||
Selenium [移动 JSON 协议规范](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) 支持一个获取和设置网络连接的[API](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#104)。这个 API 会设置一个掩码,每一个可能的网络状态对应一个掩码
|
||||
|
||||
| 值 (名称) | 数据 | Wifi | 飞行模式 |
|
||||
| ------------------ | ---- | ---- | ------------- |
|
||||
| 0 (无网) | 0 | 0 | 0 |
|
||||
| 1 (飞行模式) | 0 | 0 | 1 |
|
||||
| 2 (Wifi) | 0 | 1 | 0 |
|
||||
| 4 (移动数据) | 1 | 0 | 0 |
|
||||
| 6 (所有网络) | 1 | 1 | 0 |
|
||||
|
||||
### iOS
|
||||
|
||||
不幸的是,目前 Appium 不支持这个 API。
|
||||
|
||||
### Android
|
||||
|
||||
Android 上有如下限制:
|
||||
|
||||
#### 真机
|
||||
|
||||
* 只能在 Android 6 或者以下,改变飞行模式
|
||||
* 只能在 Android 4.4 或者以下改变数据连接状态。5.0 或者以上必须 root 了之后才能工作。(比如,可以运行 _su_ )
|
||||
* 所有的 Android 版本都能改变 WI-FI 连接状态
|
||||
|
||||
#### 模拟器
|
||||
|
||||
* 只能在 Android 6 或者以下,改变飞行模式
|
||||
* 所有的 Android 版本都能改变数据连接
|
||||
* 所有的 Android 版本都能改变 WI-FI 连接状态
|
||||
|
||||
### Windows
|
||||
|
||||
不幸的是,目前 Appium 测试 Windows 应用,不支持这个 API。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
// set airplane mode
|
||||
driver.setNetworkConnection(1)
|
||||
|
||||
// set wifi only
|
||||
driver.setNetworkConnection(2)
|
||||
|
||||
// set data only
|
||||
driver.setNetworkConnection(4)
|
||||
|
||||
// set wifi and data
|
||||
driver.setNetworkConnection(6)
|
||||
```
|
||||
|
||||
检索网络连接设置返回相同的掩码,其中状态可以解码。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.getNetworkConnection().then(function (connectionType) {
|
||||
switch (connectionType) {
|
||||
case 0:
|
||||
// no network connection
|
||||
break;
|
||||
case 1:
|
||||
// airplane mode
|
||||
break;
|
||||
case 2:
|
||||
// wifi
|
||||
break;
|
||||
case 4:
|
||||
// data
|
||||
break;
|
||||
case 6:
|
||||
// wifi and data
|
||||
break;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
本文由 [testly](https://github.com/testly) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
8
docs/cn/writing-running-appium/reset-strategies.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# 重置策略
|
||||
|
||||
| 自动化平台 | 默认 | fullReset | noReset |
|
||||
| --------------- | ------- | --------- | ------- |
|
||||
| iOS (包括XCUITest) | 测试完成后关闭模拟器。不销毁模拟器。不从真机上卸载应用。 | 测试完成后卸载应用, 模拟器测试结束后销毁模拟器。 | 测试结束后不销毁或者关闭模拟器。启动测试运行在任意正在运行的模拟器或者插入的真机。 |
|
||||
| Android | 测试结束后停止应用,清理应用数据,不卸载应用包。 | 测试结束后停止应用,清理应用数据,卸载应用包。 | 不停止应用,不清理应用数据,不卸载应用包。 |
|
||||
|
||||
本文由 yanqiang@douban.com 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,246 +0,0 @@
|
||||
# 执行测试
|
||||
|
||||
## 准备被测应用 (iOS)
|
||||
|
||||
在模拟器上测试apps必须要用模拟器专用的编译器,例如使用下列的命令来编译Xcode项目:
|
||||
|
||||
```
|
||||
> xcodebuild -sdk iphonesimulator6.0
|
||||
```
|
||||
|
||||
这行指令在Xcode项目底下创建了一个`build/Release-iphonesimulator`目录,并且生成一个可以透过Appium服务器来通讯的的`.app`封包。
|
||||
|
||||
如果需要,你可以把.app 目录压缩成一个zip压缩档! Appium 会自行解压缩。让你能方便在非本地运行Appium。
|
||||
|
||||
## 准备被测应用 (Android)
|
||||
|
||||
用Appium去执行你的.apk档其实没什么特别需要注意的事项。如果需要,你可以把它压缩成zip压缩档。
|
||||
|
||||
## 用Appium测试你的app (iOS)
|
||||
|
||||
想知道如何编写测试脚本,请参照测试范例:
|
||||
|
||||
[Node.js](https://github.com/appium/sample-code/tree/master/sample-code/examples/node) | [Python](https://github.com/appium/sample-code /tree/master/sample-code/examples/python) | [PHP](https://github.com/appium/sample-code/tree/master/sample-code/examples/php) | [Ruby](https://github.com/appium/sample-code/tree/master/sample-code/examples/ruby) | [Java](https://github.com/appium/sample-code/tree/master/sample-code/examples/java)
|
||||
|
||||
基本上来说,首先先确定你启动了Appium:
|
||||
|
||||
```
|
||||
node .
|
||||
```
|
||||
|
||||
然后执行你的WebDriver测试脚本,脚本必须包含下列的环境参数:
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'iOS',
|
||||
platformVersion: '7.1',
|
||||
deviceName: 'iPhone Simulator',
|
||||
app: myApp
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'iOS',
|
||||
'platformVersion': '7.1',
|
||||
'deviceName': 'iPhone Simulator',
|
||||
'app': myApp
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'iOS',
|
||||
'platformVersion' => '7.1',
|
||||
'deviceName' => 'iPhone Simulator',
|
||||
'app' => $myApp
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
|
||||
capabilities.setCapability(MobileCapabilityType.APP, myApp);
|
||||
```
|
||||
|
||||
在这个脚本集里,`myApp`必须是下列其中之一:
|
||||
|
||||
* 一个模拟器编译过的.app 目录或者.zip 文件的本地绝对路径
|
||||
* 一个包含着你的.app封包的zip档的url
|
||||
* appium安装根目录下的一个示例app的相对路径
|
||||
|
||||
在你选择的WebDriver库里,设定remote session使用上述的环境参数然后使用端口4723来连接本地服务器(或者使用你在Appium启动时所设定的端口)。现在你已经完成设置了!
|
||||
|
||||
## 用Appium测试你的app (Android)
|
||||
|
||||
首先,先确定你有一个而且必须是只能一个Android模拟器或者设备连接着。如果你输入`adb devices`,你应该只看到一个设备连接着。这将是Appium所用来测试的设备。当然,要连接一个设备,你需要准备好一个Android AVD (参考([Windows](../appium-setup/running-on-windows.cn.md),[Mac](../appium-setup/running-on-osx.cn.md),或者[Linux](../appium-setup/running-on-linux.cn.md))以了解更多)。 如果Android SDK工具在你的环境变量path下,你可以简单的执行:
|
||||
|
||||
```
|
||||
emulator -avd <我的Avd名称>
|
||||
```
|
||||
|
||||
然后等android模拟器启动。有时候,因为某些原因,`adb`会卡住。如果它没有显示任何的设备或其他故障,你可以使用下列指令来重启:
|
||||
|
||||
```
|
||||
adb kill-server && adb devices
|
||||
```
|
||||
|
||||
现在,确认Appium已经启动:
|
||||
|
||||
```
|
||||
node .
|
||||
```
|
||||
|
||||
有几种方法来启动一个Appium程序(效果和通过adb启动一模一样):
|
||||
|
||||
- 只有apk或者zip,默认activity将会被启动。 (只设置了'app'环境参数)
|
||||
- apk + activity ('app' + 'appActivity' 环境参数)
|
||||
- apk + activity + intent ('app' + 'appActivity' + 'appIntent' 环境参数)
|
||||
- ...
|
||||
|
||||
Activities 可以通过以下方式来指定:
|
||||
|
||||
- 名称 (如 appActivity: 'com.helloworld.SayHello')。
|
||||
- 相对于 appPackage的路径 (如 appPackage: 'com.helloworld', appActivity='.SayHello')
|
||||
|
||||
如果“appWaitPackage'和'appWaitActivity”被指定,Appium
|
||||
将自动等待,直到这些活动的被启动。你可以为实例指定多个等待的activity:
|
||||
|
||||
- appActivity: 'com.splash.SplashScreen'
|
||||
- appPackage: 'com.splash' appActivity: '.SplashScreen'
|
||||
- appPackage: 'com.splash' appActivity: '.SplashScreen,.LandingPage,com.why.GoThere'
|
||||
|
||||
如果你不是很清楚在apk中有哪些activity,你可以通过以下方式来查看:
|
||||
|
||||
- Mac/Linux: 'adb shell dumpsys window windows | grep mFocusedApp'
|
||||
- 在 Ruby 控制台运行: 'adb shell dumpsys window windows\`.each_line.grep(/mFocusedApp/).first.strip'
|
||||
- 在 Windows 终端运行 'adb shell dumpsys window windows' 然后去看mFocusedApp这一行的内容。
|
||||
|
||||
然后执行你的WebDriver测试脚本,脚本必须包含下列的环境参数:
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'Android',
|
||||
platformVersion: '4.4',
|
||||
deviceName: 'Android Emulator',
|
||||
app: myApp
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'Android',
|
||||
'platformVersion': '4.4',
|
||||
'deviceName': 'Android Emulator',
|
||||
'app': myApp
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'Android',
|
||||
'platformVersion' => '4.4',
|
||||
'deviceName' => 'Android Emulator',
|
||||
'app' => $myApp
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
|
||||
capabilities.setCapability(MobileCapabilityType.APP, myApp);
|
||||
```
|
||||
|
||||
在这个脚本集里,`myApp`必须是下列其中之一:
|
||||
|
||||
* 一个.apk 或者.zip 档的本地绝对路径
|
||||
* 一个包含着你的.apk档的zip压缩档的url
|
||||
* appium安装根目录下的一个示例app的路径
|
||||
|
||||
`myAppPackage` 必须是你的应用的java package,例如, `com.example.android.myApp`。
|
||||
|
||||
`myAppActivity` 必须是你的希望测试的Android activity, 例如, `MainActivity`。
|
||||
|
||||
在你选择的WebDriver库里,设定remote session使用上述的环境参数然后使用端口4723来连接本地服务器(或者是使用你在Appium启动时所设定的任意端口)。现在你已经设置完成了!
|
||||
|
||||
## 用Appium测试你的app (Android 设备 < 4.2, 以及混合app测试)
|
||||
|
||||
低于4.2版本的Android设备(API Level 17) 没有安装 Google 的[UiAutomator framework](http://developer.android.com/tools/help/uiautomator/index.html).下面的范例是早期Appium在这些设备上的测试方法。对于早期的设备以及使用混合模式(webview-based)制作的apps, Appium 包含了另一种自动化测试工具[Selendroid](http://selendroid.io/)。
|
||||
|
||||
要使用Selendroid, 只需要在之前提到的环境参数上稍作修改即可,添加 `automationName` 参数并指定Seledroid作为测试工具。通常你还需要在你的activity名称前加上`.` (如:在`appActivity`参数中使用`.MainActivity` 而不是 `MainActivity`) :
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
automationName: 'Selendroid',
|
||||
platformName: 'Android',
|
||||
platformVersion: '2.3',
|
||||
deviceName: 'Android Emulator',
|
||||
app: myApp,
|
||||
appPackage: 'com.mycompany.package',
|
||||
appActivity: '.MainActivity'
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'automationName': 'Selendroid',
|
||||
'platformName': 'Android',
|
||||
'platformVersion': '2.3',
|
||||
'deviceName': 'Android Emulator',
|
||||
'app': myApp,
|
||||
'appPackage': 'com.mycompany.package',
|
||||
'appActivity': '.MainActivity'
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'automationName' => 'Selendroid',
|
||||
'platformName' => 'Android',
|
||||
'platformVersion' => '2.3',
|
||||
'deviceName' => 'Android Emulator',
|
||||
'app' => $myApp,
|
||||
'appPackage' => 'com.mycompany.package',
|
||||
'appActivity'=> '.MainActivity'
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "Selendroid");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "2.3");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
|
||||
capabilities.setCapability(MobileCapabilityType.APP, myApp);
|
||||
capabilities.setCapability(MobileCapabilityType.APP_PACKAGE: "com.mycompany.package");
|
||||
capabilities.setCapability(MobileCapabilityType.APP_ACTIVITY: ".MainActivity");
|
||||
```
|
||||
|
||||
这样Appium就会启动 Selendroid 测试会话取代默认的测试会话。使用Selendroid的缺点是有时候它的API跟Appium非常不同。所以我们建议你在为你的旧设备或者混合app写测试脚本之前先仔细的阅读[Selendroid的说明文档](http://selendroid.io/native.html)。
|
||||
253
docs/cn/writing-running-appium/running-tests.md
Normal file
@@ -0,0 +1,253 @@
|
||||
## 运行测试
|
||||
|
||||
### 准备你要测试的应用(iOS)
|
||||
|
||||
被测应用要在模拟器上运行,就必须针对该模拟器进行专门的编译,例如在 Xcode 项目下执行如下命令(你可以使用 `xcodebuild -showsdks` 来看看你电脑上提供了多少 SDK):
|
||||
|
||||
> xcodebuild -sdk iphonesimulator6.0
|
||||
|
||||
这会在你的 Xcode 项目下创建一个 `build/Release-iphonesimulator` 目录。这个目录包含 `.app` 应用包。你就是用这个包和 Appium server 沟通。
|
||||
|
||||
如果需要,可以将应用程序目录压缩到ZIP文件中!Appium 会帮你解压。
|
||||
|
||||
### 准备你要测试的应用(Android)
|
||||
|
||||
你什么都不用做就可以在 Appium 上运行 apk。如果你想打包,随你。
|
||||
|
||||
### 准备你要测试的应用(Windows)
|
||||
你什么都不用做就可以在 Appium 上运行 Windows 应用。
|
||||
|
||||
|
||||
### 在 Appium 上运行你的测试应用(IOS)
|
||||
|
||||
想知道当前要做什么,最好的方法就是是查看示例代码:
|
||||
|
||||
[Node.js](https://github.com/appium/sample-code/tree/master/sample-code/examples/node) | [Python](https://github.com/appium/sample-code/tree/master/sample-code/examples/python) | [PHP](https://github.com/appium/sample-code/tree/master/sample-code/examples/php) | [Ruby](https://github.com/appium/sample-code/tree/master/sample-code/examples/ruby) | [Java](https://github.com/appium/sample-code/tree/master/sample-code/examples/java)
|
||||
|
||||
基本上,首先确保 Appium 运行:
|
||||
|
||||
node .
|
||||
|
||||
然后编写你的 WebDriver 测试脚本, 用如下的 desired capabilities:
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'iOS',
|
||||
platformVersion: '7.1',
|
||||
deviceName: 'iPhone Simulator',
|
||||
app: myApp
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'iOS',
|
||||
'platformVersion': '7.1',
|
||||
'deviceName': 'iPhone Simulator',
|
||||
'app': myApp
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'iOS',
|
||||
'platformVersion' => '7.1',
|
||||
'deviceName' => 'iPhone Simulator',
|
||||
'app' => $myApp
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
|
||||
capabilities.setCapability(MobileCapabilityType.APP, myApp);
|
||||
```
|
||||
|
||||
|
||||
在上面这一组 capabilities 里,`myApp` 必须是以下的任意一个:
|
||||
|
||||
* 基于对应模拟器编译的 .app 目录或者 zip 文件的绝对路径
|
||||
* app 应用包的 zip 文件的 URL
|
||||
* 基于 Appium 安装根目录的示例应用程序的相对路径
|
||||
|
||||
用你选择的 WebDriver (客户端)库,使用这些 capabilities 和本地的4723端口建立远程会话(或任何启动 Appium 时候指定的主机和端口)。现在你应该都设置好了!
|
||||
|
||||
|
||||
### 使用 Appium 测试你的应用 (Android)
|
||||
|
||||
首先,确保你有一个且只有一个 Android 模拟器或设备连接。例如,如果你运行 `adb devices`,
|
||||
你应该只看到一个设备连接。这个设备就是 Appium 用来测试的。当然, 要连接上一个设备,你需要配置一个 Android AVD (更多信息参考[Windows](https://github.com/appium/appium/blob/master/docs/en/appium-setup/running-on-windows.md),
|
||||
[Mac](https://github.com/appium/appium/blob/master/docs/en/appium-setup/running-on-osx.md),
|
||||
或者 [Linux](https://github.com/appium/appium/blob/master/docs/en/appium-setup/running-on-linux.md)))。如果你的系统变量 PATH 里有 Android SDK 的工具路径,你可以简单运行如下命令:
|
||||
|
||||
emulator -avd <MyAvdName>
|
||||
|
||||
等待 android 模拟器完成启动(可以去喝个咖啡)。有时,各种原因,`adb` 会卡住。如果不显示任何连接设备或否则失败,你可以通过运行以下命令重启它:
|
||||
|
||||
adb kill-server && adb devices
|
||||
|
||||
现在,确认 Appium 运行起来:
|
||||
|
||||
node .
|
||||
|
||||
有几种方法可以启动一个 Appium 应用程序(和使用 adb 启动一样):
|
||||
|
||||
- 仅仅使用 apk 或者 zip,默认 activity 会被加载 ('app' capability)
|
||||
- apk + activity ('app' + 'appActivity' capabilities)
|
||||
- apk + activity + intent ('app' + 'appActivity' + 'appIntent' capabilities)
|
||||
- ...
|
||||
|
||||
Activity 可以通过以下方式指定:
|
||||
|
||||
- absolute (比如 appActivity: 'com.helloworld.SayHello').
|
||||
- 相对于应用包名 (e.g. appPackage: 'com.helloworld', appActivity='.SayHello')
|
||||
|
||||
如果指定 'appWaitPackage' 和 'appWaitActivity',Appium 会转菊花等待,直到这些 Activity 启动。您可以指定等待多个Activity。例如:
|
||||
|
||||
- appActivity: 'com.splash.SplashScreen'
|
||||
- appPackage: 'com.splash' appActivity: '.SplashScreen'
|
||||
- appPackage: 'com.splash' appActivity: '.SplashScreen,.LandingPage,com.why.GoThere'
|
||||
|
||||
如果你不确定你的 apk 中配置的是哪个 Activity,你可以用下列方法:
|
||||
|
||||
- Mac/Linux: 'adb shell dumpsys window windows | grep mFocusedApp'
|
||||
- 在Ruby控制台: 'adb shell dumpsys window windows\`.each_line.grep(/mFocusedApp/).first.strip'
|
||||
- 在Windows终端运行 'adb shell dumpsys window windows' 然后手动找到 mFocusedApp(坑爹,windows shell 下面不是有 findStr 么?)
|
||||
|
||||
然后开始写 WebDriver 的测试脚本,使用下面的 desired capabilities:
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
platformName: 'Android',
|
||||
platformVersion: '4.4',
|
||||
deviceName: 'Android Emulator',
|
||||
app: myApp
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'platformName': 'Android',
|
||||
'platformVersion': '4.4',
|
||||
'deviceName': 'Android Emulator',
|
||||
'app': myApp
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'platformName' => 'Android',
|
||||
'platformVersion' => '4.4',
|
||||
'deviceName' => 'Android Emulator',
|
||||
'app' => $myApp
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
|
||||
capabilities.setCapability(MobileCapabilityType.APP, myApp);
|
||||
```
|
||||
|
||||
在这组 capabilities 里,`myApp` 必须是以下任意一个:
|
||||
|
||||
* apk 或者 zip 文件的绝对路径
|
||||
* apk 的 zip 文件的 url 链接
|
||||
* 基于 appium 安装根目录的示例应用的相对路径
|
||||
|
||||
用你选择的 WebDriver (客户端)库,使用这些 capabilities 和本地的4723端口建立远程会话(或任何启动 Appium 时候指定的主机和端口)。现在你应该都设置好了!
|
||||
|
||||
### 使用 Appium 运行你的测试程序(Android设备& lt;4.2,混合应用)
|
||||
|
||||
4.2版本之前的(API级别17)Android 没有集成谷歌的[UiAutomator framework](http://developer.android.com/tools/testing-support-library/index.html#UIAutomator)。
|
||||
Appium 使用 UiAutomator 来执行自动化。那么在早期的设备或混合(webview-based)应用程序,
|
||||
Appium 是与另一个自动化后台绑定 [Selendroid](http://selendroid.io/)。
|
||||
|
||||
要使用 Selendroid,只需稍微改动 desired capabilities,添加 `automationName` 并指定 Selendroid 为自动化后台。通常,你还需要在你的 activity 名字前加一个 `.`(如,`appActivity` 这个 capability 需要使用 `.MainActivity` 而不是 `MainActivity`)。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
{
|
||||
automationName: 'Selendroid',
|
||||
platformName: 'Android',
|
||||
platformVersion: '2.3',
|
||||
deviceName: 'Android Emulator',
|
||||
app: myApp,
|
||||
appPackage: 'com.mycompany.package',
|
||||
appActivity: '.MainActivity'
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
{
|
||||
'automationName': 'Selendroid',
|
||||
'platformName': 'Android',
|
||||
'platformVersion': '2.3',
|
||||
'deviceName': 'Android Emulator',
|
||||
'app': myApp,
|
||||
'appPackage': 'com.mycompany.package',
|
||||
'appActivity': '.MainActivity'
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// php
|
||||
public static $browsers = array(
|
||||
array(
|
||||
'desiredCapabilities' => array(
|
||||
'automationName' => 'Selendroid',
|
||||
'platformName' => 'Android',
|
||||
'platformVersion' => '2.3',
|
||||
'deviceName' => 'Android Emulator',
|
||||
'app' => $myApp,
|
||||
'appPackage' => 'com.mycompany.package',
|
||||
'appActivity'=> '.MainActivity'
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities();
|
||||
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "Selendroid");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
|
||||
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "2.3");
|
||||
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
|
||||
capabilities.setCapability(MobileCapabilityType.APP, myApp);
|
||||
capabilities.setCapability(MobileCapabilityType.APP_PACKAGE: "com.mycompany.package");
|
||||
capabilities.setCapability(MobileCapabilityType.APP_ACTIVITY: ".MainActivity");
|
||||
```
|
||||
|
||||
现在 Appium 将启动一个 Selendroid 测试会话而不是默认的测试会话。
|
||||
使用 Selendroid 的缺点之一是,它的一些 API 和Appium 有着显著的差别。
|
||||
因此,我们建议你在为旧设备或混合应用程序编写脚本时,彻读(Selendroid文档)(http://selendroid.io/native.html)
|
||||
|
||||
###运行你的测试程序与Appium(Windows)
|
||||
|
||||
只需确保 Appium 在监听,然后运行你的测试。
|
||||
|
||||
有关详细信息,请参阅我们的[samples](https://github.com/Microsoft/WinAppDriver/tree/master/Samples)。
|
||||
|
||||
本文由 [testly](https://github.com/testly) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
94
docs/cn/writing-running-appium/safari-launcher.md
Normal file
@@ -0,0 +1,94 @@
|
||||
## 在 iOS 9.3 及以下版本的真机上运行移动 web 测试:SafariLauncher
|
||||
|
||||
在 iOS 9.3 或更低版本的 iOS 真实设备上运行移动 web 测试需要引入第三方应用程序[SafariLauncher](https://github.com/snevesbarros/SafariLauncher)。 这是必要的,因为 Instruments 没有办法在设备上启动Safari 应用程序。只有先启动 SafariLauncher 应用程序,然后才能启动Safari。简单!
|
||||
|
||||
|
||||
In some configurations, Appium is able to automatically build, sign, and install
|
||||
`SafariLauncher` as it needs, and there is nothing else necessary to be done. If,
|
||||
however, this is not the case, as is more often so with later versions of
|
||||
[Xcode](https://developer.apple.com/xcode/), the following configuration needs to
|
||||
be done before Safari tests on real devices can be successfully run.
|
||||
|
||||
在某些配置中,Appium 能够根据需要自动构建,签名和安装 SafariLauncher,没有什么额外要做的。 但是,事实并非如此,随着[Xcode](https://developer.apple.com/xcode/)的版本更新更为常见。想要在真实设备上的 Safari 上成功运行自动化测试,需要完成以下配置。
|
||||
|
||||
### 自动配置SafariLauncher
|
||||
|
||||
The only thing needed for automatic `SafariLauncher` configuration is to create
|
||||
a **provisioning profile** that can be used to deploy the `SafariLauncher` App.
|
||||
This requires, in particular, a wildcard certificate, which is not possible if
|
||||
your Apple developer account is a free one. If that is the case, skip to the
|
||||
manual configuration below.
|
||||
|
||||
自动配置 SafariLauncher 唯一需要做的是创建一个可用于部署 SafariLauncher App 的**配置文件**。 这需要一个通配符证书。但是如果您的Apple开发者帐户是免费的,这是不可能的。 如果是这种情况,请跳转到下面的手动配置内容。
|
||||
|
||||
要创建启动器的配置文件,请进入**Apple Developers会员中心**,按如下步骤操作:
|
||||
|
||||
步骤1:创建一个新的**APP ID**,并选择WildCard APP ID选项,将其设置为“ * ”
|
||||
步骤2:创建一个**新的开发配置文件**,App Id选择在步骤1中创建的。
|
||||
步骤3:选择您的**证书和设备**,然后单击下一步。
|
||||
步骤4:设置配置文件名称并**生成配置文件**。
|
||||
步骤5:下载配置文件并用文本编辑器打开。
|
||||
步骤6:搜索**UUID**及其字符串作为您的**身份代码**。
|
||||
|
||||
现在只需将您的UDID和设备名称包含在您所需的功能中:
|
||||
|
||||
```js
|
||||
{
|
||||
udid: '...',
|
||||
deviceName: '...',
|
||||
platformName: 'iOS',
|
||||
platformVersion: '9.3',
|
||||
browserName: 'Safari'
|
||||
}
|
||||
```
|
||||
|
||||
### 手动配置 SafariLauncher
|
||||
|
||||
**注意:** 此过程假定您已经安装[Xcode](https://developer.apple.com/xcode/)7.3或7.3.1。
|
||||
|
||||
可以使用 [appium-ios-driver](https://github.com/appium/appium-ios-driver) 附带的 [SafariLauncher](https://github.com/snevesbarros/SafariLauncher) 版本,但如果这样做,每次更新Appium时,必须重新执行该过程。
|
||||
|
||||
要获取 `SafariLauncher` 的本地副本,请先从 [GitHub](https://github.com/) 克隆它:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/snevesbarros/SafariLauncher.git
|
||||
```
|
||||
|
||||
一旦您拥有 `SafariLauncher` 的源代码的本地副本,请打开 [Xcode](https://developer.apple.com/xcode/),然后打开 `SafariLauncher` 项目
|
||||
|
||||

|
||||
|
||||
在 `SafariLauncher` target 窗口中,您会看到一个错误,表示需要有一个此 app 的配置文件
|
||||
|
||||

|
||||
|
||||
为了解决这个问题,您首先需要为app输入“Bundle Identifier”。 Appium期望的默认值为com.bytearc.SafariLauncher,但这可能无法用于构建。 在这种情况下,请选择其他的东西,并记下它。 然后选择“Team”,并允许创建配置文件
|
||||
|
||||

|
||||
|
||||
最后,确保您的设备已连接到计算机,并将其选为目标设备
|
||||
|
||||

|
||||
|
||||
并运行构建和安装操作来编译app并将其推送到您的设备上
|
||||
|
||||

|
||||
|
||||
现在你的设备上有一个可用的 `SafariLauncher`。 该app本身是一个简单的屏幕,点击一个按钮将启动 `Safari`
|
||||
|
||||

|
||||
|
||||
如果您选择了与默认(com.bytearc.SafariLauncher)不同的app的软件包标识符,则最后一步是必需的。 如果你这样做,在使用bundleId所需的功能创建会话时,需要将它发送到Appium:
|
||||
|
||||
```js
|
||||
{
|
||||
udid: '...',
|
||||
deviceName: '...',
|
||||
platformName: 'iOS',
|
||||
platformVersion: '9.3',
|
||||
browserName: 'Safari',
|
||||
bundleId: 'com.imurchie.SafariLauncher'
|
||||
}
|
||||
```
|
||||
|
||||
本文由 [高鹏](https://testerhome.com/026) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
|
After Width: | Height: | Size: 216 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 214 KiB |
BIN
docs/cn/writing-running-appium/safari-launcher/opening.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
docs/cn/writing-running-appium/safari-launcher/running.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -1,85 +0,0 @@
|
||||
# Appium 服务器参数
|
||||
|
||||
使用方法: `node . [标志]`
|
||||
|
||||
## 服务器标志
|
||||
所有的标志都是可选的,但是有一些标志需要组合在一起才能生效。
|
||||
|
||||
|
||||
|
||||
<expand_table>
|
||||
|
||||
|标志|默认值|描述|例子|
|
||||
|----|-------|-----------|-------|
|
||||
|`--shell`|null|进入 REPL 模式||
|
||||
|`--localizable-strings-dir`|en.lproj|IOS only: 定位 .strings所在目录的相对路径 |`--localizable-strings-dir en.lproj`|
|
||||
|`--app`|null|iOS: 基于模拟器编译的 app 的绝对路径或者设备目标的 bundle_id; Android: apk 文件的绝对路径`--app /abs/path/to/my.app`|
|
||||
|`--ipa`|null|(IOS-only) .ipa 文件的绝对路径|`--ipa /abs/path/to/my.ipa`|
|
||||
|`-U`, `--udid`|null|连接物理设备的唯一设备标识符|`--udid 1adsf-sdfas-asdf-123sdf`|
|
||||
|`-a`, `--address`|0.0.0.0|监听的 ip 地址|`--address 0.0.0.0`|
|
||||
|`-p`, `--port`|4723|监听的端口|`--port 4723`|
|
||||
|`-ca`, `--callback-address`|null|回调IP地址 (默认: 相同的IP地址)|`--callback-address 127.0.0.1`|
|
||||
|`-cp`, `--callback-port`|null|回调端口号 (默认: 相同的端口号)|`--callback-port 4723`|
|
||||
|`-bp`, `--bootstrap-port`|4724|(Android-only) 连接设备的端口号|`--bootstrap-port 4724`|
|
||||
|`-k`, `--keep-artifacts`|false|弃用,无效。trace信息现在保留tmp目录下,每次运行前会清除该目录中的信息。 也可以参考 --trace-dir 。||
|
||||
|`-r`, `--backend-retries`|3|(iOS-only) 遇到 crash 或者 超时,Instrument 重新启动的次数。|`--backend-retries 3`|
|
||||
|`--session-override`|false|允许 session 被覆盖 (冲突的话)||
|
||||
|`--full-reset`|false|(iOS) 删除整个模拟器目录。 (Android) 通过卸载应用(而不是清除数据)重置应用状态。在 Android 上,session 完成后也会删除应用。||
|
||||
|`--no-reset`|false|session 之间不重置应用状态 (iOS: 不删除应用的 plist 文件; Android: 在创建一个新的 session 前不删除应用。)||
|
||||
|`-l`, `--pre-launch`|false|在第一个 session 前,预启动应用 (iOS 需要 --app 参数,Android 需要 --app-pkg 和 --app-activity)||
|
||||
|`-lt`, `--launch-timeout`|90000|(iOS-only) 等待 Instruments 启动的时间||
|
||||
|`-g`, `--log`|null|将日志输出到指定文件|`--log /path/to/appium.log`|
|
||||
|`--log-level`|debug|日志级别; 默认 (console[:file]): debug[:debug]|`--log-level debug`|
|
||||
|`--log-timestamp`|false|在终端输出里显示时间戳||
|
||||
|`--local-timezone`|false|使用本地时间戳||
|
||||
|`--log-no-colors`|false|不在终端输出中显示颜色||
|
||||
|`-G`, `--webhook`|null|同时发送日志到 HTTP 监听器|`--webhook localhost:9876`|
|
||||
|`--native-instruments-lib`|false|(IOS-only) iOS 内建了一个怪异的不可能避免的延迟。我们在 Appium 里修复了它。如果你想用原来的,你可以使用这个参数。||
|
||||
|`--app-pkg`|null|(Android-only) 你要运行的apk的java包。 (例如, com.example.android.myApp)|`--app-pkg com.example.android.myApp`|
|
||||
|`--app-activity`|null|(Android-only) 打开应用时,启动的 Activity 的名字(比如, MainActivity)|`--app-activity MainActivity`|
|
||||
|`--app-wait-package`|false|(Android-only) 你想等待的 Activity 的包名。(比如, com.example.android.myApp)|`--app-wait-package com.example.android.myApp`|
|
||||
|`--app-wait-activity`|false|(Android-only) 你想等待的 Activity 名字(比如, SplashActivity)|`--app-wait-activity SplashActivity`|
|
||||
|`--android-coverage`|false|(Android-only) 完全符合条件的 instrumentation 类。 作为命令 adb shell am instrument -e coverage true -w 的 -w 的参数 |`--android-coverage com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation`|
|
||||
|`--avd`|null|(Android-only) 要启动的 avd 的名字||`--avd @default`|
|
||||
|`--avd-args`|null|(Android-only) 添加额外的参数给要启动avd|`--avd-args -no-snapshot-load`|
|
||||
|`--device-ready-timeout`|5|(Android-only) 等待设备准备好的时间,以秒为单位|`--device-ready-timeout 5`|
|
||||
|`--safari`|false|(IOS-Only) 使用 Safari 应用||
|
||||
|`--device-name`|null|待使用的移动设备名字|`--device-name iPhone Retina (4-inch), Android Emulator`|
|
||||
|`--platform-name`|null|移动平台的名称: iOS, Android, or FirefoxOS|`--platform-name iOS`|
|
||||
|`--platform-version`|null|移动平台的版本|`--platform-version 7.1`|
|
||||
|`--automation-name`|null|自动化工具的名称: Appium or Selendroid|`--automation-name Appium`|
|
||||
|`--browser-name`|null|移动浏览器的名称: Safari or Chrome|`--browser-name Safari`|
|
||||
|`--default-device`, `-dd`|false|(IOS-Simulator-only) 使用instruments自己启动的默认模拟器||
|
||||
|`--force-iphone`|false|(IOS-only) 无论应用要用什么模拟器,强制使用 iPhone 模拟器||
|
||||
|`--force-ipad`|false|(IOS-only) 无论应用要用什么模拟器,强制使用 iPad 模拟器||
|
||||
|`--language`|null|iOS / Android 模拟器的语言|`--language en`|
|
||||
|`--locale`|null|Locale for the iOS simulator / Android Emulator|`--locale en_US`|
|
||||
|`--calendar-format`|null|(IOS-only) iOS 模拟器的日历格式|`--calendar-format gregorian`|
|
||||
|`--orientation`|null|(IOS-only) 初始化请求时,使用 LANDSCAPE (横屏) 或者 PORTRAIT (竖屏)|`--orientation LANDSCAPE`|
|
||||
|`--tracetemplate`|null|(IOS-only) 指定 Instruments 使用的 tracetemplate 文件|`--tracetemplate /Users/me/Automation.tracetemplate`|
|
||||
|`--show-sim-log`|false|(IOS-only) 如果设置了, iOS 模拟器的日志会写到终端上来||
|
||||
|`--show-ios-log`|false|(IOS-only) 如果设置了, iOS 系统的日志会写到终端上来||
|
||||
|`--nodeconfig`|null|指定 JSON 格式的配置文件 ,用来在 selenium grid 里注册 appiumd|`--nodeconfig /abs/path/to/nodeconfig.json`|
|
||||
|`-ra`, `--robot-address`|0.0.0.0|robot 的 ip 地址|`--robot-address 0.0.0.0`|
|
||||
|`-rp`, `--robot-port`|-1|robot 的端口地址|`--robot-port 4242`|
|
||||
|`--selendroid-port`|8080|用来和 Selendroid 交互的本地端口|`--selendroid-port 8080`|
|
||||
|`--chromedriver-port`|9515|ChromeDriver运行的端口|`--chromedriver-port 9515`|
|
||||
|`--chromedriver-executable`|null|ChromeDriver 可执行文件的完整路径||
|
||||
|`--use-keystore`|false|(Android-only) 设置签名 apk 的 keystore||
|
||||
|`--keystore-path`|(Android-only) keystore 的路径||
|
||||
|`--keystore-password`|android|(Android-only) keystore 的密码||
|
||||
|`--key-alias`|androiddebugkey|(Android-only) Key 的别名||
|
||||
|`--key-password`|android|(Android-only) Key 的密码||
|
||||
|`--show-config`|false|打印 Appium 服务器的配置信息,然后退出||
|
||||
|`--no-perms-check`|false|跳过Appium对是否可以读/写必要文件的检查||
|
||||
|`--command-timeout`|60|默认所有会话的接收命令超时时间 (在超时时间内没有接收到新命令,自动关闭会话)。 会被新的超时时间覆盖||
|
||||
|`--keep-keychains`|false|(iOS) 当 Appium 启动或者关闭的时候,是否保留 keychains (Library/Keychains)||
|
||||
|`--strict-caps`|false|如果所选设备是appium不承认的有效设备,会导致会话失败||
|
||||
|`--isolate-sim-device`|false|Xcode 6存在一个bug,那就是一些平台上如果其他模拟器设备先被删除时某个特定的模拟器只能在没有任何错误的情况下被建立。这个选项导致了Appium不得不删除除了正在使用设备以外其他所有的设备。请注意这是永久性删除,你可以使用simctl或xcode管理被Appium使用的设备类别。||
|
||||
|`--tmp`|null|可以被Appium用来管理临时文件的目录(绝对路径),比如存放需要移动的内置iOS应用程序。 默认的变量为 `APPIUM_TMP_DIR` ,在 *nix/Mac 为 `/tmp` 在windows上使用环境便令 `TEMP` 设定的目录。||
|
||||
|`--trace-dir`|null|用于保存iOS instruments trace的 appium 目录,是绝对路径, 默认为 <tmp dir>/appium-instruments||
|
||||
|`--intent-action`|android.intent.action.MAIN|(Android-only) 用于启动 activity 的intent action|`--intent-action android.intent.action.MAIN`|
|
||||
|`--intent-category`|android.intent.category.LAUNCHER|(Android-only) 用于启动 activity 的intent category|`--intent-category android.intent.category.APP_CONTACTS`|
|
||||
|`--intent-flags`|0x10200000|(Android-only) 启动 activity 的标志|`--intent-flags 0x10200000`|
|
||||
|`--intent-args`|null|(Android-only) 启动 activity 时附带额外的 intent 参数|`--intent-args 0x10200000`|
|
||||
|`--suppress-adb-kill-server`|false|(Android-only) 如果被设定,阻止Appium杀掉adb实例。||
|
||||
96
docs/cn/writing-running-appium/server-args.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Appium服务器参数
|
||||
|
||||
Appium v1.5里某些服务器参数已被弃用,取而代之使用的-default-capabilities 标志。
|
||||
|
||||
用法:node . [标志]
|
||||
|
||||
## 服务器标志
|
||||
所有标志都是可选的,但是有些必须跟指定标志组合使用才生效。
|
||||
|
||||
|
||||
|
||||
<expand_table>
|
||||
|
||||
| 标志 | 默认值 | 描述 | 示例 |
|
||||
| ------------------------------- | :------------------------------- | ---------------------------------------- | ---------------------------------------- |
|
||||
| `--shell` | 无 | 进入 REPL 模式 | |
|
||||
| `--ipa` | 无 | (仅iOS) .ipa 文件的绝对路径 | `--ipa /abs/path/to/my.ipa` |
|
||||
| `-a`, `--address` | 0.0.0.0 | 监听的 ip 地址 | `--address 0.0.0.0` |
|
||||
| `-p`, `--port` | 4723 | 监听的端口 | `--port 4723` |
|
||||
| `-ca`, `--callback-address` | 无 | 回调ip地址 (默认: 同 --address) | `--callback-address 127.0.0.1` |
|
||||
| `-cp`, `--callback-port` | 无 | 回调端口 (默认: 同 --port) | `--callback-port 4723` |
|
||||
| `-bp`, `--bootstrap-port` | 4724 | (仅安卓) 设备上跟 Appium通信的端口号 | `--bootstrap-port 4724` |
|
||||
| `-r`, `--backend-retries` | 3 | (仅iOS) 遇到crash或者超时,尝试重启Instruments的次数 | `--backend-retries 3` |
|
||||
| `--session-override` | false | 允许session覆盖 (如有冲突) | |
|
||||
| `-l`, `--pre-launch` | false | 首次建立session时预启动应用 (iOS 需要 –app参数,Android需要 –app-pkg和 –app-activity参数) | |
|
||||
| `-g`, `--log` | 无 | 将日志输出到指定文件 | `--log /path/to/appium.log` |
|
||||
| `--log-level` | debug | 日志等级;默认 (控制台[:file]): 调试[:debug] | `--log-level debug` |
|
||||
| `--log-timestamp` | false | 在终端输出里显示时间戳 | |
|
||||
| `--local-timezone` | false | 时间戳使用本地时区 | |
|
||||
| `--log-no-colors` | false | 终端输出不显示颜色 | |
|
||||
| `-G`, `--webhook` | 无 | 同时发送日志到 HTTP 监听器 | `--webhook localhost:9876` |
|
||||
| `--safari` | false | (仅iOS) 使用safari应用程序 | |
|
||||
| `--default-device`, `-dd` | false | (仅iOS模拟器) Instruments启动时使用的默认模拟器 | |
|
||||
| `--force-iphone` | false | (仅iOS) 不管应用程序指定什么设备,强制使用iPhone模拟器 | |
|
||||
| `--force-ipad` | false | (仅iOS) 不管应用程序指定什么设备,强制使用iPad模拟器 | |
|
||||
| `--tracetemplate` | 无 | (仅iOS) 指定Instruments所使用的.tracetemplate文件 | `--tracetemplate /Users/me/Automation.tracetemplate` |
|
||||
| `--instruments` | 无 | (仅iOS) Instruments二进制文件路径 | `--instruments /path/to/instruments` |
|
||||
| `--nodeconfig` | 无 | 指定 JSON格式的配置文件,用来在selenium grid里注册appium | `--nodeconfig /abs/path/to/nodeconfig.json` |
|
||||
| `-ra`, `--robot-address` | 0.0.0.0 | robot使用的IP地址 | `--robot-address 0.0.0.0` |
|
||||
| `-rp`, `--robot-port` | -1 | robot使用的端口号 | `--robot-port 4242` |
|
||||
| `--selendroid-port` | 8080 | 用于和Selendroid通信的本地端口 | `--selendroid-port 8080` |
|
||||
| `--chromedriver-port` | 9515 | ChromeDriver 运行使用的端口 | `--chromedriver-port 9515` |
|
||||
| `--chromedriver-executable` | 无 | ChromeDriver可执行文件的路径 | |
|
||||
| `--show-config` | false | 打印appium服务器的配置信息,然后退出 | |
|
||||
| `--no-perms-check` | false | 绕过Appium检查,确保用户可读/写必要的文件 | |
|
||||
| `--strict-caps` | false | 如果所选设备是appium不承认的有效设备,会导致会话失败 | |
|
||||
| `--isolate-sim-device` | false | Xcode 6存在一个bug,那就是一些平台上如果其他模拟器设备先被删除时某个特定的模拟器只能在没有任何错误的情况下被建立。这个选项导致了Appium不得不删除除了正在使用设备以外其他所有的设备。请注意这是永久性删除,你可以使用simctl或xcode管理被Appium使用的设备类别。 | |
|
||||
| `--tmp` | 无 | 可以被Appium用来管理临时文件的目录(绝对路径),比如存放需要移动的内置iOS应用程序。在*nix/Mac上默认为 /tmp,在Windows上默认为 C:\Windows\Temp | |
|
||||
| `--trace-dir` | 无 | 用于保存iOS instruments trace的 appium 目录,是绝对路径, 默认为/appium-instruments | |
|
||||
| `--debug-log-spacing` | false | 在日志中加大间距来帮助进行视觉检查 | |
|
||||
| `--suppress-adb-kill-server` | false | (仅安卓) 如果设置了,可以阻止Appium杀掉adb实例 | |
|
||||
| `--async-trace` | false | 添加长堆栈追踪到日志实体,建议仅调试时选用 | |
|
||||
| `--webkit-debug-proxy-port` | 27753 | (仅iOS) 用于ios-webkit-debug-proxy通信的本地端口 | `--webkit-debug-proxy-port 27753` |
|
||||
| `-dc`, `--default-capabilities` | {} | 设置默认desired capabilities,每个会话都将使用默认desired capabilities,除非被新的capabilities覆盖 | `--default-capabilities [ '{"app": "myapp.app", "deviceName": "iPhone Simulator"}' | /path/to/caps.json ]` |
|
||||
| `--reboot` | false | - (仅安卓) 每次建立会话重启模拟器,会话结束后杀掉模拟器 | |
|
||||
| `--command-timeout` | 60 | [弃用] 默认所有会话接收命令的超时时间 (单位是秒,但不超过2147483秒)。已被newCommandTimeout关键字替代 | |
|
||||
| `-k`, `--keep-artifacts` | false | [弃用] - 保留Instruments trace目录,请参考--trace-dir标志 | |
|
||||
| `--platform-name` | 无 | [弃用] -移动平台名称: iOS,Android或 FirefoxOS | `--platform-name iOS` |
|
||||
| `--platform-version` | 无 | [弃用] - 移动平台的版本号 | `--platform-version 7.1` |
|
||||
| `--automation-name` | 无 | [弃用] - 自动化工具的名称: Appium 或 Selendroid | `--automation-name Appium` |
|
||||
| `--device-name` | 无 | [弃用] - 要使用的移动设备的名称 | `--device-name iPhone Retina (4-inch), Android Emulator` |
|
||||
| `--browser-name` | 无 | [弃用] - 移动浏览器的名称: Safari 或者 Chrome | `--browser-name Safari` |
|
||||
| `--app` | 无 | [弃用] - IOS: 基于模拟器编译的.app文件的绝对路径或者设备上目标的BundleId; Android: .apk文件的绝对路径 | `--app /abs/path/to/my.app` |
|
||||
| `-lt`, `--launch-timeout` | 90000 | [弃用] - (仅iOS) Instruments启动等待时间(单位: ms) | |
|
||||
| `--language` | 无 | [弃用] -iOS模拟器/Android模拟器的语言 | `--language en` |
|
||||
| `--locale` | 无 | [弃用] -iOS模拟器/Android模拟器的区域 | `--locale en_US` |
|
||||
| `-U`, `--udid` | 无 | [弃用] - 连接的物理设备的udid | `--udid 1adsf-sdfas-asdf-123sdf` |
|
||||
| `--orientation` | 无 | [弃用] - (仅iOS) 初始化请求时,使用LANDSCAPE或者PORTRAIT | `--orientation LANDSCAPE` |
|
||||
| `--no-reset` | false | [弃用] - session之间不充值应用状态 (IOS: 不删除应用的 plist 文件;Android: 在创建一个新的session前不删除应用。) | |
|
||||
| `--full-reset` | false | [弃用] - (iOS) 删除整个模拟器目录。 (Android) 通过卸载应用(而不是清楚数据)重置应用状态。在Android上session完成后也会删除应用。 | |
|
||||
| `--app-pkg` | 无 | [弃用] - (仅安卓) 想要运行的apk的java包 (例如, com.example.android.myApp) | `--app-pkg com.example.android.myApp` |
|
||||
| `--app-activity` | 无 | [弃用] - (仅安卓) 打开应用时,想要启动的Activity的名称(例如 MainActivity) | `--app-activity MainActivity` |
|
||||
| `--app-wait-package` | false | [弃用] - (仅安卓) 想要等待的activity的包名 (例如 com.example.android.myApp) | `--app-wait-package com.example.android.myApp` |
|
||||
| `--app-wait-activity` | false | [弃用] - (仅安卓) 想要等待的activity名(例如 SplashActivity) | `--app-wait-activity SplashActivity` |
|
||||
| `--device-ready-timeout` | 5 | [弃用] - (仅安卓) 等待设备准备就绪的时间(单位: 秒) | `--device-ready-timeout 5` |
|
||||
| `--android-coverage` | false | [弃用] - (仅安卓) 完全符合条件的instrumentation类,作为命令 adb shell am instrument -e coverage true -w 的 -w 的参数 | `--android-coverage com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation` |
|
||||
| `--avd` | 无 | [弃用] - (仅安卓) 要启动的avd的名称 | `--avd @default` |
|
||||
| `--avd-args` | 无 | [弃用] - (仅安卓) 启动avd时额外的模拟器参数 | `--avd-args -no-snapshot-load` |
|
||||
| `--use-keystore` | false | [弃用] - (仅安卓) 设置签名apk的keystore | |
|
||||
| `--keystore-path` | <user>/.android/debug.keystore | [弃用] - (仅安卓) keystore 的路径 | |
|
||||
| `--keystore-password` | android | [弃用] - (仅安卓) keystore的密码 | |
|
||||
| `--key-alias` | androiddebugkey | [弃用] - (仅安卓) Key的别名 | |
|
||||
| `--key-password` | android | [弃用] - (仅安卓) Key 的密码 | |
|
||||
| `--intent-action` | android.intent.action.MAIN | [弃用] - (仅安卓) 用于启动activity的Intent action | `--intent-action android.intent.action.MAIN` |
|
||||
| `--intent-category` | android.intent.category.LAUNCHER | [弃用] - (仅安卓) 用于启动activity的Intent category | `--intent-category android.intent.category.APP_CONTACTS` |
|
||||
| `--intent-flags` | 0x10200000 | [弃用] - (仅安卓) 启动activity的标志 | `--intent-flags 0x10200000` |
|
||||
| `--intent-args` | 无 | [弃用] - (仅安卓)启动activity时附带额外的intent参数 | `--intent-args 0x10200000` |
|
||||
| `--dont-stop-app-on-reset` | false | [弃用] - (仅安卓) 用于设置appium重启时是否先杀掉app | |
|
||||
| `--calendar-format` | 无 | [弃用] - (仅iOS) iOS模拟器的日历格式 | `--calendar-format gregorian` |
|
||||
| `--native-instruments-lib` | false | [弃用] - (仅iOS) iOS 内建了一个怪异的不可能避免的延迟,我们在Appium里修复了它,如果你想用原来的,你可以使用这个参数 | |
|
||||
| `--keep-keychains` | false | [弃用] - (仅iOS) 当Appium启动或者关闭的时候,是否保留keychains(Library/Keychains) | |
|
||||
| `--localizable-strings-dir` | en.lproj | [弃用] - (仅iOS)定位.strings所在目录的相对路径 | `--localizable-strings-dir en.lproj` |
|
||||
| `--show-ios-log` | false | [弃用] - (仅iOS) 如果设置了,iOS系统日志会输出到终端 | |
|
||||
|`--enable-heapdump`|false|激活 NodeJS 内存 dumps 收集功能。这个功能对找到内存泄露非常有用。用 'kill -SIGUSR2 <PID>' 命令来创建 node 进程的内存堆栈dump,只有在 *nix 系统有效。dump 文件会被创建在 appium 运行的目录,文件使用 *.heapsnapshot 做后缀。如果后续想要深入研究,这个快照可以被加载到 Chrome Inspector 里去。参加 [Rising Stack article](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/) for more details.||
|
||||
|
||||
本文由 [testly](https://github.com/testly) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,125 +0,0 @@
|
||||
## 移动手势的自动化
|
||||
|
||||
虽然Selenium WebDriver的规范支持数种手机交互的方式,但它的参数并不能简单地映射到底层设备使用的自动化函数 (像在iOS上的UIAutomation) 。为此,Appium在规范的最新版本中定义了新的触摸操作/多点触控 API
|
||||
([https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#multiactions-1](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#multiactions-1))。
|
||||
注意,这跟在早期版本中使用原始JSON Wire Protocol 的触摸操作 API不同。
|
||||
|
||||
这些API可以让你使用多个驱动来建立任意手势。请参阅对应语言的Appium客户端文档,就可以找到使用这些API的例子。
|
||||
|
||||
|
||||
### 触摸操作/多点触控 API的概述
|
||||
|
||||
### 触摸操作 (TouchAction)
|
||||
|
||||
*TouchAction* 对象包含一连串的事件。
|
||||
|
||||
在所有的appium客户端库中,触摸对象创建并给出一连串的事件。
|
||||
|
||||
规范中的可用事件有:
|
||||
* 短按 (press)
|
||||
* 释放 (release)
|
||||
* 移动到 (moveTo)
|
||||
* 点击 (tap)
|
||||
* 等待 (wait)
|
||||
* 长按 (longPress)
|
||||
* 取消 (cancel)
|
||||
* 执行 (perform)
|
||||
|
||||
这里有一个通过伪代码创建动作的例子:
|
||||
|
||||
```center
|
||||
TouchAction().press(el0).moveTo(el1).release()
|
||||
```
|
||||
|
||||
上述模拟用户按下一个元素,滑动他的手指到另一个位置,然后从屏幕上释放其手指。
|
||||
|
||||
Appium按顺序执行这些事件。你可以添加一个 `wait` 事件来控制相应手势的时间。
|
||||
|
||||
appium客户端库有不同的方式来实现上述例子,比如:你可以传递一个坐标值或一个元素给 `moveTo` 事件。同时传递坐标和元素,会将坐标和元素对应起来,但这不是绝对的。
|
||||
|
||||
|
||||
调用 `perform` 事件发送整个事件序列给appium,从而使触摸手势在设备上运行。
|
||||
|
||||
Appium客户端还允许人们直接通过驱动程序对象执行触摸操作, 而不是调用触摸操作对象的`perform`事件。
|
||||
|
||||
|
||||
在伪代码中,以下两个是等价的:
|
||||
|
||||
```center
|
||||
TouchAction().tap(el).perform()
|
||||
|
||||
driver.perform(TouchAction().tap(el))
|
||||
```
|
||||
|
||||
### 多点触控 (MultiTouch)
|
||||
|
||||
*MultiTouch* 对象是触摸操作的集合。
|
||||
|
||||
多点触控手势只有两个方法,添加 (`add`) 和执行 (`perform`) 。
|
||||
|
||||
`add` 用于将不同的触摸操作添加到一个多点触控中。
|
||||
|
||||
当 `perform` 被调用的时候,所有被添加到多点触摸中的触摸事件会被发送到appium并且被执行,就像它们同时发生一样。Appium会执行“触摸事件”中的第一个事件,然后第二个,以此类推。
|
||||
|
||||
|
||||
用两只手指点击的代码示例:
|
||||
|
||||
```center
|
||||
action0 = TouchAction().tap(el)
|
||||
action1 = TouchAction().tap(el)
|
||||
MultiAction().add(action0).add(action1).perform()
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 缺陷和解决方法
|
||||
|
||||
不幸的是有一个缺陷存在于iOS的7.x的模拟器上,ScrollViews无法识别由UIAutomation创建的手势 (在iOS上Appium使用的是UIAutomation) 。 为了实现此功能,我们已经提供了新的函数, `scroll`, 在大部分情况下可以让你实现跟ScrollView一样的功能!
|
||||
|
||||
|
||||
|
||||
**滚动**
|
||||
|
||||
|
||||
要使用这特殊的功能,我们重写了driver中的 `execute` 和
|
||||
`executeScript` 方法。 可以通过在命令前加 `mobile: ` 的前缀来使用滚动。
|
||||
请参见下面的例子:
|
||||
|
||||
* **WD.js:**
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
// 把视图往下滑动
|
||||
driver.execute("mobile: scroll", [{direction: 'down'}])
|
||||
// 继续测试
|
||||
```
|
||||
|
||||
* **Java:**
|
||||
|
||||
```java
|
||||
// java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, String> scrollObject = new HashMap<String, String>();
|
||||
scrollObject.put("direction", "down");
|
||||
scrollObject.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: scroll", scrollObject);
|
||||
```
|
||||
|
||||
**滑块的自动化**
|
||||
|
||||
|
||||
**iOS**
|
||||
|
||||
* **Java**
|
||||
|
||||
```java
|
||||
// java
|
||||
// 滑动值使用0到1之间的数字以字符串的形式表示
|
||||
// 例如,“0.1”代表10%,“1.0”代表100%
|
||||
WebElement slider = driver.findElement(By.xpath("//window[1]/slider[1]"));
|
||||
slider.sendKeys("0.1");
|
||||
```
|
||||
|
||||
**Android**
|
||||
|
||||
与Android上的滑块进行交互的最佳方式是用触摸操作 (TouchActions) 。
|
||||
197
docs/cn/writing-running-appium/touch-actions.md
Normal file
@@ -0,0 +1,197 @@
|
||||
## 移动手势的自动化
|
||||
|
||||
尽管 Selenium WebDriver 的规范已经支持了一些移动交互,但它的参数并不总是那么容易地
|
||||
映射到底层设备的自动化框架所提供的方法上(比如 iOS 上的 UIAutomation)。为此,Appium 在最新的规范([https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#multiactions-1](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#multiactions-1))
|
||||
中实现了新的触摸操作和多重操作 API。
|
||||
|
||||
注意,这与早期版本中原始的 JSON Wire 协议里的触摸操作 API 不同。
|
||||
|
||||
这些 API 允许你使用多个执行器去建立任意的手势。
|
||||
请查看对应语言的 Appium 客户端文档来查看使用这些 API 的示例。
|
||||
|
||||
### 触摸操作(TouchAction)/多重操作(MultiAction) API 概述
|
||||
|
||||
### 触摸操作(TouchAction)
|
||||
|
||||
*TouchAction* 对象包含一连串的事件。
|
||||
|
||||
在所有的 appium 客户端库里,触摸对象被创建并被赋予一连串的事件。
|
||||
|
||||
规范里可用的事件有:
|
||||
* 短按(press)
|
||||
* 释放(release)
|
||||
* 移动到(moveTo)
|
||||
* 点击(tap)
|
||||
* 等待(wait)
|
||||
* 长按(longPress)
|
||||
* 取消(cancel)
|
||||
* 执行(perform)
|
||||
|
||||
这是一个使用伪代码创建一个动作的示例:
|
||||
|
||||
```center
|
||||
TouchAction().press(el0).moveTo(el1).release()
|
||||
```
|
||||
|
||||
上述模拟了一个用户按下一个元素,滑动他的手指到另一个位置,然后将他的手指从屏幕上移开。
|
||||
|
||||
Appium按顺序执行这些事件。你可以添加`wait`事件来控制事件的时长。
|
||||
|
||||
`moveTo` 的坐标与当前的位置*相关*。举例来说,从 100,100 拖拽到 200,200 可以这样实现:
|
||||
```
|
||||
.press(100,100) // 从 100,100 开始
|
||||
.moveTo(100,100) // 分别给X和Y坐标增加100,在 200,200 结束
|
||||
|
||||
```
|
||||
|
||||
Appium 客户端库有不同的实现方式,举例来说:你可以传递坐标或元素给 `moveTo` 事件。当坐标
|
||||
和元素一起传递时,该坐标是相对于元素位置的相对坐标,而不是相对于当前位置。
|
||||
|
||||
调用 `perform` 事件发送全部的事件序列给 appium,触摸手势就会在你的设备上执行。
|
||||
|
||||
Appium客户端也允许通过 driver 对象直接执行触摸操作,而不是在触摸操作对象上调用 `perform`
|
||||
事件。
|
||||
|
||||
在伪代码里,以下两者是相等的:
|
||||
|
||||
```center
|
||||
TouchAction().tap(el).perform()
|
||||
|
||||
driver.perform(TouchAction().tap(el))
|
||||
```
|
||||
|
||||
### 多点触控(MultiTouch)
|
||||
|
||||
*MultiTouch*对象是触摸操作的集合。
|
||||
|
||||
多点触控手势只有两个方法,`add`和`perform`。
|
||||
|
||||
`add` 用于将不同的触摸操作添加到当前的多点触控中。
|
||||
|
||||
当 `perform` 执行时,被添加到多点触控里的所有触摸操作会被发送给 appium 并被执行,就像它们
|
||||
同时发生一样。Appium 会按序一个个执行触摸事件,首先第一个事件,然后第二个,以此类推。
|
||||
|
||||
用两只手指点击的伪代码示例:
|
||||
|
||||
```center
|
||||
action0 = TouchAction().tap(el)
|
||||
action1 = TouchAction().tap(el)
|
||||
MultiAction().add(action0).add(action1).perform()
|
||||
```
|
||||
|
||||
### 缺陷与解决方法
|
||||
|
||||
不幸的是,在iOS 7.0 - 8.x 的模拟器上存在着一个缺陷,ScrollViews、CollectionViews和TableViews不能识别 UIAutomation(Appium在iOS底层所使用的框架)所创建的手势。为了避免这些,我们已经提供了一个可用的新函数 `scroll`,它在大多数情况下能让你完成你想在这些 view 中的任意一个上去做的事,也就是,滚动它!
|
||||
|
||||
|
||||
**滚动**
|
||||
|
||||
|
||||
为了允许使用这个特殊的手势,我们重写了 driver 的 `execute` 和 `executeScript` 方法,并且给命令
|
||||
加上 `mobile: ` 前缀。
|
||||
看下面的示例:
|
||||
|
||||
为了进行滚动,将你想滚动的方向作为参数传入。
|
||||
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.execute('mobile: scroll', {direction: 'down'})
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, String> scrollObject = new HashMap<String, String>();
|
||||
scrollObject.put("direction", "down");
|
||||
js.executeScript("mobile: scroll", scrollObject);
|
||||
```
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
execute_script 'mobile: scroll', direction: 'down'
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.execute_script("mobile: scroll", {"direction": "down"})
|
||||
```
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
Dictionary<string, string> scrollObject = new Dictionary<string, string>();
|
||||
scrollObject.Add("direction", "down");
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: scroll", scrollObject));
|
||||
```
|
||||
|
||||
```php
|
||||
$params = array(array('direction' => 'down'));
|
||||
$driver->executeScript("mobile: scroll", $params);
|
||||
```
|
||||
|
||||
使用方向和元素进行滚动的示例。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
driver.execute('mobile: scroll', {direction: 'down', element: element.value.ELEMENT});
|
||||
```
|
||||
|
||||
```java
|
||||
// java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, String> scrollObject = new HashMap<String, String>();
|
||||
scrollObject.put("direction", "down");
|
||||
scrollObject.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: scroll", scrollObject);
|
||||
```
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
execute_script 'mobile: scroll', direction: 'down', element: element.ref
|
||||
```
|
||||
|
||||
```python
|
||||
# python
|
||||
driver.execute_script("mobile: scroll", {"direction": "down", element: element.getAttribute("id")})
|
||||
```
|
||||
|
||||
```csharp
|
||||
// c#
|
||||
Dictionary<string, string> scrollObject = new Dictionary<string, string>();
|
||||
scrollObject.Add("direction", "down");
|
||||
scrollObject.Add("element", <element_id>);
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("mobile: scroll", scrollObject));
|
||||
```
|
||||
|
||||
```php
|
||||
$params = array(array('direction' => 'down', 'element' => element.GetAttribute("id")));
|
||||
$driver->executeScript("mobile: scroll", $params);
|
||||
```
|
||||
|
||||
**Swiping**
|
||||
|
||||
在 XCUITest 驱动上有一个特别的方法,和 scrolling 类似。(见
|
||||
https://developer.apple.com/reference/xctest/xcuielement)。
|
||||
|
||||
这个方法的名字和 [Scrolling](#scrolling)的 API 一样,只要用 "mobile: swipe" 替换 "mobile: scroll"。
|
||||
|
||||
**滑块的自动化**
|
||||
|
||||
|
||||
**iOS**
|
||||
|
||||
* **Java**
|
||||
|
||||
```java
|
||||
// java
|
||||
// 滑动值可以是代表0到1之间数字的字符串
|
||||
// 例如,"0.1"代表10%,"1.0"代表100%
|
||||
WebElement slider = driver.findElement(By.xpath("//window[1]/slider[1]"));
|
||||
slider.sendKeys("0.1");
|
||||
```
|
||||
|
||||
**Android**
|
||||
|
||||
在Android上与滑块交互的最佳方式是使用触摸操作。
|
||||
|
||||
本文由 [NativeZhang](https://github.com/NativeZhang) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
29
docs/cn/writing-running-appium/uiautomator2.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# UIAutomator 2
|
||||
|
||||
尽管 API 大部分依然相同,但是内部实现已经改变了。我们来看 UIObject2 的介绍:
|
||||
|
||||
### UIObject2
|
||||
|
||||
不同于 UiObject,UIElement 被绑定到一个特殊的 view 实例上,并且在底层 view 对象被销毁后变成过期的。因此,如果 UI 发生的显著变化时,可能就必须去调用 findObject(BySelector) 以获得一个新的 UiObject2 实例。
|
||||
|
||||
### 构建系统
|
||||
|
||||
UIAutomator 2利用了Gradle作为构建系统的能力。之前的UIAutomator使用Maven/Ant。
|
||||
|
||||
### 测试产出(Assets)
|
||||
|
||||
现在生成的测试包是APK。之前UIAutomator生成.jar或.zip文件。这让 UIAutomator 2 能完整地使用 Android instrumentation 的能力。
|
||||
|
||||
### ADB
|
||||
|
||||
ADB 对 UIAutomator 2 的处理有轻微的不同。
|
||||
|
||||
老版本的 UiAutomator 作为一个 shell 程序运行:
|
||||
|
||||
```adb shell uiautomator runtest ...```
|
||||
|
||||
UiAutomator 2 是基于 Android Instrumentation 的。测试被编译进APK里,并且在应用进程里运行:
|
||||
|
||||
```adb shell am instrument ...```
|
||||
|
||||
本文由 [NativeZhang](https://github.com/NativeZhang) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,44 +0,0 @@
|
||||
## uiautomator UiSelector
|
||||
|
||||
Appium可以使用 [UiSelectors](http://developer.android.com/tools/help/uiautomator/UiSelector.html)
|
||||
进行元素查找,同时也支持[UiScrollable](http://developer.android.com/tools/help/uiautomator/UiScrollable.html)
|
||||
.
|
||||
|
||||
注意:根据索引 (index) 进行查找并不可靠,请使用实例 (instance) 代替. 下面的示范是用Ruby语言编写的、针对 api demo (这是一个 appium 测试用的应用) 的实例。
|
||||
|
||||
翻译者备注:UiSelectors 和 UiScrollable 均是 Android UiAutomator 中的对象,因此以下用法仅适用于 Android 。
|
||||
|
||||
|
||||
找到第一个文本控件 (TextView) 。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
first_textview = find_element(:uiautomator, 'new UiSelector().className("android.widget.TextView").instance(0)');
|
||||
```
|
||||
|
||||
根据文本 (text) 找到第一个元素。
|
||||
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
first_text = find_element(:uiautomator, 'new UiSelector().text("Animation")')
|
||||
first_text.text # "Animation"
|
||||
```
|
||||
|
||||
找到第一个可滚动的元素, 然后找到文本是 "Tabs" 的文本控件。
|
||||
"Tabs" 元素就是将要滚动到的控件。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Tabs")')
|
||||
```
|
||||
|
||||
scrollIntoView 是一个特例,会返回滚动到指定控件的元素。
|
||||
scrollIntoView 对任何的 UiSelector 都可以执行滚动操作。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("WebView").instance(0));')
|
||||
element.text # "WebView"
|
||||
```
|
||||
|
||||
41
docs/cn/writing-running-appium/uiautomator_uiselector.md
Normal file
@@ -0,0 +1,41 @@
|
||||
## uiautomator UiSelector
|
||||
|
||||
Appium 使用 [UiSelectors](http://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html) 来进行查找。
|
||||
同时也支持 [UiScrollable](http://developer.android.com/reference/android/support/test/uiautomator/UiScrollable.html)。
|
||||
|
||||
注意,根据索引查找并不可靠,所以更应该使用实例(instance)。后续的示例是使用 Ruby 来测试 api demos apk。
|
||||
|
||||
|
||||
查找第一个 textview。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
first_textview = find_element(:uiautomator, 'new UiSelector().className("android.widget.TextView").instance(0)');
|
||||
```
|
||||
|
||||
根据文本查找第一个元素。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
first_text = find_element(:uiautomator, 'new UiSelector().text("Animation")')
|
||||
first_text.text # "Animation"
|
||||
```
|
||||
|
||||
查找第一个可滚动(scrollable)的元素,然后根据文本"Tabs"查找第一个 TextView。
|
||||
"Tabs"元素将被滚动到可见范围。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Tabs")')
|
||||
```
|
||||
|
||||
作为一个特例,scrollIntoView 返回的是被滚动到可见范围的元素。
|
||||
scrollIntoView 允许滚动到任意的 UiSelector。
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("WebView").instance(0));')
|
||||
element.text # "WebView"
|
||||
```
|
||||
|
||||
本文由 [NativeZhang](https://github.com/NativeZhang) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||
@@ -1,108 +0,0 @@
|
||||
## 多语言支持
|
||||
|
||||
程序处理非拉丁字符时存在一个的问题:对于带音标的字符,存在多种编码形式。例如,对于`é`这样的字符,有两种编码方式:一种是单独的字符`é`(Unicode中的`LATIN SMALL LETTER E WITH ACUTE`(带有音标的小写的拉丁字母'E')),另一种是音标在字符后边(`COMBINING ACUTE ACCENT`(字符和音标的组合))。为了解决这个问题,存在一个`normalization` (标准化) 方法,让["每个字符都有一个唯一的二进制表示"](http://www.unicode.org/reports/tr15/)。
|
||||
|
||||
幸运的是,对ASCII字符(例如 不需要进行标准化的字符)进行标准化将不会产生任何变化,并且多次进行标准化
|
||||
操作也不会发生额外的变化。因此,可以对所有字符使用标准化函数而不用担心产生不良影响。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
|
||||
'some ASCII text' === unorm.nfd('some ASCII text');
|
||||
unorm.nfd('Adélaïde Hervé') === unorm.nfd(unorm.nfd('Adélaïde Hervé'));
|
||||
```
|
||||
|
||||
在测试的时候遇到Unicode字符,你需要对字符进行标准化,确保期望的值和接收到的值一致。
|
||||
有很多方法可以用来进行标准化,所以你要确保执行的是同样的方法!
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
driver
|
||||
.elementByAccessibilityId('find')
|
||||
.text()
|
||||
.then(function (txt) {
|
||||
unorm.nfd(txt).should.be(unorm.nfd("é Œ ù ḍ"));
|
||||
});
|
||||
```
|
||||
|
||||
一个由不同unicode文本编码导致的问题的标志是断言失败但报告却显示两个看起来一模一样的字符串:
|
||||
|
||||
```shell
|
||||
AssertionError: expected 'François Gérard' to deeply equal 'François Gérard'
|
||||
+ expected - actual
|
||||
|
||||
+"François Gérard"
|
||||
-"François Gérard"
|
||||
```
|
||||
|
||||
当发生只因编码导致的问题时,输出_看上去_一样。从标准的角度,它们的编码应该也和它们看上去那样相同。
|
||||
|
||||
|
||||
### 查找器 (Finder)
|
||||
|
||||
需要被查找的字符也应该需要标准化。比如,你在一个iOS的app上有一个叫做`Найти`的按钮,你也应该在find命令中标准化它。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
driver
|
||||
.findElementByXPath(unorm.nfd("//UIAButton[@name='Найти']"))
|
||||
.should.eventually.exist;
|
||||
```
|
||||
|
||||
否则这个按钮可能无法被找到。
|
||||
|
||||
|
||||
### 文本框 (Text Field)
|
||||
|
||||
默认情况下,iOS和Android的自动化工具都不支持向输入框输入非ASCII字符。
|
||||
|
||||
#### iOS
|
||||
|
||||
Appium 完全绕过键盘直接向iOS设备的输入框发送非ASCII字符。虽然这让这些文本在测试中被成功输入,但必须记住由键盘输入触发的业务逻辑将不会被测试到。
|
||||
|
||||
像上边说的一样,断言收到的文本前应该先标准化它。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
var testText = unorm.nfd("é Œ ù ḍ");
|
||||
driver
|
||||
.elementsByClassName('UIATextField').at(1)
|
||||
.sendKeys(testText)
|
||||
.text()
|
||||
.should.become(testText)
|
||||
.nodeify(done);
|
||||
```
|
||||
|
||||
#### Android
|
||||
|
||||
通过下载并安装一个[特殊键盘](https://github.com/appium/io.appium.android.ime) , Android 可以支持输入 Unicode 字符,这个输入法允许文本通过ASCII在Appium和被测应用之间进行通讯。
|
||||
|
||||
为了使用这个功能,将`unicodeKeyboard`设置为`true`。如果想要键盘设置在测试完成后自动回到原始状态,
|
||||
将`resetKeyboard`设置为`true`。否则Appium测试结束后,Appium的Unicode键盘仍然会被激活。
|
||||
|
||||
翻译备注:这个Unicode键盘并非虚拟键盘,在界面上不会显示出来,所以要进行其他类型的测试必须切换回其他输入法。
|
||||
|
||||
测试时可以通过`send_keys`向输入框输入Unicode字符。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var desired = {
|
||||
app: '/path/to/app',
|
||||
deviceName: 'Android Emulator',
|
||||
deviceVersion: '4.4',
|
||||
platformName: 'Android',
|
||||
unicodeKeyboard: true,
|
||||
resetKeyboard: true
|
||||
};
|
||||
var testText = 'é Œ ù ḍ';
|
||||
driver
|
||||
.elementByClassName('android.widget.EditText')
|
||||
.sendKeys(testText)
|
||||
.text()
|
||||
.should.eventually.become(testText)
|
||||
.nodeify(done);
|
||||
```
|
||||
114
docs/cn/writing-running-appium/unicode.md
Normal file
@@ -0,0 +1,114 @@
|
||||
## 多语言支持
|
||||
|
||||
编程语言在处理非拉丁字符时候有一个问题,带重音符号的字符有多种编码方式。比如,
|
||||
字母`é`,有两种编码:一个单字符`é`(Unicode的`LATIN SMALL LETTER E WITH ACUTE`
|
||||
(带有尖标的小写拉丁字母E))和字母`e`后跟上音标`́`的组合(`COMBINING ACUTE ACCENT`
|
||||
(组合尖音标))。为了解决这个问题,就有了`normalization(标准化)`,一种让["相同的字符串有一个唯一的二进制表示"](http://www.unicode.org/reports/tr15/)
|
||||
的运算。
|
||||
|
||||
幸运的是,对ASCII文本(即不需要再被标准化的文本)进行标准化不会引起任何变化,且执行多次运算也不会有副作用。
|
||||
因此,这个标准化函数在文本上调用不会有副作用的风险。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
|
||||
'some ASCII text' === unorm.nfd('some ASCII text');
|
||||
unorm.nfd('Adélaïde Hervé') === unorm.nfd(unorm.nfd('Adélaïde Hervé'));
|
||||
```
|
||||
|
||||
因此,当处理测试中的unicode文本时,你最好对预期的文本和从Appium接收到的文本都进行标准化。
|
||||
进行标准化的方式有很多种,所以要确保对两边的字符串执行相同的运算!
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
driver
|
||||
.elementByAccessibilityId('find')
|
||||
.text()
|
||||
.then(function (txt) {
|
||||
unorm.nfd(txt).should.be(unorm.nfd("é Œ ù ḍ"));
|
||||
});
|
||||
```
|
||||
|
||||
问题的端倪是对编码后的unicode文本的断言失败但从报告上看,却是相同的字符串:
|
||||
|
||||
```shell
|
||||
AssertionError: expected 'François Gérard' to deeply equal 'François Gérard'
|
||||
+ expected - actual
|
||||
|
||||
+"François Gérard"
|
||||
-"François Gérard"
|
||||
```
|
||||
|
||||
由于问题仅仅是编码,输出 _看起来_ 一样。 标准化后,他们在程序里应该像看起来一样是相等的。
|
||||
|
||||
|
||||
### 查找器(Finders)
|
||||
|
||||
通过文本查找时也可能需要标准化。举例来说,如果你在一个iOS应用里有一个名叫`Найти`的按钮,
|
||||
你需要在查找命令里标准化文本。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
driver
|
||||
.findElementByXPath(unorm.nfd("//UIAButton[@name='Найти']"))
|
||||
.should.eventually.exist;
|
||||
```
|
||||
|
||||
否则这个元素会找不到。
|
||||
|
||||
|
||||
### 文本框(Text Fields)
|
||||
|
||||
默认情况下,iOS和Android的自动化工具都不支持通过键盘向可编辑的区域输入non-ASCII字符。
|
||||
|
||||
#### iOS
|
||||
|
||||
Appium完全绕过键盘直接向iOS可编辑区域发送non-ASCII字符。虽然这样在测试中允许了文本的输入,但
|
||||
必须记住的是任何通过键盘输入触发的业务逻辑都没有被测试到。
|
||||
|
||||
如上所述,接收到的文本在被断言前需要被标准化。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var unorm = require('unorm');
|
||||
var testText = unorm.nfd("é Œ ù ḍ");
|
||||
driver
|
||||
.elementsByClassName('UIATextField').at(1)
|
||||
.sendKeys(testText)
|
||||
.text()
|
||||
.should.become(testText)
|
||||
.nodeify(done);
|
||||
```
|
||||
|
||||
#### Android
|
||||
|
||||
Android测试通过安装和使用一个[特殊键盘](https://github.com/appium/io.appium.android.ime)
|
||||
来允许Unicode输入,它允许将文本像ASCII一样在Appium和被测应用间传递。
|
||||
|
||||
为了使用这个功能,将`unicodeKeyboard` desired capability设置为`true`。如果键盘需要被还原成初始状态,
|
||||
将`resetKeyboard` desired capability也设置为`true`。不然设备上的Appium的Unicode键盘将会在测试完成后留用。
|
||||
|
||||
之后就可以通过使用`send_keys`向可编辑区域传递Unicode文本。
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
var desired = {
|
||||
app: '/path/to/app',
|
||||
deviceName: 'Android Emulator',
|
||||
deviceVersion: '4.4',
|
||||
platformName: 'Android',
|
||||
unicodeKeyboard: true,
|
||||
resetKeyboard: true
|
||||
};
|
||||
var testText = 'é Œ ù ḍ';
|
||||
driver
|
||||
.elementByClassName('android.widget.EditText')
|
||||
.sendKeys(testText)
|
||||
.text()
|
||||
.should.eventually.become(testText)
|
||||
.nodeify(done);
|
||||
```
|
||||
本文由 [NativeZhang](https://github.com/NativeZhang) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
|
||||