RSpec HaveSelector does not work, expecting what I expect when using Capybara

Capybara HaveSelector does not work with RSpec expect what I expect. I am new to Capybara and RSpec, so I may be mistaken about RSpec or Capybara, or it may be a disadvantage of Capybara (version 2.0.2). Please help me understand my error or handle the error message / function request.

In my RSpec, I wrote:

 expect { click('.special-div .submit') }.to have_css('.submitted') 

I expected this to be functionally equivalent

 click('.special-div .submit') page.should have_css('.submitted') 

but this is not so. Instead, matcher have_css tries to combine with the string conversion of the proc object, not the result of invoking the proc object. (In other words, click('.special-div .submit') never executed.)

Capybara Behavior:

  • Pretty reasonable
  • Capybara missing function example
  • Error in Capybara 2.0.2
  • Something else?

Also, I obviously can do what I want using the 2-line version above, but our team is trying to standardize expect {} , so is there a way to use the expect {} form and get it to do what I want?

EDIT

I inherited the code that I work with, so I did not understand that, as Andrey Botalov noted, click not a standard part of Capybara. It seems to be, but again click already heavily used for other things, so it might be better that Capybara does not add another definition.

Since some people seem skeptical, let me assure you that this code is working fine:

 click('.special-div .submit') page.should have_css('.submitted') 

For those interested in have_css() , i.e. RSpec magic for has_css? . For those who are wondering about click , in my project, someone conveniently created the click function as follows:

  def click(css) page.execute_script("$('#{css}').first().trigger('click');") end 

Why? Because none of the obvious alternatives worked.

 click_on('.special-div .submit') # Fails because click_on does not take CSS # Cannot use click_button() because we are clicking on a <div> find('.special-div .submit').click # Raises exception because there are more than one first('.special-div .submit').click # Fails because the div is not visible 

Moving on, @zetetic asked if

 expect(click('.special-div .submit')).to have_css('.submitted') 

will work. No, this will not work for us, because we are still on RSpec 2.9, and this syntax was introduced in 2.11, but even if we updated it, it still will not work, because click does not return the object. Perhaps this will work if we upgrade to version 2.11 and change click to return page .

+4
source share
2 answers

There are a few problems with expect { click('.special-div .submit') }.to have_css('.submitted') , so I got so confused.

The most confusing for me is the syntax RSpec expect {...}.to ... I thought this syntax would force the co-owners to run the code in {} and apply a match to the result or something like that. An example seems to be kept in mind:

 expect { something }.to raise_error(SomeError) 

It turns out that this is not so. Only certain matches expect "actual" (what happens between "expect" and ".to") as Proc , and then call it. Most respondents expect the β€œactual” to be the object. So:

 expect { 1 + 1 }.to eq(2) 

throws an exception trying to compare a Proc with a Fixnum .

So capybara has_css? - is it quite reasonable to expect that the "actual" will be the object corresponding to has_selector? , not Proc . In fact, this was my main question, and with this Capybara disconnected.

Contributing to my confusion that Capybara helpfully provides DSL, so in my examples has_css? equivalent to page.has_css? which led me to expect that have_css(css) will continue to magically act against the page .

The best way to write a test. @deviousdodo is mostly right, so I reward a bonus for this answer. I wanted to

 expect { click('.special-div .submit') }.to change { page.has_css?('.submitted') }.from(false).to(true) 

In fact, although this is beyond the scope of the original question, I really want

 expect { click('.special-div .submit') page.should have_css('.submitted') }.to change { Click.count }.by 1 

So I want this because I want to check, most of all, that the mouse click gets written to the database ( Click.count increments), but I have to wait for the AJAX call initiated by the mouse click to finish, which is achieved on has_css? .

+2
source

EDIT: The first part of the answer was wrong, so I changed it.

I initially said that this code

 expect { click('.special-div .submit') }.to have_css('.submitted') 

is equivalent to:

 click('.special-div .submit').should have_css('.submitted') 

But this is not so, because the proc passed in expect will not really be evaluated (you can read @OldPro's answer for more details).

The solution is expect change :

 expect { click_button('Button label') }.to change { page.has_css?('.submitted') }.from(false).to(true) 

More information can be found on the rspec website .

+1
source

All Articles