Appium一本通(完整教程和索引)

概述

概念

Appium是专注于App的自动化工具。

Appium is an open source test automation framework for use with native, hybrid and mobile web apps.
It drives iOS, Android, and Windows apps using the WebDriver protocol.

Appium是一个HTTP服务端,它使用WebDriver协议进行通讯(和Selenium一样)。可以使用任何标准的Selenium客户端和Appium进行通讯。同时,Appium提供了多种编程语言版本的Appium客户端,这些客户端继承了标准的Selenium客户端的所有API,同时还增加了一些Appium独有的API。

Appium客户端的版本如下:

Language/Framework Github Repo and Installation Instructions
Ruby https://github.com/appium/ruby_lib, https://github.com/appium/ruby_lib_core
Python https://github.com/appium/python-client
Java https://github.com/appium/java-client
JavaScript (Node.js) https://github.com/admc/wd
JavaScript (Node.js) https://github.com/webdriverio/webdriverio
JavaScript (Browser) https://github.com/projectxyzio/web2driver
Objective C https://github.com/appium/selenium-objective-c
PHP https://github.com/appium/php-client
C# (.NET) https://github.com/appium/appium-dotnet-driver
RobotFramework https://github.com/jollychang/robotframework-appiumlibrary

支持特性

参见关于平台和特性的详细说明:
http://appium.io/docs/en/about-appium/platform-support/

参考

官网:http://appium.io/
Appium项目的github地址:https://github.com/appium/appium
Appium桌面吧的github地址:https://github.com/appium/appium-desktop
Appium生态圈的github地址:https://github.com/appium
Appium文档:http://appium.io/docs/en/about-appium/intro/(使用上方菜单栏导航)
快速开始:http://appium.io/docs/en/about-appium/getting-started/
API文档:http://appium.io/docs/en/about-appium/api/
样例代码:https://github.com/appium/appium/tree/master/sample-code (其下有按照编程语言分类的多个子目录)
中文文档:http://appium.io/docs/cn/about-appium/intro/ (和英文文档对比了菜单结构,同步性较差)
Appium普通使用教程:http://appium.io/docs/en/writing-running-appium/running-tests/ (使用菜单栏“Writing & Running Tests”导航)
Appium高级主题教程:http://appium.io/docs/en/advanced-concepts/image-elements/ (使用菜单栏“Advanced”导航)

安装Appium

桌面版本

直接如下地址,点击assets后下载对应版本:
https://github.com/appium/appium-desktop/releases

命令行版本(Mac系统下)

参考文档:http://appium.io/docs/en/about-appium/getting-started/

前置安装

1)Xcode和命令行工具:
App Store下载
命令行工具使用命令:xcode-select --install
2)JDK
官网下载
需要自行设置JAVA_HOME变量:

  1. 查看java命令地址,找到软链指向的真实目录;
  2. 在java命令的同目录下,运行./java_home可以得到真实的JAVA_HOME地址

3)Python3
brew install python3
4)Android SDK

  1. 安装Android Studio,谷歌地址下载速度很快:https://developer.android.google.cn/studio/
  2. 设置ANDROID_HOME地址,一般为:~/Library/Android/sdk
安装Appium

1)安装brew
参考:https://brew.sh/index_zh-cn.html
2)安装Node.js和NPM

brew install node

3)安装appium

npm install -g appium

4)安装appium-doctor

npm install -g appium-doctor

5)运行appium-doctor,根据提示进行修复

appium-doctor

缺失的组件都会有提示如何进行安装或者修复。
部分下载较慢的组件已经上传至:https://download.csdn.net/user/zhiyuan411/uploads

更新Appium

npm -g update appium

启动Appium

默认参数启动:

appium

Android带参数启动示例:

appium -p 4723 -bp 4724 --chromedriver-port 9515 --suppress-adb-kill-server --log-level debug --log /tmp/appium.log --log-timestamp --local-timezone --session-override >> ./logs/debug.log 2>&1 &

IOS带参数启动示例:

appium -p 4723 -bp 4724 --webkit-debug-proxy-port 27753 --log-level debug --log /tmp/appium.log --log-timestamp --local-timezone --session-override >> ./logs/debug.log 2>&1 &

运行测试代码

adr参见如下示例:

# -*- coding: utf-8 -*-

from appium import webdriver
from selenium.webdriver import TouchActions

import os
import threading
import time


