Module: ModalStack::Capybara
- Defined in:
- lib/modal_stack/capybara.rb
Overview
Capybara helpers for system / feature specs.
Opt in by requiring this file and including the module in your test context. For RSpec, prefer the auto-wired entrypoint:
# spec/spec_helper.rb (or rails_helper.rb)
require "modal_stack/capybara/rspec"
Constant Summary collapse
- DIALOG_SELECTOR =
"#modal-stack-root"- LAYER_SELECTOR =
'[data-modal-stack-target="layer"]:not([data-leaving])'
Instance Method Summary collapse
-
#close_all_modals(max: 16) ⇒ Object
Pop every layer by sending ESC repeatedly.
-
#close_modal ⇒ Object
Send ESC to the dialog so the runtime pops the top layer (honors the layer’s dismissible flag — a non-dismissible layer will not close).
-
#have_modal_open ⇒ Object
Capybara matcher: passes when the modal_stack <dialog> is open.
-
#have_modal_stack(depth: nil) ⇒ Object
Capybara matcher: assert the live (non-leaving) layer count.
- #have_no_modal_open ⇒ Object
- #have_no_modal_stack ⇒ Object
-
#modal_stack_depth ⇒ Object
Read the current stack depth from the live DOM.
-
#within_modal(depth: nil) ⇒ Object
Scope Capybara matchers to a specific layer of the stack.
Instance Method Details
#close_all_modals(max: 16) ⇒ Object
Pop every layer by sending ESC repeatedly. Stops as soon as no live layer remains, or after ‘max` attempts as a safety net.
69 70 71 72 73 74 75 76 77 |
# File 'lib/modal_stack/capybara.rb', line 69 def close_all_modals(max: 16) session = ::Capybara.current_session max.times do break unless session.has_css?(LAYER_SELECTOR, wait: 0) close_modal session.has_no_css?(LAYER_SELECTOR, wait: 1) end end |
#close_modal ⇒ Object
Send ESC to the dialog so the runtime pops the top layer (honors the layer’s dismissible flag — a non-dismissible layer will not close).
63 64 65 |
# File 'lib/modal_stack/capybara.rb', line 63 def close_modal ::Capybara.current_session.find(:css, DIALOG_SELECTOR).send_keys(:escape) end |
#have_modal_open ⇒ Object
Capybara matcher: passes when the modal_stack <dialog> is open.
expect(page).to have_modal_open
36 37 38 |
# File 'lib/modal_stack/capybara.rb', line 36 def have_modal_open(**) have_css("#{DIALOG_SELECTOR}[open]", **) end |
#have_modal_stack(depth: nil) ⇒ Object
Capybara matcher: assert the live (non-leaving) layer count.
expect(page).to have_modal_stack(depth: 2)
expect(page).to have_modal_stack # any open layer
48 49 50 51 52 53 54 |
# File 'lib/modal_stack/capybara.rb', line 48 def have_modal_stack(depth: nil, **) if depth have_css(LAYER_SELECTOR, count: depth, **) else have_css(LAYER_SELECTOR, **) end end |
#have_no_modal_open ⇒ Object
40 41 42 |
# File 'lib/modal_stack/capybara.rb', line 40 def have_no_modal_open(**) have_no_css("#{DIALOG_SELECTOR}[open]", **) end |
#have_no_modal_stack ⇒ Object
56 57 58 |
# File 'lib/modal_stack/capybara.rb', line 56 def have_no_modal_stack(**) have_no_css(LAYER_SELECTOR, **) end |
#modal_stack_depth ⇒ Object
Read the current stack depth from the live DOM. Useful when an explicit assertion would be clearer than ‘have_modal_stack`.
81 82 83 |
# File 'lib/modal_stack/capybara.rb', line 81 def modal_stack_depth ::Capybara.current_session.all(:css, LAYER_SELECTOR, wait: 0).size end |
#within_modal(depth: nil) ⇒ Object
Scope Capybara matchers to a specific layer of the stack.
within_modal { expect(page).to have_content("Edit") }
within_modal(depth: 1) { ... } # bottom-most layer
within_modal(depth: 2) { ... } # second from the bottom
When ‘depth:` is omitted the top-most layer is targeted.
25 26 27 28 29 30 31 |
# File 'lib/modal_stack/capybara.rb', line 25 def within_modal(depth: nil, **, &) layers = ::Capybara.current_session.all(:css, LAYER_SELECTOR, minimum: 1, **) target = depth ? layers[depth - 1] : layers.last raise ::Capybara::ElementNotFound, "no modal_stack layer at depth #{depth}" unless target ::Capybara.current_session.within(target, &) end |