Testing a 'stale' element with Selenium and rspec - ruby

Still a newbie to RSpec and Ruby, so apologies for any obvious errors, omissions, etc in my question.
What I'm looking to test using RSpec (with Selenium Webdriver) is the following;
1) I've (randomly) selected a make of car from a drop down menu
2) From this selected make, I then (randomly) selected a corresponding model of car from a drop down menu
3) Then pressed "Search" button and a list of, for example, BMW 3-Series cars were correctly displayed.
What I now need to do using RSpec is test that the (randomly selected) make and model names are displayed in a page heading and in the URL.
For example, selecting BMW 3-Series will result in the URL ending in /bmw/3-series and a heading on the page will read "BMW 3-Series Cars For Sale".
However, the problem I'm having is that a 'Stale Element' error message is being displayed when I run the test.
I know why the error is displayed (because the elements used to select the make and model are 'lost' when the Search button is pressed, as a new page opens which does not contain these elements), but I don't know how to get around this problem.
Any help would be greatly appreciated.
# This generates a random manufacturer
manuselect = #driver.find_element(:id, 'ctl00_contentHolder_topFullWidthContent_ctlCarsForSaleSearch_ctlUsedCarsSearchTab_ddlManufacturer_Control')
manufacturer = manuselect.find_elements(:tag_name => 'value').sample
#puts manufacturer.text
manufacturer.click
sleep 7
# This generates a random model
modelselect = #driver.find_element(:id, 'ctl00_contentHolder_topFullWidthContent_ctlCarsForSaleSearch_ctlUsedCarsSearchTab_ddlRange_Control')
carmodelrange = modelselect.find_elements(:tag_name => 'value').sample
puts carmodelrange.text
carmodelrange.click
sleep 5
# Click on the Search button
#driver.find_element(:id, 'ctl00_contentHolder_topFullWidthContent_ctlCarsForSaleSearch_ctlUsedCarsSearchTab_btnSearch').click

