How do the Capybara set and fill_in differ? - capybara

Recently I found that elements found using 'find' of capybara may not work properly with 'fill_in'( Refer:Capybara can find but not fill_in)
So the params used by fill_in and find are different. Hence I can use set and fill my form fields found using 'find' is what I have observed.
Is there any other difference?

In terms of actually inputting the field, set and fill_in are exactly the same.
The method definition for fill_in is:
def fill_in(locator, options={})
raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
with = options.delete(:with)
fill_options = options.delete(:fill_options)
find(:fillable_field, locator, options).set(with, fill_options)
end
As you can see on the last line, the fill_in method is doing the same thing - ie using find to get the node and then inputting it with set.

Related

Why does RSpec/Capybara throw an error with hyphenated values provided with public_send?

I have a shared example I am using to test the same thing on several controllers. I pass the controller the model and a list of fields to check to make sure they are on the page, but when the value is a hyphenated string it throws an error, even when the value is on the page. The strange thing is, though, that it drops the hyphen in the check. So, if the last name field in the user table has "Johnson-Smith" This is what I get back...
expected to find text matching "Johnson Smith" in...
And looking down in the page text it renders I can clearly see "Johnson-Smith". I don't understand why Rspec/Capybara aren't checking for the correct value. Here is the shared example code..
RSpec.shared_examples 'renders proper fields' do |klass, fields|
it 'should render the expected text' do
model_object = klass.order(:created_at).last
fields&.each do |field|
expect(page).to have_text(model_object.public_send(field))
end
end
end
EDIT I tested the results for every public_send(field) that is evaluated and it turns out that public_send is returning the field from the database as expected. So the issue is, for some reason, Capybara is evaluating it without the hyphen, even though it passed the text with the hyphen.

Multiple selectors using have_selector

I wish to convert my find's to using have_selector. Presently I have this working as:
expect(find('div[some-attr=true]'))['some-data-attr']).to eq('Hello World')
I wish to convert this to use have_selector and I tried:
expect(page).to have_selector('div[some-attr=true][some-data-attr]')
What am I doing wrong here?
This should be
expect(page).to have_css('div[some-attr=true][some-data-attr="Hello World"]')
This will only work if 'some-data-attr' isn't actually a property that has been modified since the page load. The selectors match on attribute values, but since your original method calls #[] on a returned element it could have been accessing a property with a changed value. Without knowing what those attribute names actually are and how they've been used it's impossible to say for sure. If it is actually a property and you need to use it a lot in your app you could write a custom filter on the :css selector
If Capybara.default_selector == :css then have_selector and have_css mean the same thing, but if you're using a css selector then you're better off just using have_css
For me worked like this:
expect(first("div.flex-cal-day-event-bar.flex-cal-day-event-bar--day-span-1[data-behaviour='event-listing']")).to have_content(text)

What's the best way to reuse your step definition in ruby siteprism

im having some issue trying to create a reusable step definition using siteprism
let say feature file is
Given that im on the site
Then i should see a "stack over" text
And i should see a "ask" text
And i should see a "question" text
then on my step definition will be
I want to have arg1 to be dynamic and this logic will check if its true
Then (/^i should see a "(.*?)" text$/) do |arg1|
#common_page = CommonLib.new
#ref = arg1.gsub(/\s+/,'')
expect(#common_page.*#ref*.text).to eq (arg1)
end
Then on my page def will be
class CommonLib < siteprism::page
element :stackover, "#text_header"
element :ask, "#text_ask"
element :question, "#text_question"
the issue im having is this expect(#common_page.#ref.text).to eq (arg1)
the mapping is wrong #ref need to use the data it got like 'stackover', 'ask' and 'question' and map in the CommonLib page def
Calling #text and using the eq matcher is generally a bad idea since it bypasses Capybaras builtin retry behavior and can cause flaky tests on dynamically changing pages. Instead you should use have_text or the :text option passed to the finder
expect(#common_page.send(#ref)).to have_text(arg1)
or
expect(#common_page.send(#ref, text: arg1)).to be
Also, is there a reason you've made #common_page and #ref instance variables, they seem like they should just be regular variables that go out of scope at the end of the test.

Rails capybara,fill_in failing

I have next spec:
click_link('Edit')
expect(current_path).to eq(edit_news_path(#news))
fill_in('Body', with: 'Changed body')
click_button('Edit')
expect(current_path).to eq(admin_path)
expect(#news.body).to eq('Changed body')
All expectings are passing the test, but not fill_in expecting:
Failure/Error: expect(#news.body).to eq('Changed body')
expected: "Changed body"
got: "Example"
(compared using ==)
And its all ok on site,every editings both saved,so whats the problem in rspecs?
That usually means capybara can't find the field you mean.
A couple of things you might check: is the label Body linked to the input field via ? Is there only one field with a label "Body"? You might also try using the id for the field in the fill_in call, like
fill_in("content_body", with...
I think that your click_button('edit') seems to have problem. I think that you are not saving the body, you must be having click_button('save')
Use binding.pry in between the test statements to check the value of various objects.

Capybara: How To Assert A Given Number of Elements Exist

I've upgraded my whole stack from a Rails 3.0 based project to 3.1. I have specs passing but my features are now being a bit picky. The issue I'm currently having is this step:
Then /^I should see (\d+) menu item(?:s)? within "([^"]*)"$/ do |count, selector|
page.find(:css, selector, :count => count.to_i)
end
And in the feature itself, I might put:
Then I should see 5 menu items within "tr#menu_item_row"
The message I get is:
Then I should see 5 menu items within "tr#menu_item_row" # features/step_definitions/admin_menu_steps.rb:1
Ambiguous match, found 5 elements matching css "tr#menu_item_row" (Capybara::Ambiguous)
./features/step_definitions/admin_menu_steps.rb:2:in `/^I should see (\d+) menu item(?:s)? within "([^"]*)"$/'
features/admin_menu.feature:30:in `Then I should see 5 menu items within "tr#menu_item_row"'
As far as I can tell, the 5 elements match the 5 that were actually found. Did I write this code wrong or has something major changed? Thanks!
If you want to check 5 elements you shouldn't use #find as by default since Capybara 2.0 this method always throws an exception if it finds more or less than one element. This was an intentional and (I believe) a good change.
To assert that 5 elements are present an appropriate method is a rspec matcher:
expect(page).to have_css(selector, count: count.to_i)
I don't recommend to set match to prefer_exact as recommended by #fontno as in most of situations you want Capybara to throw an exception if find finds more than one element.
Yes, this is a change between versions 1.x and 2.x. You can look at all the changes in the capybara upgrade guide and this blog post.
The find method now raises an ambiguous match error if more than one element is found. If you only have a few examples you could do something like this
Then /^I should see (\d+) menu item(?:s)? within "([^"]*)"$/ do |count, selector|
page.find(:css, selector, :count => count.to_i, match: prefer_exact)
end
or if you have many examples like this you could change the capybara configuration for backwards compatability, something like this
Capybara.configure do |config|
config.match = :prefer_exact
config.ignore_hidden_elements = false
end
You may have to modify this to get it working but this is the general idea. See the links I mention above, its all in there. Hope this sets you in the right direction

Resources