class appiumRunTest():
    DEVICE_NUM = 'xxxxxxxx'
    APP_PACKAGE = 'testdemo.example.com.app'
    APP_ACTIVITY = '.MainActivity'
    CHROME_ANDROID_PROCESS = 'com.Qunar'
    CHROME_ANDROID_PACKAGE = 'com.Qunar'
    EXECUTOR = 'http://127.0.0.1:4723/wd/hub'

    def __init__(self):
        self.desired_capabilities = {
            'udid': self.DEVICE_NUM,
            'appPackage': self.APP_PACKAGE,
            'appActivity': self.APP_ACTIVITY,
            'chromeOptions': {'androidProcess': self.CHROME_ANDROID_PROCESS,
                              'androidPackage': self.CHROME_ANDROID_PACKAGE},
            # 'browserName': 'Chrome',
            'automationName': 'UiAutomator2',
            'platformName': 'Android',
            'platformVersion': os.getenv('ANDROID_PLATFORM_VERSION') or '8.0',
            'deviceName': os.getenv('ANDROID_DEVICE_VERSION') or 'Android Emulator',
            'unicodeKeyboard': True,
            'resetKeyboard': True,
            'eventTimings': True,
            'fullReset': False,
            'recreateChromeDriverSessions': True,
            'newCommandTimeout': 120,
            'autoGrantPermissions': True,
            'nativeWebScreenshot': True,
            'enablePerformanceLogging': True,
            'chromedriverExecutableDir': '/usr/local/chromedriverExecutableDir'
        }
        self.driver = None
        self.count = 0

    def start_server(self):
        '''
        启动Appium
        :return:
        '''
        # 自动获取所连接的第一台Android设备的序列号
        # device_num = os.popen('adb devices | grep "device$" | head -1 | cut -f 1').read().strip()
        print '启动appium: '
        os.system(
                'appium -p 4723 -bp 4724 --chromedriver-port 9515 --suppress-adb-kill-server --log-level debug --log /tmp/appium.log --log-timestamp --local-timezone --session-override')
        print "appium正在启动..."

    def create_session(self):
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", self.desired_capabilities)
        self.driver.implicitly_wait(100)
        print 'session已经创建'

    def operate_phone(self):
        self.__print_page_info()

        # 以下为浏览器方式下使用
        # self.driver.execute_script('window.alert("sometext");')
        # time.sleep(2)
        # self.driver.get('https://www.baidu.com')
        # time.sleep(1)
        # self.driver.execute_script('location.href="https://www.zhihu.com";')
        # time.sleep(1)
        # self.driver.execute_script('location.href="qunaraphone://hy?url=https%3A%2F%2Fjr.qunar.com%2Fm%2Fnano%2Fious%2Fqunar%2Findex";') # 不生效
        # time.sleep(1)
        # self.driver.execute_script('location.href="https://www.baidu.com";')
        # exit(0)

        # qunar的酒店, native
        element = self.driver.find_element_by_id('urlEdit')
        element.send_keys('qunaraphone://hotel')
        element = self.driver.find_element_by_id('submit')
        element.click()
        time.sleep(2)
        self.__print_page_info()
        # native方式操作
        element = self.driver.find_element_by_xpath('//*[contains(@text, "开始搜索")]')
        element.click()
        time.sleep(2)

        # qunar的金融, hy
        self.driver.reset()
        element = self.driver.find_element_by_id('urlEdit')
        element.send_keys(
                'qunaraphone://hy?url=https%3A%2F%2Fjr.qunar.com%2Fm%2Ffinweb%2Fssr%2FfinanceCenter%3FclientSource%3DQUNAR%26from%3DfinanceCenter&type=navibar-none')
        element = self.driver.find_element_by_id('submit')
        element.click()
        time.sleep(2)
        self.__print_page_info()
        # h5方式操作
        self.driver.switch_to.context('WEBVIEW_com.Qunar')
        self.__print_page_info()
        action = TouchActions(self.driver)
        element = self.driver.find_element_by_id('autoTestId-kingkong_0')
        action.tap(element).perform()

    def __print_page_info(self):
        # 打印当前页面内容
        print '当前页面内容:'
        print self.driver.page_source
        print '当前的webview是: %s, contexts列表为: %s' % (str(self.driver.current_context), str(self.driver.contexts))
        # 保存截图
        self.driver.save_screenshot('/tmp/pic' + str(self.count) + '.png')
        self.count += 1


def run_case():
    thread2 = appiumRunTest()
    thread2.create_session()
    thread2.operate_phone()
    print 'case执行完毕.'


if __name__ == '__main__':

    # 启动Appium, 多次执行case, 只需要启动一次
    if False:
        thread1 = appiumRunTest()
        server_thread = threading.Thread(target=thread1.start_server, args=())
        server_thread.setDaemon(True)
        server_thread.start()
        time.sleep(20)

    run_case()