You just need to store the text you're going to look for into variables before the elements disappear from the page
manufacturer_name = manufacturer.text
modelrange_name = carmodelrange.text
#click the search button...
# the following expectations require Capybaras matchers, use whatever expecations are equivalent with whatever you're using
expect(page).to have_current_path(/#{Regexp.quote(manufacturer_name)}\/#{Regexp.quote(modelrange_name)}$/)
expect(page).to have_text("#{manufacturer_name} #{modelrange_name}")

Related

How to click a span in capybara tests?

I'm trying to click on a checkbox, but when I run the action, it doesn't work.
I'm using the same way to click buttons and other elements.
I'm using a data-testid to find the checkbox in the view.
I need to click on the checkbox, and after clicking execute the actions of the next step.
This checkbox is a react component that will have a span in the view.
context 'when the user agrees to charges by clicking a checkbox' do
before do
# sleep 1000
wait_before_clicking
page.find("span[data-testid='prepay-enrollment-modal-agreement-checkbox']").click
end
it 'renders new content for the user to review payment details' do
expect(page).to have_selector("[data-testid='review-step-container']")
expect(page).to have_content("Your Plan")
expect(page).to have_content("100 pages/ month")
expect(page).to have_content("Plan cost for 12 months, before discount")
expect(page).to have_content("Prepay discount (10%)")
expect(page).to have_content("Total Due:")
end
end
The data-testid attribute is on the input element not on the span, so find("span[data-testid='prepay-enrollment-modal-agreement-checkbox']") won't work. If you put the data-testid attribute on the span rather than the input then it would work, however there's a better way. Since the checkbox has an associated label element you can just tell Capybara it's allowed to click on the label element if necessary. First, since you're using test ids, set
Capybara.test_id = 'data-testid'
in your global config, and then in your test just do
page.check('prepay-enrollment-modal-agreement-checkbox', allow_label_click: true)
Note: rather than expect(page).to have_selector("[data-testid='review-step-container']") you should use expect(page).to have_css("[data-testid='review-step-container']") to make it clearer that you know you're passing CSS. Also for test speed reasons you may want to combine all of the have_content calls into one using a regex

Click on buttons on the page that has got the same class using capybara with siteprism

There are 20 different buttons to expect and needs to be clicked through to expect and verify the urls inside the code. I have tried different ways to implement my tests but they are failing.
I'm trying something like:
page.all(:class => 'action red').each do |button|
c = button.find(:class => 'action view red')
c.click
page.driver.browser.switch_to.window(#new_window)
expect('some element on those 20 different browsers sessions before closing them')
page.driver.browser.close
end
end
I'm getting this error:
ArgumentError: invalid keys :class, should be one of :count, :minimum,
:maximum, :between, :text, :visible, :exact, :match, :wait
Any can help me in the code how to perform get the elements of all the 20 buttons, store them and click them to expect the url each of them before closing it
Your "buttons" aren't buttons - since they are <a> elements they are actually links, styled to look like buttons.
Assuming that clicking each of these links actually opens a new window (since you're attempting to switch to a new window) then the code would be something like
page.all(:link, class: ['action', 'red']).each do |link|
win = page.window_opened_by { link.click }
page.within_window(win) do
expect(page).to ... # whatever you need to expect
end
win.close()
end
Note this doesn't use any driver specific (.driver.browser...) methods - you should stay away from them whenever possible since they are generally a sign you're doing something wrong. Additionally, the :class option wasn't universally available on all of Capybaras builtin selector types until v2.10, so you will need to be using a newer version of Capybara for that.

How to get the text of hidden check boxes inside a scroll bar using Selenium WebDriver?

I'm trying to automate Filter By Brand scenario in BigBasket and now stuck up in a situation where my code could not print the brand names that are hidden inside a scroll bar.
Steps to follow
Go to www.bigbasket.com
Click Skip & Explore button
Search Apple and view the list of brands on the left side
#FindAll({#FindBy(xpath="//*#id='filter_brands_list']/div/div1/li/label")})
List chkBrands;
The above lines of code identifies all the brand names but when I print them using the below code I can see only the brand names that are visible
for(WebElement eachElement:chkBrands){
System.out.println("No. of brands is "+chkBrands.size());
System.out.println(eachElement.getText());
}
Could you please let me know the solution? I apologize that I could not think of a solution as I'm an amateur in Selenium.
WebElement.getText() will return the text of the element only if it is displayed on the screen.
Meaning if the isDisplayed method returns false then getText()method will return empty.
Explanation with Examples Here
As defined in WebDriver spec, Selenium WebDriver will only interact
with visible elements, therefore the text of an invisible element will
always be returned as an empty string.
However, in some cases, one may find it useful to get the hidden text,
which can be retrieved from element's textContent, innerText or
innerHTML attribute, by calling element.attribute('attributeName') or
injecting JavaScript like return arguments[0].attributeName.
So you can get the text by textContent attribute
eachElement.getAttribute("textContent")
Try this one:
JavascriptExecutor je = (JavascriptExecutor)driver;
WebElement element = driver.findElement(By.xpath("Your_xpath"));
String text_value = ((JavascriptExecutor) driver).executeScript("return arguments[0].innerHTML;",element);

Watir-webdriver throws 'not clickable' error even when element is visible, present

I am trying to automate tests in Ruby using the latest Watir-Webdriver 0.9.1, Selenium-Webdriver 2.53.0 and Chrome extension 2.21. However the website that I am testing has static headers at the top or sometimes static footers at the bottom. Hence since Watir auto-scrolls an element into view before clicking, the elements get hidden under the static header or the static footer. I do not want to set desired_capabitlites (ElementScrollBehavior) to 1 or 0 as the websites I am testing can have both - static header or static footer or both.
Hence the question are:
1) Why does Watir throw an exception Element not clickable even when the element is visible and present? See ruby code ( I have picked a random company website for an example) and the results below.
2) How can I resolve this without resorting to ElementScrollBehaviour?
Ruby code:
require 'watir-webdriver'
browser = Watir::Browser.new :chrome
begin
# Step 1
browser.goto "shop.coles.com.au/online/mobile/national"
# Step 2 - click on 'Full Website' link at the bottom
link = browser.link(text: "Full website")
#check if link exists, present and visible?
puts link.exists?
puts link.present?
puts link.visible?
#click on link
link.click
rescue => e
puts e.inspect
ensure
sleep 5
end
puts browser.url
browser.close
Result:
$ ruby link_not_clickable.rb
true
true
true
Selenium::WebDriver::Error::UnknownError: unknown error: Element is not clickable at point (460, 1295). Other element would receive the click: div class="shoppingFooter"...div
(Session info: chrome=50.0.2661.75)
(Driver info: chromedriver=2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4),platform=Mac OS X 10.10.5 x86_64)>
http://shop.coles.com.au/online/mobile/national
thanks!
You can do a click at any element without getting it visible. Check this out:
link.fire_event('click')
BUT It is very very very not good decision as far as it will click the element even if it is not actually visible or in case when it is just impossible to click it (because of broken sticky footer for example).
That's why much better to wait the fooler, scroll the page and then click like:
browser.div(id: "footerMessageArea").wait_until_present
browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
link.click
The sticky footer is blocking webdriver from performing the click, hence the message that says 'other element would receive the click'.
There are several different ways you can get around this.
Scroll down to the bottom of the page before the click
Hide/Delete the sticky footer before any/all link clicks
Focus on an element below the element you want to click before you perform the click
I Guess your element is visible in the screen.
Before clicking on the element first you have to scroll the webpage so that element is visible then perform the click. Hope it should work.
I had similar issue,
I just used following javascript code with watir:
link = browser.link(text: "Full website")
#browser.execute_script("arguments[0].focus(); arguments[0].click();", link)
Sometimes I have to use .click! which i believe is the fire_event equivalent. Basically something is layered weird, and you just have to go around the front end mess.

