Class: Snails::Harness::IntegrationTest
- Defined in:
- runtime/snails/harness.rb,
runtime/snails/harness.rbs
Overview
Base class for a case — an app's test classes inherit it, e.g.
class UpSmokeTest < Snails::Harness::IntegrationTest. Not API-specific: it
is the shared surface (real HTTP + assertions) any integration case
uses.
base_url defaults to APP_BASE_URL (the runner's live server). Hooks
let an app extend the base: setup (per-case fixtures/auth) and
default_host (the Host header its routes expect) are reopened on the
class, while a case class overrides tables with the tables to empty
before each case.
Instance Attribute Summary collapse
-
#response ⇒ Object
readonly
Returns the value of attribute response.
Class Method Summary collapse
-
.test(name, &block) ⇒ void
case declaration inside a subclass, written as `test "description" do ...
Instance Method Summary collapse
-
#assert(value, message = nil) ⇒ void
pass when the value is truthy; the optional message rides on the failure line.
-
#assert_emails(count) ⇒ void
assert the block caused exactly
countdeliveries. -
#assert_equal(expected, actual) ⇒ void
pass when the two values match; the failure names both sides.
-
#assert_includes(collection, object) ⇒ void
pass when the collection holds the object; whatever
include?answers for that collection covers it (Array membership, String substring). -
#assert_match(pattern, actual) ⇒ void
pass when the pattern matches the actual value.
-
#assert_nil(value, message = nil) ⇒ void
pass when the value is nil; the failure names what was there instead.
-
#assert_not(value, message = nil) ⇒ void
pass when the value is false or nil; the failure names what was truthy.
-
#assert_not_equal(expected, actual, message = nil) ⇒ void
pass when the two values differ; the failure names both sides, like
assert_equal. -
#assert_not_nil(value, message = nil) ⇒ void
pass when the value is not nil; the failure names the nil it got.
-
#assert_operator(left, operator, right, message = nil) ⇒ void
pass when
left <operator> rightholds; the failure prints the comparison that did not. -
#assert_raises(error_class) ⇒ void
pass when the block raises the named exception (a subclass counts); nothing raised or a different exception fails, and the failure names what came instead.
-
#assert_response(type) ⇒ void
pass when the status matches.
-
#default_host ⇒ String?
the Host header sent with every request when the instance is built without one.
- #delete(path, params: nil, headers: nil, as: nil) ⇒ Object
-
#emails ⇒ Array[Hash]
the run's recorded deliveries so far, in send order: one hash per delivery with
"to"(array),"from", and"subject". - #get(path, params: nil, headers: nil) ⇒ Object
-
#initialize(base_url = nil, host: nil) ⇒ IntegrationTest
constructor
A new instance of IntegrationTest.
- #post(path, params: nil, headers: nil, as: nil) ⇒ Object
- #put(path, params: nil, headers: nil, as: nil) ⇒ Object
-
#setup ⇒ void
per-case hook: runs once per fresh instance, before the case body and after per-case isolation (
tables). -
#skip(message = "skipped") ⇒ void
end the case as skipped rather than failed; raises
SkipSignal, the signal thetestmacro catches. -
#tables ⇒ Array[String]
the table names emptied before each case, so a case never sees another case's writes.
Constructor Details
#initialize(base_url = nil, host: nil) ⇒ IntegrationTest
Returns a new instance of IntegrationTest.
121 122 123 124 125 126 127 128 |
# File 'runtime/snails/harness.rb', line 121 def initialize(base_url = nil, host: nil) @base_url = base_url.nil? ? ENV["APP_BASE_URL"] : base_url @host = host.nil? ? default_host : host @response = nil reset_tables reset_cache setup end |
Instance Attribute Details
#response ⇒ Object (readonly)
Returns the value of attribute response.
130 131 132 |
# File 'runtime/snails/harness.rb', line 130 def response @response end |
Class Method Details
.test(name, &block) ⇒ void
case declaration inside a subclass, written as
test "description" do ... end. The case runs immediately in a fresh
instance — spinel AOT cannot store a block's self — and name is the
printed name. In a bundle process the require loads every file, but only
the selected file's cases run (Snails::Harness.file_selected?), so
each run prints only its own file's cases.
The selection gate wraps the body in an if rather than returning
early: an early return in a method that stores &block corrupts a
later stored block's exit under spinel AOT (instance_exec then
raises TypeError after the body has finished).
147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'runtime/snails/harness.rb', line 147 def self.test(name, &block) if Snails::Harness.file_selected? instance = new begin instance.instance_exec(&block) puts "ok #{name}" rescue SkipSignal => e puts "skip #{name}: #{e.}" rescue StandardError => e puts "FAIL #{name}: #{e.class}: #{e.}" exit 1 end end end |
Instance Method Details
#assert(value, message = nil) ⇒ void
pass when the value is truthy; the optional message rides on the failure line.
320 |
# File 'runtime/snails/harness.rb', line 320
def assert: (untyped value, ?untyped message) -> void
|
#assert_emails(count) ⇒ void
assert the block caused exactly count deliveries. The server is a
separate process, so its ActionMailer::Base.deliveries is unreadable
from here; the shared observation point is the gate's mail log
(tmp/mail-capture.jsonl under the spin root, MAIL_LOG_PATH from this
target's cwd — the file the server writes in test mode, where the
stamped config/environment.rb registers the capture). The engine empties
the file before boot, so the count is the block's before/after line
delta, never an absolute. Without a live gate (a bare
spin test <file>) the case skips — a mail assertion that cannot run is
visibly skipped, not silently green.
420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'runtime/snails/harness.rb', line 420 def assert_emails(count) if ENV["APP_BASE_URL"].to_s.empty? raise SkipSignal, "assert_emails (no live gate — run bin/test)" end before = mail_log_entries.length yield actual = mail_log_entries.length - before return if actual == count raise "assert_emails failed: expected #{count} mail(s), got #{actual}" end |
#assert_equal(expected, actual) ⇒ void
pass when the two values match; the failure names both sides.
251 252 253 254 255 |
# File 'runtime/snails/harness.rb', line 251 def assert_equal(expected, actual) return if expected == actual raise "assert_equal: expected #{expected.inspect}, got #{actual.inspect}" end |
#assert_includes(collection, object) ⇒ void
pass when the collection holds the object; whatever include? answers
for that collection covers it (Array membership, String substring).
307 308 309 310 311 |
# File 'runtime/snails/harness.rb', line 307 def assert_includes(collection, object) return if collection.include?(object) raise "assert_includes: #{object.inspect} not included in #{collection.inspect}" end |
#assert_match(pattern, actual) ⇒ void
pass when the pattern matches the actual value. A String pattern is a literal substring (minitest parity: never a regexp source), so it needs no escaping pass.
287 288 289 290 291 292 293 294 295 296 |
# File 'runtime/snails/harness.rb', line 287 def assert_match(pattern, actual) matched = if pattern.is_a?(String) actual.to_s.include?(pattern) else pattern.match?(actual.to_s) end return if matched raise "assert_match: expected #{actual.inspect} to match #{pattern.inspect}" end |
#assert_nil(value, message = nil) ⇒ void
pass when the value is nil; the failure names what was there instead.
332 |
# File 'runtime/snails/harness.rb', line 332
def assert_nil: (untyped value, ?untyped message) -> void
|
#assert_not(value, message = nil) ⇒ void
pass when the value is false or nil; the failure names what was truthy.
356 |
# File 'runtime/snails/harness.rb', line 356
def assert_not: (untyped value, ?untyped message) -> void
|
#assert_not_equal(expected, actual, message = nil) ⇒ void
pass when the two values differ; the failure names both sides, like
assert_equal.
370 |
# File 'runtime/snails/harness.rb', line 370
def assert_not_equal: (untyped expected, untyped actual, ?untyped message) -> void
|
#assert_not_nil(value, message = nil) ⇒ void
pass when the value is not nil; the failure names the nil it got.
344 |
# File 'runtime/snails/harness.rb', line 344
def assert_not_nil: (untyped value, ?untyped message) -> void
|
#assert_operator(left, operator, right, message = nil) ⇒ void
pass when left <operator> right holds; the failure prints the
comparison that did not.
386 |
# File 'runtime/snails/harness.rb', line 386
def assert_operator: (untyped left, untyped operator, untyped right, ?untyped message) -> void
|
#assert_raises(error_class) ⇒ void
pass when the block raises the named exception (a subclass counts); nothing raised or a different exception fails, and the failure names what came instead.
266 267 268 269 270 271 272 273 274 275 |
# File 'runtime/snails/harness.rb', line 266 def assert_raises(error_class) begin yield rescue error_class return rescue StandardError => e raise "assert_raises: expected #{error_class}, got #{e.class}: #{e.}" end raise "assert_raises: #{error_class} not raised" end |
#assert_response(type) ⇒ void
pass when the status matches. Four category symbols take a range or
exact code: :success (2xx), :redirect (3xx), :error (5xx),
:missing (404 exactly). Any other symbol resolves through the shared
status table (Snails::Utils::SYMBOL_TO_STATUS_CODE), so every symbol
the controller's status: accepts works here too; an Integer is
compared as-is (assert_response 415).
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'runtime/snails/harness.rb', line 222 def assert_response(type) actual = @response.status ok = if type == :success actual >= 200 && actual <= 299 elsif type == :redirect actual >= 300 && actual <= 399 elsif type == :error actual >= 500 && actual <= 599 elsif type == :missing actual == 404 elsif type.is_a?(Integer) actual == type elsif type.is_a?(Symbol) code = Snails::Utils::SYMBOL_TO_STATUS_CODE[type] raise "unknown response type: #{type}" if code.nil? actual == code else raise "unknown response type: #{type}" end return if ok raise "assert_response #{type}: got #{actual} — #{@response.body.to_s[0, 200]}" end |
#default_host ⇒ String?
the Host header sent with every request when the instance is built without one. No-op (nil) here; an app reopens it with the host its routes expect.
187 188 189 |
# File 'runtime/snails/harness.rb', line 187 def default_host nil end |
#delete(path, params: nil, headers: nil, as: nil) ⇒ Object
203 204 205 |
# File 'runtime/snails/harness.rb', line 203 def delete(path, params: nil, headers: nil, as: nil) @response = Snails::Harness.request(:delete, path, @base_url, params, with_host(headers), as) end |
#emails ⇒ Array[Hash]
the run's recorded deliveries so far, in send order: one hash per
delivery with "to" (array), "from", and "subject". The gate engine
empties the log before boot; a case reads emails.last after an
assert_emails block rather than asserting absolutes.
439 440 441 |
# File 'runtime/snails/harness.rb', line 439 def emails mail_log_entries end |
#get(path, params: nil, headers: nil) ⇒ Object
191 192 193 |
# File 'runtime/snails/harness.rb', line 191 def get(path, params: nil, headers: nil) @response = Snails::Harness.request(:get, path, @base_url, params, with_host(headers), nil) end |
#post(path, params: nil, headers: nil, as: nil) ⇒ Object
195 196 197 |
# File 'runtime/snails/harness.rb', line 195 def post(path, params: nil, headers: nil, as: nil) @response = Snails::Harness.request(:post, path, @base_url, params, with_host(headers), as) end |
#put(path, params: nil, headers: nil, as: nil) ⇒ Object
199 200 201 |
# File 'runtime/snails/harness.rb', line 199 def put(path, params: nil, headers: nil, as: nil) @response = Snails::Harness.request(:put, path, @base_url, params, with_host(headers), as) end |
#setup ⇒ void
per-case hook: runs once per fresh instance, before the case body and
after per-case isolation (tables). No-op here; an app reopens it to
load fixtures or seed state.
167 168 |
# File 'runtime/snails/harness.rb', line 167 def setup end |
#skip(message = "skipped") ⇒ void
end the case as skipped rather than failed; raises SkipSignal, the
signal the test macro catches.
450 451 452 |
# File 'runtime/snails/harness.rb', line 450 def skip( = "skipped") raise SkipSignal, end |