capybara-lightpanda 0.14.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 759abeb96b5d6898d9458d2e81af39b97d155766cfd2c80fa1ed363409a6aff6
4
- data.tar.gz: 66d54d836501ab8ec7d3cc23ffc389f58777c938a19490f9dc81a076819b4489
3
+ metadata.gz: d38fc6a0a5cbba01bba3a0a1363d8e0577dc99c2cb8a77b81f407b273a91863b
4
+ data.tar.gz: 21cdea0aeba27736c52f800c22e850d80ea15d3c7bb1c6c9b173421bb227be7d
5
5
  SHA512:
6
- metadata.gz: ffdc46e2b18c6ce822fb7765cc668bfda6594e1ce27f9ad88b29e4d9a34f6882b80aad54fcb0581d460e68b3fbcaaaa853017f825295b1a8758a244da520d12d
7
- data.tar.gz: 6ae51661f2a7108ec85bebf773965dd792f74d04b80cdff7c5992b41be5c32f15b3d7e08d97a64212a64a812be4ebe811f222ad6fa91866888d1f6e50a805b71
6
+ metadata.gz: ec4a2743650df3602c43fc393a82af00c19c5b44d59fab31156aed0b3252e8fb7f3c5f06df1b6e2fe994c9b974a1b21b29707c22c6bff571d4c2b6aca195add4
7
+ data.tar.gz: ba19fbd3c2754eae2b6d3af02584d739eba498b93e0e0ff392f9dc7a9feefdc1af1ff68081cd5b6963ca41c768cf8cebcf3b48b9debd9923e5142b15ac1c9223
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.1] - 2026-10-12
4
+
5
+ ### Fixed
6
+
7
+ - **A click that loads a new page waits for that page's scripts.** `click` used to return as soon as the new document existed, before its deferred and module scripts had run. Apps load Stimulus, Turbo and Bootstrap that way, so the next action could land on a page whose handlers were not wired yet: a Bootstrap collapse that did not open, a `confirm()` that never showed (`accept_confirm` raised `ModalNotFound`) while the form was submitted anyway, a form posted before its JavaScript was ready. The click now also waits for `DOMContentLoaded`, as Cuprite waits for the load event. `send_keys`, `go_back` and `go_forward` wait the same way when they load a new page. Clicks that don't navigate are as fast as before.
8
+ - **A click on a link that Turbo hands back to the browser waits for the new page.** With Turbo on the page, such a click returned immediately on the page being left, because Turbo reported activity and went idle again before the navigation started.
9
+
3
10
  ## [0.14.0] - 2026-10-11
4
11
 
5
12
  ### Fixed
@@ -167,6 +167,7 @@ module Capybara
167
167
  subscribe_to_console_capture
168
168
  subscribe_to_execution_context
169
169
  subscribe_to_navigation
170
+ subscribe_to_document_ready
170
171
  subscribe_to_turbo_signals
171
172
  # Network owns the Network.* domain: enabling installs traffic
172
173
  # tracking AND the navigation-response capture behind status_code.
@@ -425,13 +426,15 @@ module Capybara
425
426
  #
426
427
  # Sniff window: the action returns synchronously, but the CDP events
427
428
  # signalling its async fallout arrive later on the dispatch thread. We
428
- # poll briefly for any of them — a main-frame navigation start (see
429
- # subscribe_to_navigation), Runtime.executionContextsCleared, or the
430
- # turbo sentinel — and if none fires within the window, assume the
431
- # action was inert and exit fast. Lightpanda announces a navigation
432
- # ~5 ms after the click but only swaps the execution context once the
433
- # response lands, so watching the context alone returned on the old
434
- # document whenever the server took longer than the window.
429
+ # poll briefly for either of them — a main-frame navigation start (see
430
+ # subscribe_to_navigation) or Runtime.executionContextsCleared — and if
431
+ # none fires within the window, assume the action was inert and exit
432
+ # fast. Lightpanda announces a navigation ~5 ms after the click but only
433
+ # swaps the execution context once the response lands, so watching the
434
+ # context alone returned on the old document whenever the server took
435
+ # longer than the window. The turbo sentinel does not end the sniff
436
+ # (it is awaited after): Turbo goes busy then idle within a few ms on a
437
+ # link it hands back to the browser, before the navigation start lands.
435
438
  SNIFF_WINDOW = 0.05
