feat: validate UI exists

This commit is contained in:
debugtalk
2022-07-27 21:13:53 +08:00
parent b3887d5364
commit 087743bd9c
3 changed files with 164 additions and 28 deletions

View File

@@ -172,11 +172,11 @@ type StepAndroidValidation struct {
step *TStep step *TStep
} }
func (s *StepAndroidValidation) AssertTextExists(expectedText string, msg string) *StepAndroidValidation { func (s *StepAndroidValidation) AssertXpathExists(expectedXpath string, msg string) *StepAndroidValidation {
v := Validator{ v := Validator{
Check: "android_ui", Check: "UI",
Assert: "text_exists", Assert: "xpath_exists",
Expect: expectedText, Expect: expectedXpath,
Message: msg, Message: msg,
} }
s.step.Validators = append(s.step.Validators, v) s.step.Validators = append(s.step.Validators, v)

View File

@@ -2,6 +2,7 @@ package hrp
import ( import (
"fmt" "fmt"
"strings"
"github.com/electricbubble/gwda" "github.com/electricbubble/gwda"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -140,11 +141,44 @@ type StepIOSValidation struct {
step *TStep step *TStep
} }
func (s *StepIOSValidation) AssertTextExists(expectedText string, msg string) *StepIOSValidation { func (s *StepIOSValidation) AssertNameExists(expectedName string, msg string) *StepIOSValidation {
v := Validator{ v := Validator{
Check: "ios_ui", Check: "UI",
Assert: "text_exists", Assert: "name_exists",
Expect: expectedText, Expect: expectedName,
Message: msg,
}
s.step.Validators = append(s.step.Validators, v)
return s
}
func (s *StepIOSValidation) AssertNameNotExists(expectedName string, msg string) *StepIOSValidation {
v := Validator{
Check: "UI",
Assert: "name_not_exists",
Expect: expectedName,
Message: msg,
}
s.step.Validators = append(s.step.Validators, v)
return s
}
func (s *StepIOSValidation) AssertXpathExists(expectedXpath string, msg string) *StepIOSValidation {
v := Validator{
Check: "UI",
Assert: "xpath_exists",
Expect: expectedXpath,
Message: msg,
}
s.step.Validators = append(s.step.Validators, v)
return s
}
func (s *StepIOSValidation) AssertXpathNotExists(expectedXpath string, msg string) *StepIOSValidation {
v := Validator{
Check: "UI",
Assert: "xpath_not_exists",
Expect: expectedXpath,
Message: msg, Message: msg,
} }
s.step.Validators = append(s.step.Validators, v) s.step.Validators = append(s.step.Validators, v)
@@ -282,9 +316,14 @@ func runStepIOS(r *SessionRunner, step *TStep) (stepResult *StepResult, err erro
} }
} }
// do validation // validate
// step.Validators validateResults, err := wdaClient.doValidation(step.Validators)
if err != nil {
return
}
sessionData := newSessionData()
sessionData.Validators = validateResults
stepResult.Data = sessionData
stepResult.Success = true stepResult.Success = true
return stepResult, nil return stepResult, nil
} }
@@ -314,11 +353,21 @@ func (w *wdaClient) doAction(action MobileAction) error {
} }
return w.Driver.Tap(location[0], location[1]) return w.Driver.Tap(location[0], location[1])
} }
// click on xpath // click on name or xpath
if xpath, ok := action.Params.(string); ok { if param, ok := action.Params.(string); ok {
selector := gwda.BySelector{ var selector gwda.BySelector
XPath: xpath, if strings.HasPrefix(param, "/") {
// xpath
selector = gwda.BySelector{
XPath: param,
}
} else {
// name
selector = gwda.BySelector{
Name: param,
}
} }
ele, err := w.Driver.FindElement(selector) ele, err := w.Driver.FindElement(selector)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to find element") return errors.Wrap(err, "failed to find element")
@@ -340,9 +389,9 @@ func (w *wdaClient) doAction(action MobileAction) error {
if direction, ok := action.Params.(string); ok { if direction, ok := action.Params.(string); ok {
switch direction { switch direction {
case "up": case "up":
fromX, fromY, toX, toY = width/2, height*1/4, width/2, height*3/4
case "down":
fromX, fromY, toX, toY = width/2, height*3/4, width/2, height*1/4 fromX, fromY, toX, toY = width/2, height*3/4, width/2, height*1/4
case "down":
fromX, fromY, toX, toY = width/2, height*1/4, width/2, height*3/4
case "left": case "left":
fromX, fromY, toX, toY = width*3/4, height/2, width*1/4, height/2 fromX, fromY, toX, toY = width*3/4, height/2, width*1/4, height/2
case "right": case "right":
@@ -367,7 +416,74 @@ func (w *wdaClient) doAction(action MobileAction) error {
return nil return nil
} }
func (w *wdaClient) doValidation() error { func (w *wdaClient) doValidation(iValidators []interface{}) (validateResults []*ValidationResult, err error) {
// TODO for _, iValidator := range iValidators {
return errActionNotImplemented validator, ok := iValidator.(Validator)
if !ok {
return nil, errors.New("validator type error")
}
validataResult := &ValidationResult{
Validator: validator,
CheckResult: "fail",
}
// parse check value
if validator.Check != "UI" {
validataResult.CheckResult = "skip"
log.Warn().Interface("validator", validator).Msg("skip validator")
validateResults = append(validateResults, validataResult)
continue
}
expected, ok := validator.Expect.(string)
if !ok {
return nil, errors.New("validator expect should be string")
}
var result bool
switch validator.Assert {
case "xpath_exists":
result = w.assertXpath(expected, true)
case "xpath_not_exists":
result = w.assertXpath(expected, false)
case "name_exists":
result = w.assertName(expected, true)
case "name_not_exists":
result = w.assertName(expected, false)
}
if result {
log.Info().
Str("assert", validator.Assert).
Str("expect", expected).
Msg("validate UI success")
validataResult.CheckResult = "pass"
validateResults = append(validateResults, validataResult)
} else {
log.Error().
Str("assert", validator.Assert).
Str("expect", expected).
Str("msg", validator.Message).
Msg("validate UI failed")
validateResults = append(validateResults, validataResult)
err = errors.New("step validation failed")
}
}
return
}
func (w *wdaClient) assertName(name string, exists bool) bool {
selector := gwda.BySelector{
Name: name,
}
_, err := w.Driver.FindElement(selector)
return exists == (err == nil)
}
func (w *wdaClient) assertXpath(xpath string, exists bool) bool {
selector := gwda.BySelector{
XPath: xpath,
}
_, err := w.Driver.FindElement(selector)
return exists == (err == nil)
} }

View File

@@ -12,8 +12,8 @@ func TestAndroidAction(t *testing.T) {
NewStep("launch douyin"). NewStep("launch douyin").
Android().Serial("xxx").Click("抖音"). Android().Serial("xxx").Click("抖音").
Validate(). Validate().
AssertTextExists("首页", "首页 tab 不存在"). AssertXpathExists("首页", "首页 tab 不存在").
AssertTextExists("消息", "消息 tab 不存在"), AssertXpathExists("消息", "消息 tab 不存在"),
NewStep("swipe up and down"). NewStep("swipe up and down").
Android().Serial("xxx").SwipeUp().SwipeUp().SwipeDown(), Android().Serial("xxx").SwipeUp().SwipeUp().SwipeDown(),
}, },
@@ -27,15 +27,35 @@ func TestAndroidAction(t *testing.T) {
} }
} }
func TestIOSAction(t *testing.T) { func TestIOSSettingsAction(t *testing.T) {
testCase := &TestCase{ testCase := &TestCase{
Config: NewConfig("ios ui action"), Config: NewConfig("ios ui action on Settings"),
TestSteps: []IStep{ TestSteps: []IStep{
NewStep("launch douyin"). NewStep("launch Settings").
IOS().Click("//*[@label='抖音']"). IOS().Click("//*[@label='设置']").
Validate(). Validate().
AssertTextExists("首页", "首页 tab 不存在"). AssertNameExists("飞行模式", "「飞行模式」不存在").
AssertTextExists("消息", "消息 tab 不存在"), AssertNameNotExists("飞行模式2", "「飞行模式2」不存在"),
NewStep("swipe up and down").
IOS().SwipeUp().SwipeUp().SwipeDown(),
},
}
err := NewRunner(t).Run(testCase)
if err != nil {
t.Fatal(err)
}
}
func TestIOSDouyinAction(t *testing.T) {
testCase := &TestCase{
Config: NewConfig("ios ui action on 抖音"),
TestSteps: []IStep{
NewStep("launch douyin").
IOS().Click("//*[@label='抖音']").
Validate().
AssertNameExists("首页", "首页 tab 不存在").
AssertNameExists("消息", "消息 tab 不存在"),
NewStep("swipe up and down"). NewStep("swipe up and down").
IOS().SwipeUp().SwipeUp().SwipeDown(), IOS().SwipeUp().SwipeUp().SwipeDown(),
}, },