Framework
teamcapybara/capybara avatar
teamcapybara/capybara

Capybara: acceptance tests that swap Rack::Test for Selenium

Acceptance test framework for web applications

10,171 stars1,475 forksRubyMIT

At a glance

What is it?
Capybara is a Ruby acceptance test framework that keeps one test DSL while the driver underneath changes from an in-process Rack stack to a real browser. The trade is that JavaScript coverage depends on you tagging the right examples.
Who is it for?
Adopt Capybara if your suite already lives in Ruby, targets a Rack or Rails app, and you want one test body that runs fast in process and in a real browser. Skip it if you need JavaScript coverage you do not have to opt into, or if a suite on Ruby older than 3.0.0 has to keep working.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 40 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • teamcapybara/capybara10,171 ★ · -1
Star history
Repository2026-09-222026-11-13
teamcapybara/capybara10.2k10.2k

-1 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Rack::Test is the default driver, and it never runs your JavaScript

Capybara tests a web application by simulating how a real user would interact with it. What it refuses to decide for you is the layer underneath. The framework is agnostic about the driver running your tests, and it comes with Rack::Test and Selenium support built in. WebKit is handled through an external gem you add yourself.

That agnosticism buys one concrete thing: the backend your tests run against can move from fast headless mode to an actual browser with no changes to your tests. The test body stays the same, the server stays the same, only the driver changes.

The cost lands on your first JavaScript feature. The setup section says that if you need to test JavaScript, or if your app interacts with or is located at a remote URL, you will need a different driver. Until those examples are marked, assertions run against a response that never executed a script, so a passing suite can mean an element existed in the served markup rather than that your code put it there.

One DSL across Cucumber, RSpec, Test::Unit and Minitest

Test runners attach to Capybara in different ways, and the differences are more than a require line. With cucumber-rails, support is already built in; outside Rails you load `capybara/cucumber` yourself and point it at your app. With RSpec 3.5 or later, `capybara/rspec` goes into `spec_helper.rb`, Rails users drop specs into `spec/features` or `spec/system`, and anyone using another directory tags the example groups with `type: :feature` or `type: :system`.

Metadata is where the friction shows up. Moving a spec between runners means rewriting tags, not just syntax, and the driver choice travels in the same metadata: `js: true` switches an example to the `Capybara.javascript_driver`, which is `:selenium` by default, while `driver: :selenium` pins one example to one driver. Cucumber expresses the same idea with an `@javascript` tag on a scenario, plus a tag per registered driver such as `@selenium` or `@rack_test`. A built-in `feature` DSL with `background` and `scenario` gives RSpec users Cucumber-shaped output when they want it.

gem 'capybara' on Ruby 3.0.0, then a spec that clicks for real

Capybara requires Ruby 3.0.0 or later. Installation is a single line in your Gemfile followed by `bundle install`:

ruby
gem 'capybara'

A Rails app needs `require 'capybara/rails'` in the test helper file. A Rack app that is not Rails needs its class assigned to `Capybara.app`.

Your first real test is the sign in flow, and the shape is the same in every runner:

ruby
describe "the signin process", type: :feature do
  before :each do
    User.create(email: '[email protected]', password: 'password')
  end

  it "signs me in" do
    visit '/sessions/new'
    within("#session") do
      fill_in 'Email', with: '[email protected]'
      fill_in 'Password', with: 'password'
    end
    click_button 'Sign in'
    expect(page).to have_content 'Success'
  end
end

Read it as a person would act. Visit the page, scope to `#session`, fill two fields, click the button, assert the text. Only the `#session` selector ties the test to your markup structure; the other lines use the visible labels a user would see.

The app server is a separate setting from the driver

The setup section gives a specific warning: if you use Rails 5.0 or later without the Rails system tests from 5.1, you will probably also want to swap the server used to launch your app to Puma, in order to match Rails defaults.

ruby
Capybara.server = :puma # Until your setup is working
Capybara.server = :puma, { Silent: true } # To clean up your test output

Those two comments are the documentation's own guidance on ordering. Start with the bare assignment while you get a first run working. Only switch to the Silent form once the suite actually passes.

Worth noting what this setting is not. It chooses the Rack handler Capybara boots to serve your app; it does not touch the browser. A suite that swaps to Puma and still fails on a JavaScript interaction has a driver problem, not a server problem.

Two Selenium services, one SELENIUM_IMAGE variable, port 4445 on Firefox

The repository root ships a docker-compose.yml that stands up the browser side for you, and its two services differ in one place worth reading:

