mirror of
https://github.com/httprunner/httprunner.git
synced 2026-08-25 01:59:52 +08:00
refactor: improve validation process by adding variable substitution and enhancing error handling
This commit is contained in:
@@ -1 +1 @@
|
|||||||
v5.0.0-beta-2506182235
|
v5.0.0-beta-2506182314
|
||||||
|
|||||||
@@ -2575,7 +2575,7 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<!-- Enhanced AI Validator Display -->
|
<!-- Enhanced AI Validator Display -->
|
||||||
{{if eq $validator.check "ui_ai"}}
|
{{if or (eq $validator.check "ui_ai") (eq $validator.assert "ai_assert")}}
|
||||||
<div class="validator-ai-content">
|
<div class="validator-ai-content">
|
||||||
<!-- Extract AI validation details from step logs -->
|
<!-- Extract AI validation details from step logs -->
|
||||||
{{$stepLogs := getStepLogs $step}}
|
{{$stepLogs := getStepLogs $step}}
|
||||||
|
|||||||
127
step_ui.go
127
step_ui.go
@@ -852,10 +852,7 @@ func runStepMobileUI(s *SessionRunner, step IStep) (stepResult *StepResult, err
|
|||||||
return stepResult, errors.Wrap(code.InterruptError, "mobile UI runner interrupted")
|
return stepResult, errors.Wrap(code.InterruptError, "mobile UI runner interrupted")
|
||||||
default:
|
default:
|
||||||
actionStartTime := time.Now()
|
actionStartTime := time.Now()
|
||||||
actionResult := &ActionResult{
|
// Parse action params first for variable substitution
|
||||||
MobileAction: action,
|
|
||||||
StartTime: actionStartTime.UnixMilli(), // action 开始时间
|
|
||||||
}
|
|
||||||
if action.Params, err = s.caseRunner.parser.Parse(action.Params, stepVariables); err != nil {
|
if action.Params, err = s.caseRunner.parser.Parse(action.Params, stepVariables); err != nil {
|
||||||
if !code.IsErrorPredefined(err) {
|
if !code.IsErrorPredefined(err) {
|
||||||
err = errors.Wrap(code.ParseError,
|
err = errors.Wrap(code.ParseError,
|
||||||
@@ -864,6 +861,12 @@ func runStepMobileUI(s *SessionRunner, step IStep) (stepResult *StepResult, err
|
|||||||
return stepResult, err
|
return stepResult, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create ActionResult with parsed params for accurate reporting
|
||||||
|
actionResult := &ActionResult{
|
||||||
|
MobileAction: action, // Now contains parsed params
|
||||||
|
StartTime: actionStartTime.UnixMilli(), // action start time
|
||||||
|
}
|
||||||
|
|
||||||
// Apply global configuration from testcase config
|
// Apply global configuration from testcase config
|
||||||
if s.caseRunner != nil && s.caseRunner.Config != nil {
|
if s.caseRunner != nil && s.caseRunner.Config != nil {
|
||||||
config := s.caseRunner.Config.Get()
|
config := s.caseRunner.Config.Get()
|
||||||
@@ -961,55 +964,111 @@ func runStepMobileUI(s *SessionRunner, step IStep) (stepResult *StepResult, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validate
|
// validate
|
||||||
validateResults, err := validateUI(uiDriver, stepValidators)
|
validateResults, err := validateUI(uiDriver, stepValidators, s.caseRunner.parser, stepVariables)
|
||||||
if err != nil {
|
|
||||||
if !code.IsErrorPredefined(err) {
|
|
||||||
err = errors.Wrap(code.MobileUIValidationError, err.Error())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(validateResults) > 0 {
|
if len(validateResults) > 0 {
|
||||||
|
// Always save validation results if any exist, regardless of success or failure
|
||||||
sessionData := &SessionData{
|
sessionData := &SessionData{
|
||||||
Validators: validateResults,
|
Validators: validateResults,
|
||||||
}
|
}
|
||||||
stepResult.Data = sessionData
|
stepResult.Data = sessionData
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
// Handle validation error after saving results
|
||||||
|
if !code.IsErrorPredefined(err) {
|
||||||
|
err = errors.Wrap(code.MobileUIValidationError, err.Error())
|
||||||
|
}
|
||||||
|
return stepResult, err
|
||||||
|
}
|
||||||
|
|
||||||
stepResult.Success = true
|
stepResult.Success = true
|
||||||
return stepResult, nil
|
return stepResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateUI(ud *uixt.XTDriver, iValidators []interface{}) (validateResults []*ValidationResult, err error) {
|
func validateUI(ud *uixt.XTDriver, iValidators []interface{}, parser *Parser, stepVariables map[string]interface{}) (validateResults []*ValidationResult, err error) {
|
||||||
|
// Parse all validators for variable substitution
|
||||||
|
parsedValidators, err := parseStepValidators(iValidators, parser, stepVariables)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute validation for each parsed validator
|
||||||
|
for _, validator := range parsedValidators {
|
||||||
|
// Debug: print validator details
|
||||||
|
log.Debug().
|
||||||
|
Str("check", validator.Check).
|
||||||
|
Str("assert", validator.Assert).
|
||||||
|
Interface("expect", validator.Expect).
|
||||||
|
Str("message", validator.Message).
|
||||||
|
Msg("processing validator")
|
||||||
|
|
||||||
|
validationResult := &ValidationResult{
|
||||||
|
Validator: validator, // Use parsed validator for accurate reporting
|
||||||
|
CheckResult: "fail",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is a UI validator or AI assert validator
|
||||||
|
if !strings.HasPrefix(validator.Check, "ui_") && validator.Assert != "ai_assert" {
|
||||||
|
validationResult.CheckResult = "skip"
|
||||||
|
log.Warn().Interface("validator", validator).Msg("skip validator")
|
||||||
|
validateResults = append(validateResults, validationResult)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate expected value type
|
||||||
|
expected, ok := validator.Expect.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("validator expect should be string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform validation
|
||||||
|
err = ud.DoValidation(validator.Check, validator.Assert, expected, validator.Message)
|
||||||
|
if err != nil {
|
||||||
|
// Add the failed validation result to the list before returning error
|
||||||
|
validateResults = append(validateResults, validationResult)
|
||||||
|
return validateResults, errors.Wrap(err, "step validation failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
validationResult.CheckResult = "pass"
|
||||||
|
validateResults = append(validateResults, validationResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
return validateResults, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseStepValidators parses all validators for variable substitution
|
||||||
|
func parseStepValidators(iValidators []interface{}, parser *Parser, stepVariables map[string]interface{}) ([]Validator, error) {
|
||||||
|
var parsedValidators []Validator
|
||||||
|
|
||||||
for _, iValidator := range iValidators {
|
for _, iValidator := range iValidators {
|
||||||
validator, ok := iValidator.(Validator)
|
validator, ok := iValidator.(Validator)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("validator type error")
|
return nil, errors.New("validator type error")
|
||||||
}
|
}
|
||||||
|
|
||||||
validataResult := &ValidationResult{
|
parsedValidator := validator
|
||||||
Validator: validator,
|
|
||||||
CheckResult: "fail",
|
// Parse Expect field for variable substitution
|
||||||
|
if expectedStr, ok := validator.Expect.(string); ok {
|
||||||
|
if parsedExpected, err := parser.Parse(expectedStr, stepVariables); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to parse validator expect field")
|
||||||
|
} else {
|
||||||
|
parsedValidator.Expect = parsedExpected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse check value
|
// Parse Message field for variable substitution
|
||||||
if !strings.HasPrefix(validator.Check, "ui_") {
|
if validator.Message != "" {
|
||||||
validataResult.CheckResult = "skip"
|
if parsedMessage, err := parser.Parse(validator.Message, stepVariables); err != nil {
|
||||||
log.Warn().Interface("validator", validator).Msg("skip validator")
|
return nil, errors.Wrap(err, "failed to parse validator message field")
|
||||||
validateResults = append(validateResults, validataResult)
|
} else {
|
||||||
continue
|
if msgStr, ok := parsedMessage.(string); ok {
|
||||||
|
parsedValidator.Message = msgStr
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expected, ok := validator.Expect.(string)
|
parsedValidators = append(parsedValidators, parsedValidator)
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("validator expect should be string")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := ud.DoValidation(validator.Check, validator.Assert, expected, validator.Message)
|
|
||||||
if err != nil {
|
|
||||||
return validateResults, errors.Wrap(err, "step validation failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
validataResult.CheckResult = "pass"
|
|
||||||
validateResults = append(validateResults, validataResult)
|
|
||||||
}
|
}
|
||||||
return validateResults, nil
|
|
||||||
|
return parsedValidators, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user