Module: Dommy::Rails::BrowserSpec

Defined in:
lib/dommy/rails/browser_spec.rb

Overview

Test-integration helper that runs application JavaScript against the real Rails app, bridging request-style specs to the lightweight test browser. Include it in a Minitest test or RSpec example group to get a ‘browser` (a `javascript: true` Dommy::Rack::Session bound to the Rails Rack app):

browser.visit todos_path
browser.click "li.todo"
assert browser.has_css?("li.todo.is-completed")

External ‘<script>`s and `fetch` resolve through the Rails app itself (Propshaft / Sprockets / controllers), sharing the session cookie jar. The browser is disposed at teardown, and any uncaught JS error / unhandled rejection fails the test (strict by default) unless wrapped in `allow_js_errors`.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

Auto-wire teardown: RSpec example groups get an ‘after` hook (the example is passed so we can save artifacts on failure); Minitest tests use `after_teardown` (defined below).



25
26
27
28
29
30
31
32
# File 'lib/dommy/rails/browser_spec.rb', line 25

def self.included(base)
  if base.respond_to?(:after)
    base.after do |example|
      dommy_browser_after(failed: example.exception ? true : false,
        label: example.full_description, exception: example.exception)
    end
  end
end

Instance Method Details

#after_teardownObject

Minitest teardown hook (no-op outside Minitest).



35
36
37
38
39
40
41
# File 'lib/dommy/rails/browser_spec.rb', line 35

def after_teardown
  failures = respond_to?(:failures) ? self.failures : []
  dommy_browser_after(failed: !failures.empty?, label: (name if respond_to?(:name)),
    exception: failures.first)
ensure
  super if defined?(super)
end

#allow_js_errorsObject

Suppress strict JS-error failure for errors raised inside the block (they stay in ‘browser.js_errors`). For specs that intentionally trigger one.



78
79
80
81
82
83
# File 'lib/dommy/rails/browser_spec.rb', line 78

def allow_js_errors
  @dommy_allow_js_errors = true
  yield
ensure
  dommy_browser_ack_js_errors
end

#browserObject

Memoized JS-enabled session bound to the app. Lazily requires the dommy-rack + QuickJS integration so the dependency is only needed when a browser spec actually runs.



63
64
65
66
67
68
69
# File 'lib/dommy/rails/browser_spec.rb', line 63

def browser
  @dommy_browser ||= begin
    require "dommy/js/quickjs/rack"
    ::Dommy::Rack::Session.new(dommy_browser_app, javascript: true, trace: true, trace_dom: true,
      trace_snapshots: true)
  end
end

#browser_started?Boolean

Returns:

  • (Boolean)


74
# File 'lib/dommy/rails/browser_spec.rb', line 74

def browser_started? = !@dommy_browser.nil?

#dommy_browser_after(failed:, label: nil, exception: nil) ⇒ Object

On a failed example, write debugging artifacts (page HTML + trace + visible text) before disposing, then run the normal teardown. Shared by the RSpec and Minitest hooks.



46
47
48
49
# File 'lib/dommy/rails/browser_spec.rb', line 46

def dommy_browser_after(failed:, label: nil, exception: nil)
  dommy_save_failure_artifacts(label, exception: exception) if failed && browser_started?
  dommy_browser_teardown
end

#dommy_browser_appObject

The Rack app the browser drives. Defaults to the Rails application; override ‘dommy_browser_app` to point elsewhere.



53
54
55
56
57
58
# File 'lib/dommy/rails/browser_spec.rb', line 53

def dommy_browser_app
  return ::Rails.application if defined?(::Rails) && ::Rails.respond_to?(:application)

  raise "Dommy::Rails::BrowserSpec needs a Rack app: define #dommy_browser_app " \
        "(Rails.application was not available)."
end

#dommy_browser_teardownObject

Dispose the browser and fail if uncaught JS errors were collected. Call from a Minitest #teardown / RSpec after hook (the integration modules wire this automatically).



88
89
90
91
92
93
94
95
96
97
# File 'lib/dommy/rails/browser_spec.rb', line 88

def dommy_browser_teardown
  return unless browser_started?

  pending = browser.js_errors[(@dommy_browser_acked || 0)..] || []
  browser.dispose_js
  @dommy_browser = nil
  return if @dommy_allow_js_errors || pending.empty?

  raise dommy_browser_js_error(pending)
end

#dommy_failures_dirObject

Directory failure artifacts are written under (override per host).



72
# File 'lib/dommy/rails/browser_spec.rb', line 72

def dommy_failures_dir = ::File.join("tmp", "dommy", "failures")