436
439
  private_constant :SNIFF_WINDOW
437
440
 
@@ -444,7 +447,6 @@ module Capybara
444
447
  navigating = @navigation_event.iteration > prior_navigation_iteration
445
448
  break if navigating
446
449
  break if @default_context_event.iteration > prior_context_iteration
447
- break unless @turbo_event.set?
448
450
  break if monotonic_time > sniff_deadline
449
451
 
450
452
  sleep 0.001
@@ -452,7 +454,10 @@ module Capybara
452
454
 
453
455
  # Only a navigation this action started is awaited: one left pending
454
456
  # by an earlier load must not make every later click pay the timeout.
455
- @navigation_event.wait(@options.timeout) if navigating
457
+ if navigating
458
+ @navigation_event.wait(@options.timeout)
459
+ wait_for_document_ready
460
+ end
456
461
  @default_context_event.wait(@options.timeout)
457
462
  @turbo_event.wait(@options.timeout)
458
463
  check_unhandled_modal!
@@ -658,6 +663,64 @@ module Capybara
658
663
  end
659
664
  end
660
665
 
666
+ # The new document's context exists before its deferred and module
667
+ # scripts have run: this event marks the end of that phase, at
668
+ # Page.domContentEventFired or anything later that proves it is over
669
+ # (load, the frame stopping, the document request failing).
670
+ def subscribe_to_document_ready
671
+ @document_ready_event = Utils::Event.new
672
+ @document_ready_event.set
673
+
674
+ on("Page.frameStartedNavigating") do |params|
675
+ @document_ready_event.reset if main_frame_navigation_start?(params)
676
+ end
677
+ on("Page.domContentEventFired") { @document_ready_event.set }
678
+ on("Page.loadEventFired") { @document_ready_event.set }
679
+ on("Page.frameStoppedLoading") do |params|
680
+ @document_ready_event.set if params["frameId"] == @target_id
681
+ end
682
+ on("Network.loadingFailed") do |params|
683
+ @document_ready_event.set if params["requestId"] == @navigation_request_id
684
+ end
685
+ end
686
+
687
+ # After a click that navigated, the next action must not run before the
688
+ # new page's JS has wired its handlers: Stimulus, Bootstrap's data-api
689
+ # and Turbo load as module scripts, which run after the document commits
690
+ # and before DOMContentLoaded. Cuprite waits for the load event. The
691
+ # event is awaited briefly, then document.readyState is polled for the
692
+ # rest of the budget, as #go_to does (lightpanda-io/browser#1801: page
693
+ # events may never come). Never raises: a page that never settles costs
694
+ # the timeout once, then the action returns as it did before.
695
+ DOCUMENT_READY_EVENT_WAIT = 2
696
+ private_constant :DOCUMENT_READY_EVENT_WAIT
697
+
698
+ def wait_for_document_ready
699
+ deadline = monotonic_time + @options.timeout
700
+ return if @document_ready_event.wait([DOCUMENT_READY_EVENT_WAIT, @options.timeout].min)
701
+
702
+ remaining = deadline - monotonic_time
703
+ return unless remaining.positive?
704
+
705
+ Utils::Wait.until(timeout: remaining, interval: 0.1) do
706
+ @document_ready_event.set? || @client.closed? || document_complete?
707
+ end
708
+ rescue TimeoutError
709
+ nil
710
+ end
711
+
712
+ def document_complete?
713
+ response = @client.command(
714
+ "Runtime.evaluate",
715
+ { expression: "document.readyState", returnByValue: true },
716
+ session_id: @session_id,
717
+ timeout: 2
718
+ )
719
+ response.dig("result", "value") == "complete"
720
+ rescue Error
721
+ false
722
+ end
723
+
661
724
  def main_frame_navigation_start?(params)
662
725
  params["frameId"] == @target_id && !params["navigationType"].to_s.match?(/same/i)
663
726
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Lightpanda
5
- VERSION = "0.14.0"
5
+ VERSION = "0.14.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-lightpanda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Navid Emad