Capybara matcher for presence of button or link

Users on web page don't distinguish between "button" and "link styled as button". Is there a way to add check whether a "button or link" is present on page?

For example Capybara has step:

page.should have_button('Click me')

which does not find links styled as buttons.


I already found out better answer:

page.should have_selector(:link_or_button, 'Click me')

Followed from click_link_or_button which is defined here:

def click_link_or_button(locator)
  find(:link_or_button, locator).click
alias_method :click_on, :click_link_or_button

It calls a selector :link_or_button. This selector is defined here:

Capybara.add_selector(:link_or_button) do
  label "link or button"
  xpath { |locator| XPath::HTML.link_or_button(locator) }

It calls this method:

# File 'lib/xpath/html.rb', line 33

def link_or_button(locator)
  link(locator) + button(locator)

So i tried to check the presence of the selector and it worked:

page.should have_selector(:link_or_button, 'Click me')

Using the expect syntax

expect(page).to have_selector(:link_or_button, 'Click me')

This works without needing to define a custom matcher.

Personally I would give your button or link an id and look for that using

page.should have_css('#foo')

This way you can refer to the link or button without worrying about its implementation.

I always find this useful:

You can also use a custom matcher

RSpec::Matchers::define :have_link_or_button do |text|
  match do |page|
    Capybara.string(page.body).has_selector?(:link_or_button, text: text)

Then do

expect(page).to have_link_or_button('Login')

I think you can use the find button instance method:

(Capybara::Element) find_button(locator)

Using id, name, value.

Or if you want a link

(Capybara::Element) find_link(locator)


I had an odd case where some smoke tests marched across various customer-centric login pages that had slight variations on doing the login submit button... Driven by a Cucumber table of user, org, etc.

# A bit of a hack, org_name is normally a subdomain, but sometimes it is the complete domain
def login(user, org_name)
  # Use the below to automatically hit each user's org's server
  if org_name.include? '.com'
    Capybara.app_host = "http://#{org_name}"
    Capybara.app_host = "http://#{org_name}"

  visit '/'
  fill_in 'username', :with => user
  fill_in 'userpwd', :with => '***'
    page.find(:link_or_button, 'submit')
    click_on 'submit'
  rescue Capybara::ElementNotFound
    page.find(:link_or_button, 'Log In')
    click_on 'Log In'
    rescue Capybara::ElementNotFound
      pending "Need to determine how to invoke the Login button for #{org_name} near Line ##{__LINE__} of #{__method__} in #{__FILE__} "

  # -----------------------
  # Work-around for modal popup saying SSL is mismatched if you are using actual production URLs
  # The rescue is for cases that do not exhibit the modal pop-up
  page.driver.browser.switch_to.alert.accept rescue Selenium::WebDriver::Error::NoAlertPresentError

  # Ensure that login was successful
  page.should_not have_content 'Login failed'

if html:

<a class="top-menu__item">text123
    <span class="label">
        <span class="label">86</span>

not work:

  assert page.has_selector?(:link_or_button, text: 'text123')
  assert page.should have_selector(:link_or_button, text: 'text123')

Need Your Help

Where can I get a complete list of Laravel events (fired by the core libraries)?

php laravel laravel-3

I want to know what events are fired by Laravel core libraries. I want to get the complete list, such as laravel.query and laravel.done.

Problems using Spring Hibernate

java hibernate spring

I've been using Spring JDBC with great success but I am having alot of trouble with this project. I'll post the code links here(it's just a small and silly project to test if I can get it up and ru...