mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-24 17:59:58 +08:00
- Fixed TapByOCR and TapByCV tools to properly handle ignore_NotFoundError option - Added option parameters to all MCP tool request structures - Fixed ConvertActionToCallToolRequest methods to extract action options - Added extractActionOptionsToArguments helper function for consistent option handling - Extended fix to all MCP tools: SwipeToTapApp, SwipeToTapText, SwipeToTapTexts, TapXY, TapAbsXY - Added comprehensive tests for option parameter handling - Updated test expectations to match actual registered tools This ensures that when ignore_NotFoundError is set to true, OCR/CV operations will return nil instead of throwing errors when target elements are not found, allowing tests to continue execution as expected.
184 lines
5.1 KiB
Go
184 lines
5.1 KiB
Go
package uixt
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/httprunner/httprunner/v5/uixt/option"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestNewMCPServer(t *testing.T) {
|
|
server := NewMCPServer()
|
|
assert.NotNil(t, server)
|
|
|
|
// Check that tools are registered
|
|
tools := server.ListTools()
|
|
assert.Greater(t, len(tools), 0, "Should have at least one tool registered")
|
|
|
|
// Check specific tools exist
|
|
expectedTools := []string{
|
|
"list_available_devices",
|
|
"select_device",
|
|
"tap_xy",
|
|
"tap_abs_xy",
|
|
"tap_ocr",
|
|
"tap_cv",
|
|
"double_tap_xy",
|
|
"swipe_direction",
|
|
"swipe_coordinate",
|
|
"swipe_to_tap_app",
|
|
"swipe_to_tap_text",
|
|
"swipe_to_tap_texts",
|
|
"drag",
|
|
"input",
|
|
"screenshot",
|
|
"get_screen_size",
|
|
"press_button",
|
|
"home",
|
|
"back",
|
|
"list_packages",
|
|
"app_launch",
|
|
"app_terminate",
|
|
"app_install",
|
|
"app_uninstall",
|
|
"app_clear",
|
|
"sleep",
|
|
"sleep_ms",
|
|
"sleep_random",
|
|
"set_ime",
|
|
"get_source",
|
|
"close_popups",
|
|
"web_login_none_ui",
|
|
"secondary_click",
|
|
"hover_by_selector",
|
|
"tap_by_selector",
|
|
"secondary_click_by_selector",
|
|
"web_close_tab",
|
|
"ai_action",
|
|
"finished",
|
|
}
|
|
|
|
registeredToolNames := make(map[string]bool)
|
|
for _, tool := range tools {
|
|
registeredToolNames[tool.Name] = true
|
|
}
|
|
|
|
for _, expectedTool := range expectedTools {
|
|
assert.True(t, registeredToolNames[expectedTool], "Tool %s should be registered", expectedTool)
|
|
}
|
|
}
|
|
|
|
func TestToolInterfaces(t *testing.T) {
|
|
// Test that all tools implement the ActionTool interface correctly
|
|
tools := []ActionTool{
|
|
&ToolListAvailableDevices{},
|
|
&ToolSelectDevice{},
|
|
&ToolTapXY{},
|
|
&ToolTapAbsXY{},
|
|
&ToolTapByOCR{},
|
|
&ToolTapByCV{},
|
|
&ToolDoubleTapXY{},
|
|
&ToolSwipeDirection{},
|
|
&ToolSwipeCoordinate{},
|
|
&ToolSwipeToTapApp{},
|
|
&ToolSwipeToTapText{},
|
|
&ToolSwipeToTapTexts{},
|
|
&ToolDrag{},
|
|
&ToolInput{},
|
|
&ToolScreenShot{},
|
|
&ToolGetScreenSize{},
|
|
&ToolPressButton{},
|
|
&ToolHome{},
|
|
&ToolBack{},
|
|
&ToolListPackages{},
|
|
&ToolLaunchApp{},
|
|
&ToolTerminateApp{},
|
|
&ToolAppInstall{},
|
|
&ToolAppUninstall{},
|
|
&ToolAppClear{},
|
|
&ToolSleep{},
|
|
&ToolSleepMS{},
|
|
&ToolSleepRandom{},
|
|
&ToolSetIme{},
|
|
&ToolGetSource{},
|
|
&ToolClosePopups{},
|
|
&ToolWebLoginNoneUI{},
|
|
&ToolSecondaryClick{},
|
|
&ToolHoverBySelector{},
|
|
&ToolTapBySelector{},
|
|
&ToolSecondaryClickBySelector{},
|
|
&ToolWebCloseTab{},
|
|
&ToolAIAction{},
|
|
&ToolFinished{},
|
|
}
|
|
|
|
for _, tool := range tools {
|
|
assert.NotEmpty(t, string(tool.Name()), "Tool name should not be empty")
|
|
assert.NotEmpty(t, tool.Description(), "Tool description should not be empty")
|
|
assert.NotNil(t, tool.Options(), "Tool options should not be nil")
|
|
assert.NotNil(t, tool.Implement(), "Tool implementation should not be nil")
|
|
}
|
|
}
|
|
|
|
func TestIgnoreNotFoundErrorOption(t *testing.T) {
|
|
// Test that ignore_NotFoundError option is properly extracted and applied
|
|
server := NewMCPServer()
|
|
|
|
// Test TapByOCR tool
|
|
tapOCRTool := server.GetToolByAction(option.ACTION_TapByOCR)
|
|
assert.NotNil(t, tapOCRTool, "TapByOCR tool should be available")
|
|
|
|
// Create a mock action with ignore_NotFoundError option
|
|
actionOptions := option.NewActionOptions(
|
|
option.WithIgnoreNotFoundError(true),
|
|
option.WithMaxRetryTimes(2),
|
|
option.WithIndex(1),
|
|
option.WithRegex(true),
|
|
option.WithTapRandomRect(true),
|
|
)
|
|
action := MobileAction{
|
|
Method: option.ACTION_TapByOCR,
|
|
Params: "test_text",
|
|
ActionOptions: *actionOptions,
|
|
}
|
|
|
|
// Convert action to MCP call tool request
|
|
request, err := tapOCRTool.ConvertActionToCallToolRequest(action)
|
|
assert.NoError(t, err, "Should convert action to request without error")
|
|
|
|
// Verify that ignore_NotFoundError option is included in arguments
|
|
args := request.Params.Arguments
|
|
assert.Equal(t, true, args["ignore_NotFoundError"], "ignore_NotFoundError should be true")
|
|
assert.Equal(t, 2, args["max_retry_times"], "max_retry_times should be 2")
|
|
assert.Equal(t, 1, args["index"], "index should be 1")
|
|
assert.Equal(t, true, args["regex"], "regex should be true")
|
|
assert.Equal(t, true, args["tap_random_rect"], "tap_random_rect should be true")
|
|
assert.Equal(t, "test_text", args["text"], "text should be test_text")
|
|
}
|
|
|
|
func TestExtractActionOptionsToArguments(t *testing.T) {
|
|
// Test the extractActionOptionsToArguments helper function
|
|
actionOptions := []option.ActionOption{
|
|
option.WithIgnoreNotFoundError(true),
|
|
option.WithMaxRetryTimes(3),
|
|
option.WithIndex(2),
|
|
option.WithRegex(true),
|
|
option.WithTapRandomRect(false), // false should not be included
|
|
option.WithDuration(1.5),
|
|
}
|
|
|
|
arguments := make(map[string]any)
|
|
extractActionOptionsToArguments(actionOptions, arguments)
|
|
|
|
// Verify extracted options
|
|
assert.Equal(t, true, arguments["ignore_NotFoundError"], "ignore_NotFoundError should be extracted")
|
|
assert.Equal(t, 3, arguments["max_retry_times"], "max_retry_times should be extracted")
|
|
assert.Equal(t, 2, arguments["index"], "index should be extracted")
|
|
assert.Equal(t, true, arguments["regex"], "regex should be extracted")
|
|
assert.Equal(t, 1.5, arguments["duration"], "duration should be extracted")
|
|
|
|
// tap_random_rect should not be included since it's false
|
|
_, exists := arguments["tap_random_rect"]
|
|
assert.False(t, exists, "tap_random_rect should not be included when false")
|
|
}
|