ios参见如下代码:

# -*- coding: utf-8 -*-

from appium import webdriver
from selenium.webdriver import TouchActions

import os
import threading
import time


class appiumRunTest():
    DEVICE_UDID = 'xxxxxxxxx'
    BUNDLE_ID = 'test.openschema'
    XCODE_ORG_ID = 'XXXXXXXXX'
    CHROME_ANDROID_PROCESS = 'com.Qunar'
    CHROME_ANDROID_PACKAGE = 'com.Qunar'
    EXECUTOR = 'http://127.0.0.1:4723/wd/hub'

    def __init__(self):
        self.desired_capabilities = {
            'udid': self.DEVICE_UDID,
            'bundleId': self.BUNDLE_ID,
            'xcodeOrgId': self.XCODE_ORG_ID,
            "xcodeSigningId": 'iPhone Developer',
            'platformName': 'IOS',
            'platformVersion': '12.4',
            'deviceName': 'iPhone',
            'automationName': 'XCUItest',
            'useJSONSource': True,
            'autoAcceptAlerts': True,
            'newCommandTimeout': 120,
            'wdaLocalPort': 8100,
            # 'useNewWDA': True,
            'startIWDP': True
        }
        self.driver = None
        self.count = 0

    def start_server(self):
        '''
        启动Appium
        :return:
        '''
        print '启动appium: '
        os.system(
                'appium -p 4723 -bp 4724 --webkit-debug-proxy-port 27753 --log-level debug --log /tmp/appium.log --log-timestamp --local-timezone --session-override')
        print "appium正在启动..."

    def create_session(self):
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", self.desired_capabilities)
        self.driver.implicitly_wait(100)
        print 'session已经创建'

    def operate_phone(self):
        self.__print_page_info()

        # # 以下为浏览器方式下使用
        # self.driver.execute_script('window.alert("sometext");')
        # time.sleep(2)
        # self.driver.get('https://www.baidu.com')
        # time.sleep(1)
        # self.driver.execute_script('location.href="https://www.zhihu.com";')
        # time.sleep(1)
        # self.driver.execute_script('location.href="qunaraphone://hy?url=https%3A%2F%2Fjr.qunar.com%2Fm%2Fnano%2Fious%2Fqunar%2Findex";') # 不生效
        # time.sleep(1)
        # self.driver.execute_script('location.href="https://www.baidu.com";')
        # exit(0)

        # qunar的酒店, native
        # element = self.driver.find_element_by_accessibility_id('urlEdit')
        # element.send_keys('qunariphone://home')
        # element = self.driver.find_element_by_accessibility_id('submit')
        # element.click()
        # time.sleep(2)
        # self.__print_page_info()
        # # native方式操作
        # element = self.driver.find_element_by_xpath('//*[contains(@text, "酒店")]')
        # element.click()
        # time.sleep(2)

        # qunar的金融, hy
        self.driver.reset()
        element = self.driver.find_element_by_accessibility_id('urlEdit')
        element.send_keys(
                'qunariphone://hy?url=https%3A%2F%2Fjr.qunar.com%2Fm%2Ffinweb%2Fssr%2FfinanceCenter%3FclientSource%3DQUNAR%26from%3DfinanceCenter&type=navibar-none')
        element = self.driver.find_element_by_accessibility_id('submit')
        element.click()
        time.sleep(5)
        self.__print_page_info()
        # h5方式操作
        self.driver.switch_to.context(self.driver.contexts[len(self.driver.contexts) - 1])
        self.__print_page_info()
        action = TouchActions(self.driver)
        element = self.driver.find_element_by_accessibility_id('autoTestId-kingkong_0')
        action.tap(element).perform()

    def __print_page_info(self):
        # 打印当前页面内容
        print '当前页面内容:'
        print self.driver.page_source
        print '当前的webview是: %s, contexts列表为: %s' % (str(self.driver.current_context), str(self.driver.contexts))
        # 保存截图
        self.driver.save_screenshot('/tmp/pic' + str(self.count) + '.png')
        self.count += 1


def run_case():
    thread2 = appiumRunTest()
    thread2.create_session()
    thread2.operate_phone()
    print 'case执行完毕.'


if __name__ == '__main__':

    # 启动Appium, 多次执行case, 只需要启动一次
    if False:
        thread1 = appiumRunTest()
        server_thread = threading.Thread(target=thread1.start_server, args=())
        server_thread.setDaemon(True)
        server_thread.start()
        time.sleep(20)

    run_case()

名词解释

Node.js

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。

Node.js 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。

NPM

NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。

ADB

