• #5 楼 @wyb199026 这些问题我没有遇到过,估计是之前有安装过一些包,冲突了。

    按照官方文档试下吧:

    gem update --system ;\
    gem update bundler
    gem uninstall -aIx appium_lib ;\
    gem uninstall -aIx appium_console ;\
    gem install --no-rdoc --no-ri appium_console bond
    

    另外,如果采用系统的 Ruby 环境总是有问题,还是尝试用 RVM 单独搞个环境吧。

  • #1 楼 @taki Ruby 也没啥不好吧

  • @chenhengjie123 恒捷,再请教一个问题;下图中 id 显示为 “米” 字型是什么情况呢?

  • #3 楼 @thanksdanny 我最近也是在摸索着入门,多多交流

  • 感谢推荐

  • #1 楼 @wyb199026 嗯,熟悉 console 以后效果会高很多

  • #14 楼 @chenhengjie123 太感谢啦,总算解决这些天的困惑了。

  • #11 楼 @chenhengjie123
    page 命令对应的 log 如下:

    [HTTP] --> GET /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/context {}
    
    [MJSONWP] Calling AppiumDriver.getCurrentContext() with args: ["4d6f5865-be02-4462-a33f-59304d4f2b20"]
    
    [debug] [iOS] Executing iOS command 'getCurrentContext'
    
    [MJSONWP] Responding to client with driver.getCurrentContext() result: "NATIVE_APP"
    [HTTP] <-- GET /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/context 200 8 ms - 84 
    [HTTP] --> GET /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/context {}
    [MJSONWP] Calling AppiumDriver.getCurrentContext() with args: ["4d6f5865-be02-4462-a33f-59304d4f2b20"]
    [debug] [iOS] Executing iOS command 'getCurrentContext'
    
    [MJSONWP] Responding to client with driver.getCurrentContext() result: "NATIVE_APP"
    [HTTP] <-- GET /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/context 200 3 ms - 84 
    
    [HTTP] --> POST /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/execute {"script":"UIATarget.localTarget().frontMostApp().windows()[0].getTree()","args":[]}
    [MJSONWP] Calling AppiumDriver.execute() with args: ["UIATarget.localTarget().frontMostApp().windows()[0].getTree()",[],"4d6f5865-be02-4462-a33f-59304d4f2b20"]
    [debug] [iOS] Executing iOS command 'execute'
    [debug] [UIAuto] Sending command to instruments: UIATarget.localTarget().frontMostApp().windows()[0].getTree()
    
    [debug] [Instruments] [INST] 2016-05-27 12:30:39 +0000 Debug: Got new command 3 from instruments: UIATarget.localTarget().frontMostApp().windows()[0].getTree()
    
    [debug] [Instruments] [INST] 2016-05-27 12:30:39 +0000 Debug: evaluating UIATarget.localTarget().frontMostApp().windows()[0].getTree()
    
    [debug] [Instruments] [INST] 2016-05-27 12:30:39 +0000 Debug: evaluation finished
    
    [debug] [Instruments] [INST] 2016-05-27 12:30:39 +0000 Debug: responding with:":{"x":0,"y":0},"size":{"width":375,"height":618}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[{"name":"no_login_icon","type":"UIAImage","label":null,"value":null,"rect":{"origin":{"x":157.5,"y":60},"size":{"width":60,"height":60}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"XXX","type":"UIAStaticText","label":"XXX","value":"XXX","rect":{"origin":{"x":20,"y":135},"size":{"width":335,"height":20.5}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"Label","type":"UIAStaticText","label":"Label","value":"Label","rect":{"origin":{"x":0,"y":196},"size":{"width":375,"height":20.5}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"Fans","type":"UIAStaticText","label":"Fans","value":"Fans","rect":{"origin":{"x":217.5,"y":220},"size":{"width":30.5,"height":20}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"Follow","type":"UIAStaticText","label":"Follow","value":"Follow","rect":{"origin":{"x":116,"y":220},"size":{"width":41.5,"height":20}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"100","type":"UIAStaticText","label":"100","value":"100","rect":{"origin":{"x":122.5,"y":198},"size":{"width":28.5,"height":22}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"200","type":"UIAStaticText","label":"200","value":"200","rect":{"origin":{"x":217.5,"y":198},"size":{"width":31,"height":22}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"me edite","type":"UIAButton","label":"me edite","value":null,"rect":{"origin":{"x":335,"y":25},"size":{"width":30,"height":30}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[{"name":"me_edite","type":"UIAImage","label":null,"value":null,"rect":{"origin":{"x":337.5,"y":27.5},"size":{"width":25,"height":25}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null}],"hint":null},{"name":"Login","type":"UIAButton","label":"Login","value":null,"rect":{"origin":{"x":44.5,"y":175},"size":{"width":123,"height":30}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"Register","type":"UIAButton","label":"Register","value":null,"rect":{"origin":{"x":207.5,"y":175},"size":{"width":123,"height":30}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"Hi!Guest","type":"UIAStaticText","label":"Hi!Guest","value":"Hi!Guest","rect":{"origin":{"x":0,"y":134.5},"size":{"width":375,"height":20.5}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"Label","type":"UIAStaticText","label":"Label","value":"Label","rect":{"origin":{"x":0,"y":165.5},"size":{"width":375,"height":20.5}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"User Feedback ","type":"UIATableCell","label":null,"value":"","rect":{"origin":{"x":0,"y":260},"size":{"width":375,"height":50}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[{"name":"User Feedback ","type":"UIAStaticText","label":"User Feedback ","value":"User Feedback ","rect":{"origin":{"x":50,"y":276},"size":{"width":107.5,"height":18}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null}],"hint":null},{"name":null,"type":"UIATableGroup","label":null,"value":null,"rect":{"origin":{"x":0,"y":310},"size":{"width":375,"height":20}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":"System Settings","type":"UIATableCell","label":null,"value":"","rect":{"origin":{"x":0,"y":330},"size":{"width":375,"height":50}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[{"name":"System Settings","type":"UIAStaticText","label":"System Settings","value":"System Settings","rect":{"origin":{"x":50
    ,"y":346},"size":{"width":111.5,"height":18}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null}],"hint":null}],"hint":null},{"name":null,"type":"UIATabBar","label":null,"value":null,"rect":{"origin":{"x":0,"y":618},"size":{"width":375,"height":49}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[{"name":null,"type":"UIAImage","label":null,"value":null,"rect":{"origin":{"x":0,"y":617.5},"size":{"width":375,"height":0.5}},"dom":null,"enabled":true,"valid":true,"visible":false,"children":[],"hint":null},{"name":null,"type":"UIAImage","label":null,"value":null,"rect":{"origin":{"x":0,"y":618},"size":{"width":375,"height":49}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"Store","type":"UIAButton","label":"Store","value":null,"rect":{"origin":{"x":2,"y":619},"size":{"width":71,"height":48}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"Experience","type":"UIAButton","label":"Experience","value":null,"rect":{"origin":{"x":77,"y":619},"size":{"width":71,"height":48}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"Nearby","type":"UIAButton","label":"Nearby","value":null,"rect":{"origin":{"x":152,"y":619},"size":{"width":71,"height":48}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"Forum","type":"UIAButton","label":"Forum","value":null,"rect":{"origin":{"x":227,"y":619},"size":{"width":71,"height":48}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null},{"name":"My Account","type":"UIAButton","label":"My Account","value":1,"rect":{"origin":{"x":302,"y":619},"size":{"width":71,"height":48}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[],"hint":null}],"hint":null}],"hint":null}}
    [debug] [Instruments] [INST] 2016-05-27 12:30:39 +0000 Debug: Running system command #4: /Applications/Appium.app/Contents/Resources/node/bin/node /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-ios-driver/node_modules/appium-uiauto/build/lib/bin/command-proxy-client.js /var/folders/wy/fh5d0cn53b5714pkw7282n540000gn/T/instruments_sock 2,{"status":0,"v...
    
    [debug] [UIAuto] Socket data received (6165 bytes)
    
    [debug] [UIAuto] Got result from instruments: {"status":0,"value":{"name":null,"type":"UIAWindow","label":null,"value":null,"rect":{"origin":{"x":0,"y":0},"size":{"width":375,"height":667}},"dom":null,"enabled":true,"valid":true,"visible":true,"children":[{"name":null,"type":"UIATableView","label":null,"value":"rows 1 to 2 of 2","rect":{"origin
    
    [MJSONWP] Responding to client with driver.execute() result: {"name":null,"type":"UIAWindow","label":null,"value":null,"rect":{"origin":{"x":0,"y":0},"size":{"width":375,"height":667}},"dom":null,"enabled":tr...
    
    [HTTP] <-- POST /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/execute 200 1100 ms - 6238 
    
    [HTTP] --> POST /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/appium/app/strings {}
    
    [MJSONWP] Calling AppiumDriver.getStrings() with args: [null,null,"4d6f5865-be02-4462-a33f-59304d4f2b20"]
    [debug] [iOS] Executing iOS command 'getStrings'
    [debug] [iOS] Gettings strings for language 'undefined' and string file 'null'
    [debug] [iOS] No language specified. Using default strings
    [debug] [iOS] Strings file not found. Looking in 'en.lproj' directory
    
    [debug] [iOS] Parsed app 'Localizable.strings'
    [MJSONWP] Responding to client with driver.getStrings() result: {"Pull down to refresh":"Pull down to refresh","Please input the new password.":"Please input your new password.","再看看":"Cancel","Total":"Total","我...
    [HTTP] <-- POST /wd/hub/session/4d6f5865-be02-4462-a33f-59304d4f2b20/appium/app/strings 200 34 ms - 51687 
    
    
    
  • #8 楼 @chenhengjie123

    按照你的要求,我在 Ruby Console 里面通过 id 查询某元素。

    ➜ arc
    [1] pry(main)> page
    UIAButton
       name, label: My Account
       id: My Account => My Account
    nil
    [2] pry(main)> id('My Account').name
    "My Account"
    

    Appium Server Log 里面对应的日志:

    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:33 Leos-Mac-mini CoreSimulatorBridge[52416]: Switching to keyboard: zh-Hans
    
    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:33 Leos-Mac-mini CoreSimulatorBridge[52416]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.
    
    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:33 Leos-Mac-mini CoreSimulatorBridge[52416]: Switching to keyboard: zh-Hans
    
    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:33 Leos-Mac-mini CoreSimulatorBridge[52416]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.
    
    [HTTP] --> POST /wd/hub/session/9884af6e-bb65-44d5-9489-e4e73e135f64/element {"using":"id","value":"My Account"}
    
    [MJSONWP] Calling AppiumDriver.findElement() with args: ["id","My Account","9884af6e-bb65-44d5-9489-e4e73e135f64"]
    [debug] [iOS] Executing iOS command 'findElement'
    [debug] [BaseDriver] Waiting up to 0 ms for condition
    [debug] [UIAuto] Sending command to instruments: au.getElementByAccessibilityId('My Account')
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:35 +0000 Debug: Got new command 17 from instruments: au.getElementByAccessibilityId('My Account')
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:35 +0000 Debug: evaluating au.getElementByAccessibilityId('My Account')
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:35 +0000 Debug: evaluation finished
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:35 +0000 Debug: Lookup returned [object UIAButton] with the name "My Account" (id: 2).
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:35 +0000 Debug: responding with:
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:35 +0000 Debug: Running system command #18: /Applications/Appium.app/Contents/Resources/node/bin/node /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-ios-driver/node_modules/appium-uiauto/build/lib/bin/command-proxy-client.js /var/folders/wy/fh5d0cn53b5714pkw7282n540000gn/T/instruments_sock 2,{"status":0,"v...
    
    [debug] [UIAuto] Socket data received (38 bytes)
    
    [debug] [UIAuto] Got result from instruments: {"status":0,"value":{"ELEMENT":"2"}}
    
    [MJSONWP] Responding to client with driver.findElement() result: {"ELEMENT":"2"}
    [HTTP] <-- POST /wd/hub/session/9884af6e-bb65-44d5-9489-e4e73e135f64/element 200 1226 ms - 87 
    
    [HTTP] --> GET /wd/hub/session/9884af6e-bb65-44d5-9489-e4e73e135f64/element/2/attribute/name {}
    [MJSONWP] Calling AppiumDriver.getAttribute() with args: ["name","2","9884af6e-bb65-44d5-9489-e4e73e135f64"]
    [debug] [iOS] Executing iOS command 'getAttribute'
    
    [debug] [UIAuto] Sending command to instruments: au.getElement('2').name()
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:36 +0000 Debug: Got new command 18 from instruments: au.getElement('2').name()
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:36 +0000 Debug: evaluating au.getElement('2').name()
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:36 +0000 Debug: evaluation finished
    
    [debug] [Instruments] [INST] 2016-05-27 06:12:36 +0000 Debug: responding with:
    [debug] [Instruments] [INST] 2016-05-27 06:12:36 +0000 Debug: Running system command #19: /Applications/Appium.app/Contents/Resources/node/bin/node /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-ios-driver/node_modules/appium-uiauto/build/lib/bin/command-proxy-client.js /var/folders/wy/fh5d0cn53b5714pkw7282n540000gn/T/instruments_sock 2,{"status":0,"v...
    
    [debug] [UIAuto] Socket data received (35 bytes)
    
    [debug] [UIAuto] Got result from instruments: {"status":0,"value":"My Account"}
    
    [MJSONWP] Responding to client with driver.getAttribute() result: "My Account"
    [HTTP] <-- GET /wd/hub/session/9884af6e-bb65-44d5-9489-e4e73e135f64/element/2/attribute/name 200 1064 ms - 84 
    
    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:37 Leos-Mac-mini CoreSimulatorBridge[52416]: Switching to keyboard: zh-Hans
    
    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:37 Leos-Mac-mini CoreSimulatorBridge[52416]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.
    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:37 Leos-Mac-mini CoreSimulatorBridge[52416]: Switching to keyboard: zh-Hans
    
    [iOSLog] [IOS_SYSLOG_ROW] May 27 14:12:37 Leos-Mac-mini CoreSimulatorBridge[52416]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.
    
    [HTTP] --> GET /wd/hub/status {}
    
    [MJSONWP] Calling AppiumDriver.getStatus() with args: []
    
    [MJSONWP] Responding to client with driver.getStatus() result: {"build":{"version":"1.5.2","revision":null}}
    [HTTP] <-- GET /wd/hub/status 200 17 ms - 83 
    
    [HTTP] --> GET /wd/hub/status {}
    [MJSONWP] Calling AppiumDriver.getStatus() with args: []
    [MJSONWP] Responding to client with driver.getStatus() result: {"build":{"version":"1.5.2","revision":null}}
    [HTTP] <-- GET /wd/hub/status 200 16 ms - 83 
    
  • #8 楼 @chenhengjie123
    我也是在看官方文档时看到的,说通过 ID 定位元素是更好的方式。

  • #5 楼 @lihuazhang 我还是不大明白。如果把 name,value,label 作为控件的 ID 的话,那和直接采用 find_element(:name, 'XXX') 这样的方式有什么差异呢?
    而且,如果把 name,value,label 这些作为 ID,那么 APP 在不同语言下的值很有可能不一样,而且在版本迭代中,也很有可能改变,例如按钮名称变化;这也没有享受到 ID 相对较为固定的好处啊。

  • #3 楼 @lihuazhang 以你的经验来看,定位元素的最佳实践是采用什么方式呢?当前我是打算采用 name,但是 app 存在多国语言,这样就需要针对每一种语言进行处理;官方文档推荐采用 ID,但是 APP 里面大多控件都没有 ID 这个属性(从 Console 来看);而采用 xpath 的话,考虑到需求变动频繁,很有可能 UI 变动较大,所以也是个问题。

  • #1 楼 @lihuazhang 谢谢啦,刚采用 id 命令去试了下 name、label 和 value,的确也能定位到控件。不过我还不懂的是,为什么在 Console 中可以看到 id,但是在 Inspector 中看不到

  • #1 楼 @kesha0 之前没有接触过 Appium,最近才开始摸索

  • #6 楼 @heminwon 默认的,现在还没有区分 Debug 模式和 Release 模式

  • #4 楼 @wuyuleba 测试开发,简单地说就是开发测试工具和测试平台,只是开发出的产品不是面向外面的用户,而是面向内部测试人员

  • #1 楼 @chenhengjie123 感谢补充,学习啦

  • #1 楼 @lihuazhang 是啊,不过好在从零开始,没有历史包袱

  • 通过 API 远程管理 Jenkins at 2016年05月21日

    #2 楼 @anikikun 是啊,不过 Jenkins 官方文档在这块儿还是不够详细

  • #35 楼 @seveniruby 果断要加入啊

  • 结束的时候认真的问几个围着他答疑的妹子的名字。

    @seveniruby 😄

  • 脚本中有个疑问,success 参数只进行了初始化 success = True,中途也没有更改值的地方,finally 里面就对 success 进行判断了?

  • #7 楼 @testly 多谢大神鼓励