Question

I have always learned that good coding means: do not repeat yourself. But these days I keep repeating myself, in an attempt to let my scrapers handle timeout errors.

For every link or button that I click, i add a rescue Exception => e and refresh the page.

For example

browser.link(:xpath, "//tr[@class='pager'][1]/td/a").when_present.click

turns into

begin
  browser.link(:xpath, "//tr[@class='pager'][1]/td/a").wait_until_present
  browser.link(:xpath, "//tr[@class='pager'][1]/td/a").click
rescue Exception => e
  sleep (10)
  puts "timed out, let's refresh"
  browser.refresh
end

Perhaps there is a cleaner, non-repetitive solution. I've tried manipulating the Watir::wait but I could not get that to work..

class Watir::Wait
  alias_method :__do_wait, :wait_until
  def wait_until
    begin
      __do_wait{ yield }
    rescue Exception => e
      puts "timed out. let's refresh"
      $browser.refresh
    end
  end
end
Was it helpful?

Solution 2

Sorry for my enlish, i'm french.... lol this script allows to refresh browser without to skip a step, for exemple when you have to login, you can't skip a step..... and if you have a website with too many connexion with a low bandwhith.....

I think that seeb would do this :

module Watir

class WhenPresentDecorator
def method_missing(m, *args, &block)
  unless @element.respond_to?(m)
    raise NoMethodError, "undefined method `#{m}' for #{@element.inspect}:#   {@element.class}"
  end

  begin
    while !@element.present? 
     sleep(10)
    puts "timed out, let's refresh"
    @element.browser.refresh
    end
   rescue

   else
     @element.__send__(m, *args, &block)
   end
      end
     end # WhenPresentDecorator  
   end

OTHER TIPS

If I understand your requirements correctly, I think you want to override the method_missing handling of the WhenPresentDecorator.

require 'watir-webdriver'

module Watir
  class WhenPresentDecorator
    def method_missing(m, *args, &block)
      unless @element.respond_to?(m)
        raise NoMethodError, "undefined method `#{m}' for #{@element.inspect}:#{@element.class}"
      end

      begin
        Watir::Wait.until(@timeout, @message) { @element.present? }
      rescue
        sleep(10)
        puts "timed out, let's refresh"
        @element.browser.refresh
      else
        @element.__send__(m, *args, &block)
      end
    end
  end # WhenPresentDecorator  
end

With this monkey patch, when_present will wait for the element to be present. If the element is present, it will perform the action (ie click in your example). If the element is not present, it will catch the exception, ignore it, refresh the page and continue on to the next statement.

For example, given the following page that has a div tag that shows the time of page load:

<html>
  <head>
    <script>
      function startTime()
      {
        var today=new Date();
        var h=today.getHours();
        var m=today.getMinutes();
        var s=today.getSeconds();
        document.getElementById('txt').innerHTML=h+":"+m+":"+s;
      }
    </script>
  </head>
  <body onload="startTime()">
    <div id="txt"></div>
  </body>
</html>

You can see that no exception occurs when accessing an element (link) that does exist. As well, the page refreshes after trying to find that element.

puts browser.div(:id => 'txt').text  
#=> "22:48:25"

browser.link(:id => 'asdf').when_present.click
#=> "timed out, let's refresh"

puts browser.div(:id => 'txt').text
#=> "22:48:36"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top