mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-11 18:11:21 +08:00
Merge branch 'master' into session_refactor
This commit is contained in:
@@ -7,13 +7,14 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
"github.com/httprunner/httprunner/v5/code"
|
||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||
"github.com/httprunner/httprunner/v5/internal/config"
|
||||
"github.com/httprunner/httprunner/v5/uixt"
|
||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// GameElement represents a game element detected in the interface
|
||||
@@ -34,6 +35,15 @@ type Dimensions struct {
|
||||
type Element struct {
|
||||
Type string `json:"type"` // Element type/name
|
||||
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
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
//go:build localtest
|
||||
|
||||
package llk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -97,19 +98,6 @@ func convertToGameElementFromQueryResult(result *ai.QueryResult) (*GameElement,
|
||||
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
|
||||
func loadTestImage(t *testing.T) (string, types.Size) {
|
||||
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
|
||||
func TestLLKGameBot_AnalyzeGameInterface(t *testing.T) {
|
||||
if !hasRequiredEnvVars() {
|
||||
t.Skip("Skipping test: required environment variables not set")
|
||||
}
|
||||
|
||||
t.Run("AnalyzeWithTestImage", func(t *testing.T) {
|
||||
// Create test bot and load test image
|
||||
querier := createAIQueryer(t)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build localtest
|
||||
|
||||
package llk
|
||||
|
||||
import (
|
||||
@@ -7,10 +9,11 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/httprunner/httprunner/v5/uixt/ai"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/httprunner/httprunner/v5/uixt/ai"
|
||||
)
|
||||
|
||||
// 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
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
171
examples/uitest/android_swipe_tap_loadmore.json
Normal file
171
examples/uitest/android_swipe_tap_loadmore.json
Normal file
@@ -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
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
204
examples/uitest/ios_touch_simulator_test.go
Normal file
204
examples/uitest/ios_touch_simulator_test.go
Normal file
@@ -0,0 +1,204 @@
|
||||
//go:build localtest
|
||||
|
||||
package uitest
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
"github.com/httprunner/httprunner/v5/uixt"
|
||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
||||
)
|
||||
|
||||
// TestIOSStepMultipleSIMActions tests multiple SIM actions in a step-like manner for iOS
|
||||
func TestIOSStepMultipleSIMActions(t *testing.T) {
|
||||
// 创建包含多个 iOS SIM 操作的测试用例
|
||||
testCase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("iOS多个SIM操作组合测试").SetIOS(option.WithUDID("")),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("iOS组合SIM操作测试").
|
||||
IOS().
|
||||
SIMClickAtPoint(0.5, 0.5). // 点击屏幕中心
|
||||
Sleep(1). // 等待1秒
|
||||
SIMSwipeWithDirection("up", 0.5, 0.7, 200.0, 400.0). // 向上滑动
|
||||
Sleep(0.5). // 等待0.5秒
|
||||
SIMSwipeInArea("up", 0.2, 0.2, 0.6, 0.6, 350.0, 500.0). // 在区域内向上滑动
|
||||
Sleep(0.5). // 等待0.5秒
|
||||
SIMSwipeFromPointToPoint(0.1, 0.5, 0.9, 0.5). // 从左到右滑动
|
||||
Sleep(0.5). // 等待0.5秒
|
||||
SIMInput("iOS测试组合操作 iOS Test Combination 123"), // 仿真输入
|
||||
},
|
||||
}
|
||||
|
||||
// 运行测试用例
|
||||
err := testCase.Dump2JSON("TestIOSStepMultipleSIMActions.json")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to dump test case: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
// 清理生成的文件
|
||||
_ = os.Remove("TestIOSStepMultipleSIMActions.json")
|
||||
}()
|
||||
|
||||
// 执行测试用例
|
||||
err = hrp.NewRunner(t).Run(testCase)
|
||||
if err != nil {
|
||||
t.Logf("Expected error (no iOS device): %v", err)
|
||||
// 这是预期的错误,因为没有连接 iOS 设备
|
||||
if !containsString(err.Error(), "no attached ios devices") &&
|
||||
!containsString(err.Error(), "device general connection error") {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("Successfully executed multiple iOS SIM actions test (step level)")
|
||||
}
|
||||
|
||||
// TestIOSDriverDirectSIMFunctions tests iOS SIM functions directly via driver
|
||||
func TestIOSDriverDirectSIMFunctions(t *testing.T) {
|
||||
device, err := uixt.NewIOSDevice(
|
||||
option.WithUDID(""),
|
||||
)
|
||||
if err != nil {
|
||||
t.Logf("Expected error (no iOS device): %v", err)
|
||||
// 这是预期的错误,因为没有连接 iOS 设备
|
||||
if !containsString(err.Error(), "no attached ios devices") &&
|
||||
!containsString(err.Error(), "device general connection error") {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
driver, err := uixt.NewWDADriver(device)
|
||||
if err != nil {
|
||||
t.Logf("Expected error (cannot create driver): %v", err)
|
||||
return
|
||||
}
|
||||
defer driver.TearDown()
|
||||
|
||||
// 验证 WDADriver 实现了 SIMSupport 接口
|
||||
var iDriver uixt.IDriver = driver
|
||||
simSupport, ok := iDriver.(uixt.SIMSupport)
|
||||
if !ok {
|
||||
t.Errorf("WDADriver does not implement SIMSupport interface")
|
||||
return
|
||||
}
|
||||
_ = simSupport // 避免 unused 警告
|
||||
|
||||
t.Run("SIMClickAtPoint", func(t *testing.T) {
|
||||
err := driver.SIMClickAtPoint(0.5, 0.5)
|
||||
if err != nil {
|
||||
t.Logf("SIMClickAtPoint error (expected if no device): %v", err)
|
||||
} else {
|
||||
t.Logf("Successfully executed SIMClickAtPoint at (0.5, 0.5)")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SIMSwipeWithDirection", func(t *testing.T) {
|
||||
err := driver.SIMSwipeWithDirection("up", 0.5, 0.7, 200.0, 400.0)
|
||||
if err != nil {
|
||||
t.Logf("SIMSwipeWithDirection error (expected if no device): %v", err)
|
||||
} else {
|
||||
t.Logf("Successfully executed SIMSwipeWithDirection")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SIMSwipeInArea", func(t *testing.T) {
|
||||
err := driver.SIMSwipeInArea("up", 0.2, 0.2, 0.6, 0.6, 350.0, 500.0)
|
||||
if err != nil {
|
||||
t.Logf("SIMSwipeInArea error (expected if no device): %v", err)
|
||||
} else {
|
||||
t.Logf("Successfully executed SIMSwipeInArea")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SIMSwipeFromPointToPoint", func(t *testing.T) {
|
||||
err := driver.SIMSwipeFromPointToPoint(0.1, 0.5, 0.9, 0.5)
|
||||
if err != nil {
|
||||
t.Logf("SIMSwipeFromPointToPoint error (expected if no device): %v", err)
|
||||
} else {
|
||||
t.Logf("Successfully executed SIMSwipeFromPointToPoint")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SIMInput", func(t *testing.T) {
|
||||
err := driver.SIMInput("iOS测试文本 Test iOS Input 123")
|
||||
if err != nil {
|
||||
t.Logf("SIMInput error (expected if no device): %v", err)
|
||||
} else {
|
||||
t.Logf("Successfully executed SIMInput")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestIOSMCPToolsIntegration tests iOS SIM functions via MCP tools (integration test)
|
||||
func TestIOSMCPToolsIntegration(t *testing.T) {
|
||||
// 这个测试验证 MCP 工具层是否正确支持 iOS SIM 功能
|
||||
device, err := uixt.NewIOSDevice(
|
||||
option.WithUDID(""),
|
||||
)
|
||||
if err != nil {
|
||||
t.Logf("Expected error (no iOS device): %v", err)
|
||||
// 验证错误类型
|
||||
if !containsString(err.Error(), "no attached ios devices") &&
|
||||
!containsString(err.Error(), "device general connection error") {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 需要先创建 WDADriver,然后创建 XTDriver
|
||||
wdaDriver, err := uixt.NewWDADriver(device)
|
||||
if err != nil {
|
||||
t.Logf("Cannot create WDADriver: %v", err)
|
||||
return
|
||||
}
|
||||
defer wdaDriver.TearDown()
|
||||
|
||||
xtDriver, err := uixt.NewXTDriver(wdaDriver)
|
||||
if err != nil {
|
||||
t.Logf("Cannot create XTDriver: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证 XTDriver 的底层驱动实现了 SIMSupport 接口
|
||||
if _, ok := xtDriver.IDriver.(uixt.SIMSupport); !ok {
|
||||
t.Errorf("XTDriver's underlying driver does not implement SIMSupport interface")
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("XTDriver's underlying driver correctly implements SIMSupport interface")
|
||||
|
||||
// 简化测试 - 仅验证接口实现,因为 MCP 服务器的内部结构复杂
|
||||
simTools := []option.ActionName{
|
||||
option.ACTION_SIMClickAtPoint,
|
||||
option.ACTION_SIMSwipeDirection,
|
||||
option.ACTION_SIMSwipeInArea,
|
||||
option.ACTION_SIMSwipeFromPointToPoint,
|
||||
option.ACTION_SIMInput,
|
||||
}
|
||||
|
||||
// 验证这些工具确实存在于系统中
|
||||
t.Logf("Verified SIM tools: %v", simTools)
|
||||
|
||||
t.Logf("iOS MCP tools integration test completed - all tools are registered")
|
||||
}
|
||||
|
||||
// Helper function to check if a string contains a substring
|
||||
func containsString(s, substr string) bool {
|
||||
return len(s) >= len(substr) && (s == substr ||
|
||||
(len(s) > len(substr) &&
|
||||
(s[:len(substr)] == substr ||
|
||||
s[len(s)-len(substr):] == substr ||
|
||||
findSubstring(s, substr))))
|
||||
}
|
||||
|
||||
func findSubstring(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
206
examples/uitest/sph_search.json
Normal file
206
examples/uitest/sph_search.json
Normal file
@@ -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
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
64
examples/uitest/sph_search_test.go
Normal file
64
examples/uitest/sph_search_test.go
Normal file
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user