From 2644c24fae1b4132ca161ae70b1c742572b00bc1 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Sun, 16 Apr 2023 18:50:21 +0800 Subject: [PATCH] feat: add validator AssertAppInForeground and AssertAppNotInForeground --- docs/CHANGELOG.md | 3 +- examples/uitest/demo_feed_random_slide.json | 29 ++++++++++++++- .../uitest/demo_feed_random_slide_test.go | 9 ++++- hrp/internal/version/VERSION | 2 +- hrp/pkg/uixt/android_adb_driver.go | 1 + hrp/pkg/uixt/ext.go | 37 ++++++++++++++----- hrp/step_mobile_ui.go | 30 +++++++++++++++ 7 files changed, 97 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 35632507..723ca0d4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## v4.3.3 (2023-04-14) +## v4.3.3 (2023-04-16) **go version** @@ -9,6 +9,7 @@ - feat: add adb `screencap` sub command - feat: add `IsAppInForeground` to check if the given package is in foreground - feat: check if app is in foreground when step failed +- feat: add validator AssertAppInForeground and AssertAppNotInForeground - fix: adb driver for TapFloat - fix: stop logcat only when enabled - fix: do not fail case when kill logcat error diff --git a/examples/uitest/demo_feed_random_slide.json b/examples/uitest/demo_feed_random_slide.json index 5a89c1cc..d74f45ae 100644 --- a/examples/uitest/demo_feed_random_slide.json +++ b/examples/uitest/demo_feed_random_slide.json @@ -28,7 +28,15 @@ "params": 10 } ] - } + }, + "validate": [ + { + "check": "ui_foreground_app", + "assert": "equal", + "expect": "com.ss.android.ugc.aweme", + "msg": "app [com.ss.android.ugc.aweme] should be in foreground" + } + ] }, { "name": "处理青少年弹窗", @@ -102,6 +110,25 @@ ] }, "loops": 10 + }, + { + "name": "exit", + "android": { + "actions": [ + { + "method": "app_terminate", + "params": "com.ss.android.ugc.aweme" + } + ] + }, + "validate": [ + { + "check": "ui_foreground_app", + "assert": "not_equal", + "expect": "com.ss.android.ugc.aweme", + "msg": "app [com.ss.android.ugc.aweme] should not be in foreground" + } + ] } ] } diff --git a/examples/uitest/demo_feed_random_slide_test.go b/examples/uitest/demo_feed_random_slide_test.go index ad892b87..98311c69 100644 --- a/examples/uitest/demo_feed_random_slide_test.go +++ b/examples/uitest/demo_feed_random_slide_test.go @@ -21,7 +21,9 @@ func TestAndroidDouyinFeedTest(t *testing.T) { Android(). AppTerminate("com.ss.android.ugc.aweme"). AppLaunch("com.ss.android.ugc.aweme"). - Sleep(10), + Sleep(10). + Validate(). + AssertAppInForeground("com.ss.android.ugc.aweme"), hrp.NewStep("处理青少年弹窗"). Android(). TapByOCR("我知道了", uixt.WithIgnoreNotFoundError(true)), @@ -40,6 +42,11 @@ func TestAndroidDouyinFeedTest(t *testing.T) { Android(). SwipeUp(). SleepRandom(0, 5, 0.7, 5, 10, 0.3), + hrp.NewStep("exit"). + Android(). + AppTerminate("com.ss.android.ugc.aweme"). + Validate(). + AssertAppNotInForeground("com.ss.android.ugc.aweme"), }, } diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index ff51d667..e73aa79d 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.3.3.2304161232 \ No newline at end of file +v4.3.3.2304161855 \ No newline at end of file diff --git a/hrp/pkg/uixt/android_adb_driver.go b/hrp/pkg/uixt/android_adb_driver.go index f373f924..68f8c28b 100644 --- a/hrp/pkg/uixt/android_adb_driver.go +++ b/hrp/pkg/uixt/android_adb_driver.go @@ -368,6 +368,7 @@ func (ad *adbDriver) IsAppInForeground(packageName string) (bool, error) { // adb shell dumpsys activity activities | grep mResumedActivity output, err := ad.adbClient.RunShellCommand("dumpsys", "activity", "activities") if err != nil { + log.Error().Err(err).Msg("failed to dumpsys activities") return false, err } diff --git a/hrp/pkg/uixt/ext.go b/hrp/pkg/uixt/ext.go index f110e107..093cb776 100644 --- a/hrp/pkg/uixt/ext.go +++ b/hrp/pkg/uixt/ext.go @@ -41,10 +41,15 @@ const ( RecordStop MobileMethod = "record_stop" // UI validation - SelectorName string = "ui_name" - SelectorLabel string = "ui_label" - SelectorOCR string = "ui_ocr" - SelectorImage string = "ui_image" + // selectors + SelectorName string = "ui_name" + SelectorLabel string = "ui_label" + SelectorOCR string = "ui_ocr" + SelectorImage string = "ui_image" + SelectorForegroundApp string = "ui_foreground_app" + // assertions + AssertionEqual string = "equal" + AssertionNotEqual string = "not_equal" AssertionExists string = "exists" AssertionNotExists string = "not_exists" @@ -349,6 +354,16 @@ func (dExt *DriverExt) IsImageExist(text string) bool { return err == nil } +func (dExt *DriverExt) IsAppInForeground(packageName string) bool { + // check if app is in foreground + yes, err := dExt.Driver.IsAppInForeground(packageName) + if !yes || err != nil { + log.Info().Str("packageName", packageName).Msg("app is not in foreground") + return false + } + return true +} + var errActionNotImplemented = errors.New("UI action not implemented") func convertToFloat64(val interface{}) (float64, error) { @@ -700,18 +715,20 @@ func (dExt *DriverExt) getAbsScope(x1, y1, x2, y2 float64) (int, int, int, int) } func (dExt *DriverExt) DoValidation(check, assert, expected string, message ...string) bool { - var exists bool - if assert == AssertionExists { - exists = true + var exp bool + if assert == AssertionExists || assert == AssertionEqual { + exp = true } else { - exists = false + exp = false } var result bool switch check { case SelectorOCR: - result = (dExt.IsOCRExist(expected) == exists) + result = (dExt.IsOCRExist(expected) == exp) case SelectorImage: - result = (dExt.IsImageExist(expected) == exists) + result = (dExt.IsImageExist(expected) == exp) + case SelectorForegroundApp: + result = (dExt.IsAppInForeground(expected) == exp) } if !result { diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index 99014a4c..f5483488 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -468,6 +468,36 @@ func (s *StepMobileUIValidation) AssertImageNotExists(expectedImagePath string, return s } +func (s *StepMobileUIValidation) AssertAppInForeground(packageName string, msg ...string) *StepMobileUIValidation { + v := Validator{ + Check: uixt.SelectorForegroundApp, + Assert: uixt.AssertionEqual, + Expect: packageName, + } + if len(msg) > 0 { + v.Message = msg[0] + } else { + v.Message = fmt.Sprintf("app [%s] should be in foreground", packageName) + } + s.step.Validators = append(s.step.Validators, v) + return s +} + +func (s *StepMobileUIValidation) AssertAppNotInForeground(packageName string, msg ...string) *StepMobileUIValidation { + v := Validator{ + Check: uixt.SelectorForegroundApp, + Assert: uixt.AssertionNotEqual, + Expect: packageName, + } + if len(msg) > 0 { + v.Message = msg[0] + } else { + v.Message = fmt.Sprintf("app [%s] should not be in foreground", packageName) + } + s.step.Validators = append(s.step.Validators, v) + return s +} + func (s *StepMobileUIValidation) Name() string { return s.step.Name }