mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-20 23:59:49 +08:00
refactor: improve ActionMethod type safety and eliminate type conversions
This commit is contained in:
@@ -22,17 +22,27 @@ func (r *Router) foregroundAppHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) appInfoHandler(c *gin.Context) {
|
||||
var appInfoReq option.AppInfoRequest
|
||||
if err := c.ShouldBindQuery(&appInfoReq); err != nil {
|
||||
var req option.UnifiedActionRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Set platform and serial from URL parameters
|
||||
setRequestContextFromURL(c, &req)
|
||||
|
||||
// Validate for HTTP API usage
|
||||
if err := req.ValidateForHTTPAPI(option.ACTION_AppInfo); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
device, err := r.GetDevice(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if androidDevice, ok := device.(*uixt.AndroidDevice); ok {
|
||||
appInfo, err := androidDevice.GetAppInfo(appInfoReq.PackageName)
|
||||
appInfo, err := androidDevice.GetAppInfo(req.PackageName)
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -40,7 +50,7 @@ func (r *Router) appInfoHandler(c *gin.Context) {
|
||||
RenderSuccess(c, appInfo)
|
||||
return
|
||||
} else if iOSDevice, ok := device.(*uixt.IOSDevice); ok {
|
||||
appInfo, err := iOSDevice.GetAppInfo(appInfoReq.PackageName)
|
||||
appInfo, err := iOSDevice.GetAppInfo(req.PackageName)
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -51,9 +61,8 @@ func (r *Router) appInfoHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) clearAppHandler(c *gin.Context) {
|
||||
var appClearReq option.AppClearRequest
|
||||
if err := c.ShouldBindJSON(&appClearReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_AppClear)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -61,7 +70,7 @@ func (r *Router) clearAppHandler(c *gin.Context) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = driver.AppClear(appClearReq.PackageName)
|
||||
err = driver.AppClear(req.PackageName)
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -70,16 +79,16 @@ func (r *Router) clearAppHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) launchAppHandler(c *gin.Context) {
|
||||
var appLaunchReq option.AppLaunchRequest
|
||||
if err := c.ShouldBindJSON(&appLaunchReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_AppLaunch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = driver.AppLaunch(appLaunchReq.PackageName)
|
||||
err = driver.AppLaunch(req.PackageName)
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -88,16 +97,16 @@ func (r *Router) launchAppHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) terminalAppHandler(c *gin.Context) {
|
||||
var appTerminateReq option.AppTerminateRequest
|
||||
if err := c.ShouldBindJSON(&appTerminateReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_AppTerminate)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = driver.AppTerminate(appTerminateReq.PackageName)
|
||||
_, err = driver.AppTerminate(req.PackageName)
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -106,16 +115,16 @@ func (r *Router) terminalAppHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) uninstallAppHandler(c *gin.Context) {
|
||||
var appUninstallReq option.AppUninstallRequest
|
||||
if err := c.ShouldBindJSON(&appUninstallReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_AppUninstall)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = driver.GetDevice().Uninstall(appUninstallReq.PackageName)
|
||||
err = driver.GetDevice().Uninstall(req.PackageName)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to uninstall app")
|
||||
}
|
||||
|
||||
@@ -34,19 +34,20 @@ func (r *Router) homeHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) backspaceHandler(c *gin.Context) {
|
||||
var deleteReq option.DeleteRequest
|
||||
if err := c.ShouldBindJSON(&deleteReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_Backspace)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if deleteReq.Count == 0 {
|
||||
deleteReq.Count = 20
|
||||
|
||||
count := req.GetCount()
|
||||
if count == 0 {
|
||||
count = 20
|
||||
}
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = driver.Backspace(deleteReq.Count)
|
||||
err = driver.Backspace(count)
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -55,18 +56,18 @@ func (r *Router) backspaceHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) keycodeHandler(c *gin.Context) {
|
||||
var keycodeReq option.KeycodeRequest
|
||||
if err := c.ShouldBindJSON(&keycodeReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_KeyCode)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// TODO FIXME
|
||||
err = driver.IDriver.(*uixt.ADBDriver).
|
||||
PressKeyCode(uixt.KeyCode(keycodeReq.Keycode), uixt.KMEmpty)
|
||||
PressKeyCode(uixt.KeyCode(req.GetKeycode()), uixt.KMEmpty)
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
|
||||
@@ -33,15 +33,6 @@ type UploadRequest struct {
|
||||
FileFormat string `json:"file_format"`
|
||||
}
|
||||
|
||||
type HoverRequest struct {
|
||||
X float64 `json:"x"`
|
||||
Y float64 `json:"y"`
|
||||
}
|
||||
|
||||
type ScrollRequest struct {
|
||||
Delta int `json:"delta"`
|
||||
}
|
||||
|
||||
type CreateBrowserRequest struct {
|
||||
Timeout int `json:"timeout"`
|
||||
Width int `json:"width"`
|
||||
|
||||
104
server/ui.go
104
server/ui.go
@@ -6,21 +6,55 @@ import (
|
||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
||||
)
|
||||
|
||||
func (r *Router) tapHandler(c *gin.Context) {
|
||||
var tapReq option.TapRequest
|
||||
if err := c.ShouldBindJSON(&tapReq); err != nil {
|
||||
// processUnifiedRequest is a helper function to handle common request processing
|
||||
func (r *Router) processUnifiedRequest(c *gin.Context, actionType option.ActionMethod) (*option.UnifiedActionRequest, error) {
|
||||
var req option.UnifiedActionRequest
|
||||
|
||||
// Bind JSON request
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set platform and serial from URL parameters
|
||||
setRequestContextFromURL(c, &req)
|
||||
|
||||
// Validate for HTTP API usage
|
||||
if err := req.ValidateForHTTPAPI(actionType); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
// setRequestContextFromURL sets platform and serial from URL parameters
|
||||
func setRequestContextFromURL(c *gin.Context, req *option.UnifiedActionRequest) {
|
||||
if req.Platform == "" {
|
||||
req.Platform = c.Param("platform")
|
||||
}
|
||||
if req.Serial == "" {
|
||||
req.Serial = c.Param("serial")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) tapHandler(c *gin.Context) {
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_Tap)
|
||||
if err != nil {
|
||||
return // Error already handled in processUnifiedRequest
|
||||
}
|
||||
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if tapReq.Duration > 0 {
|
||||
err = driver.Drag(tapReq.X, tapReq.Y, tapReq.X, tapReq.Y,
|
||||
option.WithDuration(tapReq.Duration))
|
||||
|
||||
// Use UnifiedActionRequest directly
|
||||
if req.GetDuration() > 0 {
|
||||
err = driver.Drag(req.GetX(), req.GetY(), req.GetX(), req.GetY(),
|
||||
option.WithDuration(req.GetDuration()))
|
||||
} else {
|
||||
err = driver.TapXY(tapReq.X, tapReq.Y)
|
||||
err = driver.TapXY(req.GetX(), req.GetY())
|
||||
}
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
@@ -30,17 +64,17 @@ func (r *Router) tapHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) rightClickHandler(c *gin.Context) {
|
||||
var rightClickReq option.TapRequest
|
||||
if err := c.ShouldBindJSON(&rightClickReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_RightClick)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = driver.IDriver.(*uixt.BrowserDriver).
|
||||
SecondaryClick(rightClickReq.X, rightClickReq.Y)
|
||||
SecondaryClick(req.GetX(), req.GetY())
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -71,9 +105,8 @@ func (r *Router) uploadHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) hoverHandler(c *gin.Context) {
|
||||
var hoverReq HoverRequest
|
||||
if err := c.ShouldBindJSON(&hoverReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_Hover)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -84,7 +117,7 @@ func (r *Router) hoverHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
err = driver.IDriver.(*uixt.BrowserDriver).
|
||||
Hover(hoverReq.X, hoverReq.Y)
|
||||
Hover(req.GetX(), req.GetY())
|
||||
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
@@ -94,9 +127,8 @@ func (r *Router) hoverHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) scrollHandler(c *gin.Context) {
|
||||
var scrollReq ScrollRequest
|
||||
if err := c.ShouldBindJSON(&scrollReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_Scroll)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -107,7 +139,7 @@ func (r *Router) scrollHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
err = driver.IDriver.(*uixt.BrowserDriver).
|
||||
Scroll(scrollReq.Delta)
|
||||
Scroll(req.GetDelta())
|
||||
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
@@ -117,9 +149,8 @@ func (r *Router) scrollHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) doubleTapHandler(c *gin.Context) {
|
||||
var tapReq option.TapRequest
|
||||
if err := c.ShouldBindJSON(&tapReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_DoubleTap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -128,7 +159,7 @@ func (r *Router) doubleTapHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err = driver.DoubleTap(tapReq.X, tapReq.Y)
|
||||
err = driver.DoubleTap(req.GetX(), req.GetY())
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -137,22 +168,23 @@ func (r *Router) doubleTapHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) dragHandler(c *gin.Context) {
|
||||
var dragReq option.DragRequest
|
||||
if err := c.ShouldBindJSON(&dragReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_Drag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dragReq.Duration == 0 {
|
||||
dragReq.Duration = 1
|
||||
|
||||
duration := req.GetDuration()
|
||||
if duration == 0 {
|
||||
duration = 1
|
||||
}
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = driver.Drag(dragReq.FromX, dragReq.FromY, dragReq.ToX, dragReq.ToY,
|
||||
option.WithDuration(dragReq.Duration),
|
||||
option.WithPressDuration(dragReq.PressDuration))
|
||||
err = driver.Drag(req.GetFromX(), req.GetFromY(), req.GetToX(), req.GetToY(),
|
||||
option.WithDuration(duration),
|
||||
option.WithPressDuration(req.GetPressDuration()))
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
@@ -161,16 +193,16 @@ func (r *Router) dragHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (r *Router) inputHandler(c *gin.Context) {
|
||||
var inputReq option.InputRequest
|
||||
if err := c.ShouldBindJSON(&inputReq); err != nil {
|
||||
RenderErrorValidateRequest(c, err)
|
||||
req, err := r.processUnifiedRequest(c, option.ACTION_Input)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
driver, err := r.GetDriver(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = driver.Input(inputReq.Text, option.WithFrequency(inputReq.Frequency))
|
||||
err = driver.Input(req.Text, option.WithFrequency(req.GetFrequency()))
|
||||
if err != nil {
|
||||
RenderError(c, err)
|
||||
return
|
||||
|
||||
@@ -18,17 +18,17 @@ func TestTapHandler(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
tapReq option.TapRequest
|
||||
req option.UnifiedActionRequest
|
||||
wantStatus int
|
||||
wantResp HttpResponse
|
||||
}{
|
||||
{
|
||||
name: "tap abs xy",
|
||||
path: fmt.Sprintf("/api/v1/android/%s/ui/tap", "4622ca24"),
|
||||
tapReq: option.TapRequest{
|
||||
X: 500,
|
||||
Y: 800,
|
||||
Duration: 0,
|
||||
req: option.UnifiedActionRequest{
|
||||
X: &[]float64{500}[0],
|
||||
Y: &[]float64{800}[0],
|
||||
Duration: &[]float64{0}[0],
|
||||
},
|
||||
wantStatus: http.StatusOK,
|
||||
wantResp: HttpResponse{
|
||||
@@ -40,10 +40,10 @@ func TestTapHandler(t *testing.T) {
|
||||
{
|
||||
name: "tap relative xy",
|
||||
path: fmt.Sprintf("/api/v1/android/%s/ui/tap", "4622ca24"),
|
||||
tapReq: option.TapRequest{
|
||||
X: 0.5,
|
||||
Y: 0.6,
|
||||
Duration: 0,
|
||||
req: option.UnifiedActionRequest{
|
||||
X: &[]float64{0.5}[0],
|
||||
Y: &[]float64{0.6}[0],
|
||||
Duration: &[]float64{0}[0],
|
||||
},
|
||||
wantStatus: http.StatusOK,
|
||||
wantResp: HttpResponse{
|
||||
@@ -56,7 +56,7 @@ func TestTapHandler(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reqBody, _ := json.Marshal(tt.tapReq)
|
||||
reqBody, _ := json.Marshal(tt.req)
|
||||
req := httptest.NewRequest(http.MethodPost, tt.path, bytes.NewBuffer(reqBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user