capybara-lightpanda 0.1.0 → 0.2.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: c46e211cf39dfb4b533c59ec88106fd9d4c72d59ed8ef11d99af0d9488885f9e
4
- data.tar.gz: 00f22e0a391ccc5c015291d72fa2d53f1d10062c0413f1fb62298a13a7006307
3
+ metadata.gz: 42246ea44b80c592e6779cf2aa95890c7635fb057b0061064b63bf15004dcde6
4
+ data.tar.gz: 63131038538438b32d39d8e46a36005df0306e8daadaa38ff88540874c6c46aa
5
5
  SHA512:
6
- metadata.gz: e3d08ffeb41acac97492d9c1cdf0aaca8499487b38afa6f1b8a1598f5c060cead1f0b4d5572f23ffeee0a49afc555f790a6e358c88816e143494619bd1f88128
7
- data.tar.gz: 7a2bfcafc663cba5614bd4385db9957f68d58255f6cfe4ee4a3090a447a5302f2a09db6dc2bcea9ce56795cb2e8739d1f440143e0c8da4d393e7078d76d9b229
6
+ metadata.gz: 1728491bdd3d3dac24559cc663ee250af16f90d7944d2c27be0b879ddbfc23a2a00181f39970d7622fd1b640449d97c7d373c4f6a414aae9073dc0f3cf92d1f8
7
+ data.tar.gz: 47e0408c55b5150347656d8136b6dc993b39d38a051a39efec480e2d913cf799f45c18242fd031bbb6962f79b7a39d63cc2eec8d2c14e2f42f34ed3b029af867
data/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.1] - 2026-05-05
4
+
5
+ ### Fixed
6
+
7
+ - Turbo Frame links now correctly swap the frame instead of falling through to a full-page navigation. Affects any test that clicks a link or submits a form inside a `<turbo-frame>`.
8
+ - Internal driver errors (`NoMethodError`, `NameError`, `Errno::*`) inside `extract_node_object_ids` and `page_ready?` are no longer swallowed and silently downgraded to `[]` / `false` — they surface as real exceptions so bugs are visible.
9
+
10
+ ### Internal
11
+
12
+ - Local test suite migrated from RSpec to Minitest::Spec. The Capybara shared-spec battery (`spec/features/session_spec.rb`) still runs on RSpec.
13
+
14
+ ## [0.2.0] - 2026-05-04
15
+
16
+ Reliability and feature polish as Lightpanda matured. **Update Lightpanda before upgrading**: this release requires a current nightly (the gem will tell you if yours is too old).
17
+
18
+ ### Added
19
+
20
+ - `Driver#wait_for_network_idle(timeout:, connections:)` — wait until in-flight HTTP requests drop to a threshold. Useful for SPAs and pages with deferred XHR.
21
+ - `handshake_timeout` driver option — cap how long the gem waits for the browser process to come up, separate from per-command timeouts.
22
+ - `Cookies` is now `Enumerable` — `cookies.find`, `cookies.select`, etc. work directly.
23
+ - `set_cookie` now infers the domain from the current URL (or `Capybara.app_host`) when you don't pass one.
24
+
25
+ ### Changed
26
+
27
+ - `accept_modal(:confirm)` and `accept_modal(:prompt)` now actually drive the JS return value. Previously they only captured the dialog message; the page-side `confirm()` / `prompt()` always saw the dismiss outcome.
28
+ - `prompt` dialogs now respect the `defaultText` argument when you call `accept_modal(:prompt)` without `with:`.
29
+ - Form interactions are noticeably more reliable on Turbo Drive pages, redirects, and JS-heavy SPAs — many subtle navigation/form-submit edge cases are now handled natively.
30
+ - All transient CDP errors inherit from `BrowserError`. A single `rescue Capybara::Lightpanda::BrowserError` catches the lot.
31
+
32
+ ### Fixed
33
+
34
+ - Capybara's `node #send_keys should generate key events`, `#has_field with valid`, `#fill_in` with range/date/time inputs, `#refresh reposts`, `attach_file` (most cases), `accept_confirm`, label clicks, image-button submits, and `<summary>` clicks all pass against the new nightly floor.
35
+ - A subscription leak in `Page.loadEventFired` after navigation could slowly accumulate listeners on long-running suites.
36
+ - `visibleText` no longer inserts a stray newline between adjacent empty block elements.
37
+ - A clearer error message when `lsof` isn't installed and the gem can't reclaim a stuck port.
38
+
39
+ ### Removed
40
+
41
+ - Most of the gem's JS polyfills — Lightpanda implements these natively now: the `#id` selector rewriter, the form-submission fetch+swap, the label/image-button/summary click handlers, and large parts of the visibility/disabled-state polyfills. No code change required on your end; tests should just pass.
42
+
43
+ ### Internal
44
+
45
+ - 91-case XPath 1.0 conformance battery (replaced ad-hoc specs).
46
+ - README redesign.
47
+
3
48
  ## [0.1.0] - 2026-04-27
