mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-14 11:57:36 +08:00
Merge pull request #1587 from httprunner/fix-android-ui
feat: add validator AssertAppInForeground and AssertAppNotInForeground feat: save screenshots of all steps including ocr and cv recognition process data
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Release History
|
||||
|
||||
## v4.3.3 (2023-04-14)
|
||||
## v4.3.3 (2023-04-18)
|
||||
|
||||
**go version**
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
- feat: add adb `screencap` sub command
|
||||
- feat: add `IsAppInForeground` to check if the given package is in foreground
|
||||
- feat: check if app is in foreground when step failed
|
||||
- feat: add validator AssertAppInForeground and AssertAppNotInForeground
|
||||
- feat: save screenshots of all steps including ocr and cv recognition process data
|
||||
- fix: adb driver for TapFloat
|
||||
- fix: stop logcat only when enabled
|
||||
- fix: do not fail case when kill logcat error
|
||||
- fix: take screenshot after each step
|
||||
- fix: screencap compatibility for shell v1 and v2
|
||||
- fix: screencap compatibility for shell v1 and v2 protocol
|
||||
|
||||
## v4.3.2 (2022-12-26)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
config:
|
||||
name: basic test with httpbin
|
||||
base_url: http://httpbin.org/
|
||||
base_url: https://httpbin.org/
|
||||
|
||||
teststeps:
|
||||
-
|
||||
|
||||
@@ -5,7 +5,7 @@ from httprunner import HttpRunner, Config, Step, RunRequest
|
||||
|
||||
class TestCaseValidate(HttpRunner):
|
||||
|
||||
config = Config("basic test with httpbin").base_url("http://httpbin.org/")
|
||||
config = Config("basic test with httpbin").base_url("https://httpbin.org/")
|
||||
|
||||
teststeps = [
|
||||
Step(
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
//go:build localtest
|
||||
|
||||
package uitest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp"
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
|
||||
)
|
||||
|
||||
func TestAndroidDouYinLive(t *testing.T) {
|
||||
testCase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("通过 feed 头像进入抖音直播间").
|
||||
SetAndroid(uixt.WithUIA2(false), uixt.WithAdbLogOn(true)),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("启动抖音").
|
||||
Android().
|
||||
Home().
|
||||
AppTerminate("com.ss.android.ugc.aweme"). // 关闭已运行的抖音,确保启动抖音后在「抖音」首页
|
||||
SwipeToTapApp("抖音", uixt.WithMaxRetryTimes(5)).
|
||||
Sleep(10),
|
||||
hrp.NewStep("处理青少年弹窗").
|
||||
Android().
|
||||
Tap("推荐").
|
||||
TapByOCR("我知道了", uixt.WithIgnoreNotFoundError(true)).
|
||||
Validate().
|
||||
AssertOCRExists("首页", "抖音启动失败,「首页」不存在"),
|
||||
hrp.NewStep("在推荐页上划,直到出现 feed 头像「直播」").
|
||||
Android().
|
||||
SwipeToTapText("直播", uixt.WithMaxRetryTimes(10), uixt.WithIdentifier("进入直播间")),
|
||||
hrp.NewStep("向上滑动,等待 10s").
|
||||
Android().
|
||||
SwipeUp(uixt.WithIdentifier("第一次上划")).Sleep(10).ScreenShot(). // 上划 1 次,等待 10s,截图保存
|
||||
SwipeUp(uixt.WithIdentifier("第二次上划")).Sleep(10).ScreenShot(), // 再上划 1 次,等待 10s,截图保存
|
||||
},
|
||||
}
|
||||
|
||||
runner := hrp.NewRunner(t).SetSaveTests(true)
|
||||
err := runner.Run(testCase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,15 @@
|
||||
"params": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"validate": [
|
||||
{
|
||||
"check": "ui_foreground_app",
|
||||
"assert": "equal",
|
||||
"expect": "com.ss.android.ugc.aweme",
|
||||
"msg": "app [com.ss.android.ugc.aweme] should be in foreground"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "处理青少年弹窗",
|
||||
@@ -102,6 +110,25 @@
|
||||
]
|
||||
},
|
||||
"loops": 10
|
||||
},
|
||||
{
|
||||
"name": "exit",
|
||||
"android": {
|
||||
"actions": [
|
||||
{
|
||||
"method": "app_terminate",
|
||||
"params": "com.ss.android.ugc.aweme"
|
||||
}
|
||||
]
|
||||
},
|
||||
"validate": [
|
||||
{
|
||||
"check": "ui_foreground_app",
|
||||
"assert": "not_equal",
|
||||
"expect": "com.ss.android.ugc.aweme",
|
||||
"msg": "app [com.ss.android.ugc.aweme] should not be in foreground"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -21,7 +21,9 @@ func TestAndroidDouyinFeedTest(t *testing.T) {
|
||||
Android().
|
||||
AppTerminate("com.ss.android.ugc.aweme").
|
||||
AppLaunch("com.ss.android.ugc.aweme").
|
||||
Sleep(10),
|
||||
Sleep(10).
|
||||
Validate().
|
||||
AssertAppInForeground("com.ss.android.ugc.aweme"),
|
||||
hrp.NewStep("处理青少年弹窗").
|
||||
Android().
|
||||
TapByOCR("我知道了", uixt.WithIgnoreNotFoundError(true)),
|
||||
@@ -40,10 +42,15 @@ func TestAndroidDouyinFeedTest(t *testing.T) {
|
||||
Android().
|
||||
SwipeUp().
|
||||
SleepRandom(0, 5, 0.7, 5, 10, 0.3),
|
||||
hrp.NewStep("exit").
|
||||
Android().
|
||||
AppTerminate("com.ss.android.ugc.aweme").
|
||||
Validate().
|
||||
AssertAppNotInForeground("com.ss.android.ugc.aweme"),
|
||||
},
|
||||
}
|
||||
|
||||
if err := testCase.Dump2JSON("demo_feed_random_slide.json"); err != nil {
|
||||
if err := testCase.Dump2JSON("demo_android_feed_swipe.json"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
140
examples/uitest/demo_android_live_swipe.json
Normal file
140
examples/uitest/demo_android_live_swipe.json
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"config": {
|
||||
"name": "点播_抖音_滑动场景_随机间隔_android",
|
||||
"variables": {
|
||||
"device": "${ENV(SerialNumber)}"
|
||||
},
|
||||
"android": [
|
||||
{
|
||||
"serial": "$device"
|
||||
}
|
||||
]
|
||||
},
|
||||
"teststeps": [
|
||||
{
|
||||
"name": "启动抖音",
|
||||
"android": {
|
||||
"actions": [
|
||||
{
|
||||
"method": "app_terminate",
|
||||
"params": "com.ss.android.ugc.aweme"
|
||||
},
|
||||
{
|
||||
"method": "app_launch",
|
||||
"params": "com.ss.android.ugc.aweme"
|
||||
},
|
||||
{
|
||||
"method": "sleep",
|
||||
"params": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"validate": [
|
||||
{
|
||||
"check": "ui_foreground_app",
|
||||
"assert": "equal",
|
||||
"expect": "com.ss.android.ugc.aweme",
|
||||
"msg": "app [com.ss.android.ugc.aweme] should be in foreground"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "处理青少年弹窗",
|
||||
"android": {
|
||||
"actions": [
|
||||
{
|
||||
"method": "tap_ocr",
|
||||
"params": "我知道了",
|
||||
"ignore_NotFoundError": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "在推荐页上划,直到出现「点击进入直播间」",
|
||||
"android": {
|
||||
"actions": [
|
||||
{
|
||||
"method": "swipe_to_tap_text",
|
||||
"params": "点击进入直播间",
|
||||
"identifier": "进入直播间",
|
||||
"max_retry_times": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "滑动 Feed 5 次,60% 随机间隔 0-5s,40% 随机间隔 5-10s",
|
||||
"android": {
|
||||
"actions": [
|
||||
{
|
||||
"method": "swipe",
|
||||
"params": "up"
|
||||
},
|
||||
{
|
||||
"method": "sleep_random",
|
||||
"params": [
|
||||
0,
|
||||
5,
|
||||
0.6,
|
||||
5,
|
||||
10,
|
||||
0.4
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"loops": 5
|
||||
},
|
||||
{
|
||||
"name": "向上滑动,等待 10s",
|
||||
"android": {
|
||||
"actions": [
|
||||
{
|
||||
"method": "swipe",
|
||||
"params": "up",
|
||||
"identifier": "第一次上划"
|
||||
},
|
||||
{
|
||||
"method": "sleep",
|
||||
"params": 10
|
||||
},
|
||||
{
|
||||
"method": "screenshot"
|
||||
},
|
||||
{
|
||||
"method": "swipe",
|
||||
"params": "up",
|
||||
"identifier": "第二次上划"
|
||||
},
|
||||
{
|
||||
"method": "sleep",
|
||||
"params": 10
|
||||
},
|
||||
{
|
||||
"method": "screenshot"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "exit",
|
||||
"android": {
|
||||
"actions": [
|
||||
{
|
||||
"method": "app_terminate",
|
||||
"params": "com.ss.android.ugc.aweme"
|
||||
}
|
||||
]
|
||||
},
|
||||
"validate": [
|
||||
{
|
||||
"check": "ui_foreground_app",
|
||||
"assert": "not_equal",
|
||||
"expect": "com.ss.android.ugc.aweme",
|
||||
"msg": "app [com.ss.android.ugc.aweme] should not be in foreground"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
59
examples/uitest/demo_android_live_swipe_test.go
Normal file
59
examples/uitest/demo_android_live_swipe_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
//go:build localtest
|
||||
|
||||
package uitest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp"
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
|
||||
)
|
||||
|
||||
func TestAndroidLiveSwipeTest(t *testing.T) {
|
||||
testCase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("点播_抖音_滑动场景_随机间隔_android").
|
||||
WithVariables(map[string]interface{}{
|
||||
"device": "${ENV(SerialNumber)}",
|
||||
}).
|
||||
SetAndroid(uixt.WithSerialNumber("$device")),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("启动抖音").
|
||||
Android().
|
||||
AppTerminate("com.ss.android.ugc.aweme").
|
||||
AppLaunch("com.ss.android.ugc.aweme").
|
||||
Sleep(5).
|
||||
Validate().
|
||||
AssertAppInForeground("com.ss.android.ugc.aweme"),
|
||||
hrp.NewStep("处理青少年弹窗").
|
||||
Android().
|
||||
TapByOCR("我知道了", uixt.WithIgnoreNotFoundError(true)),
|
||||
hrp.NewStep("在推荐页上划,直到出现「点击进入直播间」").
|
||||
Android().
|
||||
SwipeToTapText("点击进入直播间", uixt.WithMaxRetryTimes(10), uixt.WithIdentifier("进入直播间")),
|
||||
hrp.NewStep("滑动 Feed 5 次,60% 随机间隔 0-5s,40% 随机间隔 5-10s").
|
||||
Loop(5).
|
||||
Android().
|
||||
SwipeUp().
|
||||
SleepRandom(0, 5, 0.6, 5, 10, 0.4),
|
||||
hrp.NewStep("向上滑动,等待 10s").
|
||||
Android().
|
||||
SwipeUp(uixt.WithIdentifier("第一次上划")).Sleep(10).ScreenShot(). // 上划 1 次,等待 10s,截图保存
|
||||
SwipeUp(uixt.WithIdentifier("第二次上划")).Sleep(10).ScreenShot(), // 再上划 1 次,等待 10s,截图保存
|
||||
hrp.NewStep("exit").
|
||||
Android().
|
||||
AppTerminate("com.ss.android.ugc.aweme").
|
||||
Validate().
|
||||
AssertAppNotInForeground("com.ss.android.ugc.aweme"),
|
||||
},
|
||||
}
|
||||
|
||||
if err := testCase.Dump2JSON("demo_android_live_swipe.json"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
runner := hrp.NewRunner(t).SetSaveTests(true)
|
||||
err := runner.Run(testCase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -45,10 +45,7 @@ func TestIOSDouyinLive(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
if err := testCase.Dump2JSON("demo_douyin_live.json"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := testCase.Dump2YAML("demo_douyin_live.yaml"); err != nil {
|
||||
if err := testCase.Dump2JSON("demo_ios_live_swipe.json"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -150,11 +150,7 @@ func NewWorldCupLive(device uixt.Device, matchName, bundleID string, duration, i
|
||||
|
||||
func (wc *WorldCupLive) getCurrentLiveTime(utcTime time.Time) error {
|
||||
utcTimeStr := utcTime.Format("15:04:05")
|
||||
fileName := filepath.Join(
|
||||
wc.resultDir, "screenshot", utcTimeStr)
|
||||
ocrTexts, err := wc.driver.GetTextsByOCR(
|
||||
uixt.WithScreenShot(fileName),
|
||||
)
|
||||
ocrTexts, err := wc.driver.GetTextsByOCR()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("get ocr texts failed")
|
||||
return err
|
||||
|
||||
6
go.mod
6
go.mod
@@ -22,7 +22,7 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/rs/zerolog v1.28.0
|
||||
github.com/rs/zerolog v1.29.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/spf13/cobra v1.5.0
|
||||
@@ -56,7 +56,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
@@ -75,7 +75,7 @@ require (
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sync v0.0.0-20220907140024-f12130a52804 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
|
||||
14
go.sum
14
go.sum
@@ -89,7 +89,7 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -301,8 +301,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
@@ -370,8 +371,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
||||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
||||
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
@@ -626,8 +627,9 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -10,7 +10,7 @@ func TestBoomerStandaloneRun(t *testing.T) {
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
testcase1 := &TestCase{
|
||||
Config: NewConfig("TestCase1").SetBaseURL("http://httpbin.org"),
|
||||
Config: NewConfig("TestCase1").SetBaseURL("https://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("headers").
|
||||
GET("/headers").
|
||||
|
||||
@@ -3,9 +3,10 @@ package adb
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||
)
|
||||
|
||||
var screencapAndroidDevicesCmd = &cobra.Command{
|
||||
@@ -22,7 +23,7 @@ var screencapAndroidDevicesCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
filepath := fmt.Sprintf("screencap_%d.png", time.Now().Unix())
|
||||
filepath := fmt.Sprintf("%s.png", builtin.GenNameWithTimestamp("screencap_%d"))
|
||||
if err = ioutil.WriteFile(filepath, res, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -443,3 +443,10 @@ func Sign(ver string, ak string, sk string, body []byte) string {
|
||||
signResult := sha256HMAC(signKey, body)
|
||||
return fmt.Sprintf("%v/%v", signKeyInfo, string(signResult))
|
||||
}
|
||||
|
||||
func GenNameWithTimestamp(tmpl string) string {
|
||||
if !strings.Contains(tmpl, "%d") {
|
||||
tmpl = tmpl + "_%d"
|
||||
}
|
||||
return fmt.Sprintf(tmpl, time.Now().Unix())
|
||||
}
|
||||
|
||||
@@ -124,8 +124,9 @@ var errorsMap = map[error]int{
|
||||
AndroidCaptureLogError: 66,
|
||||
|
||||
// UI automation related
|
||||
MobileUIDriverError: 70,
|
||||
MobileUIValidationError: 75,
|
||||
MobileUIDriverError: 70,
|
||||
MobileUIValidationError: 75,
|
||||
MobileUIAppNotInForegroundError: 76,
|
||||
|
||||
// OCR related
|
||||
OCREnvMissedError: 80,
|
||||
|
||||
@@ -1 +1 @@
|
||||
v4.3.3.2304142356
|
||||
v4.3.3.2304181958
|
||||
@@ -24,7 +24,7 @@ func TestLoadCurlCase(t *testing.T) {
|
||||
if !assert.EqualValues(t, "GET", tCase.TestSteps[0].Request.Method) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.Equal(t, "http://httpbin.org", tCase.TestSteps[0].Request.URL) {
|
||||
if !assert.Equal(t, "https://httpbin.org", tCase.TestSteps[0].Request.URL) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||
)
|
||||
|
||||
type DeviceFileInfo struct {
|
||||
@@ -538,7 +540,7 @@ func (d *Device) InstallAPK(apk io.ReadSeeker) (string, error) {
|
||||
return string(raw), err
|
||||
}
|
||||
|
||||
remote := fmt.Sprintf("/data/local/tmp/gadb_remote_%d.apk", time.Now().Unix())
|
||||
remote := fmt.Sprintf("/data/local/tmp/%s.apk", builtin.GenNameWithTimestamp("gadb_remote_%d"))
|
||||
err := d.Push(apk, remote, time.Now())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error pushing: %v", err)
|
||||
|
||||
@@ -368,6 +368,7 @@ func (ad *adbDriver) IsAppInForeground(packageName string) (bool, error) {
|
||||
// adb shell dumpsys activity activities | grep mResumedActivity
|
||||
output, err := ad.adbClient.RunShellCommand("dumpsys", "activity", "activities")
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to dumpsys activities")
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
||||
@@ -41,10 +41,15 @@ const (
|
||||
RecordStop MobileMethod = "record_stop"
|
||||
|
||||
// UI validation
|
||||
SelectorName string = "ui_name"
|
||||
SelectorLabel string = "ui_label"
|
||||
SelectorOCR string = "ui_ocr"
|
||||
SelectorImage string = "ui_image"
|
||||
// selectors
|
||||
SelectorName string = "ui_name"
|
||||
SelectorLabel string = "ui_label"
|
||||
SelectorOCR string = "ui_ocr"
|
||||
SelectorImage string = "ui_image"
|
||||
SelectorForegroundApp string = "ui_foreground_app"
|
||||
// assertions
|
||||
AssertionEqual string = "equal"
|
||||
AssertionNotEqual string = "not_equal"
|
||||
AssertionExists string = "exists"
|
||||
AssertionNotExists string = "not_exists"
|
||||
|
||||
@@ -212,7 +217,7 @@ type DriverExt struct {
|
||||
doneMjpegStream chan bool
|
||||
scale float64
|
||||
ocrService OCRService // used to get text from image
|
||||
ScreenShots []string // save screenshots path
|
||||
screenShots []string // cache screenshot paths
|
||||
|
||||
CVArgs
|
||||
}
|
||||
@@ -248,7 +253,9 @@ func NewDriverExt(device Device, driver WebDriver) (dExt *DriverExt, err error)
|
||||
return dExt, nil
|
||||
}
|
||||
|
||||
func (dExt *DriverExt) takeScreenShot() (raw *bytes.Buffer, err error) {
|
||||
// TakeScreenShot takes screenshot and saves image file to $CWD/screenshots/ folder
|
||||
// if fileName is empty, it will not save image file and only return raw image data
|
||||
func (dExt *DriverExt) TakeScreenShot(fileName ...string) (raw *bytes.Buffer, err error) {
|
||||
// wait for action done
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
@@ -258,15 +265,34 @@ func (dExt *DriverExt) takeScreenShot() (raw *bytes.Buffer, err error) {
|
||||
return dExt.frame, nil
|
||||
}
|
||||
if raw, err = dExt.Driver.Screenshot(); err != nil {
|
||||
log.Error().Err(err).Msg("takeScreenShot failed")
|
||||
log.Error().Err(err).Msg("capture screenshot data failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// save screenshot to file
|
||||
if len(fileName) > 0 && fileName[0] != "" {
|
||||
path := filepath.Join(env.ScreenShotsPath, fileName[0])
|
||||
path, err := dExt.saveScreenShot(raw, path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("save screenshot file failed")
|
||||
return nil, err
|
||||
}
|
||||
dExt.screenShots = append(dExt.screenShots, path)
|
||||
log.Info().Str("path", path).Msg("save screenshot file success")
|
||||
}
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// saveScreenShot saves image file with file name
|
||||
func saveScreenShot(raw *bytes.Buffer, fileName string) (string, error) {
|
||||
img, format, err := image.Decode(raw)
|
||||
func (dExt *DriverExt) saveScreenShot(raw *bytes.Buffer, fileName string) (string, error) {
|
||||
// notice: screenshot data is a stream, so we need to copy it to a new buffer
|
||||
copiedBuffer := &bytes.Buffer{}
|
||||
if _, err := copiedBuffer.Write(raw.Bytes()); err != nil {
|
||||
log.Error().Err(err).Msg("copy screenshot buffer failed")
|
||||
}
|
||||
|
||||
img, format, err := image.Decode(copiedBuffer)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "decode screenshot image failed")
|
||||
}
|
||||
@@ -297,19 +323,11 @@ func saveScreenShot(raw *bytes.Buffer, fileName string) (string, error) {
|
||||
return screenshotPath, nil
|
||||
}
|
||||
|
||||
// ScreenShot takes screenshot and saves image file to $CWD/screenshots/ folder
|
||||
func (dExt *DriverExt) ScreenShot(fileName string) (string, error) {
|
||||
raw, err := dExt.takeScreenShot()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "screenshot failed")
|
||||
}
|
||||
|
||||
fileName = filepath.Join(env.ScreenShotsPath, fileName)
|
||||
path, err := saveScreenShot(raw, fileName)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "save screenshot failed")
|
||||
}
|
||||
return path, nil
|
||||
func (dExt *DriverExt) GetScreenShots() []string {
|
||||
defer func() {
|
||||
dExt.screenShots = nil
|
||||
}()
|
||||
return dExt.screenShots
|
||||
}
|
||||
|
||||
// isPathExists returns true if path exists, whether path is file or dir
|
||||
@@ -349,6 +367,16 @@ func (dExt *DriverExt) IsImageExist(text string) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (dExt *DriverExt) IsAppInForeground(packageName string) bool {
|
||||
// check if app is in foreground
|
||||
yes, err := dExt.Driver.IsAppInForeground(packageName)
|
||||
if !yes || err != nil {
|
||||
log.Info().Str("packageName", packageName).Msg("app is not in foreground")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var errActionNotImplemented = errors.New("UI action not implemented")
|
||||
|
||||
func convertToFloat64(val interface{}) (float64, error) {
|
||||
@@ -674,15 +702,9 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
}
|
||||
}
|
||||
case CtlScreenShot:
|
||||
// take snapshot
|
||||
log.Info().Msg("take snapshot for current screen")
|
||||
screenshotPath, err := dExt.ScreenShot(fmt.Sprintf("screenshot_%d",
|
||||
time.Now().Unix()))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "take screenshot failed")
|
||||
}
|
||||
log.Info().Str("path", screenshotPath).Msg("take screenshot")
|
||||
dExt.ScreenShots = append(dExt.ScreenShots, screenshotPath)
|
||||
// take screenshot
|
||||
log.Info().Msg("take screenshot for current screen")
|
||||
_, err := dExt.TakeScreenShot(builtin.GenNameWithTimestamp("screenshot_%d"))
|
||||
return err
|
||||
case CtlStartCamera:
|
||||
return dExt.Driver.StartCamera()
|
||||
@@ -700,18 +722,20 @@ func (dExt *DriverExt) getAbsScope(x1, y1, x2, y2 float64) (int, int, int, int)
|
||||
}
|
||||
|
||||
func (dExt *DriverExt) DoValidation(check, assert, expected string, message ...string) bool {
|
||||
var exists bool
|
||||
if assert == AssertionExists {
|
||||
exists = true
|
||||
var exp bool
|
||||
if assert == AssertionExists || assert == AssertionEqual {
|
||||
exp = true
|
||||
} else {
|
||||
exists = false
|
||||
exp = false
|
||||
}
|
||||
var result bool
|
||||
switch check {
|
||||
case SelectorOCR:
|
||||
result = (dExt.IsOCRExist(expected) == exists)
|
||||
result = (dExt.IsOCRExist(expected) == exp)
|
||||
case SelectorImage:
|
||||
result = (dExt.IsImageExist(expected) == exists)
|
||||
result = (dExt.IsImageExist(expected) == exp)
|
||||
case SelectorForegroundApp:
|
||||
result = (dExt.IsAppInForeground(expected) == exp)
|
||||
}
|
||||
|
||||
if !result {
|
||||
|
||||
@@ -2,7 +2,6 @@ package uixt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -437,7 +436,6 @@ type DataOptions struct {
|
||||
IgnoreNotFoundError bool // ignore error if target element not found
|
||||
MaxRetryTimes int // max retry times if target element not found
|
||||
Interval float64 // interval between retries in seconds
|
||||
ScreenShotFilename string // turn on screenshot and specify file name
|
||||
}
|
||||
|
||||
type DataOption func(data *DataOptions)
|
||||
@@ -514,16 +512,6 @@ func WithDataWaitTime(sec float64) DataOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithScreenShot(fileName ...string) DataOption {
|
||||
return func(data *DataOptions) {
|
||||
if len(fileName) > 0 {
|
||||
data.ScreenShotFilename = fileName[0]
|
||||
} else {
|
||||
data.ScreenShotFilename = fmt.Sprintf("screenshot_%d", time.Now().Unix())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewDataOptions(options ...DataOption) *DataOptions {
|
||||
dataOptions := &DataOptions{
|
||||
Data: make(map[string]interface{}),
|
||||
|
||||
@@ -175,14 +175,6 @@ func (s *veDEMOCRService) GetTexts(imageBuf *bytes.Buffer, options ...DataOption
|
||||
|
||||
dataOptions := NewDataOptions(options...)
|
||||
|
||||
if dataOptions.ScreenShotFilename != "" {
|
||||
path, err := saveScreenShot(imageBuf, dataOptions.ScreenShotFilename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "save screenshot failed")
|
||||
}
|
||||
log.Debug().Str("path", path).Msg("save screenshot")
|
||||
}
|
||||
|
||||
for _, ocrResult := range ocrResults {
|
||||
rect := image.Rectangle{
|
||||
// ocrResult.Points 顺序:左上 -> 右上 -> 右下 -> 左下
|
||||
@@ -313,8 +305,7 @@ type OCRService interface {
|
||||
|
||||
func (dExt *DriverExt) GetTextsByOCR(options ...DataOption) (texts OCRTexts, err error) {
|
||||
var bufSource *bytes.Buffer
|
||||
if bufSource, err = dExt.takeScreenShot(); err != nil {
|
||||
err = fmt.Errorf("takeScreenShot error: %v", err)
|
||||
if bufSource, err = dExt.TakeScreenShot(builtin.GenNameWithTimestamp("step_%d_ocr")); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -329,8 +320,7 @@ func (dExt *DriverExt) GetTextsByOCR(options ...DataOption) (texts OCRTexts, err
|
||||
|
||||
func (dExt *DriverExt) FindTextByOCR(ocrText string, options ...DataOption) (x, y, width, height float64, err error) {
|
||||
var bufSource *bytes.Buffer
|
||||
if bufSource, err = dExt.takeScreenShot(); err != nil {
|
||||
err = fmt.Errorf("takeScreenShot error: %v", err)
|
||||
if bufSource, err = dExt.TakeScreenShot(builtin.GenNameWithTimestamp("step_%d_ocr")); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -348,8 +338,7 @@ func (dExt *DriverExt) FindTextByOCR(ocrText string, options ...DataOption) (x,
|
||||
|
||||
func (dExt *DriverExt) FindTextsByOCR(ocrTexts []string, options ...DataOption) (points [][]float64, err error) {
|
||||
var bufSource *bytes.Buffer
|
||||
if bufSource, err = dExt.takeScreenShot(); err != nil {
|
||||
err = fmt.Errorf("takeScreenShot error: %v", err)
|
||||
if bufSource, err = dExt.TakeScreenShot(builtin.GenNameWithTimestamp("step_%d_ocr")); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gocv.io/x/gocv"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -101,7 +103,7 @@ func (dExt *DriverExt) FindAllImageRect(search string) (rects []image.Rectangle,
|
||||
if bufSearch, err = getBufFromDisk(search); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if bufSource, err = dExt.takeScreenShot(); err != nil {
|
||||
if bufSource, err = dExt.TakeScreenShot(builtin.GenNameWithTimestamp("step_%d_cv")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -116,7 +118,7 @@ func (dExt *DriverExt) FindImageRectInUIKit(imagePath string, options ...DataOpt
|
||||
if bufSearch, err = getBufFromDisk(imagePath); err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
}
|
||||
if bufSource, err = dExt.takeScreenShot(); err != nil {
|
||||
if bufSource, err = dExt.TakeScreenShot(builtin.GenNameWithTimestamp("step_%d_cv")); err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ func assertRunTestCases(t *testing.T) {
|
||||
refCase := TestCasePath(demoTestCaseWithPluginJSONPath)
|
||||
testcase1 := &TestCase{
|
||||
Config: NewConfig("TestCase1").
|
||||
SetBaseURL("http://httpbin.org"),
|
||||
SetBaseURL("https://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("testcase1-step1").
|
||||
GET("/headers").
|
||||
@@ -77,7 +77,7 @@ func assertRunTestCases(t *testing.T) {
|
||||
AssertEqual("headers.\"Content-Type\"", "application/json", "check http response Content-Type"),
|
||||
NewStep("testcase1-step3").CallRefCase(
|
||||
&TestCase{
|
||||
Config: NewConfig("testcase1-step3-ref-case").SetBaseURL("http://httpbin.org"),
|
||||
Config: NewConfig("testcase1-step3-ref-case").SetBaseURL("https://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("ip").
|
||||
GET("/ip").
|
||||
|
||||
@@ -2,11 +2,11 @@ package hrp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
|
||||
)
|
||||
@@ -468,6 +468,36 @@ func (s *StepMobileUIValidation) AssertImageNotExists(expectedImagePath string,
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *StepMobileUIValidation) AssertAppInForeground(packageName string, msg ...string) *StepMobileUIValidation {
|
||||
v := Validator{
|
||||
Check: uixt.SelectorForegroundApp,
|
||||
Assert: uixt.AssertionEqual,
|
||||
Expect: packageName,
|
||||
}
|
||||
if len(msg) > 0 {
|
||||
v.Message = msg[0]
|
||||
} else {
|
||||
v.Message = fmt.Sprintf("app [%s] should be in foreground", packageName)
|
||||
}
|
||||
s.step.Validators = append(s.step.Validators, v)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *StepMobileUIValidation) AssertAppNotInForeground(packageName string, msg ...string) *StepMobileUIValidation {
|
||||
v := Validator{
|
||||
Check: uixt.SelectorForegroundApp,
|
||||
Assert: uixt.AssertionNotEqual,
|
||||
Expect: packageName,
|
||||
}
|
||||
if len(msg) > 0 {
|
||||
v.Message = msg[0]
|
||||
} else {
|
||||
v.Message = fmt.Sprintf("app [%s] should not be in foreground", packageName)
|
||||
}
|
||||
s.step.Validators = append(s.step.Validators, v)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *StepMobileUIValidation) Name() string {
|
||||
return s.step.Name
|
||||
}
|
||||
@@ -542,7 +572,6 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err
|
||||
Success: false,
|
||||
ContentSize: 0,
|
||||
}
|
||||
screenshots := make([]string, 0)
|
||||
|
||||
// merge step variables with session variables
|
||||
stepVariables, err := s.ParseStepVariables(step.Variables)
|
||||
@@ -572,18 +601,14 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err
|
||||
}
|
||||
|
||||
// take screenshot after each step
|
||||
screenshotPath, err := uiDriver.ScreenShot(
|
||||
fmt.Sprintf("step_%d", time.Now().Unix()))
|
||||
_, err := uiDriver.TakeScreenShot(
|
||||
builtin.GenNameWithTimestamp("step_%d_") + step.Name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("step", step.Name).Msg("take screenshot failed")
|
||||
} else {
|
||||
log.Info().Str("path", screenshotPath).Msg("take screenshot on step finished")
|
||||
screenshots = append(screenshots, screenshotPath)
|
||||
log.Error().Err(err).Str("step", step.Name).Msg("take screenshot failed on step finished")
|
||||
}
|
||||
|
||||
// save attachments
|
||||
screenshots = append(screenshots, uiDriver.ScreenShots...)
|
||||
attachments["screenshots"] = screenshots
|
||||
attachments["screenshots"] = uiDriver.GetScreenShots()
|
||||
stepResult.Attachments = attachments
|
||||
}()
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ func TestRunRequestStatOn(t *testing.T) {
|
||||
if !assert.Greater(t, stat["Total"], int64(1)) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.Less(t, stat["Total"]-summary.Records[0].Elapsed, int64(3)) {
|
||||
if !assert.Less(t, stat["Total"]-summary.Records[0].Elapsed, int64(100)) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ func TestRunCaseWithTimeout(t *testing.T) {
|
||||
testcase1 := &TestCase{
|
||||
Config: NewConfig("TestCase1").
|
||||
SetTimeout(2 * time.Second). // set global timeout to 2s
|
||||
SetBaseURL("http://httpbin.org"),
|
||||
SetBaseURL("https://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("step1").
|
||||
GET("/delay/1").
|
||||
@@ -181,7 +181,7 @@ func TestRunCaseWithTimeout(t *testing.T) {
|
||||
testcase2 := &TestCase{
|
||||
Config: NewConfig("TestCase2").
|
||||
SetTimeout(2 * time.Second). // set global timeout to 2s
|
||||
SetBaseURL("http://httpbin.org"),
|
||||
SetBaseURL("https://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("step1").
|
||||
GET("/delay/3").
|
||||
@@ -198,7 +198,7 @@ func TestRunCaseWithTimeout(t *testing.T) {
|
||||
testcase3 := &TestCase{
|
||||
Config: NewConfig("TestCase3").
|
||||
SetTimeout(2 * time.Second).
|
||||
SetBaseURL("http://httpbin.org"),
|
||||
SetBaseURL("https://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("step2").
|
||||
GET("/delay/3").
|
||||
|
||||
@@ -8,7 +8,7 @@ class TestHttpSession(unittest.TestCase):
|
||||
self.session = HttpSession()
|
||||
|
||||
def test_request_http(self):
|
||||
self.session.request("get", "http://httpbin.org/get")
|
||||
self.session.request("get", "https://httpbin.org/get")
|
||||
address = self.session.data.address
|
||||
self.assertGreater(len(address.server_ip), 0)
|
||||
self.assertEqual(address.server_port, 80)
|
||||
@@ -26,7 +26,7 @@ class TestHttpSession(unittest.TestCase):
|
||||
def test_request_http_allow_redirects(self):
|
||||
self.session.request(
|
||||
"get",
|
||||
"http://httpbin.org/redirect-to?url=https%3A%2F%2Fgithub.com",
|
||||
"https://httpbin.org/redirect-to?url=https%3A%2F%2Fgithub.com",
|
||||
allow_redirects=True,
|
||||
)
|
||||
address = self.session.data.address
|
||||
@@ -50,7 +50,7 @@ class TestHttpSession(unittest.TestCase):
|
||||
def test_request_http_not_allow_redirects(self):
|
||||
self.session.request(
|
||||
"get",
|
||||
"http://httpbin.org/redirect-to?url=https%3A%2F%2Fgithub.com",
|
||||
"https://httpbin.org/redirect-to?url=https%3A%2F%2Fgithub.com",
|
||||
allow_redirects=False,
|
||||
)
|
||||
address = self.session.data.address
|
||||
|
||||
@@ -10,7 +10,7 @@ Then you can write upload test script as below:
|
||||
- test:
|
||||
name: upload file
|
||||
request:
|
||||
url: http://httpbin.org/upload
|
||||
url: https://httpbin.org/upload
|
||||
method: POST
|
||||
headers:
|
||||
Cookie: session=AAA-BBB-CCC
|
||||
@@ -31,7 +31,7 @@ For compatibility, you can also write upload test script in old way:
|
||||
field2: "value2"
|
||||
m_encoder: ${multipart_encoder(file=$file, field1=$field1, field2=$field2)}
|
||||
request:
|
||||
url: http://httpbin.org/upload
|
||||
url: https://httpbin.org/upload
|
||||
method: POST
|
||||
headers:
|
||||
Content-Type: ${multipart_content_type($m_encoder)}
|
||||
@@ -75,7 +75,9 @@ def ensure_upload_ready():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def prepare_upload_step(step: TStep, step_variables: VariablesMapping, functions: FunctionsMapping):
|
||||
def prepare_upload_step(
|
||||
step: TStep, step_variables: VariablesMapping, functions: FunctionsMapping
|
||||
):
|
||||
"""preprocess for upload test
|
||||
replace `upload` info with MultipartEncoder
|
||||
|
||||
@@ -84,7 +86,7 @@ def prepare_upload_step(step: TStep, step_variables: VariablesMapping, functions
|
||||
{
|
||||
"variables": {},
|
||||
"request": {
|
||||
"url": "http://httpbin.org/upload",
|
||||
"url": "https://httpbin.org/upload",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Cookie": "session=AAA-BBB-CCC"
|
||||
|
||||
Reference in New Issue
Block a user