merge master

This commit is contained in:
lilong.129
2023-09-05 21:37:08 +08:00
8 changed files with 99 additions and 38 deletions

View File

@@ -455,3 +455,31 @@ func IsZeroFloat64(f float64) bool {
threshold := 1e-9 threshold := 1e-9
return math.Abs(f) < threshold return math.Abs(f) < threshold
} }
func ConvertToFloat64(val interface{}) (float64, error) {
switch v := val.(type) {
case float64:
return v, nil
case int:
return float64(v), nil
case int64:
return float64(v), nil
default:
return 0, fmt.Errorf("invalid type for conversion to float64: %T, value: %+v", val, val)
}
}
func ConvertToStringSlice(val interface{}) ([]string, error) {
if valSlice, ok := val.([]interface{}); ok {
var res []string
for _, iVal := range valSlice {
valString, ok := iVal.(string)
if !ok {
return nil, fmt.Errorf("invalid type for converting one of the elements to string: %T, value: %v", iVal, iVal)
}
res = append(res, valString)
}
return res, nil
}
return nil, fmt.Errorf("invalid type for conversion to []string")
}

View File

@@ -520,7 +520,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) {
if texts, ok := action.Params.([]string); ok { if texts, ok := action.Params.([]string); ok {
return dExt.swipeToTapTexts(texts, action.GetOptions()...) return dExt.swipeToTapTexts(texts, action.GetOptions()...)
} }
if texts, err := convertToStringSlice(action.Params); err == nil { if texts, err := builtin.ConvertToStringSlice(action.Params); err == nil {
return dExt.swipeToTapTexts(texts, action.GetOptions()...) return dExt.swipeToTapTexts(texts, action.GetOptions()...)
} }
return fmt.Errorf("invalid %s params: %v", ACTION_SwipeToTapTexts, action.Params) return fmt.Errorf("invalid %s params: %v", ACTION_SwipeToTapTexts, action.Params)
@@ -652,39 +652,11 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) {
var errActionNotImplemented = errors.New("UI action not implemented") var errActionNotImplemented = errors.New("UI action not implemented")
func convertToFloat64(val interface{}) (float64, error) {
switch v := val.(type) {
case float64:
return v, nil
case int:
return float64(v), nil
case int64:
return float64(v), nil
default:
return 0, fmt.Errorf("invalid type for conversion to float64: %T, value: %+v", val, val)
}
}
func convertToStringSlice(val interface{}) ([]string, error) {
if valSlice, ok := val.([]interface{}); ok {
var res []string
for _, iVal := range valSlice {
valString, ok := iVal.(string)
if !ok {
return nil, fmt.Errorf("invalid type for converting one of the elements to string: %T, value: %v", iVal, iVal)
}
res = append(res, valString)
}
return res, nil
}
return nil, fmt.Errorf("invalid type for conversion to []string")
}
// getSimulationDuration returns simulation duration by given params (in seconds) // getSimulationDuration returns simulation duration by given params (in seconds)
func getSimulationDuration(params []interface{}) (milliseconds int64) { func getSimulationDuration(params []interface{}) (milliseconds int64) {
if len(params) == 1 { if len(params) == 1 {
// given constant duration time // given constant duration time
seconds, err := convertToFloat64(params[0]) seconds, err := builtin.ConvertToFloat64(params[0])
if err != nil { if err != nil {
log.Error().Err(err).Interface("params", params).Msg("invalid params") log.Error().Err(err).Interface("params", params).Msg("invalid params")
return 0 return 0
@@ -703,17 +675,17 @@ func getSimulationDuration(params []interface{}) (milliseconds int64) {
} }
totalProb := 0.0 totalProb := 0.0
for i := 0; i+3 <= len(params); i += 3 { for i := 0; i+3 <= len(params); i += 3 {
min, err := convertToFloat64(params[i]) min, err := builtin.ConvertToFloat64(params[i])
if err != nil { if err != nil {
log.Error().Err(err).Interface("min", params[i]).Msg("invalid minimum time") log.Error().Err(err).Interface("min", params[i]).Msg("invalid minimum time")
return 0 return 0
} }
max, err := convertToFloat64(params[i+1]) max, err := builtin.ConvertToFloat64(params[i+1])
if err != nil { if err != nil {
log.Error().Err(err).Interface("max", params[i+1]).Msg("invalid maximum time") log.Error().Err(err).Interface("max", params[i+1]).Msg("invalid maximum time")
return 0 return 0
} }
weight, err := convertToFloat64(params[i+2]) weight, err := builtin.ConvertToFloat64(params[i+2])
if err != nil { if err != nil {
log.Error().Err(err).Interface("weight", params[i+2]).Msg("invalid weight value") log.Error().Err(err).Interface("weight", params[i+2]).Msg("invalid weight value")
return 0 return 0

View File

@@ -114,12 +114,12 @@ func (screenResults ScreenResultMap) updatePopupCloseStatus() {
continue continue
} }
// popup existed, but identical popups occurs during next retry // popup existed, but identical popups occurs during next retry
if curPopup.Text == nextPopup.Text && curPopup.Type == nextPopup.Type { if nextPopup.CloseArea.IsIdentical(curPopup.CloseArea) {
popupScreenResultList[i].Popup.CloseStatus = "fail" popupScreenResultList[i].Popup.CloseStatus = CloseStatusFail
continue continue
} }
// popup existed, but no popup or different popup occurs during next retry (IsClosed=true) // popup existed, but no popup or different popup occurs during next retry (IsClosed=true)
popupScreenResultList[i].Popup.CloseStatus = "success" popupScreenResultList[i].Popup.CloseStatus = CloseStatusSuccess
} }
} }

View File

@@ -2,10 +2,13 @@ package uixt
import ( import (
"bytes" "bytes"
"math"
"strings" "strings"
"time" "time"
"github.com/httprunner/funplugin" "github.com/httprunner/funplugin"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
) )
var ( var (
@@ -434,6 +437,11 @@ type PointF struct {
Y float64 `json:"y"` Y float64 `json:"y"`
} }
func (p PointF) IsIdentical(p2 PointF) bool {
return builtin.IsZeroFloat64(math.Abs(p.X-p2.X)) &&
builtin.IsZeroFloat64(math.Abs(p.Y-p2.Y))
}
type Rect struct { type Rect struct {
Point Point
Size Size

View File

@@ -27,6 +27,12 @@ var popups = [][]string{
{"管理使用时间", ".*忽略.*"}, {"管理使用时间", ".*忽略.*"},
} }
const (
CloseStatusFound = "found"
CloseStatusSuccess = "success"
CloseStatusFail = "fail"
)
func findTextPopup(screenTexts OCRTexts) (closePoint *OCRText) { func findTextPopup(screenTexts OCRTexts) (closePoint *OCRText) {
for _, popup := range popups { for _, popup := range popups {
if len(popup) != 2 { if len(popup) != 2 {
@@ -127,9 +133,13 @@ func (dExt *DriverExt) ClosePopupsHandler(options ...ActionOption) error {
break break
} }
screenResult.Popup.RetryCount = retryCount screenResult.Popup.RetryCount = retryCount
if !screenResult.Popup.PopupArea.IsEmpty() {
screenResult.Popup.CloseStatus = CloseStatusFound
}
if screenResult.Popup.CloseArea.IsEmpty() { if screenResult.Popup.CloseArea.IsEmpty() {
break break
} }
screenResult.Popup.CloseStatus = CloseStatusFound
if err = dExt.tapPopupHandler(screenResult.Popup); err != nil { if err = dExt.tapPopupHandler(screenResult.Popup); err != nil {
return err return err

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"image" "image"
"io" "io"
"math"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"regexp" "regexp"
@@ -133,6 +134,11 @@ func (t OCRTexts) FindText(text string, options ...ActionOption) (result OCRText
} }
results = append(results, ocrText) results = append(results, ocrText)
// return the first one matched exactly when index not specified
if ocrText.Text == text && actionOptions.Index == 0 {
return ocrText, nil
}
} }
if len(results) == 0 { if len(results) == 0 {
@@ -468,6 +474,12 @@ func (box Box) IsEmpty() bool {
return builtin.IsZeroFloat64(box.Width) && builtin.IsZeroFloat64(box.Height) return builtin.IsZeroFloat64(box.Width) && builtin.IsZeroFloat64(box.Height)
} }
func (box Box) IsIdentical(box2 Box) bool {
return box.Point.IsIdentical(box2.Point) &&
builtin.IsZeroFloat64(math.Abs(box.Width-box2.Width)) &&
builtin.IsZeroFloat64(math.Abs(box.Height-box2.Height))
}
func (box Box) Center() PointF { func (box Box) Center() PointF {
return PointF{ return PointF{
X: box.Point.X + box.Width*0.5, X: box.Point.X + box.Width*0.5,

View File

@@ -133,7 +133,7 @@ func (dExt *DriverExt) swipeToTapTexts(texts []string, options ...ActionOption)
return errors.New("no text to tap") return errors.New("no text to tap")
} }
options = append(options, WithMatchOne(true)) options = append(options, WithMatchOne(true), WithRegex(true))
var point PointF var point PointF
findTexts := func(d *DriverExt) error { findTexts := func(d *DriverExt) error {
var err error var err error
@@ -181,7 +181,6 @@ func (dExt *DriverExt) swipeToTapApp(appName string, options ...ActionOption) er
} }
options = append(options, WithDirection("left")) options = append(options, WithDirection("left"))
options = append(options, WithRegex(true))
actionOptions := NewActionOptions(options...) actionOptions := NewActionOptions(options...)
// default to retry 5 times // default to retry 5 times

View File

@@ -11,6 +11,7 @@ import (
"github.com/httprunner/httprunner/v4/hrp/internal/builtin" "github.com/httprunner/httprunner/v4/hrp/internal/builtin"
"github.com/httprunner/httprunner/v4/hrp/internal/code" "github.com/httprunner/httprunner/v4/hrp/internal/code"
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
) )
// ITestCase represents interface for testcases, // ITestCase represents interface for testcases,
@@ -112,6 +113,13 @@ func (tc *TCase) MakeCompat() (err error) {
// 3. deal with extract expr including hyphen // 3. deal with extract expr including hyphen
convertExtract(step.Extract) convertExtract(step.Extract)
// 4. deal with mobile step compatibility
if step.Android != nil {
convertCompatMobileStep(step.Android)
} else if step.IOS != nil {
convertCompatMobileStep(step.IOS)
}
} }
return nil return nil
} }
@@ -352,6 +360,30 @@ func convertExtract(extract map[string]string) {
} }
} }
func convertCompatMobileStep(mobileStep *MobileStep) {
if mobileStep == nil {
return
}
for i := 0; i < len(mobileStep.Actions); i++ {
ma := mobileStep.Actions[i]
actionOptions := uixt.NewActionOptions(ma.GetOptions()...)
// append tap_cv params to screenshot_with_ui_types option
if ma.Method == uixt.ACTION_TapByCV {
uiTypes, _ := builtin.ConvertToStringSlice(ma.Params)
ma.ActionOptions.ScreenShotWithUITypes = append(ma.ActionOptions.ScreenShotWithUITypes, uiTypes...)
}
// set default max_retry_times to 10 for swipe_to_tap_texts
if ma.Method == uixt.ACTION_SwipeToTapTexts && actionOptions.MaxRetryTimes == 0 {
ma.ActionOptions.MaxRetryTimes = 10
}
// set default max_retry_times to 10 for swipe_to_tap_text
if ma.Method == uixt.ACTION_SwipeToTapText && actionOptions.MaxRetryTimes == 0 {
ma.ActionOptions.MaxRetryTimes = 10
}
mobileStep.Actions[i] = ma
}
}
// convertJmespathExpr deals with limited jmespath expression conversion // convertJmespathExpr deals with limited jmespath expression conversion
func convertJmespathExpr(checkExpr string) string { func convertJmespathExpr(checkExpr string) string {
if strings.Contains(checkExpr, textExtractorSubRegexp) { if strings.Contains(checkExpr, textExtractorSubRegexp) {