Files
httprunner/uixt/mcp_server_test.go
lilong.129 df65f9a828 fix: MCP server ignore_NotFoundError option not working
- 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.
2025-05-26 22:02:01 +08:00

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")
}