• 收到。已分配任务。
    美女组需要帮助的话,一组随时 stand by 哦。

  • @lihuazhang 还没 checkin。谢谢你的建议,我修改一下。

  • 这类 bug 手工测试确实比较难发现(手工测试一般不会老是去重装应用),但优先级却比较高(影响用户体验)。
    可以试试把安装测试放在弱网络中进行来尽早发现这类问题。

  • Appium 是什么? at 2015年02月28日

    赞一个!我觉得已经足够精炼了。想了解 appium 这些都是必备知识。

  • 你确定那个菜单栏是点击这个控件就会出现的?

  • @lihuazhang good idea!

  • @doctorq 我们要 fix 这个的话最好先和 appium 的 JessicaSachs 打个招呼,免得重复操作。现在貌似所有 issue 默认都是自动 assign 给他的。

  • 开源项目启动倒计时 at 2015年02月27日

    @doctorq 加一下 @lipijin 吧?
    @lipijin 你加到 teserthome 官方群(315508626 ),然后找 doctorq 吧。

  • KTAllTestSuite的 import 展开看看。
    最好还是直接贴代码吧。截图看得很累……

  • github 上已经有人报过类似的 bug 了:https://github.com/appium/appium/issues/4611
    官方团队目前还没有把修复这个 bug 提上 milestone。

  • 找到 windows 下可以使用的可能原因了。我分析的源码是master上的 (1.3.5解析 xpath 的部分和我分析的源码一样)...切换到1.3.4的 tag 后看到 dump file 用的是 UiDevice 的 dump 方法。
    相关源码:
    appium-1.3.4:
    https://github.com/appium/appium/blob/v1.3.4/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/utils/XMLHierarchy.java
    appium-1.3.5:
    https://github.com/appium/appium/blob/v1.3.5/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/utils/XMLHierarchy.java

    @jinjun0620 你在 windows 下用的是打包好的 exe 程序吗?windows 的 exe 最新版本的是 1.3.4.1,mac 的最新版本是 1.3.5。所以用 exe 不会出现这个问题。

  • @zuoan 我没在 x86 模拟器下装过……像手机那样下载安装 apk 不行吗?

  • @doctorq 也有可能。现在我的电脑都开着 shadowsocks 了。

  • 只要 android 的版本是 4.4 或以上,webview 就是 chrome 内核的。
    如果 android 版本是 4.4 以下,appium 会使用 selendroid 控制 webview。此时需要在初始化 driver 时指定使用 seledroid:"automationName": "selendroid"

    另外就算你装了 chrome.apk,webview 也不会自动变成 chrome 内核。如果你想在 4.4 以下获得 chrome 内核的 webview,只能在应用里加上crosswalk。不过是这会让应用变大(crosswalk是在应用里加入了完整的 chrome 内核,所以会大不少)。

  • @doctorq 或者你查一下 grunt 里面的源码吧,看看那个 task 具体做了什么。
    reset.sh 的 log 在用了--verbose后还是挺清晰的。
    解决以后分享一下哈。我这个只记录了 mac 的,没有试过在 windows 下配置。

  • @jinjun0620 这么神奇?今晚回去研究研究。这是一个很有趣的问题。因为根据上面的分析应该无论哪个平台都找不到的(bootstrap 是在 android 上运行的)。

  • @doctorq 执行成功的标志是最后一行是

    ---- reset.sh completed successfully ----
    
  • 用 appium 的 bootstrap debug 过了, 确实 appium 1.3.5 在 android 平台下的 findElementByXPath 不支持中文

    appium 用 xpath 定位的原理是先用 dump 把当前界面所有元素保存到一个 xml 文件里面,然后再读取 dump 出来的 xml 文件,最后用 xpath 去查那个 xml 文件。(xpath 本来设计就是用来做 xml 的元素定位的)
    不能支持中文(严格地说是不支持所有非 ascii 字符)的原因是这个 dump 用的是 bootstrap 里面自己的 dump,而不是 uiautomator 的,这个 dump 会把所有不支持的字符替换成?,所以你用包含中文的 xpath 去找会找不到。

    借个地方贴一下相关源码方便后面研究:
    通过 xpath 查找元素的函数:
    io.appium.android.bootstrap.utils.XMLHierarchy.java

    public static ArrayList<ClassInstancePair> getClassInstancePairs(String xpathExpression)
              throws ElementNotFoundException, InvalidSelectorException, ParserConfigurationException {
        XPath xpath = XPathFactory.newInstance().newXPath();
        XPathExpression exp = null;
        try {
          exp = xpath.compile(xpathExpression);
        } catch (XPathExpressionException e) {
          throw new InvalidSelectorException(e.getMessage());
        }
    
        Node formattedXmlRoot;
    
        formattedXmlRoot = getFormattedXMLDoc();
    
        return getClassInstancePairs(exp, formattedXmlRoot);
      }
    
      public static ArrayList<ClassInstancePair> getClassInstancePairs(XPathExpression xpathExpression, Node root) throws ElementNotFoundException {
    
        NodeList nodes;
        try {
          nodes = (NodeList) xpathExpression.evaluate(root, XPathConstants.NODESET);
        } catch (XPathExpressionException e) {
          e.printStackTrace();
          throw new ElementNotFoundException("XMLWindowHierarchy could not be parsed: " + e.getMessage());
        }
    
        ArrayList<ClassInstancePair> pairs = new ArrayList<ClassInstancePair>();
        for (int i = 0; i < nodes.getLength(); i++) {
          if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
            try {
              pairs.add(getPairFromNode(nodes.item(i)));
            } catch (PairCreationException e) { }
          }
        }
    
        return pairs;
      }
    

    替换字符的函数:
    io.appium.uiautomator.core.AccessibilityNodeInfoDumper.java

    private static String stripInvalidXMLChars(CharSequence cs) {
            StringBuilder ret = new StringBuilder();
            char ch;
            for (int i = 0; i < cs.length(); i++) {
                ch = cs.charAt(i);
                // code below from Html#withinStyle, this is a temporary workaround because XML
                // serializer does not support surrogates
                if (ch >= 0xD800 && ch <= 0xDFFF) {
                    if (ch < 0xDC00 && i + 1 < cs.length()) {
                        char d = cs.charAt(i + 1);
                        if (d >= 0xDC00 && d <= 0xDFFF) {
                            i++;
                            ret.append("?");
                        }
                    }
                } else if (ch > 0x7E || ch < ' ') {
                    ret.append("?");
                } else {
                    ret.append(ch);
                }
            }
            return ret.toString();
        }
    

    其他方法(如 findElementByAccessibilityId)能找到包含中文的元素的原因是它直接使用 uiautomator 的对应方法。而 uiautomator api 并没有根据 xpath 查找元素的方法,所以 appium 是自己另外实现的。

    这里替换掉字符的原因应该是基于安全性考虑( evaluate 是一个权限很高的函数,不对参数进行过滤的话很危险)。

    @doctorq 我们那个项目第一个任务可以考虑修复这个问题,让 appium 支持通过含有非 ascii 字符的 xpath 来查找元素。

  • 我的意思是你的 Java 文件应该使用 utf-8 编码。这样中文的编码才和 app 对应元素一致(android testview 内容默认使用 utf-8 编码)。
    不过我也没使用 Java 的 client 试验过。明天试一下。

  • 你用的什么编码?是 utf-8 吗?
    要支持中文应该要 utf-8 的吧。
    可以肯定 appium 的 xpath 定位应该是支持中文的。

  • @doctorq 对,其实就是一种流行的 http api 编写风格。因为没有严格的规定,所以连规范都说不上。
    曾经尝试写一个系统的 REST api,查了不少资料。当时天真地以为 REST api+html5 可以一套代码通杀 Web+Mobile,结果被 Android 的 html5 性能打败了……

  • @doctorq ok,我更新一下文章

  • REST 是指 RESTful 的 api 吗。个人理解就是 http 的 GET、POST、PUT 和 DELETE 对应资源的 CRUD(增删改查),把所有的对象(例如论坛里的用户、用户组、帖子、专区)都设计成资源。然后就能像写 CRUD 那样使用 api 了。
    话说 appium 使用 Http REST 方式是因为遵循了webDriver 的规范吧?