Skip to main content
Related: Observability, DX, Client, Troubleshooting Test-only helpers to run the search layer offline (no I/O by default) and write ergonomic assertions against unified events and compiled params.

Quick start

The engine automatically uses an offline client in test mode (Rails test environment or RACK_ENV=test). For programmable responses, enable the stub client:
# test_helper.rb or spec_helper.rb
require 'search_engine/test'

SearchEngine.configure do |c|
  c.client = SearchEngine::Test::StubClient.new
end
  • Queue responses and inspect captured calls:
stub = SearchEngine.client
stub.enqueue_response(:search, { 'hits' => [], 'found' => 0, 'out_of' => 0 })

# your relation execution here ...

calls = stub.search_calls
first = calls.first
first.url        # => compiled search URL
first.redacted?  # => true
first.redacted_body # => redacted subset for safe logs
  • Programmable responses via blocks or exceptions:
stub.enqueue_response(:search, ->(req) { { 'hits' => [], 'found' => 42, 'out_of' => 42 } })
stub.enqueue_response(:multi_search, RuntimeError.new('boom'))
  • Use the SearchEngine.client helper to access the configured client:
client = SearchEngine.client  # Returns StubClient, OfflineClient, or Client

Event assertions

Unified events are emitted via ActiveSupport::Notifications. Capture them for a block and assert.
  • RSpec matcher:
expect { rel.to_a }.to emit_event("search_engine.search").with(hash_including(collection: "books"))
  • Minitest helpers:
include SearchEngine::Test::MinitestAssertions

assert_emits("search_engine.search", payload: ->(p) { p[:collection] == "books" }) { rel.to_a }

events = capture_events { rel.to_a }
  • Params helpers in tests:
expect(rel.to_params_json).to include("filter_by")
See also: Relation#to_params_json, Relation#to_curl, and Relation#dry_run!.

Test mode and offline client

The engine automatically enables test mode when running in Rails test environment or when RACK_ENV=test is set. In test mode, SearchEngine.client returns a no-op SearchEngine::Test::OfflineClient that avoids network I/O and returns safe empty responses.

Environment overrides

You can control test mode via environment variables:
  • SEARCH_ENGINE_TEST_MODE=1 or SEARCH_ENGINE_TEST_MODE=0 (explicit override)
  • SEARCH_ENGINE_OFFLINE=1 or SEARCH_ENGINE_OFFLINE=0 (legacy alias)
When SearchEngine.config.client is explicitly set (e.g., StubClient), it always takes precedence over automatic offline mode.

OfflineClient behavior

SearchEngine::Test::OfflineClient implements all client methods but performs no network I/O:
  • search returns empty results (found: 0)
  • multi_search returns empty results array
  • import_documents returns success JSONL
  • All other operations return safe empty responses

Offline strategy & safety

  • Captured bodies and event payloads are redacted via the central helper.
  • No API keys, raw filter literals, or PII are stored; long strings are truncated.
  • A redacted? marker is present on captured request entries.

Parallel test safety

  • Internals are protected by a lightweight mutex.
  • Use stub.reset! between examples if needed.
Backlinks: Observability, DX, CLI, Client