How to use assert_select to test for presence of a given link?
Asked Answered
M

7

35

My page should contain a link that looks like <a href="/desired_path/1">Click to go</a>.

How would you test for that using assert_select? I want to check for the presence of an a tag with href="/desired_path/1". How do you test the attributes of a tag?

Are there any resources to explain how to use assert_select? I read the Guides and API documentation, but didn't figure it out. Are there any recommended better ways of doing this?

I am working in Rails 3 and using the built-in test framework.

Thanks.

Mcclendon answered 17/8, 2011 at 19:43 Comment(0)
F
20

You can pass any CSS selector to assert_select. So to test the attribute of a tag, you use [attrname=attrvalue]:

assert_select("a[href=/desired_path/1]") do |elements|
   # Here you can test that elements.count == 1 for instance, or anything else
end
Finance answered 17/8, 2011 at 22:32 Comment(1)
This no longer works in Rails 5, nor, I believe, in Rails 4. See my answer for the current syntax.Diamagnetic
P
35

In assert_select, you can also use a question mark for the attribute value, and then follow with a string to match.

assert_select "a[href=?]", "/desired_path/1"

There's another way to use assert_select that is more friendly, especially if you want to match a partial string or regexp pattern:

assert_select "a", :href => /acebook\.com\/share/

Pug answered 28/6, 2012 at 18:23 Comment(5)
The second form appears to only work for the text of an element and not attributes. It ignored the href condition when I tried it.Tachograph
Yes, this works, however, I don't see any doc about it (except an example and a passing mention).Tamah
As @Tachograph mentioned, the 2nd form does not work (Rails 3.2.15). Unfortunately, it does not cause the assert to fail, I believe the :href option is silently ignored. If anyone wants to prove this for themselves, write something that should fail in the :href regular expression argument and see how the assert_select still passes.Metamorphism
In Rails 5.0, I had to use "a[href]" instead of "a[href=?]"Behead
The second half of this answer continues to be incorrect for Rails 5.0.Steamtight
M
21

Here is how you can assert a number of things about a link using assert_select. The 2nd argument can either be a String or a Regexp to test the href attribute against:

  # URL string (2nd arg) is compared to the href attribute thanks to the '?' in
  # CSS selector string. Also asserts that there is only one link matching
  # the arguments (:count option) and that the link has the text
  # 'Your Dashboard' (:text option)
  assert_select '.menu a[href=?]', 'http://test.host/dashboard',
      { :count => 1, :text => 'Your Dashboard' }

  # Regular expression (2nd arg) tests the href attribute thanks to the '?' in
  # the CSS selector string.
  assert_select '.menu a[href=?]', /\Ahttp:\/\/test.host\/dashboard\z/,
      { :count => 1, :text => 'Your Dashboard' }

For other ways you can use assert_select, here are the examples taken from the Rails actionpack 3.2.15 docs (see file actionpack-3.2.15/lib/action_dispatch/testing/assertions/selector.rb):

  # At least one form element
  assert_select "form"

  # Form element includes four input fields
  assert_select "form input", 4

  # Page title is "Welcome"
  assert_select "title", "Welcome"

  # Page title is "Welcome" and there is only one title element
  assert_select "title", {:count => 1, :text => "Welcome"},
      "Wrong title or more than one title element"

  # Page contains no forms
  assert_select "form", false, "This page must contain no forms"

  # Test the content and style
  assert_select "body div.header ul.menu"

  # Use substitution values
  assert_select "ol>li#?", /item-\d+/

  # All input fields in the form have a name
  assert_select "form input" do
    assert_select "[name=?]", /.+/  # Not empty
  end
Metamorphism answered 18/11, 2013 at 16:4 Comment(2)
How would you test for multiple attributes? Like a[href=? data-foo="bar"]]?Hardner
@Mohamad, I think this will do it, where each attribute goes in its own square brackets: assert_select 'a[href=?][data-foo="bar"]', 'http://test.host/dashboard'Metamorphism
F
20

You can pass any CSS selector to assert_select. So to test the attribute of a tag, you use [attrname=attrvalue]:

assert_select("a[href=/desired_path/1]") do |elements|
   # Here you can test that elements.count == 1 for instance, or anything else
end
Finance answered 17/8, 2011 at 22:32 Comment(1)
This no longer works in Rails 5, nor, I believe, in Rails 4. See my answer for the current syntax.Diamagnetic
D
8

The question specifically asks, “How do you test the attributes of [an element]?”

The other answers here use assert_select in ways that no longer work in current Rails / MiniTest. As per this issue, assertions about attribute contents now use this more Xpath-y ‘match’ syntax:

assert_select "a:match('href', ?)", /jm3\.net/
Diamagnetic answered 23/1, 2018 at 4:24 Comment(0)
C
4

For anyone using assert_select coming from Rails 4.1 and upgrading to Rails 4.2.

In 4.1 this worked:

my_url = "/my_results?search=hello"
my_text = "(My Results)"
assert_select 'a[href=?]', my_url, my_text

In 4.2 this gave an error: "DEPRECATION WARNING: The assertion was not run because of an invalid css selector. unexpected '(' after '[:equal, "\"/my_results\""]'"

I changed the syntax to this and it worked!:

assert_select 'a[href=?]', my_url, { text: my_text }

Eliots answer above helped me, thanks :)

Congou answered 28/8, 2015 at 8:47 Comment(2)
Searched for an answer to this problem everywhere. Thanks for posting this!Rubetta
Thanks. In 4.2 the 2nd parameter 'my_url' must be an String. So if you are checking against an integer, remember to use to_s. For example assert_select 'a[foo-id=?]', foo.id.to_sFlourish
D
2
assert_select 'a' do |link|
  expect(link.attr('href').to_s).to eq expected_url
end
Diphenylhydantoin answered 3/8, 2016 at 9:43 Comment(0)
D
0

rails (7.0.8), selenium-webdriver (4.12.0), capybara (3.39.2)

assert_selector :link, I18n.t("en.yml path here"), href: url_path

If you are passing variables to the I18n:

en.yml:
en:
  objects:
    cool_text: Im the %{variable}

assert_selector :link, I18n.t("objects.cool_text", variable: @object.attribute), href: url_path

regulat string no I18n:

assert_selector :link, "Im the path", href: url_path
Daunt answered 12/9, 2023 at 20:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.