Module: RailsAiContext::TestHelper
- Defined in:
- lib/rails_ai_context/test_helper.rb
Overview
Reusable test helper for verifying MCP tools — both built-in and custom. Works with RSpec and Minitest.
# RSpec
RSpec.configure { |c| c.include RailsAiContext::TestHelper }
# Minitest
class MyToolTest < ActiveSupport::TestCase
include RailsAiContext::TestHelper
end
Instance Method Summary collapse
-
#assert_tool_findable(name_or_class) ⇒ Object
Assert that a tool is registered and discoverable.
-
#assert_tool_response_excludes(response, excluded) ⇒ Object
Assert the response text does NOT include the given string.
-
#assert_tool_response_includes(response, expected) ⇒ Object
Assert the response text includes the expected string.
-
#execute_tool(name_or_class, **args) ⇒ Object
Execute a tool by name or class, returning the MCP::Tool::Response.
-
#execute_tool_with_error(name_or_class, **args) ⇒ Object
Execute a tool expecting an error response (non-empty error content).
-
#extract_response_text(response) ⇒ Object
Extract the text content from an MCP::Tool::Response.
Instance Method Details
#assert_tool_findable(name_or_class) ⇒ Object
Assert that a tool is registered and discoverable.
assert_tool_findable("rails_get_schema")
assert_tool_findable(MyApp::CustomTool)
50 51 52 53 54 |
# File 'lib/rails_ai_context/test_helper.rb', line 50 def assert_tool_findable(name_or_class) tool_class = resolve_tool(name_or_class) label = name_or_class.is_a?(Class) ? name_or_class.name : name_or_class _test_assert tool_class, "Expected tool '#{label}' to be registered, but it was not found" end |
#assert_tool_response_excludes(response, excluded) ⇒ Object
Assert the response text does NOT include the given string.
assert_tool_response_excludes(response, "password_digest")
70 71 72 73 74 |
# File 'lib/rails_ai_context/test_helper.rb', line 70 def assert_tool_response_excludes(response, excluded) text = extract_response_text(response) _test_assert !text.include?(excluded), "Expected tool response NOT to include #{excluded.inspect}, but it was present" end |
#assert_tool_response_includes(response, expected) ⇒ Object
Assert the response text includes the expected string.
assert_tool_response_includes(response, "users")
60 61 62 63 64 |
# File 'lib/rails_ai_context/test_helper.rb', line 60 def assert_tool_response_includes(response, expected) text = extract_response_text(response) _test_assert text.include?(expected), "Expected tool response to include #{expected.inspect}, but got:\n#{text[0..500]}" end |
#execute_tool(name_or_class, **args) ⇒ Object
Execute a tool by name or class, returning the MCP::Tool::Response. Raises if the tool is not found or returns an error.
response = execute_tool("rails_get_schema", table: "users")
response = execute_tool(MyApp::CustomTool, query: "test")
22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/rails_ai_context/test_helper.rb', line 22 def execute_tool(name_or_class, **args) tool_class = resolve_tool(name_or_class) raise ArgumentError, "Tool not found: #{name_or_class.inspect}. Available: #{available_tool_names.join(', ')}" unless tool_class response = tool_class.call(**args) unless response.is_a?(MCP::Tool::Response) raise "Expected MCP::Tool::Response, got #{response.class}" end response end |
#execute_tool_with_error(name_or_class, **args) ⇒ Object
Execute a tool expecting an error response (non-empty error content).
response = execute_tool_with_error("rails_query", sql: "DROP TABLE users")
38 39 40 41 42 43 |
# File 'lib/rails_ai_context/test_helper.rb', line 38 def execute_tool_with_error(name_or_class, **args) tool_class = resolve_tool(name_or_class) raise ArgumentError, "Tool not found: #{name_or_class.inspect}" unless tool_class tool_class.call(**args) end |
#extract_response_text(response) ⇒ Object
Extract the text content from an MCP::Tool::Response.
text = extract_response_text(response)
80 81 82 83 84 85 |
# File 'lib/rails_ai_context/test_helper.rb', line 80 def extract_response_text(response) content = response.is_a?(MCP::Tool::Response) ? response.content : response.to_h[:content] return "" unless content.is_a?(Array) content.filter_map { |c| c[:text] || c["text"] }.join("\n") end |