Differences between assert_tag and assert_select

Hi all,

I can’t seem to make assert_select work for the more complex cases for
me.

Here’s a sample:

View

<%= link_to_remote ‘Add new’, :url => new_phone_url, :submit =>
‘phones_head’ %>

Generated code:

    <a href="#" onclick="new

Ajax.Request(‘http://test.host/admin/parties/phone/new’,
{asynchronous:true, evalScripts:true,
parameters:Form.serialize(‘phones_head’)}); return false;">Add new

Succeeds:

assert_tag :a, :attributes => {:onclick =>
Regexp.new(Regexp.escape(new_phone_url))}, :content => /add new/i

Fails

assert_select “a[onclick=?]”,
Regexp.new(Regexp.escape(new_phone_url)), /add new/i

test_link_to_add_address_exists(NewPartyViewTest)
[/home/francois/src/config/…/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb:281:in
assert_select' test/functional/admin/parties_controller_test.rb:1518:in test_link_to_add_address_exists’]:
Expected at least 1 elements, found 0.
is not true.

There’s probably something I’m not doing right, for sure.
#assert_select is supposed to be so much easier to use, but I’m not
find that at all. I just learned about “a[onclick*=?]”, and I can
make my test pass with that. But regexps sure are something I use
very often.

Thanks !

François Beausoleil
http://blog.teksol.info/
http://piston.rubyforge.org/

On 1/24/07, Francois B. [email protected] wrote:

    <a href="#" onclick="new

Regexp.new(Regexp.escape(new_phone_url)), /add new/i
#assert_select is supposed to be so much easier to use, but I’m not

François,

You probably don’t need to be this exact to test the accuracy of your
view rendering. To make things easier you might want to just add a
class to your anchor.

assert_select ‘a[class=my-link-class]’, /Add new/i

Hope this helps.


Zack C.
http://depixelate.com

Hello Zack,

2007/1/24, Zack C. [email protected]:

You probably don’t need to be this exact to test the accuracy of your
view rendering. To make things easier you might want to just add a
class to your anchor.

assert_select ‘a[class=my-link-class]’, /Add new/i

Thanks for replying. But unfortunately, I do need to be exact. Is
there or isn’t there a link on that page that allows adding a phone ?
Putting a class isn’t exactly the same.

Thanks again !

François Beausoleil
http://blog.teksol.info/
http://piston.rubyforge.org/

Hello Andy,

2007/1/25, Andrew S. [email protected]:

I don’t think you can pass a regular expression to your attribute
selector, i.e. in a[onclick=XXX], XXX must be a string. Therefore I
think you have to express the test for the attribute value and the
test for the link’s text in two separate selector statements.

http://labnotes.org/svn/public/ruby/rails_plugins/assert_select/cheat/assert_select.html

Look at the “Substitution Values” section.

assert_select “a[onclick]”, /add new/i
assert_select “a[onclick=?]”, Regexp.new(Regexp.escape(new_phone_url))

There’s nothing that confirms that the same node was used here. It
might be an entirely different one. The form on which this is checked
has the capability of adding phones, addresses, tesimonials, invoices,
payments and other objects too. And “Add new” is the standard text to
add a new something.

Thanks for the reply !

François Beausoleil
http://blog.teksol.info/
http://piston.rubyforge.org/

Succeeds:

assert_tag :a, :attributes => {:onclick =>
Regexp.new(Regexp.escape(new_phone_url))}, :content => /add new/i

Fails

assert_select “a[onclick=?]”,
Regexp.new(Regexp.escape(new_phone_url)), /add new/i

I don’t think you can pass a regular expression to your attribute
selector, i.e. in a[onclick=XXX], XXX must be a string. Therefore I
think you have to express the test for the attribute value and the
test for the link’s text in two separate selector statements.

Using a substitution value as you have done allows you to test the
attribute’s value but precludes testing the link’s text in the same
line (I think).

This might do it:

assert_select “a[onclick]”, /add new/i
assert_select “a[onclick=?]”, Regexp.new(Regexp.escape(new_phone_url))

Hope that helps somehow.

Regards,
Andy S.

How would I turn the following into using assert_select?

assert_tag :tag => /input|textarea|select/, :attributes => { :name =>
/#{obj}[#{field_name}]|#{obj}[#{field_name}(\di)]/ }

May it’s obvious and assert_select will take a regex like this but I
couldn’t find any info. Thanks.

Jason

Hello Francis,

assert_select “a[onclick]”, /add new/i
assert_select “a[onclick=?]”, Regexp.new(Regexp.escape
(new_phone_url))

Try this (it works for me):

assert_select “a[onclick=?]”,
Regexp.new(".+#{Regexp.escape(new_phone_url)}.+")),
:text => /add new/i

The substitution value consumes the next argument, the regular
expression, and one can test the text as usual.

The trick seems to be – at least on my system – that the regexp
substitution value does not behave as one would expect. It appears
to assume anchors to the start and end of the attribute value even if
one doesn’t put in those anchors.

For example, your onclick attribute value is a long AJAXy string and
you just want to match the new_phone_url somewhere inside it. Let’s
say that URL is: /phones/123/new’

I originally assumed that this would be the correct regexp to use: //
phones/\d+/new/

But in my experiments I found assert_select behaves as if I had
used: /^/phones/\d+/new$/

So I added .+ to the start and end of my regexp to allow for the
AJAXy stuff between the start of the onlick attribute’s value and the
end, giving:

/.+/phones/\d+/new.+/

Does that make sense? And if it does, does it work for you? :slight_smile:

Regards,
Andy S.

Hello Andrew,

2007/1/25, Andrew S. [email protected]:

So I added .+ to the start and end of my regexp to allow for the
AJAXy stuff between the start of the onlick attribute’s value and the
end, giving:

/.+/phones/\d+/new.+/

Does that make sense? And if it does, does it work for you? :slight_smile:

It makes perfect sense, and I changed only one thing from your
solution. I used .* instead of .+, to allow for the fact that the
string might be anywhere.

Looking at Rails code, I can see this:

actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb

Lines 682 and later (Rails 1.2.1)

def attribute_match(equality, value)
regexp = value.is_a?(Regexp) ? value : Regexp.escape(value.to_s)
case equality
when “=” then
# Match the attribute value in full
Regexp.new(“^#{regexp}$”)

^^^ see this ?

end
end

So, using “a[onclick*=?]”, Regexp is the right solution, then.

Thanks for your digging around.

Bye !

François Beausoleil
http://blog.teksol.info/
http://piston.rubyforge.org/