ADB的全称为Android Debug Bridge,它是android sdk里的一个工具,用这个工具可以直接操作管理android模拟器或者真实的android设备。ADB是一个 客户端-服务器端 程序,其中客户端是你用来操作的电脑,服务器端是android设备。

它的主要功能有:

  1. 运行设备的shell(命令行)
  2. 管理模拟器或设备的端口映射
  3. 计算机和设备之间上传/下载文件
  4. 将本地apk软件安装至模拟器或android设备

JSON Wire Protocol (JSONWP)

https://code.google.com/p/selenium/wiki/JsonWireProtocol
扩展之后的Mobile JSON Wire Protocol:
https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md

WebDriver协议

https://w3c.github.io/webdriver/

WkWebView,UIWebView和SafariViewController

https://developer.apple.com/documentation/webkit/wkwebview
https://developer.apple.com/documentation/uikit/uiwebview
https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller

开发者证书

参见:https://www.jianshu.com/p/e6b86bef7a90

生态系统

Appium驱动

XCUITest Driver

for iOS and tvOS apps
http://appium.io/docs/en/drivers/ios-xcuitest/index.html

Appium’s primary support for automating iOS apps is via the XCUITest driver.
This driver leverages Apple’s XCUITest libraries under the hood in order to facilitate automation of your app .
This access to XCUITest is mediated by the WebDriverAgent server. WebDriverAgent (also referred to as “WDA”) is a project managed by Facebook, to which the Appium core team contributes heavily. WDA is a WebDriver-compatible server that runs in the context of an iOS simulator or device and exposes the XCUITest API. Appium’s XCUITest driver manages WDA as a subprocess opaque to the Appium user, proxies commands to/from WDA, and provides a host of additional functionality (like simulator management and other methods, for example).

UiAutomator2 Driver

for Android apps ( Older Android-based drivers include: * The UiAutomator Driver
)
http://appium.io/docs/en/drivers/android-uiautomator2/index.html

Appium’s flagship support for automating Android apps is via the UiAutomator2 driver.
This driver leverages Google’s UiAutomator2 technology to facilitate automation on a device or emulator.

Windows Driver

for Windows Desktop apps
http://appium.io/docs/en/drivers/windows/index.html

Appium has the ability to automate Windows PC Desktop apps. This driver relies on a project from Microsoft called WinAppDriver, which is an Appium-compatible WebDriver server for Windows Desktop apps (and more in the future). WinAppDriver is often abbreviated “WAD”. WAD is bundled with Appium and does not need to be installed separately.

Mac Driver

for Mac Desktop apps
http://appium.io/docs/en/drivers/mac/index.html

Appium has beta support for automation of OS X desktop applications.
This driver relies on a native OS X binary called AppiumForMac.

Espresso Driver

for Android apps(BETA)
http://appium.io/docs/en/drivers/android-espresso/index.html

Appium currently has support for the Espresso automation technology via its own Espresso driver. This driver works by kicking off an Espresso run on a device, with our own automation server as part of the Espresso test APK. Appium can then communicate with this automation server and trigger Espresso commands as the result of Appium client calls.

Appium客户端

支持的客户端列表参见:http://appium.io/docs/en/about-appium/appium-clients/index.html

python-client

https://github.com/appium/python-client

WDA(WebDriverAgent)

https://github.com/facebookarchive/WebDriverAgent

WebDriverAgent is a WebDriver server implementation for iOS that can be used to remote control iOS devices. It allows you to launch & kill applications, tap & scroll views or confirm view presence on a screen. This makes it a perfect tool for application end-to-end testing or general purpose device automation. It works by linking XCTest.framework and calling Apple’s API to execute commands directly on a device. WebDriverAgent is developed and used at Facebook for end-to-end testing and is successfully adopted by Appium.

ios-webkit-debug-proxy

使用说明:http://appium.io/docs/en/writing-running-appium/web/ios-webkit-debug-proxy/
首页:https://github.com/google/ios-webkit-debug-proxy/

更多

参见:http://appium.io/docs/en/contributing-to-appium/credits/

系统结构和流程图

系统结构

http://appium.io/docs/en/contributing-to-appium/appium-packages/
系统结构图

核心流程

Android

IOS

热点问题

Appium启动参数列表

http://appium.io/docs/en/writing-running-appium/server-args/index.html
中文版:http://appium.io/docs/cn/writing-running-appium/server-args/index.html(同步性较差,小心有坑)

Appium客户端列表

http://appium.io/docs/en/about-appium/appium-clients/index.html

Appium Desired Capabilities