4
49
 
5
50
  Initial release. Capybara driver for the [Lightpanda](https://github.com/lightpanda-io/browser) headless browser.
data/README.md CHANGED
@@ -1,200 +1,44 @@
1
- # Capybara::Lightpanda
1
+ <div align="center">
2
2
 
3
- A [Capybara](https://github.com/teamcapybara/capybara) driver for [Lightpanda](https://lightpanda.io/), the fast headless browser built in Zig.
3
+ # Capybara::Lightpanda
4
4
 
5
- This gem provides a **self-contained, production-ready** Capybara driver with a built-in CDP client. No external browser-client gem required — just install and go:
5
+ [![Gem version](https://img.shields.io/gem/v/capybara-lightpanda?logo=rubygems&logoColor=white&label=gem)](https://rubygems.org/gems/capybara-lightpanda)
6
+ [![Total downloads](https://img.shields.io/gem/dt/capybara-lightpanda?label=downloads)](https://rubygems.org/gems/capybara-lightpanda)
7
+ [![Tests](https://img.shields.io/github/actions/workflow/status/navidemad/capybara-lightpanda/ci.yml?branch=main&logo=github&label=tests)](https://github.com/navidemad/capybara-lightpanda/actions/workflows/ci.yml)
8
+ [![Rails compatible](https://img.shields.io/badge/Rails-compatible-CC0000?logo=rubyonrails&logoColor=white)](https://rubyonrails.org/)
9
+ [![Turbo friendly](https://img.shields.io/badge/Turbo-friendly-CC0000?logo=hotwire&logoColor=white)](https://turbo.hotwired.dev/)
6
10
 
7
- - **Reliable navigation** — falls back to `document.readyState` polling when `Page.loadEventFired` doesn't fire (a known Lightpanda limitation on pages with complex JS)
8
- - **XPath polyfill** auto-injected after each navigation so Capybara's internal XPath selectors work (`find`, `click_on`, `fill_in`, `assert_selector`, etc.)
9
- - **Cookie management** — `set_cookie`, `clear_cookies`, `remove_cookie` on the driver + graceful fallback when `Network.clearBrowserCookies` crashes the CDP connection
10
- - **Drop-in Capybara integration** — registers a `:lightpanda` driver, configure and go
11
+ A [Capybara](https://github.com/teamcapybara/capybara) driver for [Lightpanda](https://lightpanda.io/), the fast headless browser built in Zig.<br>
12
+ Self-containedbuilt-in CDP client, no external browser-client gem required.
11
13
 
12
- ## Architecture
14
+ <strong>Capybara</strong>&nbsp;&nbsp;→&nbsp;&nbsp;<code>capybara-lightpanda</code>&nbsp;&nbsp;→&nbsp;&nbsp;<a href="https://lightpanda.io/"><img src="docs/static/img/lightpanda-logo.svg" alt="Lightpanda" height="22" valign="middle"></a>&nbsp;<a href="https://github.com/lightpanda-io/browser/stargazers"><img src="https://img.shields.io/github/stars/lightpanda-io/browser?logo=github&label=stars" alt="GitHub stars" valign="middle"></a>
13
15
 
14
- Similar to how [Cuprite](https://github.com/rubycdp/cuprite) builds on [Ferrum](https://github.com/rubycdp/ferrum), but as a single gem:
16
+ [![Capybara::Lightpanda faster system tests for Rails, without Chromium](docs/static/img/banner.png)](https://navidemad.github.io/capybara-lightpanda/)
17
+ <sub><em>Configuration · dual-driver setups · Turbo Rails · capability matrix · beta-testing guide</em></sub>
15
18
 
16
- ```
17
- Capybara → capybara-lightpanda (driver + CDP client) → Lightpanda browser
18
- ```
19
+ [![Read the docs](https://img.shields.io/badge/https%3A%2F%2Fnavidemad.github.io%2Fcapybara--lightpanda-→%20Visit%20the%20website-1F2937?style=for-the-badge)](https://navidemad.github.io/capybara-lightpanda/)
19
20
 
20
- ## Installation
21
+ </div>
21
22
 
22
- ### 1. Install the Lightpanda browser
23
-
24
- ```bash
25
- # macOS
26
- brew install lightpanda-io/lightpanda/lightpanda
27
-
28
- # Linux (Debian/Ubuntu) — see https://lightpanda.io/docs/
29
- ```
23
+ ## Install
30
24
 
31
- ### 2. Add the gem
25
+ Add this to your `Gemfile` and run `bundle install`:
32
26
 
33
27
  ```ruby
34
- # Gemfile
35
28
  group :test do
36
29
  gem "capybara-lightpanda"
37
30
  end
38
31
  ```
39
32
 
40
- ```bash
41
- bundle install
42
- ```
43
-
44
- ## Usage
45
-
46
- ### Basic setup
33
+ In your test setup:
47
34
 
48
35
  ```ruby
49
- # test/support/capybara.rb or spec/support/capybara.rb
50
36
  require "capybara-lightpanda"
51
-
52
- Capybara::Lightpanda.configure do |config|
53
- config.host = "127.0.0.1"
54
- config.port = 9222
55
- config.timeout = 15
56
- config.browser_path = "/usr/local/bin/lightpanda" # optional, auto-detected
57
- end
58
-
59
- Capybara.default_driver = :lightpanda
60
37
  Capybara.javascript_driver = :lightpanda
61
38
  ```
62
39
 
63
- ### Dual-driver setup (recommended)
64
-
65
- Run most tests with Chrome, use Lightpanda for fast DOM-only tests:
66
-
67
- ```ruby
68
- if ENV["BROWSER"] == "lightpanda"
69
- require "capybara-lightpanda"
70
-
71
- Capybara::Lightpanda.configure do |config|
72
- config.timeout = 15
73
- end
74
-
75
- Capybara.default_driver = :lightpanda
76
- Capybara.javascript_driver = :lightpanda
77
- else
78
- # Your existing Chrome/Cuprite setup
79
- Capybara.default_driver = :cuprite
80
- end
81
- ```
82
-
83
- ```bash
84
- # Run with Lightpanda
85
- BROWSER=lightpanda bundle exec rails test test/system/
86
-
87
- # Run with Chrome (default)
88
- bundle exec rails test test/system/
89
- ```
90
-
91
- ### Setting cookies (e.g. login helper)
92
-
93
- ```ruby
94
- class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
95
- def login_as(user)
96
- session = user.sessions.first_or_create!
97
- cookie_jar = ActionDispatch::TestRequest.create({ "REQUEST_METHOD" => "GET" }).cookie_jar
98
- cookie_jar.signed[:session_id] = { value: session.id }
99
-
100
- page.driver.set_cookie(
101
- "session_id",
102
- cookie_jar[:session_id],
103
- domain: "127.0.0.1",
104
- httpOnly: true,
105
- secure: false,
106
- )
107
- end
108
- end
109
- ```
110
-
111
- ## What works
112
-
113
- - Navigation (`visit`, `click_link`, `go_back`, `go_forward`, `refresh`)
114
- - JavaScript execution (V8 engine) — `evaluate_script`, `execute_script`, `evaluate_async_script`
115
- - Forms — `fill_in`, `click_button`, `select`, `choose`, `check`, `uncheck`
116
- - Finding — `find`, `all`, `within`, CSS and XPath selectors
117
- - Matchers — `assert_selector`, `assert_text`, `assert_current_path`, `has_field?`, `has_select?`
118
- - Cookies — set/get/clear/remove via CDP
119
- - Frames — `within_frame`, scoped finding
120
- - Keyboard — `send_keys` with modifiers and special keys
121
- - Network — traffic tracking, custom headers, idle waiting
122
-
123
- ### Turbo Rails support
124
-
125
- The gem handles Turbo-enabled Rails apps transparently:
126
-
127
- | Feature | Status | How |
128
- |---------|--------|-----|
129
- | **Turbo Frames** | Works natively | Lazy-loading (`src=`), scoped link navigation |
130
- | **Turbo Drive** | Auto-disabled | Gem disables Drive (body replacement fails in Lightpanda) — standard link navigation restored |
131
- | **Form submission** | Auto-handled | When Turbo is present, forms submit via `fetch()` + `document.write()` to bypass Turbo's interception |
132
- | **Turbo Streams** | Not supported | Depends on Turbo's fetch pipeline which Lightpanda can't render |
133
-
134
- **Root cause**: Lightpanda's `document.body` is read-only — Turbo Drive's body replacement and frame form responses can't be applied. The gem works around this automatically.
135
-
136
- ## Known limitations
137
-
138
- These are Lightpanda browser limitations, not driver limitations:
139
-
140
- | Feature | Status |
141
- |---------|--------|
142
- | Screenshots | Not supported (no rendering engine) |
143
- | `window.getComputedStyle()` | Returns defaults (no CSS engine) |
144
- | `scroll_to`, `resize` | No layout engine |
145
- | Complex Stimulus controllers | Some may not execute fully |
146
- | XPath axes/functions | Polyfill covers ~80% of Capybara usage |
147
- | File uploads | Not yet supported |
148
- | Turbo Streams | Not supported (Turbo's fetch-then-render pipeline) |
149
-
150
- ## Benchmark
151
-
152
- Tested on a Rails 8.1 app (Turbo + Stimulus), 24 DOM-only tests:
153
-
154
- | Driver | Tests | Time | Speed |
155
- |--------|-------|------|-------|
156
- | **Lightpanda** | 24/24 pass | 6.89s | 3.48 tests/s |
157
- | **Chrome** | 24/24 pass | 7.09s | 3.38 tests/s |
158
-
159
- Lightpanda's advantage is expected to grow on larger suites due to faster startup and lower memory usage.
160
-
161
- ## Configuration
162
-
163
- ```ruby
164
- Capybara::Lightpanda.configure do |config|
165
- config.host = "127.0.0.1" # Lightpanda bind host
166
- config.port = 9222 # Lightpanda CDP port
167
- config.timeout = 15 # Navigation/command timeout (seconds)
168
- config.process_timeout = 10 # Browser process startup timeout
169
- config.browser_path = nil # Path to lightpanda binary (auto-detected)
170
- end
171
- ```
172
-
173
- ### Dynamic port (parallel tests)
174
-
175
- ```ruby
176
- def available_port
177
- server = TCPServer.new("127.0.0.1", 0)
178
- port = server.addr[1]
179
- server.close
180
- port
181
- end
182
-
183
- Capybara::Lightpanda.configure do |config|
184
- config.port = ENV.fetch("LIGHTPANDA_PORT", available_port).to_i
185
- end
186
- ```
187
-
188
- ## How it works
189
-
190
- | Component | Description |
191
- |-----------|-------------|
192
- | `Browser` | High-level API with readyState polling fallback when `Page.loadEventFired` never fires |
193
- | `Cookies` | Catches `BrowserError` from unsupported `Network.clearBrowserCookies`, deletes cookies individually |
194
- | `XPathPolyfill` | Provides `document.evaluate` + `XPathResult` shim for Capybara's XPath selectors |
195
- | `Client` | CDP command dispatch over WebSocket with timeout and event subscription |
196
- | `Driver` | Complete Capybara driver with `set_cookie`, `clear_cookies`, `remove_cookie` |
197
- | `Node` | DOM interactions via JavaScript evaluation |
40
+ > [!TIP]
41
+ > The Lightpanda binary is auto-downloaded on first use — no separate install step needed.
198
42
 
199
43
  ## Credits
200
44
 
@@ -202,13 +46,12 @@ end
202
46
  - [Capybara](https://github.com/teamcapybara/capybara) — the test framework
203
47
  - Inspired by the [Cuprite](https://github.com/rubycdp/cuprite) / [Ferrum](https://github.com/rubycdp/ferrum) architecture and [`lightpanda-ruby`](https://github.com/marcoroth/lightpanda-ruby)
204
48
 
205
- Patterns adapted from these MIT-licensed projects (cookies API, frame switching,
206
- node call/error conventions, retry/event utilities) are acknowledged with the
207
- original copyright notices in [NOTICE.md](NOTICE.md).
49
+ Patterns adapted from these MIT-licensed projects (cookies API, frame switching, node call/error conventions, retry/event utilities) are acknowledged with the original copyright notices in [NOTICE.md](NOTICE.md).
208
50
 
209
51
  ## Contributing
210
52
 
211
- Bug reports and pull requests are welcome on [GitHub](https://github.com/navidemad/capybara-lightpanda).
53
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/navidemad/capybara-lightpanda).<br>
54
+ For beta-testing tips and how to file useful feedback, see [BETA_TESTING.md](BETA_TESTING.md).
212
55
 
213
56
  ## License
214
57
 
@@ -73,7 +73,7 @@ module Capybara
73
73
  end
74
74
 
75
75
  def find
76
- env_path = ENV.fetch("LIGHTPANDA_PATH", nil)
76
+ env_path = ENV.fetch("LIGHTPANDA_BIN", nil)
77
77
  return env_path if env_path && File.executable?(env_path)
78
78
 
79
79
  path_binary = find_in_path