capybara_cr

Version, currently master branch1 version
  • master branchlatestOct 15, 2026

github.com/OrelSokolov/capybara.cr

Порт capybara 3.40.0 (github.com/teamcapybara/capybara) на Crystal — P0-подмножество для system-тестов: Session DSL (visit/click_link/ click_button/fill_in/has_content?/has_selector?/find/all/evaluate_script/ go_back/go_forward/save_screenshot) поверх ChromiumDriver — собственного минимального CDP-клиента (headless Chromium, websocket, без внешних зависимостей). Оракул — настоящая Capybara 3.40.0 + selenium-webdriver (oracle/capybara_cases.rb → capybara_expected.yml).

0 stars
0 dependents
License: not declared

Installation

# Add this to your shard.yml
dependencies:
  capybara_cr:
    github: OrelSokolov/capybara.cr
    branch: master

master is a branch, not a release, so this tracks it rather than pinning a version.

Then run:

shards install

shard.yml

Crystal
>= 1.21.0
Author
oleg

Dependencies

Runtime Dependencies

README

capybara.cr

A Crystal port of Capybara 3.40.0 (P0 scope) — browser-level system testing for CRails applications, built on a minimal homegrown CDP client (Chrome DevTools Protocol) over the stdlib HTTP::WebSocket, with no external dependencies (a replacement for selenium-webdriver). Request- level testing without a browser is covered separately by ActionDispatch::IntegrationSession in railties.cr.

⚠️ EXPERIMENTAL — DO NOT USE IN PRODUCTION YET.

Installation

dependencies:
  capybara_cr:
    github: OrelSokolov/capybara.cr
shards install

The port itself is pure stdlib; railties_cr is needed only by the specs (demo app).

Usage

session = Capybara::Session.new(
  Capybara::ChromiumDriver.new,
  base_url: "http://127.0.0.1:3000"
)

session.visit "/posts"
session.click_link "New Post"
session.fill_in "Title", with: "Hello"
session.click_button "Create"
session.has_content?("Post was successfully created") # => true (waits)
session.save_screenshot("tmp/screenshot.png")

Chromium binary: CHROMIUM_BIN or auto-detection of chromium/chromium-browser/google-chrome[-stable]; launched headless (--headless=new --remote-debugging-port=0, throwaway user-data-dir).

Feature comparison vs capybara 3.40.0

FeatureOriginal (capybara)Port (capybara.cr)Status
Drivers: rack_test✅Not ported — request-level is ActionDispatch::IntegrationSession (railties.cr)❌ (equivalent: integration session)
Drivers: selenium✅Capybara::ChromiumDriver — own CDP client: page target, Page.navigate, Runtime.evaluate (returnByValue + awaitPromise), Page.captureScreenshot, readiness polling on document.readyState🔶
visit / current_path / current_url / title✅Same✅
click_link / click_button (id / exact text / aria-label, substring fallback)✅Click is a JS el.click(), not trusted Input.dispatchMouseEvent events🔶
fill_in(locator, with:) (label[for] → id/name/placeholder)✅Same✅
find / all → Node (.text, [](attr), .click, .set)✅Nodes pinned via an internal data-capybara-node attribute instead of backend RemoteObject handles🔶
has_content? / has_no_content? / has_selector? with waiting✅Polling up to Capybara.default_wait_time (2 s), like the gem's default_max_wait_time✅
evaluate_script / execute_script✅Same✅
go_back / go_forward✅Same✅
save_screenshot✅Same✅
Capybara.app_host✅base_url on the session; visit("/path") navigates the browser to the real HTTP server🔶
select / check / uncheck / attach_file, within, windows/iframes, match/text locator options, modal dialogs, save_and_open_page, JS errors raised in has_*✅Not ported⬜

Deviations & Crystal-specific notes

  • No external shards: CDP over stdlib websockets; chromedriver is not used at all.
  • has_*/find wait semantics match the gem; non-waiting assertions (has_content? in the gem's non-waiting form) always poll.

Testing

crystal spec

Oracle: oracle/capybara_cases.rb runs a mini Rack app with fixed HTML through the real capybara 3.40.0 + selenium-webdriver (headless Chrome) — 10 cases (visit, click_link, fill_in+submit, has_content true/false, item count, href attribute, evaluate_script, async content appearing after 300 ms, go_back/forward, screenshot). The mirror spec/capybara_spec.cr runs a CRails app with byte-identical HTML — 10/10. The spec skips cleanly when no chromium binary is available. Regenerate the oracle with PATH=/usr/bin:/bin ruby oracle/capybara_cases.rb > oracle/capybara_expected.yml.