what is the best method using ruby/mechanize/nokogiri to go/click through all pages in case there is more than 1 page I need to access/click on? For example here Page 1 of 34 Should I click the page number or next? Or is out there any better solution?
It looks like the link ">" takes you to the next page, and it does not appear if you are on the last page. So:
page = ... # fetch the first page
loop do
# process the page
break unless link = page.link_with(:text=>'>')
page = link.click
end
You should try out scrubyt. It's described as "mechanize on steroids". It has dedicated method for clicking through pages.
Related
I have a page that lists job openings at my company. I want to use Capybara tests to click on each of the links and determine if the target page contains certain content.
I have the step below. The next step in the process checks for the content on the new page.
When("I click on each job title") do
page.all('.job-box').each do |item|
within(item) do
find('a').click
end
end
end
Once the first link is clicked the browser goes to a different page. At that point, I would like to check the content on that page, then return to the previous step to check the next link. What actually happens is that the code clicks the first link, and then attempts to click the second link. Since the first link sent it to another page, the second link is no longer present, so it returns a stale element error.
Obviously, I need a way to deal with multiple pages before continuing with the next step in the iteration, but I haven't found any documentation that addresses that problem.
You probably want to use page.go_back (or page.driver.go_back depending on the driver you're using). Something like this:
When("I click on each job title") do
page.all('.job-box').each do |item|
within(item) do
find('a').click
# do stuff
end
# roll back (granting you went but one click away)
page.go_back
end
end
As you've recognized the issue here is that the elements are stale when you return to the previous page. Depending on what limitations you're willing to accept there are multiple ways to deal with this. The bigger issue you have is that you're doing this in Cucumber which really doesn't have support for scoping/looping in its test structure. If you're willing for this to only work on a specific browser/platform you can use the respective key modifiers on click to have the browser open a new tab for each job entry and then your next step could run through all the open tabs checking those
When("I click on each job title") do
page.all('.job-box').each do |item|
item.find('a').click(:alt, :cmd) # alt,cmd click in Chrome MacOS opens in new tab
end
end
But really you're going to be better off doing something like
When("I click on each job title and verify info") do
page.all('.job-box').each do |item|
window = page.window_opened_by do
item.find('a').click(:alt, :cmd)
end
page.within_window(window) do
# verify whatever needs to be verified
end
window.close
end
end
Thomas Walpole's answer got me close enough to figure it out. Here is what ended up working:
When("I click on each job title and verify info") do
page.all('.job-box').each do |item|
new_window = window_opened_by do
url = item.find('a')[:href]
within_window open_new_window do
visit url
end
end
page.within_window(new_window) do
# do stuff
end
end
end
It doesn't close each new tab after it checks it, which could be a problem if you are working with a lot of links. I only have about 15, so it wasn't an issue for me. They all closed when the browser closed after the test finished.
I have created this method to loop through the links in a certain div in the web site. My porpose of the method Is to collect the links insert them in an array then click each one of them.
require 'watir-webdriver'
require 'watir-webdriver/wait'
site = Watir::Browser.new :chrome
url = "http://www.cnn.com/"
site.goto url
box = Array.new
container = site.div(class: "column zn__column--idx-1")
wanted_links = container.links
box << wanted_links
wanted_links.each do |link|
link.click
site.goto url
site.div(id: "nav__plain-header").wait_until_present
end
site.close
So far it seems like I am only able to click on the first link then I get an error message stating this:
unable to locate element, using {:element=>#<Selenium::WebDriver::Element:0x634e0a5400fdfade id="0.06177683611003881-3">} (Watir::Exception::UnknownObjectException)
I am very new to ruby. I appreciate any help. Thank you.
The problem is that once you navigate to another page, all of the element references (ie those in wanted_links) become stale. Even if you return to the same page, Watir/Selenium does not know it is the same page and does not know where the stored elements are.
If you are going to navigate away, you need to collect all of the data you need first. In this case, you just need the href values.
# Collect the href of each link
wanted_links = container.links.map(&:href)
# You have each page URL, so you can navigate directly without returning to the homepage
wanted_links.each do |link|
site.goto url
end
In the event that the links do not directly navigate to a page (eg they execute JavaScript when clicked), you will need to collect enough data to re-locate the elements later. What you use as the locator will depend on what is known to be static/unique. As an example, I will assume that the link text is a good locator.
# Collect the text of each link
wanted_links = container.links.map(&:text)
# Iterate through the links
wanted_links.each do |link_text|
container = site.div(class: "column zn__column--idx-1")
container.link(text: link_text).click
site.back
end
So I have the following code:
list = [#array of xpaths pointing to each of the 41 links]
begin
list.each do |entry|
wait.until {browser.find_element(xpath: entry)}
browser.find_element(xpath: entry).click
... #do what needs to be done inside link
browser.find_element(xpath: #location of back button) #goes back to list
end
wait.until{browser.find_element(css: ".next>a")}
browser.find_element(css: ".next>a").click
# ^ clicks the next button to get to next page
sleep 2
end while browser.find_element(class_name: "next").displayed?
# ^ end when there is no next button because were on the last page.
I am looping through each link on the page, doing what I need to do with it, and returning to the list. When all 41 links have been hit on the page, I tell it to load the next page. The issue is that for some reason going back to the list always goes back to the first page. So if I am on the third page and I click the link, do what I have to do, and return to the list I am back on the first page of the list. Anyone have an ideas on how to deal with this?
I have a cucumber feature file which looks like below,
Given I am logged in to the console
When I navigate to the "href1" page
When I navigate to the "href2" page
When I navigate to the "href3" page
When I navigate to the "href4" page
Instead on writing the when command 4 times I want to know if I can somehow pass the value of the href and call it in the when statement.
I have a step definition which looks like this :
When(/^I navigate to the "(.*)" page$/) do |navigation_link|
#browser.link(:href => navigation_link).when_present.click
end
Let me know if you need more information.
Multiple options to do it:
a) If you need to test that you can navigate to each of the pages independtly, you can use a Scenario Outline like:
Scenario Outline: Test navigation
Given I am logged in to the console
When I navigate to the "<href>" page
Examples:
|href |
|<actual_url1>|
|.... |
|<actual_url4>|
In this case, your step doesn't need to be modified, and should work as is.
b) If you need to navigate to the pages in a dependent manner, i.e., reaching page 4 requires you to follow through page1 -> page2 ->... page X -> page 4, you can use a table like:
Scenario: Test navigation
Given I am logged in to the console
When I navigate through the following pages:
|<actual_url1>|
|.... |
|<actual_url4>|
And then in your step definition:
When(/^i navigate through the following pages:$/) do |table|
table.raw.each do |navigation_link|
#browser.link(:href => navigation_link.join).when_present.click
end
end
(Read more on tables & outlines here: http://cukes.info/step-definitions.html)
Though, I wouldn't suggest using either of them if you just want to check that you can navigate to page4. I'd rather create the step to only navigate to page 4, and within that step's definition-> take the url_paths in variables (much better to have in a separate paths file and load from there)-> navigate to other pre-requisite pages-> Navigate to the final page.
This way you would only describe the behaviour and not literal navigation points.
My application prints statements for customers. Naturally, I want each customer's statement to start at the top of a page. How do I make it do that?
In the Section Expert, if I check 'new page before' the first group, it wastes a page at the beginning, and if I check 'new page after' the last group, it wastes a page at the end. I don't mind so much when printing 350 statements, but when I print just one, it's pretty low class as well as wasteful.
This is the 'built in' Crystal Reports in Visual Studio.
use this on new page after
Not(OnLastRecord)
Do you have 'keeptogether' set? You should be able to do 'new page after' on the group footer and it will only go to the next page if there is a following group. Otherwise it will print the page and report footer.
You might be able to use a formula for the 'new page before' option. Something like the below would return true for pages 2+ of course, giving you the new page when needed. Just a theory. :)
PageNumber > 1
Just write down the two lines of codes and it will work properly--
rDoc.ReportDefinition.Sections["GroupHeaderSection1"].SectionFormat.EnableNewPageBefore = true;
rDoc.ReportDefinition.Sections["GroupHeaderSection1"].SectionFormat.EnableKeepTogether = true;
Thanks and Regards