Skip to content

Debugging

Bryan edited this page Jan 30, 2026 · 5 revisions

This guide covers debugging techniques in SpecForge to help you troubleshoot test failures and understand what's happening during test execution.

Verbosity Flags

The quickest way to debug is using CLI verbosity flags -- no changes to your blueprints needed:

spec_forge run --verbose        # Level 1: Show step names
spec_forge run --debug          # Level 2: Show request/response on failures  
spec_forge run --trace          # Level 3: Show everything for all steps

Start with --verbose to see which step is failing, then escalate to --debug or --trace for more detail.

The Debug Flag

For interactive debugging, add debug: true to any step:

- name: "Debug this step"
  debug: true
  request:
    url: /users
  expect:
  - status: 200

Aliases: pry: true, breakpoint: true

Note: The debug flag does not inherit to nested steps -- it only triggers for the step it's defined on.

Configuring the Debug Handler

Configure your debug handler in forge_helper.rb:

SpecForge.configure do |config|
  # Simple: drop into Pry
  config.on_debug { binding.pry }
end

The handler receives a context parameter if your block accepts one:

config.on_debug do |context|
  puts "Step: #{context.step.name}"
  puts "Variables: #{context.variables.inspect}"
  binding.pry
end

The Context Object

When your debug handler receives context, it has access to:

Property Description
context.variables Current variable state (including request and response if a request was made)
context.forge The forge instance
context.blueprint The current blueprint being executed
context.step The current step

Inspecting Variables

The most useful property for debugging is usually context.variables:

config.on_debug do |context|
  vars = context.variables
  
  # See all available variables
  puts "Available variables: #{vars.keys}"
  
  # If this step made a request, inspect request/response
  if vars[:request]
    puts "Request URL: #{vars[:request][:url]}"
    puts "Request method: #{vars[:request][:http_verb]}"
  end
  
  if vars[:response]
    puts "Response status: #{vars[:response][:status]}"
    puts "Response body: #{vars[:response][:body]}"
  end
  
  binding.pry
end

Inspecting the Step

The context.step object contains the step's configuration:

config.on_debug do |context|
  step = context.step
  
  puts "Step name: #{step.name}"
  puts "Has request? #{step.request?}"
  puts "Has expectations? #{step.expects?}"
  puts "Tags: #{step.tags}"
  
  binding.pry
end

Common Debugging Scenarios

Unexpected Status Code

config.on_debug do |context|
  response = context.variables[:response]
  
  puts "Status: #{response[:status]}"
  puts "Body: #{response[:body].inspect}"
  
  binding.pry
end

Variable Resolution Issues

config.on_debug do |context|
  puts "All variables:"
  context.variables.each do |key, value|
    puts "  #{key}: #{value.inspect}"
  end
  
  binding.pry
end

Request Formation Problems

config.on_debug do |context|
  request = context.variables[:request]
  
  puts "URL: #{request[:url]}"
  puts "Method: #{request[:http_verb]}"
  puts "Headers: #{request[:headers].inspect}"
  puts "Body: #{request[:body].inspect}"
  
  binding.pry
end

Debugging with Callbacks

You can also use callbacks for debugging specific lifecycle points:

SpecForge.configure do |config|
  # Log every request
  config.after(:step) do |context|
    next unless context.step&.request?
    
    request = context.variables[:request]
    response = context.variables[:response]
    
    puts "#{request[:http_verb]} #{request[:url]}#{response[:status]}"
  end
end

See Callbacks for more on lifecycle hooks.

Related Documentation

Clone this wiki locally