http://appium.io/docs/en/writing-running-appium/caps/index.html
中文版:http://appium.io/docs/cn/writing-running-appium/caps/index.html(同步性较差,小心有坑)

XCUITest-specific capabilities:
https://github.com/appium/appium-xcuitest-driver#desired-capabilities

支持的命令列表(即API文档)

http://appium.io/docs/en/about-appium/api/ (也可以使用上方的“Commands”菜单来导航)
也可以从github查看:
https://github.com/appium/appium/blob/master/docs/en/commands/README.md
以上每个命令的详情页,列出了该命令的意义,具体参数和多种代码示例,给出了Appium Server的支持版本信息,Appium Client的支持版本信息,以及该命令的底层实现的HTTP的具体形式和参数。
注意:

  1. 所有标准selenium客户端兼容的命令和Appium客户端的新增命令都会在上表中列出;
  2. 命令的更详细说明,应该参见Appium Client支持版本信息这个小节里,对应编码语言的参考文档链接。(该参考文档可能链接到selenium或者appium client项目的页面)

定位元素find_element_by_xx

可以按照多种locator selector来进行元素定位,locator selector列表参见:
https://github.com/appium/appium/blob/master/docs/en/commands/element/find-elements.md#selector-strategies

Strategy Description
Accessibility ID Read a unique identifier for a UI element. For XCUITest it is the element’s accessibility-id attribute. For Android it is the element’s content-desc attribute.
Class name For IOS it is the full name of the XCUI element and begins with XCUIElementType. For Android it is the full name of the UIAutomator2 class (e.g.: android.widget.TextView)
ID Native element identifier. resource-id for android; name for iOS.
Name Name of element
XPath Search the app XML source using xpath (not recommended, has performance issues)
Image Locate an element by matching it with a base 64 encoded image file
Android UiAutomator (UiAutomator2 only) Use the UI Automator API, in particular the UiSelector class to locate elements. In Appium you send the Java code, as a string, to the server, which executes it in the application’s environment, returning the element or elements.
Android View Tag (Espresso only) Locate an element by its view tag
Android Data Matcher (Espresso only) Locate an element using Espresso DataMatcher
IOS UIAutomation When automating an iOS application, Apple’s Instruments framework can be used to find elements

关于Selector和定位元素更多的说明参见:http://appium.io/docs/en/writing-running-appium/finding-elements/

平台及细节特性的支持描述

http://appium.io/docs/en/about-appium/platform-support/
详细说明了支持的平台及支持的该平台的特性,例如是否支持native,h5或者hybrid,是否支持多手机并发。

浏览器内的web应用测试

主要参考:
http://appium.io/docs/en/writing-running-appium/web/mobile-web/

iOS真机的准备

  1. 安装ios-webkit-debug-proxy,并手动启动(监听默认端口:27753)或者使用appium的Desired Capabilities参数:startIWDP=true来启动。
  2. 手机上:设置->Safari->高级→打开Web检查器。
  3. 手机上提示是否信任该电脑时,选择“信任”,并输入锁屏密码。

Android真机的准备

  1. 安装Chrome浏览器。
  2. 安装匹配的Chromedriver版本。

执行测试

指定Desired Capabilities参数:browserName=Safari或者Chrome。对于Android的4.4+版本也支持browserName=Browser来驱动内置浏览器。

hybrid应用内的web views测试

主要参考:
http://appium.io/docs/en/writing-running-appium/web/hybrid/

iOS真机准备

  1. 安装ios-webkit-debugger-proxy。并手动启动(监听默认端口:27753)或者使用appium的Desired Capabilities参数:startIWDP=true来启动。
  2. 手机上:设置->Safari->高级→打开Web检查器。
  3. 手机上提示是否信任该电脑时,选择“信任”,并输入锁屏密码。
  4. 需要调试证书签名的客户端。个人免费账号证书签名,或者个人/公司开发者账号证书签名。

Android真机准备

  1. 调试/测试版本的客户端。即:把android.webkit.WebView元素的setWebContentsDebuggingEnabled属性设置为true,参见remote debugging docs

执行测试

示例代码如下:

# 查看所有的context
print driver.contexts
# 安卓下切换到webview的操作
contextname='待切换的context的名称'
driver.switch_to.context(contextname)
# ios下切换到webview的操作
driver.switch_to.context(driver.contexts.last)
# 退出webview
driver.switch_to.context("NATIVE_APP")

Chromedriver/Chrome兼容性列表和多ChromeDriver版本的自动适配