Ruby/Selenium: How to click on a specific item that appears multiple times on a page

Here's the item in question - specifically that little caret:
http://screencast.com/t/NMPOM9Ok58q
As you can see there are multiples of those within the same page, they all have the same class etc.
I've tried several different routes and I've not been able to successfully click on that item.
I always want to click on the last of them present on that page (the number of them are dynamic so sometimes it's the 2nd one and sometimes it's the 6th - so referring to it with a specific number doesn't work)
Thanks for the help (my tests are written in ruby, using selenium and testunit)
Here are some things I've tried and a few variations of these as well (none of which actually produce a click on that item)
#driver.find_element(:class, "dropdown-toggle")[-1].click
#driver.find_element(:css, "(//*[contains,'a.dropdown-toggle')]").click
element_present?(:css, "div.dropdown.open > a.dropdown-toggle").click
#driver.find_element(:css, "div.dropdown.open > a.dropdown-toggle").click
#driver.find_elements(:css, "caret")[-1].click
#driver.find_element(:css, "caret:last-of-type").click
#driver.find_element(:css, "div.dropdown.open > a.dropdown-toggle:last-child").click
#driver.find_element(:class, "span1").find_element(:tag_name, "a").click
^ This one actually is the only one that clicks anything - but it only clicks the first carat.
Ultimately what I'm doing with this test is adding a filter, closing the filter window, re-opening the filter window, deleting the previous filter, adding a new one and closing the window.
how about using the CSS last child selector?
#driver.find_element(:css, "div.dropdown.open > a.dropdown-toggle:last-child").click
If <div class="span1"> is unique, you can try someth like:
#driver.find_element(:class, "span1").find_element(:tag_name, "a").click
ok, so, if you need to click all links, or just someth of it, then:
#links = #driver.find_element(:class, "span1").find_elements(:tag_name, "a")
#links[0].click - for first link
#links[1].click - for second link
etc.

Resources