unknown property or method: `readyState' HRESULT error code:0x80010108 The object invoked has disconnected from its clients. (NoMethodError)

0
    unknown property or method: `readyState'
        HRESULT error code:0x80010108
          The object invoked has disconnected from its clients. (NoMethodError)
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/browser.rb:603:in `method_missing'
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/browser.rb:603:in `block in wait'
C:/Opt/Ruby/Ruby193/lib/ruby/1.9.1/timeout.rb:69:in `timeout'
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/browser.rb:597:in `wait'
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/container.rb:56:in `wait'
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/container.rb:56:in `wait'
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/element.rb:210:in `block in fire_event'
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/element.rb:489:in `perform_action'
C:/Opt/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.3.0/lib/watir-classic/element.rb:210:in `fire_event'
C:/Jenkins/workspace/UI_Automation_Dev/trunk/Automation/ocelot/lib/ocelot/extensions.rb:400:in `method_missing'

I am getting the above error when executing in a virtual node through Jenkins. When I run the same in my local machine manually, there's no error. Here's the block where its throwing the error.

browser.frame(id: 'Iframe1').table(id: 'reviewHeader').td(id: 'RESAVE').when_present.click #clicking Save button
sleep(3) # Wait after Save so the 3rd party app. window closes
browser.window(title: /user/).use # Switch back to the main app window
browser.wait_for_page_load

Here I click the save button, which closes the tab. Then, I sleep for 3 seconds. Then, I use the window having title 'user', and I wait until the page is loaded. The error shows up after I click the Save button; it does not switch to the window. I even tried giving more/less sleep time, but it didn't work. BTW I am using Watir Classic.

ruby
watir
watir-classic
asked on Stack Overflow Jan 20, 2017 by exl • edited Jan 20, 2017 by orde

1 Answer

0

Reproducing the Exception

Looking at where the exception occurred, I was able to simulate the exception by:

1. Creating and opening a window with HTML (this is the main window):

<html>
  <head><title>user</title></head>
  <body><a href="popup.htm" target="_blank">popup</a></body>
</html>

2. Creating and opening a window with a file name of "popup.htm" and HTML (this is the popup window):

<html>
  <head><title>popup</title></head>
  <body><a href="#" id="RESAVE">Re-save</a></body>
</html>

3. Running the following Watir script with manual interaction:

browser = Watir::Browser.attach(:url, /popup/)
Watir::Browser::READYSTATES = {complete: 5}
browser.link.click # while this is running, which is 300 seconds, manually close the popup
#=> `method_missing': unknown property or method: `readyState' (NoMethodError)
#=>    HRESULT error code:0x80010108
#=>      The object invoked has disconnected from its clients.

Solution

The exception is occurring in this part of the Browser#wait method, specifically the @ie.readyState command:

begin
  while @ie.busy
    sleep interval
  end

  until READYSTATES.has_value?(@ie.readyState)
    sleep interval
  end

  until @ie.document
    sleep interval
  end

  documents_to_wait_for = [@ie.document]
rescue WIN32OLERuntimeError # IE window must have been closed
  @down_load_time = ::Time.now - start_load_time
  return @down_load_time
end

The code was written to rescue the window being closed. However, I am not sure why it only includes WIN32OLERuntimeError when we are getting a NoMethodError. Given the age of this code, it is possible that the underlying WIN32OLE has changed its return type over time or it could just be another possible exception. At any rate, monkey patching the wait method to also handle NoMethodError will address the exception.

require 'watir-classic'
module Watir
  class Browser
    def wait(no_sleep=false)
      @xml_parser_doc = nil
      @down_load_time = 0.0
      interval = 0.05
      start_load_time = ::Time.now

      Timeout::timeout(5*60) do
        begin
          while @ie.busy
            sleep interval
          end

          until READYSTATES.has_value?(@ie.readyState)
            sleep interval
          end

          until @ie.document
            sleep interval
          end

          documents_to_wait_for = [@ie.document]
        rescue WIN32OLERuntimeError, NoMethodError # this is the only line modified
          # IE window must have been closed
          @down_load_time = ::Time.now - start_load_time
          return @down_load_time
        end

        while doc = documents_to_wait_for.shift
          begin
            until READYSTATES.has_key?(doc.readyState.to_sym)
              sleep interval
            end
            @url_list << doc.location.href unless @url_list.include?(doc.location.href)
            doc.frames.length.times do |n|
              begin
                documents_to_wait_for << doc.frames[n.to_s].document
              rescue WIN32OLERuntimeError, NoMethodError
              end
            end
          rescue WIN32OLERuntimeError
          end
        end
      end

      @down_load_time = ::Time.now - start_load_time
      run_error_checks
      sleep @pause_after_wait unless no_sleep
      @down_load_time
    end  
  end
end

If the problem only occurs on this one step of a single script, the safest solution might just be to rescue the exception in the one spot:

begin
  browser.frame(id: 'Iframe1').table(id: 'reviewHeader').td(id: 'RESAVE').when_present.click #clicking Save button
rescue NoMethodError
  # window was likely closed
end
answered on Stack Overflow Jan 22, 2017 by Justin Ko

User contributions licensed under CC BY-SA 3.0