yaml
  selenium_chrome:
    network_mode: "host"
    image: "selenium/${SELENIUM_IMAGE:-standalone-chrome}"
    volumes:
      - "/dev/shm:/dev/shm"
  selenium_firefox:
    network_mode: "host"
    image: "selenium/${SELENIUM_IMAGE:-standalone-firefox}"
    volumes:
      - "/dev/shm:/dev/shm"
    environment:
      - SE_OPTS=-port 4445

Both services share host networking and the `/dev/shm` mount. The Firefox service passes `SE_OPTS=-port 4445`, so it listens on a port you can point at by number, while the Chrome service keeps whatever the image ships with. Run both at once and you are tracking two different endpoints.

`SELENIUM_IMAGE` is the single knob, and it has a sharp edge. The default is per service, standalone-chrome for one and standalone-firefox for the other, but export one value and both services switch to that image together. Setting it to a Chrome tag to pin your own browser build quietly replaces the Firefox service too, which is the kind of thing you find out about from a failing Firefox run.

No GitHub releases, so the gem version is the only release handle

Capybara has no GitHub releases and ships as a gem. The repository uses master as its default branch and was last pushed to on 2026-10-05, so work continues, but there is no GitHub release page to compare versions on. What you pin instead is the version resolved in your Gemfile.lock.

The release record lives in files. History.md at the root is the changelog, and UPGRADING.md sits next to it, which makes it the file to read before a major version bump rather than discovering the breakage from a red suite. The gem's own definition is capybara.gemspec, the Rakefile sits beside it, and a file named gem-public_cert.pem sits at the root as the public certificate used to sign those releases. Linting config for contributors lives in .rubocop.yml and .yardopts.

Support follows the same shape. The README points help requests at the teamcapybara Discussions board and asks that you do not open an issue for them, and ongoing work is funded through a Patreon page.

What Capybara will not do, and where a browser-first runner differs

Three boundaries matter before you commit a suite to it. Ruby 3.0.0 is the floor, so a codebase stuck on an older interpreter cannot adopt the current gem. JavaScript is opt in per example, so coverage of your front end exists only where someone remembered to mark it. And there are no GitHub releases, so tracking upstream means watching History.md.

The alternative shape is a browser-first runner such as Playwright or Cypress, which drive a real browser from their own runtime and never boot your Rack app in process. You lose Capybara's central bargain, the same test body running on a fast in-process driver and on a real browser, and you gain a tool that speaks to a browser directly with no Ruby in the chain. Driving Selenium yourself is the middle path: same browser, but the waiting and the element lookup become your code instead of the framework's.

The documentation reserves separate sections for selector name, locator and filters, then for matching exactness and strategy, plus lists of gotchas and a "Threadsafe" mode.

Editorial conclusion

Adopt Capybara if your suite already lives in Ruby, targets a Rack or Rails app, and you want one test body that runs fast in process and in a real browser. Skip it if you need JavaScript coverage you do not have to opt into, or if a suite on Ruby older than 3.0.0 has to keep working. Before adding the gem, read the compose file in the repository root and decide whether SELENIUM_IMAGE will point at your own browser image, because that one environment variable changes both Selenium services at once.

Frequently asked questions

Which Ruby version does Capybara need?

Capybara requires Ruby 3.0.0 or later. Anything older cannot run the current gem.

Does Capybara need a real browser to run a basic test?

Rack::Test support is built in, along with Selenium support, so simple requests run against your app in process. A different driver is needed when the test needs JavaScript, or when your app interacts with or is located at a remote URL.

How do I run Capybara with RSpec?

Load `capybara/rspec` in your spec_helper.rb, which needs RSpec 3.5 or later. Put Rails specs in spec/features or spec/system, or tag example groups with type: :feature when you are not using Rails.

How do I switch one Capybara example to Selenium?

Mark it with js: true to use the Capybara.javascript_driver, which is :selenium by default, or pass driver: :selenium to pin that single example. In Cucumber the same choice is the @javascript tag on a scenario.

How do I add Capybara to a non-Rails project?

Assign your application class to Capybara.app, and use Capybara.server to control which server is launched. For Cucumber without Rails, require capybara/cucumber and set Capybara.app yourself.

What licence is Capybara released under?

The project is released under the MIT licence, with the text in License.txt at the repository root. Maintenance is funded through a Patreon page linked from the README.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. teamcapybara/capybara on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/teamcapybara-capybara.svg)](https://hysenlabs.com/projects/teamcapybara-capybara)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/teamcapybara-capybara.svg)](https://hysenlabs.com/projects/teamcapybara-capybara)

Was this useful?