mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-07 08:27:35 +08:00
Merge branch 'master' into bugfix/huangbin/ai_service
This commit is contained in:
@@ -2,11 +2,11 @@ name: Claude Code
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
issue_comment:
|
issue_comment:
|
||||||
types: [created]
|
types: [created, edited]
|
||||||
pull_request_review_comment:
|
pull_request_review_comment:
|
||||||
types: [created]
|
types: [created, edited]
|
||||||
issues:
|
issues:
|
||||||
types: [opened, assigned]
|
types: [opened, assigned, edited]
|
||||||
pull_request_review:
|
pull_request_review:
|
||||||
types: [submitted]
|
types: [submitted]
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ jobs:
|
|||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
- name: Install Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python3 -m pip install --upgrade pip
|
||||||
|
python3 -m pip install funppy httprunner
|
||||||
- name: Build hrp binary
|
- name: Build hrp binary
|
||||||
run: make build
|
run: make build
|
||||||
- name: Run smoketest - run with parameters
|
- name: Run smoketest - run with parameters
|
||||||
|
|||||||
@@ -23,8 +23,14 @@ jobs:
|
|||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
- name: Install Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
- name: Install Python plugin dependencies
|
- name: Install Python plugin dependencies
|
||||||
run: python3 -m pip install funppy
|
run: |
|
||||||
|
python3 -m pip install --upgrade pip
|
||||||
|
python3 -m pip install funppy httprunner
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Run coverage
|
- name: Run coverage
|
||||||
|
|||||||
@@ -45,3 +45,7 @@ dist
|
|||||||
*.egg-info
|
*.egg-info
|
||||||
.python-version
|
.python-version
|
||||||
.pytest_cache
|
.pytest_cache
|
||||||
|
|
||||||
|
# generated go module files in templates
|
||||||
|
internal/scaffold/templates/plugin/go.mod
|
||||||
|
internal/scaffold/templates/plugin/go.sum
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
HttpRunner v5 is a comprehensive testing framework written in Go that supports API testing, load testing, and UI automation across multiple platforms (Android/iOS/Harmony/Browser). The framework integrates LLM technology for intelligent test automation and uses a pure visual-driven approach (OCR/CV/VLM) for UI testing.
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
### Building
|
||||||
|
- `make build` - Build the hrp CLI tool with static linking and embedded version info
|
||||||
|
- `go build -o output/hrp ./cmd/cli` - Alternative build command
|
||||||
|
- `make test` - Run unit tests with race detection
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
- `go test -race -v ./...` - Run all tests with race detection
|
||||||
|
- `go test -v ./tests/...` - Run test suite only
|
||||||
|
- `go test -v ./uixt/...` - Run UI automation tests
|
||||||
|
- `go test -v ./cmd/...` - Run CLI command tests
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
- `go mod tidy` - Clean up dependencies
|
||||||
|
- `gofmt -w .` - Format code
|
||||||
|
- Pre-commit hooks are available in `scripts/` directory
|
||||||
|
|
||||||
|
## Core Architecture
|
||||||
|
|
||||||
|
### Main Components
|
||||||
|
|
||||||
|
**Core Testing Engine**
|
||||||
|
- `runner.go` - Main test runner (HRPRunner, CaseRunner, SessionRunner)
|
||||||
|
- `testcase.go` - Test case definitions and loading (ITestCase interface)
|
||||||
|
- `step.go` - Step definitions and configurations
|
||||||
|
- `step_*.go` - Specific step implementations (request, api, testcase, ui, etc.)
|
||||||
|
|
||||||
|
**Step Types**
|
||||||
|
- `step_request.go` - HTTP/HTTPS requests
|
||||||
|
- `step_api.go` - API calls with parameters
|
||||||
|
- `step_testcase.go` - Nested test cases
|
||||||
|
- `step_websocket.go` - WebSocket communication
|
||||||
|
- `step_ui.go` - UI automation steps
|
||||||
|
- `step_transaction.go` - Transaction grouping
|
||||||
|
- `step_rendezvous.go` - Synchronization points
|
||||||
|
- `step_shell.go` - Shell command execution
|
||||||
|
- `step_function.go` - Custom function calls
|
||||||
|
|
||||||
|
**UI Automation (uixt/)**
|
||||||
|
- `device.go` - Device abstraction interface (IDevice)
|
||||||
|
- `driver.go` - Driver interface and session management
|
||||||
|
- `android_*.go` - Android platform implementation (ADB/UIAutomator2)
|
||||||
|
- `ios_*.go` - iOS platform implementation (WDA)
|
||||||
|
- `harmony_*.go` - HarmonyOS implementation (HDC)
|
||||||
|
- `browser_*.go` - Web browser automation
|
||||||
|
- `ai/` - AI-powered UI interaction (OCR/VLM)
|
||||||
|
|
||||||
|
**CLI Interface (cmd/)**
|
||||||
|
- `root.go` - Root command and global configuration
|
||||||
|
- `run.go` - Test execution
|
||||||
|
- `server.go` - HTTP server mode
|
||||||
|
- `convert.go` - Format conversion utilities
|
||||||
|
- `build.go` - Plugin building
|
||||||
|
- `adb/` - Android device management
|
||||||
|
- `ios/` - iOS device management
|
||||||
|
|
||||||
|
### Plugin System
|
||||||
|
|
||||||
|
The framework supports both Go and Python plugins:
|
||||||
|
- `build.go` - Plugin compilation system
|
||||||
|
- `plugin.go` - Plugin interface definitions
|
||||||
|
- Templates in `internal/scaffold/templates/plugin/`
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
|
||||||
|
- `config.go` - Global configuration
|
||||||
|
- `internal/config/` - Environment and settings management
|
||||||
|
- Environment variables and .env file support
|
||||||
|
|
||||||
|
## Key Design Patterns
|
||||||
|
|
||||||
|
### Interface-Driven Architecture
|
||||||
|
- `ITestCase` interface for different test case sources
|
||||||
|
- `IDevice` interface for multi-platform support
|
||||||
|
- `IDriver` interface for different automation drivers
|
||||||
|
|
||||||
|
### Step-Based Testing
|
||||||
|
- Each test consists of configurable steps
|
||||||
|
- Steps support setup/teardown hooks
|
||||||
|
- Variables and parameters flow between steps
|
||||||
|
|
||||||
|
### Plugin Architecture
|
||||||
|
- Hashicorp go-plugin for Go plugins
|
||||||
|
- Python plugin support via funplugin
|
||||||
|
- Template-based plugin generation
|
||||||
|
|
||||||
|
## Testing Approach
|
||||||
|
|
||||||
|
### Test Formats Supported
|
||||||
|
- YAML/JSON test cases
|
||||||
|
- Go test files
|
||||||
|
- Python pytest integration
|
||||||
|
- HAR, Postman, cURL conversion
|
||||||
|
|
||||||
|
### UI Testing Strategy
|
||||||
|
- Pure visual-driven (no element locators)
|
||||||
|
- OCR/VLM for text recognition
|
||||||
|
- Cross-platform unified API
|
||||||
|
- AI-powered interaction planning
|
||||||
|
|
||||||
|
## Development Guidelines
|
||||||
|
|
||||||
|
### Code Structure
|
||||||
|
- Core framework logic in root directory
|
||||||
|
- Platform-specific implementations in `uixt/`
|
||||||
|
- CLI commands in `cmd/`
|
||||||
|
- Internal utilities in `internal/`
|
||||||
|
- Examples in `examples/`
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
- Go 1.23+ required
|
||||||
|
- Uses Cobra for CLI
|
||||||
|
- Integrates with multiple automation frameworks
|
||||||
|
- LLM integration via CloudWeGo Eino
|
||||||
|
|
||||||
|
### Build Configuration
|
||||||
|
- Static linking for deployment
|
||||||
|
- Version info embedded via ldflags
|
||||||
|
- Cross-platform builds supported
|
||||||
+1
-1
@@ -63,4 +63,4 @@ Copyright © 2017-present debugtalk. Apache-2.0 License.
|
|||||||
* [hrp startproject](hrp_startproject.md) - Create a scaffold project
|
* [hrp startproject](hrp_startproject.md) - Create a scaffold project
|
||||||
* [hrp wiki](hrp_wiki.md) - visit https://httprunner.com
|
* [hrp wiki](hrp_wiki.md) - visit https://httprunner.com
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
+1
-1
@@ -23,4 +23,4 @@ simple utils for android device management
|
|||||||
* [hrp adb install](hrp_adb_install.md) - push package to the device and install them automatically
|
* [hrp adb install](hrp_adb_install.md) - push package to the device and install them automatically
|
||||||
* [hrp adb screencap](hrp_adb_screencap.md) - Start android screen capture
|
* [hrp adb screencap](hrp_adb_screencap.md) - Start android screen capture
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ hrp adb devices [flags]
|
|||||||
|
|
||||||
* [hrp adb](hrp_adb.md) - simple utils for android device management
|
* [hrp adb](hrp_adb.md) - simple utils for android device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ hrp adb install [flags] PACKAGE
|
|||||||
|
|
||||||
* [hrp adb](hrp_adb.md) - simple utils for android device management
|
* [hrp adb](hrp_adb.md) - simple utils for android device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ hrp adb screencap [flags]
|
|||||||
|
|
||||||
* [hrp adb](hrp_adb.md) - simple utils for android device management
|
* [hrp adb](hrp_adb.md) - simple utils for android device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -36,4 +36,4 @@ hrp build $path ... [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -34,4 +34,4 @@ hrp convert $path... [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
+1
-1
@@ -29,4 +29,4 @@ simple utils for ios device management
|
|||||||
* [hrp ios uninstall](hrp_ios_uninstall.md) - uninstall package automatically
|
* [hrp ios uninstall](hrp_ios_uninstall.md) - uninstall package automatically
|
||||||
* [hrp ios xctest](hrp_ios_xctest.md) - run xctest
|
* [hrp ios xctest](hrp_ios_xctest.md) - run xctest
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -26,4 +26,4 @@ hrp ios apps [flags]
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ hrp ios devices [flags]
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ hrp ios install [flags] PACKAGE
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ hrp ios mount [flags]
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -26,4 +26,4 @@ hrp ios ps [flags]
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ hrp ios reboot [flags]
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ hrp ios tunnel [flags]
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -26,4 +26,4 @@ hrp ios uninstall [flags] PACKAGE
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ hrp ios xctest [flags]
|
|||||||
|
|
||||||
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
* [hrp ios](hrp_ios.md) - simple utils for ios device management
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ hrp mcp-server [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ hrp mcphost [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ hrp pytest $path ... [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ hrp report [result_folder] [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
+1
-1
@@ -46,4 +46,4 @@ hrp run $path... [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -30,4 +30,4 @@ hrp server start [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -29,4 +29,4 @@ hrp startproject $project_name [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ hrp wiki [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
* [hrp](hrp.md) - All-in-One Testing Framework for API, UI and Performance
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 28-Jun-2025
|
###### Auto generated by spf13/cobra on 3-Aug-2025
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ type Dimensions struct {
|
|||||||
type Element struct {
|
type Element struct {
|
||||||
Type string `json:"type"` // Element type/name
|
Type string `json:"type"` // Element type/name
|
||||||
Position Position `json:"position"` // Position in grid
|
Position Position `json:"position"` // Position in grid
|
||||||
|
BoundBox BoundBox `json:"boundBox"` // Bounding box coordinates
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoundBox represents bounding box coordinates
|
||||||
|
type BoundBox struct {
|
||||||
|
X float64 `json:"x"` // X coordinate
|
||||||
|
Y float64 `json:"y"` // Y coordinate
|
||||||
|
Width float64 `json:"width"` // Box width
|
||||||
|
Height float64 `json:"height"` // Box height
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position represents grid position
|
// Position represents grid position
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
//go:build localtest
|
||||||
|
|
||||||
package llk
|
package llk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -97,19 +98,6 @@ func convertToGameElementFromQueryResult(result *ai.QueryResult) (*GameElement,
|
|||||||
return &gameElement, nil
|
return &gameElement, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasRequiredEnvVars checks if the required environment variables are set for testing
|
|
||||||
func hasRequiredEnvVars() bool {
|
|
||||||
// Check for OpenAI environment variables
|
|
||||||
if os.Getenv("OPENAI_BASE_URL") != "" && os.Getenv("OPENAI_API_KEY") != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Check for GPT-4O specific environment variables
|
|
||||||
if os.Getenv("OPENAI_GPT_4O_BASE_URL") != "" && os.Getenv("OPENAI_GPT_4O_API_KEY") != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadTestImage loads the test image from testdata
|
// loadTestImage loads the test image from testdata
|
||||||
func loadTestImage(t *testing.T) (string, types.Size) {
|
func loadTestImage(t *testing.T) (string, types.Size) {
|
||||||
screenshot, size, err := builtin.LoadImage("../../../uixt/ai/testdata/llk_1.png")
|
screenshot, size, err := builtin.LoadImage("../../../uixt/ai/testdata/llk_1.png")
|
||||||
@@ -129,10 +117,6 @@ func createAIQueryer(t *testing.T) *ai.Querier {
|
|||||||
|
|
||||||
// TestLLKGameBot_AnalyzeGameInterface comprehensive test for game interface analysis
|
// TestLLKGameBot_AnalyzeGameInterface comprehensive test for game interface analysis
|
||||||
func TestLLKGameBot_AnalyzeGameInterface(t *testing.T) {
|
func TestLLKGameBot_AnalyzeGameInterface(t *testing.T) {
|
||||||
if !hasRequiredEnvVars() {
|
|
||||||
t.Skip("Skipping test: required environment variables not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("AnalyzeWithTestImage", func(t *testing.T) {
|
t.Run("AnalyzeWithTestImage", func(t *testing.T) {
|
||||||
// Create test bot and load test image
|
// Create test bot and load test image
|
||||||
querier := createAIQueryer(t)
|
querier := createAIQueryer(t)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build localtest
|
||||||
|
|
||||||
package llk
|
package llk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,10 +9,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/v5/uixt/ai"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/httprunner/httprunner/v5/uixt/ai"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestLLKSolver tests the LianLianKan solver functionality
|
// TestLLKSolver tests the LianLianKan solver functionality
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
package uitest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
hrp "github.com/httprunner/httprunner/v5"
|
|
||||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAndroidDouyinE2E(t *testing.T) {
|
|
||||||
testCase := &hrp.TestCase{
|
|
||||||
Config: hrp.NewConfig("直播_抖音_端到端时延_android").
|
|
||||||
WithVariables(map[string]interface{}{
|
|
||||||
"device": "${ENV(SerialNumber)}",
|
|
||||||
"ups": "${ENV(LIVEUPLIST)}",
|
|
||||||
}).
|
|
||||||
SetAndroid(
|
|
||||||
option.WithSerialNumber("$device"),
|
|
||||||
option.WithAdbLogOn(true)),
|
|
||||||
TestSteps: []hrp.IStep{
|
|
||||||
hrp.NewStep("启动抖音").
|
|
||||||
Android().
|
|
||||||
AppTerminate("com.ss.android.ugc.aweme").
|
|
||||||
AppLaunch("com.ss.android.ugc.aweme").
|
|
||||||
Home().
|
|
||||||
SwipeToTapApp(
|
|
||||||
"抖音",
|
|
||||||
option.WithMaxRetryTimes(5),
|
|
||||||
option.WithTapOffset(0, -50),
|
|
||||||
).
|
|
||||||
Sleep(20).
|
|
||||||
Validate().
|
|
||||||
AssertOCRExists("推荐", "进入抖音失败"),
|
|
||||||
hrp.NewStep("点击放大镜").
|
|
||||||
Android().
|
|
||||||
TapXY(0.9, 0.08).
|
|
||||||
Sleep(5),
|
|
||||||
hrp.NewStep("输入账号名称").
|
|
||||||
Android().
|
|
||||||
Input("$ups").
|
|
||||||
Sleep(5),
|
|
||||||
hrp.NewStep("点击搜索").
|
|
||||||
Android().
|
|
||||||
TapByOCR("搜索").
|
|
||||||
Sleep(5),
|
|
||||||
hrp.NewStep("端到端采集").Loop(5).
|
|
||||||
Android().
|
|
||||||
TapByOCR(
|
|
||||||
"直播中",
|
|
||||||
option.WithIgnoreNotFoundError(true),
|
|
||||||
option.WithIndex(-1),
|
|
||||||
).
|
|
||||||
EndToEndDelay(option.WithInterval(5), option.WithTimeout(120)).
|
|
||||||
TapByUITypes(option.WithScreenShotUITypes("close")),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := testCase.Dump2JSON("android_e2e_delay_test.json"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
{
|
|
||||||
"config": {
|
|
||||||
"name": "直播_抖音_端到端时延_android",
|
|
||||||
"variables": {
|
|
||||||
"device": "${ENV(SerialNumber)}",
|
|
||||||
"ups": "${ENV(LIVEUPLIST)}"
|
|
||||||
},
|
|
||||||
"android": [
|
|
||||||
{
|
|
||||||
"serial": "$device",
|
|
||||||
"log_on": true,
|
|
||||||
"adb_server_host": "localhost",
|
|
||||||
"adb_server_port": 5037,
|
|
||||||
"uia2_ip": "localhost",
|
|
||||||
"uia2_port": 6790,
|
|
||||||
"uia2_server_package_name": "io.appium.uiautomator2.server",
|
|
||||||
"uia2_server_test_package_name": "io.appium.uiautomator2.server.test"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"teststeps": [
|
|
||||||
{
|
|
||||||
"name": "启动抖音",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "app_terminate",
|
|
||||||
"params": "com.ss.android.ugc.aweme"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "app_launch",
|
|
||||||
"params": "com.ss.android.ugc.aweme"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "抖音",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 5,
|
|
||||||
"tap_offset": [
|
|
||||||
0,
|
|
||||||
-50
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 20
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_ocr",
|
|
||||||
"assert": "exists",
|
|
||||||
"expect": "推荐",
|
|
||||||
"msg": "进入抖音失败"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "点击放大镜",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_xy",
|
|
||||||
"params": [
|
|
||||||
0.9,
|
|
||||||
0.08
|
|
||||||
],
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "输入账号名称",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "input",
|
|
||||||
"params": "$ups",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "点击搜索",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "搜索",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "端到端采集",
|
|
||||||
"loops": 5,
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "直播中",
|
|
||||||
"options": {
|
|
||||||
"index": -1,
|
|
||||||
"ignore_NotFoundError": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "live_e2e",
|
|
||||||
"options": {
|
|
||||||
"interval": 5,
|
|
||||||
"timeout": 120
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "tap_cv",
|
|
||||||
"options": {
|
|
||||||
"screenshot_with_ui_types": [
|
|
||||||
"close"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,409 +0,0 @@
|
|||||||
{
|
|
||||||
"config": {
|
|
||||||
"name": "安卓专家用例",
|
|
||||||
"variables": {
|
|
||||||
"app_name": "抖音",
|
|
||||||
"bundle_id": "com.ss.android.ugc.aweme",
|
|
||||||
"device": "${ENV(SerialNumber)}",
|
|
||||||
"query": "${ENV(query)}"
|
|
||||||
},
|
|
||||||
"android": [
|
|
||||||
{
|
|
||||||
"serial": "$device",
|
|
||||||
"log_on": true,
|
|
||||||
"adb_server_host": "localhost",
|
|
||||||
"adb_server_port": 5037,
|
|
||||||
"uia2": true,
|
|
||||||
"uia2_ip": "localhost",
|
|
||||||
"uia2_port": 6790,
|
|
||||||
"uia2_server_package_name": "io.appium.uiautomator2.server",
|
|
||||||
"uia2_server_test_package_name": "io.appium.uiautomator2.server.test"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"teststeps": [
|
|
||||||
{
|
|
||||||
"name": "app_launch 以及 ui_foreground_app equal 断言",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "app_launch",
|
|
||||||
"params": "$bundle_id"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_foreground_app",
|
|
||||||
"assert": "equal",
|
|
||||||
"expect": "$bundle_id",
|
|
||||||
"msg": "app [$bundle_id] should be in foreground"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "home 以及 swipe_to_tap_app 默认配置",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "$app_name",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "处理弹窗 close_popups 默认配置 以及 ui_ocr exists 断言",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "close_popups",
|
|
||||||
"options": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_ocr",
|
|
||||||
"assert": "exists",
|
|
||||||
"expect": "推荐",
|
|
||||||
"msg": "进入抖音失败"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【直播】feed头像或卡片进房 swipe_to_tap_texts 自定义配置",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_texts",
|
|
||||||
"params": [
|
|
||||||
"直播",
|
|
||||||
"直播中",
|
|
||||||
"点击进入直播间"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_live",
|
|
||||||
"max_retry_times": 50,
|
|
||||||
"interval": 1.5,
|
|
||||||
"direction": [
|
|
||||||
0.5,
|
|
||||||
0.7,
|
|
||||||
0.5,
|
|
||||||
0.3
|
|
||||||
],
|
|
||||||
"scope": [
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
1,
|
|
||||||
0.8
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "sleep 10s",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【直播】swipe 自定义配置 以及 back",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "swipe_coordinate",
|
|
||||||
"params": [
|
|
||||||
0.5,
|
|
||||||
0.7,
|
|
||||||
0.5,
|
|
||||||
0.3
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"identifier": "slide_in_live"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "back"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【搜索】点击放大镜 tap_xy 自定义配置",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_xy",
|
|
||||||
"params": [
|
|
||||||
0.9,
|
|
||||||
0.08
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_search_in_middle_page"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【搜索】输入query词 input",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "input",
|
|
||||||
"params": "$query",
|
|
||||||
"options": {
|
|
||||||
"identifier": "input_query"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【搜索】点击搜索按钮 tap_ocr 自定义配置",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "搜索",
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_search_after_input_query"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "选择直播页签 tap_ocr 默认配置",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "直播",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【生活服务】进入直播间 tap_xy",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_xy",
|
|
||||||
"params": [
|
|
||||||
0.5,
|
|
||||||
0.5
|
|
||||||
],
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【生活服务】点击货架商品 tap_ocr 自定义配置",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_cv",
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_sales_rack",
|
|
||||||
"screenshot_with_ui_types": [
|
|
||||||
"dyhouse",
|
|
||||||
"shoppingbag"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "app_terminate 以及 ui_foreground_app not_equal 断言",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "app_terminate",
|
|
||||||
"params": "$bundle_id"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_foreground_app",
|
|
||||||
"assert": "not_equal",
|
|
||||||
"expect": "$bundle_id",
|
|
||||||
"msg": "app [$bundle_id] should not be in foreground"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "home 以及 swipe_to_tap_app 自定义配置",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "$app_name",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 5,
|
|
||||||
"interval": 1,
|
|
||||||
"tap_offset": [
|
|
||||||
0,
|
|
||||||
-50
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "处理弹窗 close_popups 自定义配置 以及 ui_ocr exists 断言",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "close_popups",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 3,
|
|
||||||
"interval": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_ocr",
|
|
||||||
"assert": "exists",
|
|
||||||
"expect": "推荐",
|
|
||||||
"msg": "进入抖音失败"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "返回主界面,并打开本地时间戳",
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "app_terminate",
|
|
||||||
"params": "$bundle_id"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "local",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 5
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "screeshot 以及 sleep_random",
|
|
||||||
"loops": 3,
|
|
||||||
"android": {
|
|
||||||
"os_type": "android",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "screenshot",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep_random",
|
|
||||||
"params": [
|
|
||||||
1,
|
|
||||||
3
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "起点_安卓_无限流加载耗时",
|
||||||
|
"variables": {
|
||||||
|
"device": "${ENV(SerialNumber)}"
|
||||||
|
},
|
||||||
|
"android": [
|
||||||
|
{
|
||||||
|
"serial": "$device",
|
||||||
|
"log_on": true,
|
||||||
|
"ignore_popup": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"teststeps": [
|
||||||
|
{
|
||||||
|
"name": "杀掉之前清除缓存的进程",
|
||||||
|
"android": {
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"method": "app_terminate",
|
||||||
|
"params": "com.qidian.QDReader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 30
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "冷启动起点读书app",
|
||||||
|
"android": {
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"method": "app_launch",
|
||||||
|
"params": "com.qidian.QDReader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 30
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "进入精选-男生频道",
|
||||||
|
"android":{
|
||||||
|
"actions":[
|
||||||
|
{
|
||||||
|
"method": "tap_ocr",
|
||||||
|
"params": "精选",
|
||||||
|
"offset": [
|
||||||
|
0,
|
||||||
|
-50
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "tap_ocr",
|
||||||
|
"params": "男生"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 7
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "向下滑动,触发加载",
|
||||||
|
"android": {
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"method": "swipe",
|
||||||
|
"params": [
|
||||||
|
0.5,
|
||||||
|
0.8,
|
||||||
|
0.5,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
"steps": 1,
|
||||||
|
"identifier": "xiaoshuo_swip_tab_loadmore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe",
|
||||||
|
"params": [
|
||||||
|
0.5,
|
||||||
|
0.8,
|
||||||
|
0.5,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
"steps": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe",
|
||||||
|
"params": [
|
||||||
|
0.5,
|
||||||
|
0.8,
|
||||||
|
0.5,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
"steps": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe",
|
||||||
|
"params": [
|
||||||
|
0.5,
|
||||||
|
0.8,
|
||||||
|
0.5,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
"steps": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe",
|
||||||
|
"params": [
|
||||||
|
0.5,
|
||||||
|
0.8,
|
||||||
|
0.5,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
"steps": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "返回",
|
||||||
|
"android": {
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"method": "home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_to_tap_app",
|
||||||
|
"params": "local",
|
||||||
|
"offset": [
|
||||||
|
0,
|
||||||
|
-50
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 7
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
package uitest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
hrp "github.com/httprunner/httprunner/v5"
|
|
||||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHarmonyDouyinE2E(t *testing.T) {
|
|
||||||
testCase := &hrp.TestCase{
|
|
||||||
Config: hrp.NewConfig("直播_抖音_端到端时延_harmony").
|
|
||||||
WithVariables(map[string]interface{}{
|
|
||||||
"device": "${ENV(SerialNumber)}",
|
|
||||||
"ups": "${ENV(LIVEUPLIST)}",
|
|
||||||
}).
|
|
||||||
SetHarmony(
|
|
||||||
option.WithConnectKey("$device"),
|
|
||||||
option.WithLogOn(true)),
|
|
||||||
TestSteps: []hrp.IStep{
|
|
||||||
hrp.NewStep("启动抖音").
|
|
||||||
Harmony().
|
|
||||||
AppTerminate("com.ss.hm.ugc.aweme").
|
|
||||||
SwipeToTapApp("com.ss.hm.ugc.aweme").
|
|
||||||
Home().
|
|
||||||
SwipeToTapApp(
|
|
||||||
"抖音",
|
|
||||||
option.WithMaxRetryTimes(5),
|
|
||||||
option.WithTapOffset(0, -50),
|
|
||||||
).
|
|
||||||
Sleep(20).
|
|
||||||
Validate().
|
|
||||||
AssertOCRExists("推荐", "进入抖音失败"),
|
|
||||||
hrp.NewStep("点击放大镜").
|
|
||||||
Harmony().
|
|
||||||
TapXY(0.9, 0.08).
|
|
||||||
Sleep(5),
|
|
||||||
hrp.NewStep("输入账号名称").
|
|
||||||
Harmony().
|
|
||||||
Input("$ups").
|
|
||||||
Sleep(5),
|
|
||||||
hrp.NewStep("点击搜索").
|
|
||||||
Harmony().
|
|
||||||
TapByOCR("搜索").
|
|
||||||
Sleep(5),
|
|
||||||
hrp.NewStep("端到端采集").Loop(5).
|
|
||||||
Harmony().
|
|
||||||
TapByOCR(
|
|
||||||
"直播中",
|
|
||||||
option.WithIgnoreNotFoundError(true),
|
|
||||||
option.WithIndex(-1),
|
|
||||||
).
|
|
||||||
EndToEndDelay(option.WithInterval(5), option.WithTimeout(120)).
|
|
||||||
TapByUITypes(option.WithScreenShotUITypes("close")),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := testCase.Dump2JSON("harmony_e2e_delay_test.json"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := hrp.Run(t, testCase)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
{
|
|
||||||
"config": {
|
|
||||||
"name": "直播_抖音_端到端时延_harmony",
|
|
||||||
"variables": {
|
|
||||||
"device": "${ENV(SerialNumber)}",
|
|
||||||
"ups": "${ENV(LIVEUPLIST)}"
|
|
||||||
},
|
|
||||||
"harmony": [
|
|
||||||
{
|
|
||||||
"connect_key": "$device",
|
|
||||||
"log_on": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"teststeps": [
|
|
||||||
{
|
|
||||||
"name": "启动抖音",
|
|
||||||
"harmony": {
|
|
||||||
"os_type": "harmony",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "app_terminate",
|
|
||||||
"params": "com.ss.hm.ugc.aweme"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "com.ss.hm.ugc.aweme",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "抖音",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 5,
|
|
||||||
"tap_offset": [
|
|
||||||
0,
|
|
||||||
-50
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 20
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_ocr",
|
|
||||||
"assert": "exists",
|
|
||||||
"expect": "推荐",
|
|
||||||
"msg": "进入抖音失败"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "点击放大镜",
|
|
||||||
"harmony": {
|
|
||||||
"os_type": "harmony",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_xy",
|
|
||||||
"params": [
|
|
||||||
0.9,
|
|
||||||
0.08
|
|
||||||
],
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "输入账号名称",
|
|
||||||
"harmony": {
|
|
||||||
"os_type": "harmony",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "input",
|
|
||||||
"params": "$ups",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "点击搜索",
|
|
||||||
"harmony": {
|
|
||||||
"os_type": "harmony",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "搜索",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "端到端采集",
|
|
||||||
"loops": 5,
|
|
||||||
"harmony": {
|
|
||||||
"os_type": "harmony",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "直播中",
|
|
||||||
"options": {
|
|
||||||
"index": -1,
|
|
||||||
"ignore_NotFoundError": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "live_e2e",
|
|
||||||
"options": {
|
|
||||||
"interval": 5,
|
|
||||||
"timeout": 120
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "tap_cv",
|
|
||||||
"options": {
|
|
||||||
"screenshot_with_ui_types": [
|
|
||||||
"close"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,388 +0,0 @@
|
|||||||
{
|
|
||||||
"config": {
|
|
||||||
"name": "iOS 专家用例",
|
|
||||||
"variables": {
|
|
||||||
"app_name": "抖音",
|
|
||||||
"bundle_id": "com.ss.iphone.ugc.Aweme",
|
|
||||||
"device": "${ENV(UDID)}",
|
|
||||||
"query": "${ENV(query)}"
|
|
||||||
},
|
|
||||||
"ios": [
|
|
||||||
{
|
|
||||||
"udid": "$device",
|
|
||||||
"port": 8700,
|
|
||||||
"mjpeg_port": 8800,
|
|
||||||
"log_on": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"teststeps": [
|
|
||||||
{
|
|
||||||
"name": "启动应用程序 app_launch",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "app_launch",
|
|
||||||
"params": "$bundle_id"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "home 以及 swipe_to_tap_app 默认配置",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "$app_name",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "处理弹窗 close_popups 默认配置 以及 ui_ocr exists 断言",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "close_popups",
|
|
||||||
"options": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_ocr",
|
|
||||||
"assert": "exists",
|
|
||||||
"expect": "推荐",
|
|
||||||
"msg": "进入抖音失败"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【直播】feed头像或卡片进房 swipe_to_tap_texts 自定义配置",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_texts",
|
|
||||||
"params": [
|
|
||||||
"直播",
|
|
||||||
"直播中",
|
|
||||||
"点击进入直播间"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_live",
|
|
||||||
"max_retry_times": 50,
|
|
||||||
"interval": 1.5,
|
|
||||||
"direction": [
|
|
||||||
0.5,
|
|
||||||
0.7,
|
|
||||||
0.5,
|
|
||||||
0.3
|
|
||||||
],
|
|
||||||
"scope": [
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
1,
|
|
||||||
0.8
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "sleep 10s",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【直播】swipe 自定义配置 以及 back",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "swipe_coordinate",
|
|
||||||
"params": [
|
|
||||||
0.5,
|
|
||||||
0.7,
|
|
||||||
0.5,
|
|
||||||
0.3
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"identifier": "slide_in_live"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "back"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【搜索】点击放大镜 tap_xy 自定义配置",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_xy",
|
|
||||||
"params": [
|
|
||||||
0.9,
|
|
||||||
0.075
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_search_in_middle_page"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【搜索】输入query词 input",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "input",
|
|
||||||
"params": "$query",
|
|
||||||
"options": {
|
|
||||||
"identifier": "input_query"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【搜索】点击搜索按钮 tap_ocr 自定义配置",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "搜索",
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_search_after_input_query"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "选择直播页签 tap_ocr 默认配置",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_ocr",
|
|
||||||
"params": "直播",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【生活服务】进入直播间 tap_xy",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_xy",
|
|
||||||
"params": [
|
|
||||||
0.5,
|
|
||||||
0.5
|
|
||||||
],
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "【生活服务】点击货架商品 tap_ocr 自定义配置",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "tap_cv",
|
|
||||||
"options": {
|
|
||||||
"identifier": "click_sales_rack",
|
|
||||||
"screenshot_with_ui_types": [
|
|
||||||
"dyhouse",
|
|
||||||
"shoppingbag"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "终止应用程序 app_terminate",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "app_terminate",
|
|
||||||
"params": "$bundle_id"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "home 以及 swipe_to_tap_app 自定义配置",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "$app_name",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 5,
|
|
||||||
"interval": 1,
|
|
||||||
"tap_offset": [
|
|
||||||
0,
|
|
||||||
-50
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "处理弹窗 close_popups 自定义配置 以及 ui_ocr exists 断言",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "close_popups",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 3,
|
|
||||||
"interval": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{
|
|
||||||
"check": "ui_ocr",
|
|
||||||
"assert": "exists",
|
|
||||||
"expect": "推荐",
|
|
||||||
"msg": "进入抖音失败"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "返回主界面,并打开本地时间戳",
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "app_terminate",
|
|
||||||
"params": "$bundle_id"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "swipe_to_tap_app",
|
|
||||||
"params": "local",
|
|
||||||
"options": {
|
|
||||||
"max_retry_times": 5
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep",
|
|
||||||
"params": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "screeshot 以及 sleep_random",
|
|
||||||
"loops": 3,
|
|
||||||
"ios": {
|
|
||||||
"os_type": "ios",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"method": "screenshot",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "sleep_random",
|
|
||||||
"params": [
|
|
||||||
1,
|
|
||||||
3
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "视频号搜索",
|
||||||
|
"ai_options": {
|
||||||
|
"llm_service": "doubao-1.5-ui-tars-250328"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"teststeps": [
|
||||||
|
{
|
||||||
|
"name": "启动视频号 app",
|
||||||
|
"android": {
|
||||||
|
"os_type": "android",
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"method": "app_launch",
|
||||||
|
"params": "com.tencent.mm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"validate": [
|
||||||
|
{
|
||||||
|
"check": "ui_foreground_app",
|
||||||
|
"assert": "equal",
|
||||||
|
"expect": "com.tencent.mm",
|
||||||
|
"msg": "app [com.tencent.mm] should be in foreground"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "进入视频号搜索页面",
|
||||||
|
"android": {
|
||||||
|
"os_type": "android",
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"method": "start_to_goal",
|
||||||
|
"params": "进入「发现」页,点击进入「视频号」页面,点击搜索框",
|
||||||
|
"options": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"validate": [
|
||||||
|
{
|
||||||
|
"check": "ui_ai",
|
||||||
|
"assert": "ai_assert",
|
||||||
|
"expect": "当前页面包含搜索框和搜索按钮",
|
||||||
|
"msg": "assert ai prompt [当前页面包含搜索框和搜索按钮] failed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "搜索短剧「$dramaName」",
|
||||||
|
"parameters": {
|
||||||
|
"dramaName": [
|
||||||
|
"督军,你家小福包有祖传乌鸦嘴",
|
||||||
|
"换亲后我顺便换了江山,很合理吧",
|
||||||
|
"穿过荆棘拥抱你",
|
||||||
|
"认亲后,误入帮派成团宠",
|
||||||
|
"欲念疯长",
|
||||||
|
"花轿临门她拒嫁,只盼故人归",
|
||||||
|
"太监武帝,功法自动大圆满",
|
||||||
|
"容先生,你的爱意藏不住了",
|
||||||
|
"回家给娘亲改命,心声咋还泄露了",
|
||||||
|
"相亲遇甜妹,偷娶她闺蜜"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"os_type": "android",
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"method": "start_to_goal",
|
||||||
|
"params": "输入「$dramaName」,点击搜索",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep",
|
||||||
|
"params": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "swipe_direction",
|
||||||
|
"params": "up",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "sleep_random",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package uitest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
hrp "github.com/httprunner/httprunner/v5"
|
||||||
|
"github.com/httprunner/httprunner/v5/uixt/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSPHSearchPage(t *testing.T) {
|
||||||
|
testCase := &hrp.TestCase{
|
||||||
|
Config: hrp.NewConfig("视频号搜索").
|
||||||
|
SetLLMService(option.DOUBAO_1_5_UI_TARS_250328), // Configure LLM service for AI operations
|
||||||
|
TestSteps: []hrp.IStep{
|
||||||
|
hrp.NewStep("启动视频号 app").
|
||||||
|
Android().
|
||||||
|
AppLaunch("com.tencent.mm").
|
||||||
|
Sleep(5).
|
||||||
|
Validate().
|
||||||
|
AssertAppInForeground("com.tencent.mm"),
|
||||||
|
hrp.NewStep("进入视频号搜索页面").
|
||||||
|
Android().
|
||||||
|
StartToGoal("进入「发现」页,点击进入「视频号」页面,点击搜索框").
|
||||||
|
Validate().
|
||||||
|
AssertAI("当前页面包含搜索框和搜索按钮"),
|
||||||
|
hrp.NewStep("搜索短剧「$dramaName」").
|
||||||
|
WithParameters(map[string]interface{}{
|
||||||
|
"dramaName": []string{
|
||||||
|
"督军,你家小福包有祖传乌鸦嘴",
|
||||||
|
"换亲后我顺便换了江山,很合理吧",
|
||||||
|
"穿过荆棘拥抱你",
|
||||||
|
"认亲后,误入帮派成团宠",
|
||||||
|
"欲念疯长",
|
||||||
|
"花轿临门她拒嫁,只盼故人归",
|
||||||
|
"太监武帝,功法自动大圆满",
|
||||||
|
"容先生,你的爱意藏不住了",
|
||||||
|
"回家给娘亲改命,心声咋还泄露了",
|
||||||
|
"相亲遇甜妹,偷娶她闺蜜",
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
Android().
|
||||||
|
StartToGoal("输入「$dramaName」,点击搜索").
|
||||||
|
Sleep(1).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2).
|
||||||
|
SwipeUp().SleepRandom(1, 2),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := testCase.Dump2JSON("sph_search.json")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// err := hrp.NewRunner(t).Run(testCase)
|
||||||
|
// assert.Nil(t, err)
|
||||||
|
}
|
||||||
@@ -610,6 +610,55 @@ func (d *Device) Pull(remotePath string, dest io.Writer) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Device) PullFolder(remotePath string, localPath string) (err error) {
|
||||||
|
// Check if remote path exists and is a directory
|
||||||
|
fileInfos, err := d.List(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to list remote directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create local directory if it doesn't exist
|
||||||
|
if err = os.MkdirAll(localPath, 0o755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create local directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull each file/directory recursively
|
||||||
|
for _, fileInfo := range fileInfos {
|
||||||
|
remoteItemPath := remotePath + "/" + fileInfo.Name
|
||||||
|
localItemPath := localPath + "/" + fileInfo.Name
|
||||||
|
|
||||||
|
if fileInfo.IsDir() {
|
||||||
|
// Recursively pull subdirectory
|
||||||
|
if err = d.PullFolder(remoteItemPath, localItemPath); err != nil {
|
||||||
|
return fmt.Errorf("failed to pull subdirectory %s: %w", remoteItemPath, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pull file
|
||||||
|
if err = d.PullFile(remoteItemPath, localItemPath); err != nil {
|
||||||
|
return fmt.Errorf("failed to pull file %s: %w", remoteItemPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) PullFile(remotePath string, localPath string) (err error) {
|
||||||
|
// Create local file
|
||||||
|
localFile, err := os.Create(localPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create local file: %w", err)
|
||||||
|
}
|
||||||
|
defer localFile.Close()
|
||||||
|
|
||||||
|
// Use existing Pull method to pull file content
|
||||||
|
if err = d.Pull(remotePath, localFile); err != nil {
|
||||||
|
return fmt.Errorf("failed to pull file content: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Device) installViaABBExec(apk io.ReadSeeker, args ...string) (raw []byte, err error) {
|
func (d *Device) installViaABBExec(apk io.ReadSeeker, args ...string) (raw []byte, err error) {
|
||||||
var (
|
var (
|
||||||
tp transport
|
tp transport
|
||||||
|
|||||||
@@ -296,6 +296,17 @@ func TestDevice_Pull(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDevice_PullFolder(t *testing.T) {
|
||||||
|
setupDevices(t)
|
||||||
|
|
||||||
|
for _, dev := range devices {
|
||||||
|
err := dev.PullFolder("/storage/emulated/0/Download/", "/tmp/test/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_ScreenRecord(t *testing.T) {
|
func TestDevice_ScreenRecord(t *testing.T) {
|
||||||
setupDevices(t)
|
setupDevices(t)
|
||||||
|
|
||||||
|
|||||||
+2
-22
@@ -1,8 +1,9 @@
|
|||||||
|
//go:build localtest
|
||||||
|
|
||||||
package ai
|
package ai
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||||
@@ -11,24 +12,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// hasRequiredEnvVars checks if the required environment variables are set for testing
|
|
||||||
func hasRequiredEnvVars() bool {
|
|
||||||
// Check for OpenAI environment variables
|
|
||||||
if os.Getenv("OPENAI_BASE_URL") != "" && os.Getenv("OPENAI_API_KEY") != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Check for GPT-4O specific environment variables
|
|
||||||
if os.Getenv("OPENAI_GPT_4O_BASE_URL") != "" && os.Getenv("OPENAI_GPT_4O_API_KEY") != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestILLMServiceQuery(t *testing.T) {
|
func TestILLMServiceQuery(t *testing.T) {
|
||||||
// Skip test if required environment variables are not set
|
|
||||||
if !hasRequiredEnvVars() {
|
|
||||||
t.Skip("Skipping test: required environment variables not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create LLM service
|
// Create LLM service
|
||||||
service, err := NewLLMService(option.OPENAI_GPT_4O)
|
service, err := NewLLMService(option.OPENAI_GPT_4O)
|
||||||
@@ -96,10 +80,6 @@ func TestILLMServiceQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestILLMServiceIntegration(t *testing.T) {
|
func TestILLMServiceIntegration(t *testing.T) {
|
||||||
// Skip test if required environment variables are not set
|
|
||||||
if !hasRequiredEnvVars() {
|
|
||||||
t.Skip("Skipping test: required environment variables not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create LLM service
|
// Create LLM service
|
||||||
service, err := NewLLMService(option.OPENAI_GPT_4O)
|
service, err := NewLLMService(option.OPENAI_GPT_4O)
|
||||||
|
|||||||
Reference in New Issue
Block a user