Benito Serna Tips and tools for Ruby on Rails developers

Use dom_id helper on capybara with rspec and rails

May 2, 2022

At least for me it is very common to use the within method in capybara, to match the dom_id output.

And is very common to do it with code like "#user_#{user.id}" or #project_#{project.id}.

In this way:

within "#user_#{user.id}" do
  expect(page).to have_text user.name
end

# or...

within "#project_#{project.id}" do
  expect(page).to have_text project.name
end

If you do it one time, there is no trouble, but if you start doing it in every file, maybe you will want to do something to remove the repetition.

Here I will show you two tips, to help you avoid this repetition.

Tip 1: Include ActionView::RecordIdentifier module to use the dom_id on your specs

On your spec you can include ActionView::RecordIdentifier and use the dom_id helper in your spec/scenario.

RSpec.describe "My spec" do
  include ActionView::RecordIdentifier

  scenario do
    within "##{dom_id(user)}" do
      expect(page).to have_text user.name
    end

    within "##{dom_id(project)}" do
      expect(page).to have_text project.name
    end
  end
end

You can do it because the module ActionView::RecordIdentifier defines the method dom_id.

If you want to use you the helper in all your specs you can include the module inside you rspec configuration block like this:

RSpec.configure do |config|
  config.include ActionView::RecordIdentifier, type: :system
end

And now you will be able to use the helper without including the module on each spec file.

RSpec.describe "My spec" do
  scenario do
    within "##{dom_id(user)}" do
      expect(page).to have_text user.name
    end

    within "##{dom_id(project)}" do
      expect(page).to have_text project.name
    end
  end
end

Tip 2: Create a css_id helper to also avoid the interpolation

If you don’t want to repeat yourself doing "##{dom_id(user)}" all over the place, you can write a method css_id (or whatever you want to call it) to do it for you.

You can add a new file spec/support/record_identifier_helper.rb and write something like this:

module RecordIdentifierHelper
  include ActionView::RecordIdentifier

  def css_id(*args)
    "#" + dom_id(*args)
  end
end

Then you need to be sure that in your rails_helper you are loading that file.

# Normally you will have something like this.
Dir[File.join(__dir__, "system/support/**/*.rb")].sort.each { |file| require file }

Then include your module on your rspec configuration block:

RSpec.configure do |config|
  config.include RecordIdentifierHelper, type: :system
end

And now you will be able to use the helper on your specs, like this:

RSpec.describe "My spec" do
  scenario do
    within css_id(user) do
      expect(page).to have_text user.name
    end

    within css_id(project) do
      expect(page).to have_text project.name
    end
  end
end

Related articles

Weekly tips and tools for Ruby on Rails developers

I send an email each week, trying to share knowledge and fixes to common problems and struggles for ruby on rails developers, like How to fetch the latest-N-of-each record or How to test that an specific mail was sent or a Capybara cheatsheet. You can see more examples on Most recent posts or All post by topic.