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

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

Raises:

  • (ArgumentError)


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

Raises:

  • (ArgumentError)


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