Appium对多ChromeDriver版本的自动适配是通过在Desired Capabilities中指定了参数:chromedriverExecutableDir,具体说明参见:
http://appium.io/docs/en/writing-running-appium/web/chromedriver/index.html
如下链接是ChromeDriver的下载地址,在每个版本的ChromeDriver的说明里可以看到其支持的Chrome版本,比上面的链接里的列表要齐全:
https://chromedriver.storage.googleapis.com/index.html
另附所有版本的ChromeDriver的集合下载:
2.23-77.0.3865.40版本:
https://download.csdn.net/download/zhiyuan411/11603565
2.0-2.22版本:
https://download.csdn.net/download/zhiyuan411/11604840

Selenium WebDriver API

https://www.seleniumhq.org/docs/03_webdriver.jsp

代码覆盖率收集

仅安卓平台支持,且条件苛刻:手机必须root,且需要修改被测客户端的源码添加对UiAutomator2的支持来收集覆盖率并将覆盖率写入文件。
详情参考:http://appium.io/docs/en/writing-running-appium/android/android-coverage/

多版本Node和安装STF

多版本Node安装

因为STF需要Node.js 8.x版本,所以,需要管理多版本Node以支持。
多版本Node的安装和管理使用nvm,更多内容和具体参见:https://github.com/nvm-sh/nvm/blob/master/README.md
常见命令如下:

# 安装nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
# 重启terminal或者执行source ~/.bash_profile后,验证是否安装成功
nvm --version
# 查看本地已经安装的node版本,目前使用的版本(绿色->标识),和默认版本(default->标识)
nvm ls
# 查看可用的安装版本
nvm ls-remote
# 查看可用的LTS版本的安装版本
nvm ls-remote --lts
# 安装指定版本
nvm install 8.16.1 # 或者 v8.16.1
# 查看已安装版本的目录
nvm which 8.16.1
# 设置默认版本为系统版本,注意:使用system来代指系统使用npm安装的版本
nvm alias default system # 或者具体某个已经安装的版本,例如 8.16.1
# 在当前shell中使用某个版本的node
nvm use 8.16.1

nvm命令帮助

nvm --help

Node Version Manager

Note: <version> refers to any version-like string nvm understands. This includes:
  - full or partial version numbers, starting with an optional "v" (0.10, v0.1.2, v1)
  - default (built-in) aliases: node, stable, unstable, iojs, system
  - custom aliases you define with `nvm alias foo`

 Any options that produce colorized output should respect the `--no-colors` option.

Usage:
  nvm --help                                Show this message
  nvm --version                             Print out the installed version of nvm
  nvm install [-s] <version>                Download and install a <version>, [-s] from source. Uses .nvmrc if available
    --reinstall-packages-from=<version>     When installing, reinstall packages installed in <node|iojs|node version number>
    --lts                                   When installing, only select from LTS (long-term support) versions
    --lts=<LTS name>                        When installing, only select from versions for a specific LTS line
    --skip-default-packages                 When installing, skip the default-packages file if it exists
    --latest-npm                            After installing, attempt to upgrade to the latest working npm on the given node version
    --no-progress                           Disable the progress bar on any downloads
  nvm uninstall <version>                   Uninstall a version
  nvm uninstall --lts                       Uninstall using automatic LTS (long-term support) alias `lts/*`, if available.
  nvm uninstall --lts=<LTS name>            Uninstall using automatic alias for provided LTS line, if available.
  nvm use [--silent] <version>              Modify PATH to use <version>. Uses .nvmrc if available
    --lts                                   Uses automatic LTS (long-term support) alias `lts/*`, if available.
    --lts=<LTS name>                        Uses automatic alias for provided LTS line, if available.
  nvm exec [--silent] <version> [<command>] Run <command> on <version>. Uses .nvmrc if available
    --lts                                   Uses automatic LTS (long-term support) alias `lts/*`, if available.
    --lts=<LTS name>                        Uses automatic alias for provided LTS line, if available.
  nvm run [--silent] <version> [<args>]     Run `node` on <version> with <args> as arguments. Uses .nvmrc if available
    --lts                                   Uses automatic LTS (long-term support) alias `lts/*`, if available.
    --lts=<LTS name>                        Uses automatic alias for provided LTS line, if available.
  nvm current                               Display currently activated version of Node
  nvm ls                                    List installed versions
  nvm ls <version>                          List versions matching a given <version>
  nvm ls-remote                             List remote versions available for install
    --lts                                   When listing, only show LTS (long-term support) versions
  nvm ls-remote <version>                   List remote versions available for install, matching a given <version>
    --lts                                   When listing, only show LTS (long-term support) versions
    --lts=<LTS name>                        When listing, only show versions for a specific LTS line
  nvm version <version>                     Resolve the given description to a single local version
  nvm version-remote <version>              Resolve the given description to a single remote version
    --lts                                   When listing, only select from LTS (long-term support) versions
    --lts=<LTS name>                        When listing, only select from versions for a specific LTS line
  nvm deactivate                            Undo effects of `nvm` on current shell
  nvm alias [<pattern>]                     Show all aliases beginning with <pattern>
  nvm alias <name> <version>                Set an alias named <name> pointing to <version>
  nvm unalias <name>                        Deletes the alias named <name>
  nvm install-latest-npm                    Attempt to upgrade to the latest working `npm` on the current node version
  nvm reinstall-packages <version>          Reinstall global `npm` packages contained in <version> to current version
  nvm unload                                Unload `nvm` from shell
  nvm which [current | <version>]           Display path to installed node version. Uses .nvmrc if available
  nvm cache dir                             Display path to the cache directory for nvm
  nvm cache clear                           Empty cache directory for nvm

