Capybara find all links on page and check url - ruby-on-rails

I want to check that all links on a page contain a certain element. This is the current web_step I have but it is not working. Any ideas?
Then /^all links above footer should countain "([^"]+)"$/ do |parameter|
al = page.all('a')
al.each do |i|
i.include?(parameter).should be_true
end
end

You probably need to assert against a particular attribute of each a element - if you're checking that the 'src' attribute contains 'parameter' then:
i[:href].include?(parameter).should be_true
Or, to make better use of the rspec matchers (and get better failure messages):
i[:href].should include parameter

[:src] no longer appears to work. Use [:href] instead.

Related

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.

Rspec with Capybara have_css matcher is not working

In Cucumber, with Rspec and Capybara I have a test to check that a button has a class. Here it is
expect(#some_button).to have_css(".in-cart")
it fails, but
#some_button['class']
returns
'btn product in-cart'
so the button definitely has the 'in-cart' class.
As a temporary measure I've changed my test to be;-
expect(#some_button['class']).to match /in-cart/
Which is obviously insane. But why should 'have_css', or 'has_css?' return false for a DOM element that clearly has the expected class?
Also page.all('.in-cart') includes the button, so Capybara can definitely find it.
Incidentally I also tried 'button.in-cart', 'in-cart',expect (etc).to have_selector, expect(etc.has_selector?('.in-cart')).to be_truthy and all combinations.
have_css matcher is expected to be applied to the parent container instead of the actual element
# your view
<div id="container">
<div class="in_cart product"></div>
</div>
# your step definition
parent = page.find('div#container')
expect(parent).to have_css(".in-cart")
# => returns true, as there is nested div.in_cart
expect('div#container div').to have_css(".in-cart")
# => returns false, as there is no such selector inside of the latter div
As of matching attributes of the exact object, you've got to stick with simple quering by key
element = page.find('div#container div')
element['class'].should include('in-cart')
expect(element['class']).to match /in-cart/
Same logic applies to all of the RSpecMatchers.
In newer versions of Capybara/Rspec, by default, expect(page) will query the entire page looking for a match; however, sometimes we may not want that and instead will prefer to target a specific class/region of the page. For those cases, narrow down the context of page using within:
within('.container') do
expect(page).to have_css(".in-cart")
end
Assuming, the parent has a class container Capybara will only search within this element.
expect(page).to have_css('button.in-cart')

click element if it exists in capybara

I wish to click a popup message that appears on my test app if it is present. I am new to capybara and cant seem to find a way to do this. I have previous experience with watir and if I were doing it with watir it would be something like:
if browser.link(:text, "name").exists? do
browser.link(:text, "name").click
end
How can I do the same in capybara? Note this link will not always appear hence why I wish to have the if statement.
A straight of the head code is to just invoke a has_link? matcher and then click_link action:
if page.has_link?('name')
page.click_link('name')
end
But it will be not the fastest solution as Capybara will make two queries to driver to get element: first one in has_link? and the second one in click_link.
A better variant may be to make only one query to get an element:
# This code doesn't check that an element exists only at one place and just chooses the first one
link = first('name')
link.click if link
or
# This code checks that element exists only at one place
links = all('name')
unless links.empty?
links.count.should == 1
link = links.first
link.click
end
Personally I would go with has_link?/click_link implementation as the second variant does't check that element exists only at one place and the third one is too long.
In case I used has_css? query :
if page.has_css?("button #popUpButton")
click_button(#popUpButton")
end
You can use first, with option minimum: 0
item = first ".dropdown-item", minimum: 0
item.click if item&.visible?
Have you tried doing something like:
if page.find('.id') do
click_link('Some Link') # or page.find('.id').click
else
page.should_not have_selector('.id') # or something like that
end

How can I detect if an html page element exists by using RoR RJS Template code?

I tried several ways but all are failing.
As dbarker mentioned, you can use page['theElementID'] to test whether a specific HTML element exists based on its ID.
If your target element doesn't have an ID attribute, you can also check for it with a CSS selector, including class names. For example:
if page.select('div.comment').any?
# Logic here if there is at least one comment
else
# Logic for no comments
end
Documentation on page.select: http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html#M001632
Actually, I couldn't get the
if page[:element]
# code here
end
to work. Instead, I ended up using
page << "if( $('element') ) {"
# code here
page << "}"
You can use the [ ] method of the JavascriptGenerator to find an element like this:
page['theElementId']
Here's a link to the details:
Module
ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods
You could use what dbarker said like this:
if page['theElementId'].nil?
# then have you logic here if the element does not exist
else
# if the element does exist
end

Resources