1

I want to make a monkey patch for a selenium ruby gem.

Here is the article that I am following.

However, when I do define my own code:

module Selenium
  module WebDriver
    module Driver
      module CookieManagement
        # This is the same as Driver.get, but I just want it to save all the domains it goes to in an easily accessible variable
        def get_and_save(url)
          puts "You've asked me to get, so I am getting"
          get(url)
        end
      end
    end
  end
end

I get an error:

Uncaught exception: Driver is not a module

I understand that this happens because I already have a Driver class defined, so that's ok. But then how does it not happen to the dude in the article and more importantly, what's the accepted workaround then?

UPDATE

I guess my bad for not including the line of code where I do include that causes the above error.

Selenium::WebDriver::Driver.include Selenium::WebDriver::Driver::CookieManagement

Also, it's plain ruby. No rails involved.

iehrlich
  • 3,572
  • 4
  • 34
  • 43
user3081519
  • 2,659
  • 5
  • 25
  • 35
  • "Driver is not a module" - it's a class, see [the source](https://github.com/SeleniumHQ/selenium/blob/master/rb/lib/selenium/webdriver/common/driver.rb#L31) – wiesion Jun 28 '17 at 22:29
  • @wiesion Yes, I can see that as I have stated above. Thus, my question. The dude did exactly the same thing and wrote an article about it. It works for him and I don't understand why. – user3081519 Jun 28 '17 at 22:33
  • The article mentions that you should organize your Monkey patches in custom files and `{Target}.include` (Look for the comment `# Actually monkey-patch DateTime`) them somewhere. That's the only time he mentions it, but it's a requirement. – wiesion Jun 28 '17 at 22:34
  • In your case you should put your monkey patch within `/lib/core_extensions/selenium/web_driver/driver/cookie_management.rb` and within an initializer (Make sure that at that point Selenium was loaded) do the include on the target Class/Module. You could also check [this post](https://stackoverflow.com/questions/5654517/in-ruby-on-rails-to-extend-the-string-class-where-should-the-code-be-put-in) – wiesion Jun 28 '17 at 22:39
  • What do you mean by "why does it not happen to the dude in the article"? Where in the article does he define a `Selenium::WebDriver::Driver` module? – Jörg W Mittag Jun 29 '17 at 07:41
  • @JörgWMittag No, he doesn't. But an attentive reader may notice that he uses DateTime class. – user3081519 Jun 29 '17 at 17:19
  • No, he uses a `CoreExtensions::DateTime` module which is completely different from the `::DateTime` class. – Jörg W Mittag Jun 29 '17 at 18:50
  • @JörgWMittag he uses module DateTime to monkey patch DateTime class. – user3081519 Jun 29 '17 at 21:11
  • Yes, he includes the `CoreExtensions::DateTime` module into the `::DateTime` class. There's nothing special about that. *You* are trying to change the *existing* `Selenium::WebDriver::Driver` class into a module, and that is not allowed. – Jörg W Mittag Jun 29 '17 at 21:59
  • @JörgWMittag ooohhh! Now it all makes sense. Thanks for this conversation! – user3081519 Jun 29 '17 at 22:29

1 Answers1

0

Ok, so using this answer When monkey patching a method, can you call the overridden method from the new implementation?

I came up with:

require 'selenium-webdriver'

module CookieManagement
  def get_and_save(url)
    puts "You told me to get, so I am getting"
    get(url)
  end
end


class Selenium::WebDriver::Driver
  include CookieManagement
end

Which I then require_relative instead of standard selenium-webdriver gem in the .rb files that need that functionality.

user3081519
  • 2,659
  • 5
  • 25
  • 35