capybara-simulated 0.8.0 → 0.9.0
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 +4 -4
- data/README.md +8 -7
- data/lib/capybara/simulated/browser.rb +537 -33
- data/lib/capybara/simulated/driver.rb +42 -13
- data/lib/capybara/simulated/js/bridge.bundle.js +6606 -3888
- data/lib/capybara/simulated/node.rb +8 -0
- data/lib/capybara/simulated/quickjs_runtime.rb +22 -8
- data/lib/capybara/simulated/runtime_shared.rb +29 -28
- data/lib/capybara/simulated/v8_runtime.rb +69 -20
- data/lib/capybara/simulated/version.rb +1 -1
- metadata +1 -1
|
@@ -52,7 +52,10 @@ module Capybara
|
|
|
52
52
|
@@live.select!(&:weakref_alive?)
|
|
53
53
|
@@live.filter_map {|ref| ref.__getobj__ rescue nil }
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
# A DISPOSED driver is not live: its runtime context is gone, so calling into it raises
|
|
56
|
+
# (`undefined method 'call' for nil` out of `run_loop_step`). `dispose` deregisters, but the
|
|
57
|
+
# predicate is the belt — a WeakRef stays in the list until GC actually collects.
|
|
58
|
+
drivers.each {|d| yield d if d.owner_thread == thread && !d.disposed? }
|
|
56
59
|
end
|
|
57
60
|
|
|
58
61
|
# `viewport: [w, h]` and `user_agent:` (typically supplied via
|
|
@@ -310,9 +313,18 @@ module Capybara
|
|
|
310
313
|
# isolate per cross-origin file (hundreds over the suite); disposing here
|
|
311
314
|
# incrementally is what reset_windows! already does for aux windows.
|
|
312
315
|
def dispose
|
|
316
|
+
return if @disposed
|
|
317
|
+
@disposed = true
|
|
318
|
+
# Drop out of the live registry FIRST: everything below tears down the runtime this driver
|
|
319
|
+
# would be asked to step if `each_live_on_thread` still yielded it.
|
|
320
|
+
@@live_lock.synchronize { @@live.reject! {|ref| (ref.__getobj__ rescue nil).equal?(self) } }
|
|
313
321
|
reset_windows!
|
|
314
322
|
@browser.dispose rescue nil
|
|
315
323
|
end
|
|
324
|
+
|
|
325
|
+
# Has this driver been permanently dropped? (A `reset!` between examples does NOT set this —
|
|
326
|
+
# that rebuilds the page on a live runtime.)
|
|
327
|
+
def disposed? = @disposed == true
|
|
316
328
|
def go_back = current_browser.go_back
|
|
317
329
|
def go_forward = current_browser.go_forward
|
|
318
330
|
def reset_history! = current_browser.reset_history!
|
|
@@ -362,6 +374,12 @@ module Capybara
|
|
|
362
374
|
window_entries.find {|w| w[:handle] == handle }&.fetch(:browser)
|
|
363
375
|
end
|
|
364
376
|
|
|
377
|
+
# Same, but for the operations that ADDRESS a window rather than probe for one: a closed or
|
|
378
|
+
# unknown handle is Capybara's `WindowError`, never a silent fall back to the current window.
|
|
379
|
+
def window_browser!(handle)
|
|
380
|
+
window_browser(handle) or raise Capybara::WindowError, "Unknown window handle: #{handle}"
|
|
381
|
+
end
|
|
382
|
+
|
|
365
383
|
# Open (or, by `name`, reuse) an auxiliary window. `target="_blank"`
|
|
366
384
|
# clicks and `window.open` both land here. A non-empty `name` that
|
|
367
385
|
# matches an existing window navigates that window instead of opening a
|
|
@@ -425,7 +443,7 @@ module Capybara
|
|
|
425
443
|
|
|
426
444
|
# `window.open(url, name)` from the `opener` window's JS. Resolves the URL
|
|
427
445
|
# against the opener's document and records the opener relationship.
|
|
428
|
-
def open_window_from_js(opener_browser, url, name, opener_realm_id = 0)
|
|
446
|
+
def open_window_from_js(opener_browser, url, name, opener_realm_id = 0, about_base = nil, about_origin = nil)
|
|
429
447
|
resolved = url.to_s.empty? ? nil : opener_browser.resolve_document_url(url)
|
|
430
448
|
# Opening a blob: URL whose storage partition differs from the opener's
|
|
431
449
|
# top-level site is forced NOOPENER (cross-partition-navigation): the new
|
|
@@ -441,7 +459,7 @@ module Capybara
|
|
|
441
459
|
# cross-window scripting/adoption need no cross-isolate RPC. The opener's realm
|
|
442
460
|
# id wires the popup's window.opener. Falls through to the separate-VM aux path
|
|
443
461
|
# (cross-origin, or a URL we don't yet realm-load).
|
|
444
|
-
if (rid = opener_browser.open_window_realm(resolved, name: name, opener_realm_id: opener_realm_id))
|
|
462
|
+
if (rid = opener_browser.open_window_realm(resolved, name: name, opener_realm_id: opener_realm_id, about_base: about_base, about_origin: about_origin))
|
|
445
463
|
return rid
|
|
446
464
|
end
|
|
447
465
|
open_aux_window(resolved, name: name, opener_handle: handle_for(opener_browser), source: opener_browser)
|
|
@@ -634,7 +652,14 @@ module Capybara
|
|
|
634
652
|
def open_new_window(_kind = :tab)
|
|
635
653
|
open_aux_window('about:blank')
|
|
636
654
|
end
|
|
637
|
-
|
|
655
|
+
# Every window has its own viewport, so these address the window the
|
|
656
|
+
# handle names — not the active one. `Capybara::Window#resize_to` on a
|
|
657
|
+
# background window must resize THAT window and leave the current one
|
|
658
|
+
# (and Capybara's idea of which window is current) alone.
|
|
659
|
+
def window_size(handle)
|
|
660
|
+
b = window_browser!(handle)
|
|
661
|
+
[b.viewport_width, b.viewport_height]
|
|
662
|
+
end
|
|
638
663
|
def close_window(h)
|
|
639
664
|
return if h == PRIMARY_HANDLE
|
|
640
665
|
@aux_windows.reject! {|w|
|
|
@@ -655,19 +680,23 @@ module Capybara
|
|
|
655
680
|
end
|
|
656
681
|
end
|
|
657
682
|
def switch_to_window(h)
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
elsif @aux_windows.any? {|w| w[:handle] == h }
|
|
661
|
-
@active_handle = h
|
|
662
|
-
else
|
|
663
|
-
raise Capybara::WindowError, "Unknown window handle: #{h}"
|
|
664
|
-
end
|
|
683
|
+
window_browser!(h) # unknown / already-closed handle → WindowError
|
|
684
|
+
@active_handle = (h == PRIMARY_HANDLE ? nil : h)
|
|
665
685
|
end
|
|
666
|
-
def resize_window_to(
|
|
686
|
+
def resize_window_to(handle, w, h) = window_browser!(handle).set_viewport(w, h)
|
|
667
687
|
# Forem's ahoy-tracking spec calls `driver.resize(w, h)` directly
|
|
668
688
|
# rather than through `current_window.resize_to`.
|
|
669
689
|
def resize(w, h) = current_browser.set_viewport(w, h)
|
|
670
|
-
|
|
690
|
+
# Both restore the window to the display it lives on (`Browser#screen_size`), which is where
|
|
691
|
+
# it started — so they undo a `resize_to` rather than doing nothing. Coarse: we model no
|
|
692
|
+
# window chrome, so a maximized window and a fullscreen one end up the same size (a real
|
|
693
|
+
# browser's fullscreen is taller by the chrome it hides).
|
|
694
|
+
def maximize_window(handle) = restore_window_size(handle)
|
|
695
|
+
def fullscreen_window(handle) = restore_window_size(handle)
|
|
696
|
+
private def restore_window_size(handle)
|
|
697
|
+
b = window_browser!(handle)
|
|
698
|
+
b.set_viewport(*b.screen_size)
|
|
699
|
+
end
|
|
671
700
|
|
|
672
701
|
def evaluate_script(script, *args)
|
|
673
702
|
unwrap(current_browser.evaluate_script(script, args))
|