capybara-simulated 0.7.0 → 0.8.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.
@@ -71,7 +71,12 @@ module Capybara
71
71
  # level and inject them into every per-window Browser. Each
72
72
  # Browser still has its own sessionStorage + DOM + JS VM.
73
73
  @cookies = {}
74
+ @auth_cache = {}
74
75
  @local_storage = {}
76
+ # Cache Storage (caches/Cache) is origin-shared like localStorage — owned at the
77
+ # Driver level and injected, so a service worker and every same-origin window see
78
+ # the same caches (partitioned by origin key within the store).
79
+ @cache_storage = {}
75
80
  # Capture the universal-server flag ONCE, at session construction — the WPT
76
81
  # runner sets CSIM_LOCAL_ALL_HOSTS only while building the session, then
77
82
  # restores it. Every window (incl. aux windows opened later) inherits this so
@@ -100,7 +105,9 @@ module Capybara
100
105
  driver: self,
101
106
  js_engine: @js_engine,
102
107
  cookies: @cookies,
108
+ auth_cache: @auth_cache,
103
109
  local_storage: @local_storage,
110
+ cache_storage: @cache_storage,
104
111
  all_hosts_local: @all_hosts_local)
105
112
  end
106
113
 
@@ -292,6 +299,20 @@ module Capybara
292
299
  @active_handle = nil
293
300
  @blob_partitions_lock.synchronize { @blob_partitions.clear }
294
301
  end
302
+
303
+ # Full teardown of the whole driver: aux windows AND the primary browser's
304
+ # V8 isolate. `reset_windows!` deliberately keeps the primary alive (the
305
+ # per-test reset path rebuilds only its page); this is for permanently
306
+ # DROPPING a session. A caller that nils its session without this leaks the
307
+ # primary isolate — with its heap, canvas pixel buffers, and worker threads —
308
+ # into V8Runtime's process-wide `@@live` until at_exit. The WPT runner recycles
309
+ # the cross-origin session per `.sub.`/`.https.` file, so that leak is ~one
310
+ # isolate per cross-origin file (hundreds over the suite); disposing here
311
+ # incrementally is what reset_windows! already does for aux windows.
312
+ def dispose
313
+ reset_windows!
314
+ @browser.dispose rescue nil
315
+ end
295
316
  def go_back = current_browser.go_back
296
317
  def go_forward = current_browser.go_forward
297
318
  def reset_history! = current_browser.reset_history!
@@ -506,10 +527,30 @@ module Capybara
506
527
 
507
528
  # `BroadcastChannel.postMessage` — deliver to every OTHER window's channels
508
529
  # with the same name (same-window delivery is handled in-VM by the sender).
509
- def broadcast_channel(source_browser, name, data)
530
+ def broadcast_channel(source_browser, name, data, origin = nil)
531
+ # An opaque origin is unique to its own agent cluster; its key is a token ('opaque:…') minted
532
+ # per-realm and therefore only unique WITHIN one isolate — two unrelated opaque contexts in
533
+ # DIFFERENT windows could mint the same token. A BroadcastChannel never bridges two distinct
534
+ # opaque origins, and no opaque origin spans separate top-level windows here, so a cross-
535
+ # WINDOW post from an opaque origin reaches no one: drop it rather than risk a cross-isolate
536
+ # token collision. (Same-isolate opaque peers are reached in-VM / via enqueue_broadcast; an
537
+ # inherited-origin blob worker via its own inbox — neither goes through this cross-window path.)
538
+ return if origin.to_s.start_with?('opaque:')
539
+ window_entries.each do |w|
540
+ next if w[:browser].equal?(source_browser)
541
+ w[:browser].enqueue_broadcast(name, data, nil, origin)
542
+ end
543
+ end
544
+
545
+ # A localStorage change fans out to every OTHER window (localStorage spans same-origin
546
+ # browsing contexts). Every window shares the Driver's one `@local_storage` jar, so all
547
+ # windows are same-origin peers here (cross-origin storage partitioning is a separate
548
+ # backlog item); a nil source realm reaches each target's every realm. sessionStorage is
549
+ # per-context and never reaches this path.
550
+ def storage_broadcast(source_browser, kind, key, old, new, url)
510
551
  window_entries.each do |w|
511
552
  next if w[:browser].equal?(source_browser)
512
- w[:browser].enqueue_broadcast(name, data)
553
+ w[:browser].enqueue_storage_event(kind, key, old, new, url, nil)
513
554
  end
514
555
  end
515
556