Example:
  nvm install 8.0.0                     Install a specific version number
  nvm use 8.0                           Use the latest available 8.0.x release
  nvm run 6.10.3 app.js                 Run app.js using node 6.10.3
  nvm exec 4.8.3 node app.js            Run `node app.js` with the PATH pointing to node 4.8.3
  nvm alias default 8.1.0               Set default node version on a shell
  nvm alias default node                Always default to the latest available node version on a shell

Note:
  to remove, delete, or uninstall nvm - just remove the `$NVM_DIR` folder (usually `~/.nvm`)

安装和启动STF

什么是STF?

参见官网的首页介绍。
官网:https://openstf.io/

安装和启动STF

参见GitHub首页说明。
GitHub:https://github.com/openstf/stf
注意:STF依赖Node.js 8.x,在进行安装和使用之前,先使用nvm切换到8.x版本之下。

  1. 安装依赖:brew install rethinkdb graphicsmagick zeromq protobuf yasm pkg-config
  2. 安装STF:npm install -g stf
  3. (开发使用)安装NPM依赖,首先进入STF的安装目录,然后执行npm install,并链接全局命令npm link
  4. 先启动rethinkdb:nohup rethinkdb > rethinkdb.log 2>&1 &,然后启动STF,其中xx.xx.xx.xx为可以被外部访问的ip地址:nohup stf local --public-ip xx.xx.xx.xx > stf.log 2>&1 &
STF更多参数

stf的更多参数:

stf --help
Usage: stf <command> [options]

命令:
  api                   Start an API unit.
  app                   Start an app unit.
  auth-ldap             Start an LDAP auth unit.
  auth-mock             Start a mock auth unit that accepts any user.
  auth-oauth2           Start an OAuth 2.0 auth unit.
  auth-openid           Start an OpenID auth unit.
  auth-saml2            Start a SAML 2.0 auth unit.
  doctor                Diagnose potential issues with your installation.
  local [serial..]      Start a complete local development environment.
  log-rethinkdb         Start a RethinkDB log unit.
  migrate               Migrates the database to the latest version.
  notify-hipchat        Start a HipChat notifier unit.
  notify-slack          Start a Slack notifier unit.
  processor [name]      Start a processor unit.
  provider [serial..]   Start a provider unit.
  reaper [name]         Start a reaper unit.
  storage-plugin-apk    Start an APK storage plugin unit.
  storage-plugin-image  Start an image storage plugin unit.
  storage-s3            Start an S3 storage unit.
  storage-temp          Start a temp storage unit.
  triproxy [name]       Start a triproxy unit.
  websocket             Start a websocket unit.

选项:
  -h, --help     Show help.                                               [布尔]
  -V, --version  Show version.                                            [布尔]

stf local的更多参数:

stf help local
stf local [serial..]

