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 +4 -4
- data/CHANGELOG.md +45 -0
- data/README.md +22 -179
- data/lib/capybara/lightpanda/binary.rb +1 -1
- data/lib/capybara/lightpanda/browser.rb +179 -85
- data/lib/capybara/lightpanda/client/subscriber.rb +29 -2
- data/lib/capybara/lightpanda/client/web_socket.rb +4 -2
- data/lib/capybara/lightpanda/client.rb +7 -0
- data/lib/capybara/lightpanda/cookies.rb +14 -53
- data/lib/capybara/lightpanda/driver.rb +43 -6
- data/lib/capybara/lightpanda/errors.rb +58 -15
- data/lib/capybara/lightpanda/javascripts/index.js +33 -143
- data/lib/capybara/lightpanda/javascripts/polyfills.js +81 -0
- data/lib/capybara/lightpanda/keyboard.rb +45 -4
- data/lib/capybara/lightpanda/network.rb +32 -2
- data/lib/capybara/lightpanda/node.rb +97 -209
- data/lib/capybara/lightpanda/options.rb +9 -1
- data/lib/capybara/lightpanda/process.rb +53 -13
- data/lib/capybara/lightpanda/utils/attempt.rb +30 -0
- data/lib/capybara/lightpanda/version.rb +1 -1
- data/lib/capybara/lightpanda/xpath_polyfill.rb +5 -0
- data/lib/capybara-lightpanda.rb +1 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 42246ea44b80c592e6779cf2aa95890c7635fb057b0061064b63bf15004dcde6
|
|
4
|
+
data.tar.gz: 63131038538438b32d39d8e46a36005df0306e8daadaa38ff88540874c6c46aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Capybara::Lightpanda
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://rubygems.org/gems/capybara-lightpanda)
|
|
6
|
+
[](https://rubygems.org/gems/capybara-lightpanda)
|
|
7
|
+
[](https://github.com/navidemad/capybara-lightpanda/actions/workflows/ci.yml)
|
|
8
|
+
[](https://rubyonrails.org/)
|
|
9
|
+
[](https://turbo.hotwired.dev/)
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
-
|
|
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-contained — built-in CDP client, no external browser-client gem required.
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
<strong>Capybara</strong> → <code>capybara-lightpanda</code> → <a href="https://lightpanda.io/"><img src="docs/static/img/lightpanda-logo.svg" alt="Lightpanda" height="22" valign="middle"></a> <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
|
-
|
|
16
|
+
[](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
|
+
[](https://navidemad.github.io/capybara-lightpanda/)
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
</div>
|
|
21
22
|
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|