#9 楼 @seveniruby 在这种遍历里面,是不是一定要有引导规则在里面
思寒 什么时候开源能通过啊,想学习一下代码呢 .
之前使用 Uiautomator 做了一个遍历的工具,最多执行到 3 层,再多逻辑就不好控制,
研究一下你这个
已经报名
这个问题 我之前遇到过一次 .
我当时出现这个错误的原因是,滑动的坐标范围超出了对应控件的 bounds
@chenhengjie123 恒捷你好. 我想在招聘板块发布一条关于公司招聘测试开发的帖子,但没有权限,麻烦开通一下呢
还需要注意一点:
#!/usr/bin/env bash
# Fail on error, verbose output
set -exo pipefail
# Build project
ndk-build 1>&2
# Figure out which ABI and SDK the device has
abi=$(adb shell getprop ro.product.cpu.abi | tr -d '\r')
sdk=$(adb shell getprop ro.build.version.sdk | tr -d '\r')
rel=$(adb shell getprop ro.build.version.release | tr -d '\r')
# PIE is only supported since SDK 16
if (($sdk >= 16)); then
bin=minicap
else
bin=minicap-nopie
fi
args=
if [ "$1" = "autosize" ]; then
set +o pipefail
size=$(adb shell dumpsys window | grep -Eo 'init=\d+x\d+' | head -1 | cut -d= -f 2)
if [ "$size" = "" ]; then
w=$(adb shell dumpsys window | grep -Eo 'DisplayWidth=\d+' | head -1 | cut -d= -f 2)
h=$(adb shell dumpsys window | grep -Eo 'DisplayHeight=\d+' | head -1 | cut -d= -f 2)
size="${w}x${h}"
fi
args="-P $size@$size/0"
set -o pipefail
shift
fi
# Create a directory for our resources
dir=/data/local/tmp/minicap-devel
adb shell "mkdir $dir 2>/dev/null"
# Upload the binary
adb push libs/$abi/$bin $dir
# Upload the shared library
if [ -e jni/minicap-shared/aosp/libs/android-$rel/$abi/minicap.so ]; then
adb push jni/minicap-shared/aosp/libs/android-$rel/$abi/minicap.so $dir
else
adb push jni/minicap-shared/aosp/libs/android-$sdk/$abi/minicap.so $dir
fi
# Run!
adb shell LD_LIBRARY_PATH=$dir $dir/$bin $args "$@"
# Clean up
adb shell rm -r $dir
在一些电脑上面
size=$(adb shell dumpsys window | grep -Eo 'init=\d+x\d+' | head -1 | cut -d= -f 2)
需要修改成
size=$(adb shell dumpsys window | grep -Eo 'init=[0-9]+x[0-9]+' | head -1 | cut -d= -f 2)
不然无法获取大 height 和 width
按照 LZ 的文章步骤不能成功。
很多手机直接 push 对应的 minicap 和 minicap.so 文件后,
执行 adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 480x854@480x854/0 -t 命令会出现错误。
错误信息 “/system/bin/sh: /data/local/tmp/minicap: can't execute: Permission denied”
建议按照https://github.com/openstf/minicap 中的描述进行。
总结一下直接的步骤:
git clone https://github.com/openstf/minicap.git
cd minicap
git submodule init
git submodule update
ndk-build
注意 ndk 的版本,android-ndk-r10e-linux-x86_64.bin
由于直 git 的 minicap 项目依赖 libjpeg-turbo 模块 ,所以需要进行
git submodule init
git submodule update
注意:直接下载项目和 git clone 项目是不一样的,所以要用 git clone 。否则 submodule 的操作不会成功。
哭着跪了 .
为啥没有成都的测试开发工程师招聘
#3 楼 @chenhengjie123 嗯 . 需要验证切换用户前和切换用户后 一切设定和属性的正确性 .
Android L 加入了多用户的概念。
至于 adb 重连和当前 Bootstrap 挂掉的原因,不是很清楚,毕竟属于 Android 开发的范畴了 。
只是从 Appium 维度来解决这个问题 .
我们和日本人说四川话
#14 楼 @chenhengjie123 可以 .
看到这篇文档,说说我的理解.
文件:
ib\appium.js
函数:
Appium.prototype.invoke = function (cb)
if (this.device.args.autoLaunch === false) {
// if user has passed in desiredCaps.autoLaunch = false
// meaning they will manage app install / launching
if (typeof this.device.noLaunchSetup === "function") {
this.device.noLaunchSetup(function (err) {
if (err) return cb(err);
cb(null, this.device);
}.bind(this));
} else {
cb(null, this.device);
}
} else {
// the normal case, where we launch the device for folks
var onStart = function (err, sessionIdOverride) {
if (sessionIdOverride) {
this.sessionId = sessionIdOverride;
logger.debug("Overriding session id with " +
JSON.stringify(sessionIdOverride));
}
if (err) return this.cleanupSession(err, cb);
logger.debug("Device launched! Ready for commands");
this.setCommandTimeout(this.desiredCapabilities.newCommandTimeout);
cb(null, this.device);
}.bind(this);
this.device.start(onStart, _.once(this.cleanupSession.bind(this)));
}
这个函数会判断 autoLaunch 参数,直接将判断部分代码注释掉。只留下
var onStart = function (err, sessionIdOverride) {
if (sessionIdOverride) {
this.sessionId = sessionIdOverride;
logger.debug("Overriding session id with " +
JSON.stringify(sessionIdOverride));
}
if (err) return this.cleanupSession(err, cb);
logger.debug("Device launched! Ready for commands");
this.setCommandTimeout(this.desiredCapabilities.newCommandTimeout);
cb(null, this.device);
}.bind(this);
this.device.start(onStart, _.once(this.cleanupSession.bind(this)));
在回放脚本时 不设置 app 的参数,autoLaunch = false,就可以不启动 APP,直接执行脚本中的动作。
STF 前提依赖都安装好了
执行 sudo npm install -g stf 不成功
错误信息:
gyp WARN EACCES user "root" does not have permission to access the dev dir "/home/zhaojiajun/.node-gyp/4.0.0"
gyp WARN EACCES attempting to reinstall using temporary dev dir "/usr/local/lib/node_modules/stf/node_modules/ws/node_modules/utf-8-validate/.node-gyp"
请问这是什么原因导致的呢
准确的来说 Appium 支持在父控件中查找子控件。
在 selenium 的 webelement 类中你可以查找到对应的内容:
def find_element_by_class_name(self, name):
"""Finds element within this element's children by class name.
:Args:
- name - class name to search for.
"""
return self.find_element(by=By.CLASS_NAME, value=name)
在 Appium python clinet 中的 WebElement 就是继承 Selenum 的 WebElement 扩展了在 UiAutomator 中的 accessibility id 以及直接使用 Uiautomator 的语法规则。
class WebElement(SeleniumWebElement):
def find_element_by_ios_uiautomation(self, uia_string):
"""Finds an element by uiautomation in iOS.
:Args:
- uia_string - The element name in the iOS UIAutomation library
:Usage:
driver.find_element_by_ios_uiautomation('.elements()[1].cells()[2]')
"""
return self.find_element(by=By.IOS_UIAUTOMATION, value=uia_string)
def find_elements_by_ios_uiautomation(self, uia_string):
"""Finds elements by uiautomation in iOS.
:Args:
- uia_string - The element name in the iOS UIAutomation library
:Usage:
driver.find_elements_by_ios_uiautomation('.elements()[1].cells()[2]')
"""
return self.find_elements(by=By.IOS_UIAUTOMATION, value=uia_string)
def find_element_by_android_uiautomator(self, uia_string):
"""Finds element by uiautomator in Android.
:Args:
- uia_string - The element name in the Android UIAutomator library
:Usage:
driver.find_element_by_android_uiautomator('.elements()[1].cells()[2]')
"""
return self.find_element(by=By.ANDROID_UIAUTOMATOR, value=uia_string)
def find_elements_by_android_uiautomator(self, uia_string):
"""Finds elements by uiautomator in Android.
:Args:
- uia_string - The element name in the Android UIAutomator library
:Usage:
driver.find_elements_by_android_uiautomator('.elements()[1].cells()[2]')
"""
return self.find_elements(by=By.ANDROID_UIAUTOMATOR, value=uia_string)
def find_element_by_accessibility_id(self, id):
"""Finds an element by accessibility id.
:Args:
- id - a string corresponding to a recursive element search using the
Id/Name that the native Accessibility options utilize
:Usage:
driver.find_element_by_accessibility_id()
"""
return self.find_element(by=By.ACCESSIBILITY_ID, value=id)
def find_elements_by_accessibility_id(self, id):
"""Finds elements by accessibility id.
:Args:
- id - a string corresponding to a recursive element search using the
Id/Name that the native Accessibility options utilize
:Usage:
driver.find_elements_by_accessibility_id()
"""
return self.find_elements(by=By.ACCESSIBILITY_ID, value=id)
def set_text(self, keys=''):
"""Sends text to the element. Previous text is removed.
Android only.
:Args:
- keys - the text to be sent to the element.
:Usage:
element.set_text('some text')
"""
data = {
'elementId': self._id,
'value': [keys]
}
self._execute(Command.REPLACE_KEYS, data)
return self
uid 区分设备 id
和对应的 Server port 和 Bootstrap port . 就可以解决 .
问题已经解决了 。
检查
python-client-master\appium\webdriver\webdriver.py 中是否还有这个方法.
启动慢是一回事,脚本没单个动作慢是另一回事。
脚本单个动作慢 可能需要看看具体实现
def _get_opts(self, element, x, y, duration = None):
opts = {}
if element is not None:
opts['element'] = element.id
# it makes no sense to have x but no y, or vice versa.
if x is None or y is None:
x, y = None, None
opts['x'] = x
opts['y'] = y
if duration is not None:
opts['duration'] = duration
return opts
得看看默认 duration 是不是为 None,有些默认 duration 可能设置有基础时间
最好的资料就是源代码
源代码中直接有 doc~