选项:
  -h, --help                   Show help.                                 [布尔]
  -V, --version                Show version.                              [布尔]
  --adb-host                   The ADB server host.
                                                  [字符串] [默认值: "127.0.0.1"]
  --adb-port                   The ADB server port.        [数字] [默认值: 5037]
  --allow-remote, -R           Whether to allow remote devices in STF. Highly
                               unrecommended due to almost unbelievable slowness
                               on the ADB side and duplicate device issues when
                               used locally while having a cable connected at
                               the same time.                             [布尔]
  --api-port                   The port the api unit should run at.
                                                           [数字] [默认值: 7106]
  --app-port                   The port the app unit should run at.
                                                           [数字] [默认值: 7105]
  --auth-options               JSON array of options to pass to the auth unit.
                                                         [字符串] [默认值: "[]"]
  --auth-port                  The port the auth unit should run at.
                                                           [数字] [默认值: 7120]
  --auth-secret                The secret to use for auth JSON Web Tokens.
                               Anyone who knows this token can freely enter the
                               system if they want, so keep it safe.
                                              [字符串] [默认值: "kute kittykat"]
  --auth-type                  The type of auth unit to start.
         [字符串] [可选值: "mock", "ldap", "oauth2", "saml2", "openid"] [默认值:
                                                                         "mock"]
  --auth-url, -a               URL to the auth unit.                    [字符串]
  --bind-app-dealer            The address to bind the app-side ZeroMQ DEALER
                               endpoint to.
                                       [字符串] [默认值: "tcp://127.0.0.1:7112"]
  --bind-app-pub               The address to bind the app-side ZeroMQ PUB
                               endpoint to.
                                       [字符串] [默认值: "tcp://127.0.0.1:7111"]
  --bind-app-pull              The address to bind the app-side ZeroMQ PULL
                               endpoint to.
                                       [字符串] [默认值: "tcp://127.0.0.1:7113"]
  --bind-dev-dealer            The address to bind the device-side ZeroMQ DEALER
                               endpoint to.
                                       [字符串] [默认值: "tcp://127.0.0.1:7115"]
  --bind-dev-pub               The address to bind the device-side ZeroMQ PUB
                               endpoint to.
                                       [字符串] [默认值: "tcp://127.0.0.1:7114"]
  --bind-dev-pull              The address to bind the device-side ZeroMQ PULL
                               endpoint to.
                                       [字符串] [默认值: "tcp://127.0.0.1:7116"]
  --cleanup                    Attempt to reset the device between uses by
                               uninstallingapps, resetting accounts and clearing
                               caches. Does not do a perfect job currently.
                               Negate with --no-cleanup.   [布尔] [默认值: true]
  --group-timeout, -t          Timeout in seconds for automatic release of
                               inactive devices.            [数字] [默认值: 900]
  --lock-rotation              Whether to lock rotation when devices are being
                               used. Otherwise changing device orientation may
                               not always work due to sensitive sensors quickly
                               or immediately reverting it back to the physical
                               orientation.                               [布尔]
  --mute-master                Whether to mute master volume.
                          [可选值: "always", "inuse", "never"] [默认值: "never"]
  --port, -p, --poorxy-port    The port STF should run at. [数字] [默认值: 7100]
  --provider                   An easily identifiable name for the UI and/or log
                               output.
                               [字符串] [默认值: 本机名称]
  --provider-max-port          Highest port number for device workers to use.
                                                           [数字] [默认值: 7700]
  --provider-min-port          Lowest port number for device workers to use.
                                                           [数字] [默认值: 7400]
  --public-ip                  The IP or hostname to use in URLs.
                                                  [字符串] [默认值: "localhost"]
  --screen-reset               Go back to home screen and reset screen rotation
                               when user releases device. Negate with
                               --no-screen-reset.          [布尔] [默认值: true]
  --serial                     Only use devices with these serial numbers.[数组]
  --storage-options            JSON array of options to pass to the storage
                               unit.                     [字符串] [默认值: "[]"]
  --storage-plugin-apk-port    The port the storage-plugin-apk unit should run
                               at.                         [数字] [默认值: 7104]
  --storage-plugin-image-port  The port the storage-plugin-image unit should run
                               at.                         [数字] [默认值: 7103]
  --storage-port               The port the storage unit should run at.
                                                           [数字] [默认值: 7102]
  --storage-type               The type of storage unit to start.
                                [字符串] [可选值: "temp", "s3"] [默认值: "temp"]
  --user-profile-url           URL to external user profile page        [字符串]
  --vnc-initial-size           The initial size to use for the experimental VNC
                               server.              [字符串] [默认值: "600x800"]
  --websocket-port             The port the websocket unit should run at.
                                                           [数字] [默认值: 7110]

Each option can be be overwritten with an environment variable by converting the
option to uppercase, replacing dashes with underscores and prefixing it with
`STF_LOCAL_` (e.g. `STF_LOCAL_ALLOW_REMOTE`).

Tips

获取Android和iPhone手机的序列号

adb devices
idevice_id -l

获取Android应用的Package和Activity

Mac/Linux: ‘adb shell dumpsys window windows | grep mFocusedApp’
Windows不支持grep命令,需要自行查找

获取iPhone应用的Bundle Id

ideviceinstaller -l
或者:打开Mac 应用Console,左侧栏选中手机,搜索App的名称,然后查看消息里含有Bootstrapping的内容,可以看到有关Bundle Id的信息

发布了193 篇原创文章 · 获赞 23 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/zhiyuan411/article/details/100514728