mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-06 23:11:21 +08:00
Merge pull request #1484 from httprunner/dev-v4.3-bugfix
fix: failed to input on android device
This commit is contained in:
@@ -11,12 +11,12 @@ import (
|
|||||||
func TestAndroidDouYinLive(t *testing.T) {
|
func TestAndroidDouYinLive(t *testing.T) {
|
||||||
testCase := &hrp.TestCase{
|
testCase := &hrp.TestCase{
|
||||||
Config: hrp.NewConfig("通过 feed 头像进入抖音直播间").
|
Config: hrp.NewConfig("通过 feed 头像进入抖音直播间").
|
||||||
SetAndroid(hrp.WithAdbLogOn(true)),
|
SetAndroid(hrp.WithAdbLogOn(true), hrp.WithSerialNumber("2d06bf70")),
|
||||||
TestSteps: []hrp.IStep{
|
TestSteps: []hrp.IStep{
|
||||||
hrp.NewStep("打开网页").
|
hrp.NewStep("打开网页").
|
||||||
Android().
|
Android().
|
||||||
Home().
|
Home().
|
||||||
AppTerminate("com.google.android.apps.chrome.Main").Sleep(1). // 关闭已运行的抖音,确保启动抖音后在「抖音」首页
|
AppTerminate("com.google.android.apps.chrome.Main").Sleep(1).
|
||||||
SwipeToTapApp("Chrome", hrp.WithMaxRetryTimes(5)).TapByOCR("搜索").Input("https://gtftask.bytedance.com/local-time").TapByOCR("前往").Sleep(5).
|
SwipeToTapApp("Chrome", hrp.WithMaxRetryTimes(5)).TapByOCR("搜索").Input("https://gtftask.bytedance.com/local-time").TapByOCR("前往").Sleep(5).
|
||||||
Validate().
|
Validate().
|
||||||
AssertOCRExists("1664", "网页打开失败"),
|
AssertOCRExists("1664", "网页打开失败"),
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ func ensurePython3Venv(venv string, packages ...string) (python3 string, err err
|
|||||||
return python3, nil
|
return python3, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Command(name string, arg ...string) *exec.Cmd {
|
||||||
|
args := strings.Join(arg, " ")
|
||||||
|
return exec.Command("bash", "-c", name, args)
|
||||||
|
}
|
||||||
|
|
||||||
func ExecCommand(cmdName string, args ...string) error {
|
func ExecCommand(cmdName string, args ...string) error {
|
||||||
cmd := exec.Command(cmdName, args...)
|
cmd := exec.Command(cmdName, args...)
|
||||||
log.Info().Str("cmd", cmd.String()).Msg("exec command")
|
log.Info().Str("cmd", cmd.String()).Msg("exec command")
|
||||||
|
|||||||
@@ -100,6 +100,11 @@ func ensurePython3Venv(venvDir string, packages ...string) (python3 string, err
|
|||||||
return python3, nil
|
return python3, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Command(name string, arg ...string) *exec.Cmd {
|
||||||
|
args := strings.Join(arg, " ")
|
||||||
|
return exec.Command("cmd", "/c", name, args)
|
||||||
|
}
|
||||||
|
|
||||||
func ExecCommand(cmdName string, args ...string) error {
|
func ExecCommand(cmdName string, args ...string) error {
|
||||||
// "cmd /c" carries out the command specified by string and then stops
|
// "cmd /c" carries out the command specified by string and then stops
|
||||||
// refer: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd
|
// refer: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd
|
||||||
|
|||||||
@@ -2,12 +2,20 @@ package uixt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"os/exec"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/electricbubble/gadb"
|
"github.com/electricbubble/gadb"
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -19,6 +27,15 @@ var (
|
|||||||
|
|
||||||
const forwardToPrefix = "forward-to-"
|
const forwardToPrefix = "forward-to-"
|
||||||
|
|
||||||
|
const (
|
||||||
|
regexFloat = `[0-9\.]*`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
regexCompileSwipe = regexp.MustCompile(fmt.Sprintf(`timesec=(%s)\s*startX=(%s)\s*startY=(%s)\s*endX=(%s)\s*endY=(%s)`, regexFloat, regexFloat, regexFloat, regexFloat, regexFloat)) // parse ${var} or $var
|
||||||
|
regexCompileTap = regexp.MustCompile(fmt.Sprintf(`timesec=(%s)\s*x=(%s)\s*y=(%s)`, regexFloat, regexFloat, regexFloat)) // parse ${func1($a, $b)} // parse number
|
||||||
|
)
|
||||||
|
|
||||||
func InitUIAClient(device *AndroidDevice) (*DriverExt, error) {
|
func InitUIAClient(device *AndroidDevice) (*DriverExt, error) {
|
||||||
var deviceOptions []AndroidDeviceOption
|
var deviceOptions []AndroidDeviceOption
|
||||||
if device.SerialNumber != "" {
|
if device.SerialNumber != "" {
|
||||||
@@ -51,10 +68,13 @@ func InitUIAClient(device *AndroidDevice) (*DriverExt, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if device.LogOn {
|
if device.LogOn {
|
||||||
// TODO
|
err = driverExt.Driver.StartCaptureLog("hrp_adb_log")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return driverExt, nil
|
return driverExt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type AndroidDeviceOption func(*AndroidDevice)
|
type AndroidDeviceOption func(*AndroidDevice)
|
||||||
@@ -106,6 +126,7 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er
|
|||||||
|
|
||||||
device.SerialNumber = dev.Serial()
|
device.SerialNumber = dev.Serial()
|
||||||
device.d = dev
|
device.d = dev
|
||||||
|
device.logcat = NewAdbLogcat(serialNumber)
|
||||||
return device, nil
|
return device, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +135,7 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er
|
|||||||
|
|
||||||
type AndroidDevice struct {
|
type AndroidDevice struct {
|
||||||
d gadb.Device
|
d gadb.Device
|
||||||
|
logcat *DeviceLogcat
|
||||||
SerialNumber string `json:"serial,omitempty" yaml:"serial,omitempty"`
|
SerialNumber string `json:"serial,omitempty" yaml:"serial,omitempty"`
|
||||||
IP string `json:"ip,omitempty" yaml:"ip,omitempty"`
|
IP string `json:"ip,omitempty" yaml:"ip,omitempty"`
|
||||||
Port int `json:"port,omitempty" yaml:"port,omitempty"`
|
Port int `json:"port,omitempty" yaml:"port,omitempty"`
|
||||||
@@ -152,6 +174,7 @@ func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver *uiaDr
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
driver.adbDevice = dev.d
|
driver.adbDevice = dev.d
|
||||||
|
driver.logcat = dev.logcat
|
||||||
driver.localPort = localPort
|
driver.localPort = localPort
|
||||||
|
|
||||||
return driver, nil
|
return driver, nil
|
||||||
@@ -182,6 +205,151 @@ func getFreePort() (int, error) {
|
|||||||
return l.Addr().(*net.TCPAddr).Port, nil
|
return l.Addr().(*net.TCPAddr).Port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeviceLogcat struct {
|
||||||
|
serial string
|
||||||
|
logBuffer *bytes.Buffer
|
||||||
|
errs []error
|
||||||
|
stopping chan struct{}
|
||||||
|
done chan struct{}
|
||||||
|
cmd *exec.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAdbLogcat(serial string) *DeviceLogcat {
|
||||||
|
return &DeviceLogcat{
|
||||||
|
serial: serial,
|
||||||
|
logBuffer: new(bytes.Buffer),
|
||||||
|
stopping: make(chan struct{}),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CatchLogcatContext starts logcat with timeout context
|
||||||
|
func (l *DeviceLogcat) CatchLogcatContext(timeoutCtx context.Context) (err error) {
|
||||||
|
if err = l.CatchLogcat(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-timeoutCtx.Done():
|
||||||
|
_ = l.Stop()
|
||||||
|
case <-l.stopping:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *DeviceLogcat) Stop() error {
|
||||||
|
select {
|
||||||
|
case <-l.stopping:
|
||||||
|
default:
|
||||||
|
close(l.stopping)
|
||||||
|
<-l.done
|
||||||
|
close(l.done)
|
||||||
|
}
|
||||||
|
return l.Errors()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *DeviceLogcat) Errors() (err error) {
|
||||||
|
for _, e := range l.errs {
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("%v |[DeviceLogcatErr] %v", err, e)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("[DeviceLogcatErr] %v", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *DeviceLogcat) CatchLogcat() (err error) {
|
||||||
|
if l.cmd != nil {
|
||||||
|
err = fmt.Errorf("logcat already start")
|
||||||
|
}
|
||||||
|
cmdLine := fmt.Sprintf("adb -s %s logcat -c && adb -s %s logcat -v time -s iesqaMonitor:V", l.serial, l.serial)
|
||||||
|
l.cmd = builtin.Command(cmdLine)
|
||||||
|
l.cmd.Stderr = l.logBuffer
|
||||||
|
l.cmd.Stdout = l.logBuffer
|
||||||
|
l.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
|
if err = l.cmd.Start(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
<-l.stopping
|
||||||
|
if e := syscall.Kill(-l.cmd.Process.Pid, syscall.SIGKILL); e != nil {
|
||||||
|
l.errs = append(l.errs, fmt.Errorf("kill logcat process err:%v", e))
|
||||||
|
}
|
||||||
|
l.done <- struct{}{}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *DeviceLogcat) BufferedLogcat() (err error) {
|
||||||
|
// -d: dump the current buffered logcat result and exits
|
||||||
|
cmdLine := fmt.Sprintf("adb -s %s logcat -d", l.serial)
|
||||||
|
cmd := builtin.Command(cmdLine)
|
||||||
|
cmd.Stdout = l.logBuffer
|
||||||
|
cmd.Stderr = l.logBuffer
|
||||||
|
if err = cmd.Run(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExportPoint struct {
|
||||||
|
Start int `json:"start" yaml:"start"`
|
||||||
|
End int `json:"end" yaml:"end"`
|
||||||
|
From interface{} `json:"from" yaml:"from"`
|
||||||
|
To interface{} `json:"to" yaml:"to"`
|
||||||
|
Operation string `json:"operation" yaml:"operation"`
|
||||||
|
Ext string `json:"ext" yaml:"ext"`
|
||||||
|
RunTime int `json:"run_time,omitempty" yaml:"run_time,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertPoints(data string) (eps []ExportPoint) {
|
||||||
|
lines := strings.Split(data, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.Contains(line, "startX") {
|
||||||
|
matched := regexCompileSwipe.FindStringSubmatch(line)
|
||||||
|
if len(matched) != 6 {
|
||||||
|
log.Error().Msg("failed to parse point data")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
start, _ := strconv.Atoi(matched[1])
|
||||||
|
fromX, _ := strconv.ParseFloat(matched[2], 64)
|
||||||
|
fromY, _ := strconv.ParseFloat(matched[3], 64)
|
||||||
|
toX, _ := strconv.ParseFloat(matched[4], 64)
|
||||||
|
toY, _ := strconv.ParseFloat(matched[5], 64)
|
||||||
|
p := ExportPoint{
|
||||||
|
Start: start,
|
||||||
|
End: start,
|
||||||
|
From: []float64{fromX, fromY},
|
||||||
|
To: []float64{toX, toY},
|
||||||
|
Operation: "Gtf-Drag",
|
||||||
|
Ext: "",
|
||||||
|
}
|
||||||
|
eps = append(eps, p)
|
||||||
|
} else if strings.Contains(line, "x=") {
|
||||||
|
matched := regexCompileTap.FindStringSubmatch(line)
|
||||||
|
if len(matched) != 4 {
|
||||||
|
log.Error().Msg("failed to parse point data")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
start, _ := strconv.Atoi(matched[1])
|
||||||
|
x, _ := strconv.ParseFloat(matched[2], 64)
|
||||||
|
y, _ := strconv.ParseFloat(matched[3], 64)
|
||||||
|
p := ExportPoint{
|
||||||
|
Start: start,
|
||||||
|
End: start,
|
||||||
|
From: []float64{x, y},
|
||||||
|
To: []float64{x, y},
|
||||||
|
Operation: "Gtf-Tap",
|
||||||
|
Ext: "",
|
||||||
|
}
|
||||||
|
eps = append(eps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type UiSelectorHelper struct {
|
type UiSelectorHelper struct {
|
||||||
value *bytes.Buffer
|
value *bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|||||||
18
hrp/internal/uixt/android_device_test.go
Normal file
18
hrp/internal/uixt/android_device_test.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package uixt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertPoints(t *testing.T) {
|
||||||
|
data := "09-29 15:02:08.379 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434928378\tstartX=720.000000\tstartY=1462.000000\tendX=1296.000000\tendY=1462.000000\n09-29 15:02:09.433 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434929432\tstartX=720.000000\tstartY=1462.000000\tendX=1296.000000\tendY=1462.000000\n09-29 15:02:10.452 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434930452\tstartX=720.000000\tstartY=1462.000000\tendX=1296.000000\tendY=1462.000000\n09-29 15:02:11.451 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434931450\tstartX=720.000000\tstartY=1462.000000\tendX=1296.000000\tendY=1462.000000\n09-29 15:02:12.491 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434932489\tstartX=720.000000\tstartY=1462.000000\tendX=1296.000000\tendY=1462.000000\n09-29 15:02:16.028 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434936027\tstartX=720.000000\tstartY=1462.000000\tendX=144.000000\tendY=1462.000000\n09-29 15:02:21.424 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434941423\tstartX=720.000000\tstartY=1462.000000\tendX=144.000000\tendY=1462.000000\n09-29 15:02:27.923 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434947922\tstartX=720.000000\tstartY=1462.000000\tendX=144.000000\tendY=1462.000000\n09-29 15:02:33.628 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434953628\tstartX=720.000000\tstartY=1462.000000\tendX=144.000000\tendY=1462.000000\n09-29 15:02:39.347 I/iesqaMonitor( 9938): [tap]\ttimesec=1664434959347\tx=1259.5y=1868.5"
|
||||||
|
eps := ConvertPoints(data)
|
||||||
|
if len(eps) != 10 {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
jsons, _ := json.Marshal(eps)
|
||||||
|
println(fmt.Sprintf("%v", string(jsons)))
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ type uiaDriver struct {
|
|||||||
Driver
|
Driver
|
||||||
|
|
||||||
adbDevice gadb.Device
|
adbDevice gadb.Device
|
||||||
|
logcat *DeviceLogcat
|
||||||
localPort int
|
localPort int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,10 +238,37 @@ func (ud *uiaDriver) PressBack() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ud *uiaDriver) StartCamera() (err error) {
|
func (ud *uiaDriver) StartCamera() (err error) {
|
||||||
if _, err = ud.adbDevice.RunShellCommand("am", "start", "-a", "android.media.action.VIDEO_CAPTURE"); err != nil {
|
if _, err = ud.adbDevice.RunShellCommand("rm", "-r", "/sdcard/DCIM/Camera"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return
|
time.Sleep(5 * time.Second)
|
||||||
|
var version string
|
||||||
|
if version, err = ud.adbDevice.RunShellCommand("getprop", "ro.build.version.release"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if version == "11" || version == "12" {
|
||||||
|
if _, err = ud.adbDevice.RunShellCommand("am", "start", "-a", "android.media.action.STILL_IMAGE_CAMERA"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
if _, err = ud.adbDevice.RunShellCommand("input", "swipe", "750", "1000", "250", "1000"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
if _, err = ud.adbDevice.RunShellCommand("input", "keyevent", "27"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if _, err = ud.adbDevice.RunShellCommand("am", "start", "-a", "android.media.action.VIDEO_CAPTURE"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
if _, err = ud.adbDevice.RunShellCommand("input", "keyevent", "27"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ud *uiaDriver) StopCamera() (err error) {
|
func (ud *uiaDriver) StopCamera() (err error) {
|
||||||
@@ -265,24 +293,6 @@ func (ud *uiaDriver) StopCamera() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ud *uiaDriver) StartRecording() (err error) {
|
|
||||||
var res string
|
|
||||||
if res, err = ud.adbDevice.RunShellCommand("input", "keyevent", "27"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Info().Str("shell", res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ud *uiaDriver) StopRecording() (err error) {
|
|
||||||
var res string
|
|
||||||
if res, err = ud.adbDevice.RunShellCommand("input", "keyevent", "27"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Info().Str("shell", res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ud *uiaDriver) ActiveAppInfo() (info AppInfo, err error) {
|
func (ud *uiaDriver) ActiveAppInfo() (info AppInfo, err error) {
|
||||||
// TODO
|
// TODO
|
||||||
return info, errDriverNotImplemented
|
return info, errDriverNotImplemented
|
||||||
@@ -675,6 +685,14 @@ func (ud *uiaDriver) SendKeys(text string, options ...DataOption) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ud *uiaDriver) Input(text string, options ...DataOption) (err error) {
|
||||||
|
element, err := ud.FindElement(BySelector{ClassName: ElementType{EditText: true}})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return element.SendKeys(text)
|
||||||
|
}
|
||||||
|
|
||||||
func (ud *uiaDriver) KeyboardDismiss(keyNames ...string) (err error) {
|
func (ud *uiaDriver) KeyboardDismiss(keyNames ...string) (err error) {
|
||||||
// TODO
|
// TODO
|
||||||
return errDriverNotImplemented
|
return errDriverNotImplemented
|
||||||
@@ -946,11 +964,18 @@ func (ud *uiaDriver) Wait(condition Condition) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ud *uiaDriver) StartCaptureLog(identifier ...string) (err error) {
|
func (ud *uiaDriver) StartCaptureLog(identifier ...string) (err error) {
|
||||||
// TODO
|
log.Info().Msg("start adb log recording")
|
||||||
|
err = ud.logcat.CatchLogcat()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ud *uiaDriver) StopCaptureLog() (result interface{}, err error) {
|
func (ud *uiaDriver) StopCaptureLog() (result interface{}, err error) {
|
||||||
// TODO
|
log.Info().Msg("stop adb log recording")
|
||||||
return
|
err = ud.logcat.Stop()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("failed to get adb log recording")
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
content := ud.logcat.logBuffer.String()
|
||||||
|
return ConvertPoints(content), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -469,9 +469,9 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
|||||||
"enable": true,
|
"enable": true,
|
||||||
"data": action.Identifier,
|
"data": action.Identifier,
|
||||||
})
|
})
|
||||||
return dExt.Driver.SendKeys(param, option)
|
return dExt.Driver.Input(param, option)
|
||||||
}
|
}
|
||||||
return dExt.Driver.SendKeys(param)
|
return dExt.Driver.Input(param)
|
||||||
case CtlSleep:
|
case CtlSleep:
|
||||||
if param, ok := action.Params.(json.Number); ok {
|
if param, ok := action.Params.(json.Number); ok {
|
||||||
seconds, _ := param.Float64()
|
seconds, _ := param.Float64()
|
||||||
@@ -500,10 +500,6 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
|||||||
return dExt.Driver.StartCamera()
|
return dExt.Driver.StartCamera()
|
||||||
case CtlStopCamera:
|
case CtlStopCamera:
|
||||||
return dExt.Driver.StopCamera()
|
return dExt.Driver.StopCamera()
|
||||||
case RecordStart:
|
|
||||||
return dExt.Driver.StartRecording()
|
|
||||||
case RecordStop:
|
|
||||||
return dExt.Driver.StopRecording()
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -715,6 +715,7 @@ type ElementType struct {
|
|||||||
Tab bool `json:"XCUIElementTypeTab"`
|
Tab bool `json:"XCUIElementTypeTab"`
|
||||||
TouchBar bool `json:"XCUIElementTypeTouchBar"`
|
TouchBar bool `json:"XCUIElementTypeTouchBar"`
|
||||||
StatusItem bool `json:"XCUIElementTypeStatusItem"`
|
StatusItem bool `json:"XCUIElementTypeStatusItem"`
|
||||||
|
EditText bool `json:"android.widget.EditText"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtectedResource A system resource that requires user authorization to access.
|
// ProtectedResource A system resource that requires user authorization to access.
|
||||||
@@ -884,9 +885,6 @@ type WebDriver interface {
|
|||||||
// StopCamera Stops the camera for recording
|
// StopCamera Stops the camera for recording
|
||||||
StopCamera() error
|
StopCamera() error
|
||||||
|
|
||||||
StartRecording() error
|
|
||||||
StopRecording() error
|
|
||||||
|
|
||||||
// Tap Sends a tap event at the coordinate.
|
// Tap Sends a tap event at the coordinate.
|
||||||
Tap(x, y int, options ...DataOption) error
|
Tap(x, y int, options ...DataOption) error
|
||||||
TapFloat(x, y float64, options ...DataOption) error
|
TapFloat(x, y float64, options ...DataOption) error
|
||||||
@@ -927,6 +925,9 @@ type WebDriver interface {
|
|||||||
// WithFrequency option can be used to set frequency of typing (letters per sec). The default value is 60
|
// WithFrequency option can be used to set frequency of typing (letters per sec). The default value is 60
|
||||||
SendKeys(text string, options ...DataOption) error
|
SendKeys(text string, options ...DataOption) error
|
||||||
|
|
||||||
|
// Input works like SendKeys
|
||||||
|
Input(text string, options ...DataOption) error
|
||||||
|
|
||||||
// KeyboardDismiss Tries to dismiss the on-screen keyboard
|
// KeyboardDismiss Tries to dismiss the on-screen keyboard
|
||||||
KeyboardDismiss(keyNames ...string) error
|
KeyboardDismiss(keyNames ...string) error
|
||||||
|
|
||||||
|
|||||||
@@ -527,6 +527,10 @@ func (wd *wdaDriver) SendKeys(text string, options ...DataOption) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wd *wdaDriver) Input(text string, options ...DataOption) (err error) {
|
||||||
|
return wd.SendKeys(text, options...)
|
||||||
|
}
|
||||||
|
|
||||||
func (wd *wdaDriver) KeyboardDismiss(keyNames ...string) (err error) {
|
func (wd *wdaDriver) KeyboardDismiss(keyNames ...string) (err error) {
|
||||||
// [[FBRoute POST:@"/wda/keyboard/dismiss"] respondWithTarget:self action:@selector(handleDismissKeyboardCommand:)]
|
// [[FBRoute POST:@"/wda/keyboard/dismiss"] respondWithTarget:self action:@selector(handleDismissKeyboardCommand:)]
|
||||||
if len(keyNames) == 0 {
|
if len(keyNames) == 0 {
|
||||||
@@ -575,16 +579,6 @@ func (wd *wdaDriver) StopCamera() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wd *wdaDriver) StartRecording() (err error) {
|
|
||||||
// TODO
|
|
||||||
return errDriverNotImplemented
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wd *wdaDriver) StopRecording() (err error) {
|
|
||||||
// TODO
|
|
||||||
return errDriverNotImplemented
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wd *wdaDriver) ExpectNotification(notifyName string, notifyType NotificationType, second ...int) (err error) {
|
func (wd *wdaDriver) ExpectNotification(notifyName string, notifyType NotificationType, second ...int) (err error) {
|
||||||
// [[FBRoute POST:@"/wda/expectNotification"] respondWithTarget:self action:@selector(handleExpectNotification:)]
|
// [[FBRoute POST:@"/wda/expectNotification"] respondWithTarget:self action:@selector(handleExpectNotification:)]
|
||||||
if len(second) == 0 {
|
if len(second) == 0 {
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ func (r *HRPRunner) initUIClient(device uixt.Device) (client *uixt.DriverExt, er
|
|||||||
uuid := device.UUID()
|
uuid := device.UUID()
|
||||||
|
|
||||||
// avoid duplicate init
|
// avoid duplicate init
|
||||||
if uuid == "" && len(r.uiClients) == 1 {
|
if uuid == "" && len(r.uiClients) > 0 {
|
||||||
for _, v := range r.uiClients {
|
for _, v := range r.uiClients {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user