9

I searched for a while for this one and was surprised i couldn't find anything, maybe because it's simple. I've been programming in python for about 3 months doing automated testing with selenium webdriver. I was thinking it would be convenient to have a class inherit from my webdriver class to add more functionality to it.

    from selenium import webdriver

    class myPage(webdriver):

          def __init__(self):
                super(myPage, self).__init__()

          def set_up(self):
                #doStuff...

but when i do this i get the error>>>

    File "c:\Users\me\...\myProgram.py", line 6, in <module>
        class myPage(webdriver):
    TypeError: module.__init__() takes at most 2 arguments (3 given)

When I create the myPage object the code is...

    from myProgram import myPage
    class Test():
          def do(self):
                self.browser = myPage.Firefox()

So it goes through and does the self.browser = myPage.Firefox() line and when it runs the .__init__() somehow it gives it three arguments and I'm not sure where they come from. I'm clearly missing something because inheritance isn't hard to do. Thanks for any help

ReckerDan
  • 326
  • 2
  • 8

3 Answers3

10

You'd have to change:

class myPage(webdriver)

To:

class myPage(webdriver.Firefox)

However that would remove the ability to choose the browser you would like to run it on. This is because webdriver isn't actually a class, but a package (I believe). When you call something like: webdriver.Firefox() it is actually an instance of the Firefox class, not the webdriver class. To get what you desire you're probably better off doing something like this:

from selenium import webdriver

class myPage(webdriver.Firefox, webdriver.Chrome, webdriver.Ie):
    def __init__(self, browser):
        if browser.lower() == "ie":
            webdriver.Ie.__init__(self)
        elif browser.lower() == "chrome":
            webdriver.Chrome.__init__(self)
        else:
            webdriver.Firefox.__init__(self)
Bob
  • 684
  • 4
  • 4
  • This may not apply to Python 3 or things may have changed... creating a new answer as comments are awkward for code formatting – gotofritz Sep 11 '21 at 12:35
1

The best way to do it is to inherit from webdriver.Remote.

what is selenium remote?

selenium remote is basically a way to run selenium on another server, but it can be used locally (and works like a charm).
The advantage here is that you will have one interface that works for all browsers, and supports both local and remote execution.

In the future, you might want to run tests in multiple servers via some CI tool, so this can come in handy.

implementation

class izWebDriver(webdriver.Remote):
"""
iz implementation for selenium remote web-driver    
"""
def __init__(self, url, capabilities):
    super().__init__(url, capabilities)

## add more custome functions here !

How to use this implementation

new_driver = izWebDriver(driver_url, DesiredCapabilities.CHROME)

I did some more abstractions, to basically be able to do get_driver(browser='chrome').

A reference - my working framework

Take a look at my own selenium wrapper for reference, It has some knit capabilities like

  • sharing a driver between tests\projects (for testing integration between to GUIs for example).
  • Retries before failing, for example - element.click() tries to click using JS event before failing.

and many more

All the code is available in this github repo
the actual selenium wrapper is in Core folder.
Also, here is an example of a project implemented using my framework

itay zohar
  • 177
  • 10
  • 1
    also the remote.WebDriver has a nice feature for debugging - attaching to existing browser session. It's convenient to have separate process, which starts a browser, saves its session_id, executor_url, and waits forever. then in the code being debugged we just get those id and url, and do a "warm" attach. It's much faster not to wait the browser to initialize. – Mechanic Feb 22 '22 at 07:36
0

@bob's answer is almost right, but with Python 3.9 and Selenium 3.1 I did

class ExtendedWebDriver(webdriver.Firefox):
    def __init__(self):
        super(ExtendedWebDriver, self).__init__()

    def find_elements_by_testid(self, testid):
        return self.find_elements_by_xpath(f"//*[@data-testid='{testid}']")
    
    ...

class HomepageTest(unittest.TestCase):
    def setUp(self):
        self.browser = ExtendedWebDriver()

    def tearDown(self):
        self.browser.quit()

    def test_can_access_homepage(self):
        self.browser.get(HOME) 

    ...

This of course only for FF, you'll have to adapt for multiple browsers by playing with the __init__ part

gotofritz
  • 3,341
  • 1
  • 31
  • 47