x-treme
x-treme

Reputation: 1636

PageObject collection

I am forming a collection of links based on the title attribute using the following syntax

in_frame(name: 'example frame') do |frame|
  links(:example_link, {title: 'This is an example title', frame: frame})
end

SNIPPET - 1

Then i try to click each link (there are 2 in the collection) and get some info from the window that pops up

self.example_link_elements.each do |one_link|
  one_link.click
  @browser.window(index: 1).use do
    # do something here
    @browser.window.close
  end
end

SNIPPET - 2

This runs fine for the first link, but it throws Element is no longer valid (Selenium::WebDriver::Error::StaleElementReferenceError) error for the second iteration at the one_link.click statement!! I tried to do it this way then

2.times do |i|
  self.example_link_elements[i].click
    @browser.window(index: 1).use do
      # do something here
      @browser.window.close
    end
  end
end

The above mentioned snippet works fine!! I don't understand why the first snippet would throw that error!! Can any body shed light on the reason for the first snippet acting up?!

UPDATE

To make sure I understand it, I just coded up the following test page

<html>
<body>
    <a target="_blank" href="http://www.google.com">click here</a>
    <a target="_blank" href="http://www.google.com">click here</a>  
</body>
</html>

and ran the following ruby code on it

require 'watir-webdriver'
require 'page-object'

class MyPageObject
  include PageObject

  def initialize(browser, visit)
    @browser = browser
    super browser, visit
  end

  def goto
    @browser.goto "file:///C:/Users/raveej1/Desktop/test.html"
  end
end

browser = Watir::Browser.new :firefox
page = MyPageObject.new browser, true
page.class.send(:links, :search_link, text: "click here")
page.search_link_elements.each_with_index do |p, p_index|
  p.click
  browser.window(index: 1).use do
    page.class.send(:link, :singin_link, text: "Sign in")
    page.singin_link
    browser.window.close
  end
end

It worked!! I believe it is exactly the same way as snippet 1. Why do the two pages act differently?!!

Upvotes: 1

Views: 352

Answers (1)

Justin Ko
Justin Ko

Reputation: 46836

The documentation for the Selenium Element#click (which is what one_link.click eventually calls) says:

Click this element. If this causes a new page to load, this method will attempt to block until the page has loaded. At this point, you should discard all references to this element and any further operations performed on this element will raise a StaleElementReferenceError unless you know that the element and the page will still be present. If click() causes a new page to be loaded via an event or is done by sending a native event then the method will not wait for it to be loaded and the caller should verify that a new page has been loaded.

In your case, opening the popup window means your reference to elements is going to be considered stale.

The different behaviour you are seeing is due to how you are referencing the elements.

In your first code snippet:

  1. You get a reference to all matching elements
  2. You click the first link that opens the popup, which makes all of your existing references stale
  3. You click the second link, which is now stale

In your second code snippet:

  1. You get a reference to all matching elements
  2. You click the first link that opens the popup, which makes all of your existing references stale
  3. You get a new reference to all matching elements
  4. You click the second link that opens the popup, which makes all of your existing references stale

As you can see, your second code snippet is always using a fresh reference to elements, which is why you do not get the StaleReferenceError.

Upvotes: 1

Related Questions