capybara-simulated 0.8.0 → 0.10.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.
@@ -5,26 +5,49 @@ module Capybara
5
5
  # Engine-uniform adapter Browser#run_worker drives. Each engine
6
6
  # class (`V8Runtime`, `QuickJSRuntime`) has a `build_worker` class
7
7
  # method that constructs the engine-specific Context/VM and wires
8
- # it through these five callbacks. Worker thread doesn't care
9
- # which engine it's running on; it just calls `eval` / `call` /
8
+ # it through these callbacks. Worker thread doesn't care
9
+ # which engine it's running on; it just calls `eval_void` / `call` /
10
10
  # `drain_microtasks` / `drain_timers` / `has_ready_timer?` /
11
- # `dispose`.
11
+ # `terminate` / `dispose`.
12
12
  class WorkerRuntime
13
- def initialize(eval_fn:, call_fn:, drain_microtasks:, drain_timers:, has_ready_timer:, dispose:)
14
- @eval = eval_fn
15
- @call = call_fn
16
- @drain_microtasks = drain_microtasks
17
- @drain_timers = drain_timers
18
- @has_ready_timer = has_ready_timer
19
- @dispose = dispose
13
+ def initialize(eval_void_fn:, call_fn:, drain_microtasks:, drain_timers:, has_ready_timer:, dispose:, terminate: nil, eval_module_graph: nil)
14
+ @eval_void = eval_void_fn
15
+ @call = call_fn
16
+ @drain_microtasks = drain_microtasks
17
+ @drain_timers = drain_timers
18
+ @has_ready_timer = has_ready_timer
19
+ @dispose = dispose
20
+ @terminate = terminate
21
+ @eval_module_graph = eval_module_graph
20
22
  end
21
23
 
22
- def eval(src) = @eval.call(src)
24
+ def eval_void(src) = @eval_void.call(src)
23
25
  def call(name, *args) = @call.call(name, *args)
24
26
  def drain_microtasks = @drain_microtasks.call
25
27
  def drain_timers = @drain_timers.call
26
28
  def has_ready_timer? = @has_ready_timer.call
27
29
  def dispose = @dispose.call
30
+ # Stop whatever JavaScript this worker is running, FROM ANOTHER THREAD — the one thing the
31
+ # main thread can do to a worker that is inside a call, where the `:terminate` inbox message
32
+ # cannot reach it and `Thread#kill` does not land (see `Browser#stop_worker_js`). The call in
33
+ # flight ends as a terminated call; the worker's own loop then unwinds and disposes.
34
+ # `nil` on an engine with nothing to hand back — QuickJS — where this is a no-op.
35
+ def terminate = @terminate&.call
36
+ # Can this engine stop a call from ANOTHER thread at all? V8 can; QuickJS cannot. The
37
+ # boundary asks, because the answer changes what it should do next: where there is nothing
38
+ # to terminate, waiting for a terminate to work is pure delay and `Thread#kill` — which does
39
+ # land on that engine — is the right escalation.
40
+ def terminable? = !@terminate.nil?
41
+
42
+ # Native ES-module evaluation of a worker MAIN script + its static import
43
+ # graph (a `{type: 'module'}` service worker). `fetch_import` is called on
44
+ # the worker's own thread for each resolved static import URL and returns
45
+ # the script source (raising fails the evaluation — an import that 404s or
46
+ # has a non-JS MIME type fails the module script, and with it the Run
47
+ # Service Worker job). nil on engines without a native module API
48
+ # (QuickJS) — the caller falls back to the classic-eval path.
49
+ def module_graph? = !@eval_module_graph.nil?
50
+ def eval_module_graph(src, url, fetch_import) = @eval_module_graph.call(src, url, fetch_import)
28
51
  end
29
52
  end
30
53
  end
@@ -1,6 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'capybara'
4
+ # The rasteriser behind image decoding and the canvas surface — required HERE rather than lazily at
5
+ # each use, because a bundle without it does not merely lose canvas: an image's intrinsic size feeds
6
+ # LAYOUT, so pages with images would be laid out wrong while only warning. The gem is a hard
7
+ # dependency; what can still be missing is the libvips SYSTEM library it binds to, so name it.
8
+ begin
9
+ require 'vips'
10
+ rescue LoadError => e
11
+ raise LoadError, "capybara-simulated needs the libvips system library (Debian/Ubuntu " \
12
+ "`libvips42`, Homebrew `vips`, Gentoo `media-libs/vips`): #{e.message}"
13
+ end
4
14
  require 'capybara/simulated/version'
5
15
  require 'capybara/simulated/driver'
6
16
 
@@ -24,6 +34,10 @@ module Capybara
24
34
  # set together. Read-and-cleared by the register_driver block.
25
35
  class << self
26
36
  attr_accessor :next_driver_viewport, :next_driver_user_agent
37
+
38
+ # Empty the process-wide HTTP cache (see `Driver#clear_http_cache`) — the
39
+ # module-level form for a hook that runs before any session exists.
40
+ def clear_http_cache = Browser.clear_http_cache
27
41
  end
28
42
  end
29
43
  end