Search code examples
pythongoogle-chromeselenium-webdriverwebdrivermicrosoft-edge

Python Selenium: Calling same WebDriver for multiple function calls


I want to create 2 Tests (basically the same test, but 1 is in Chrome and the other in Edge). Just a simple connecting to a webpage and confirming some text on the page.

Original Python Project

If everything is in 1 Python file, it's quite simple:

test_homepage.py

import time

from selenium import webdriver
from selenium.webdriver.common.by import By

# ----------- Connection Test (Chrome) ---------------------------------------------------------------
url = "https://localhost/home"
driver=webdriver.Chrome("C:\Drivers\chromedriver_win32\chromedriver.exe")
driver.get(url)

# "Your connection is not private"
driver.find_element(By.ID, "details-button").click() # Click the "Advanced" button
time.sleep(1)
driver.find_element(By.ID, "proceed-link").click() # Click the "Proceed to localhost (unsafe)" link
time.sleep(1)

# Login Page
driver.find_element(By.ID, "userNameInput").send_keys("TestUser")
driver.find_element(By.ID, "passwordInput").send_keys("Password123")
driver.find_element(By.ID, "submitButton").click()
time.sleep(1)

# Search for text on the Homepage to confirm reaching the destination
get_source = driver.page_source
search_text = "Welcome to the Homepage!"
driver.close()

try:
    if (search_text in get_source):
        assert True
        print("Chrome Test: Passed")
    else:
        assert False
except:
    print("Chrome Test: Failed")

# ----------- Connection Test (Edge) ---------------------------------------------------------------
driver=webdriver.Edge("C:\Drivers\edgedriver_win64\msedgedriver.exe")
driver.get(url)

driver.find_element(By.ID, "details-button").click() # Click the "Advanced" button
time.sleep(1)
driver.find_element(By.ID, "proceed-link").click() # Click the "Proceed to localhost (unsafe)" link
time.sleep(1)

# Login Page
driver.find_element(By.ID, "userNameInput").send_keys("TestUser")
driver.find_element(By.ID, "passwordInput").send_keys("Password123")
driver.find_element(By.ID, "submitButton").click()
time.sleep(1)

# Search for text on the Homepage to confirm reaching the destination
get_source = driver.page_source
search_text = "Welcome to the Homepage!"
driver.close()

try:
    if (search_text in get_source):
        assert True
        print("Edge Test: Passed")
    else:
        assert False
except:
    print("Edge Test: Failed")

When testing in Python Selenium, in both browsers, you get an error message NET::ERR_CERT_COMMON_NAME_INVALID when initially connecting to https://localhost/home, so I have to confirm advancing to the Login Page, logging in and then checking the Text on the homepage. This code will start with Chrome, and then proceed with the same steps in Edge.

Now, this code is quite inefficient: it's basically doubling the same code. I also plan to create more tests that will involve testing more aspects of the website, meaning the Login process will be necessary for every Test I perform.

Updated Python Project

As a friend recommended, I should create some functions for this test_ python file to call.

libraries/
├── chrome.py
├── edge.py
tests/
├── test_homepage.py

A libraries folder for Chrome and Edge Functions (they'll generally be very similar ... and even then, I'm thinking they should probably be combined, but I have a feeling trying to call 2 different WebDrivers from the same library python files will become difficult), and then a tests folder for each test (I want to be sure every test is performed in both Chrome and Edge). Here are the updates to my Python Project:

chrome.py

import time

from selenium import webdriver
from selenium.webdriver.common.by import By

class WebChrome:
    def __init__(self):
        print("")
    
    def connect(self, username: str, password: str):
        self.driver = webdriver.Chrome("C:\Drivers\chromedriver_win32\chromedriver.exe")
        self.driver.get("https://localhost/homepage")
        time.sleep(1)
        
        get_source = self.driver.page_source
        not_private = "Your connection is not private"
        if (not_private in get_source):
            # NET::ERR_CERT_COMMON_NAME_INVALID
            self.driver.find_element(By.ID, "details-button").click()
            self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # Scrolls to the bottom of the page
            time.sleep(1)
            self.driver.find_element(By.ID, "proceed-link").click()
            time.sleep(1)
        
        get_source = self.driver.page_source
        login_page = "Login Page"
        if (login_page in get_source):
            self.driver.find_element(By.ID, "userNameInput").send_keys(username)
            self.driver.find_element(By.ID, "passwordInput").send_keys(password)
            self.driver.find_element(By.ID, "submitButton").click()
            time.sleep(1)

    def find_string(self, search_text: str):
        self.driver = webdriver.Chrome("C:\Drivers\chromedriver_win32\chromedriver.exe")
        get_source = self.driver.page_source
        self.driver.close()

        try:
            if (search_text in get_source):
                assert True
                print("Chrome Test: Passed")
            else:
                assert False
        except:
            print("Chrome Test: Failed")

(I'll get to edge.py when I get Chrome working. I also wanted to update my Code so it looks to see whether it's on the "Your connection is not private" or "Login Page" before moving on to the next steps, and that code looks to be working correctly.)

test_homepage.py

from libraries.chrome import WebChrome
from selenium import webdriver

# ----------- Connection Test (Chrome) ---------------------------------------------------------------
WebChrome().connect("TestUser", "Password123")
WebChrome().find_string("Welcome to the Homepage!")

Now, the connect function looks to be working as I would expect. However, once Selenium reaches the Homepage, the current Chrome Browser closes out, and a new Chrome Browser appears for a millisecond before ending, causing the Test to Fail.

What I assume is going on: when I call find_string, I'm starting a new session because I'm called self.driver. I really only want the WebDriver to be called in the connect function, and then when I call find_string to continue the current driver. However, when I tried including self.driver = webdriver.Chrome("C:\Drivers\chromedriver_win32\chromedriver.exe") in __init__, Selenium would open 2 Chrome Browsers (the first goes unused) and I run into errors (I'm afraid I don't really understand Constructors too well: all I really know is that __init__ is supposed to run the code as soon as the Class or Program is started?). I also tried moving self.driver = webdriver.Chrome("C:\Drivers\chromedriver_win32\chromedriver.exe") to the beginning of the WebChrome class, before the 2 Functions, as well as removing the code from find_string, but that causes Syntax Errors when the program runs: AttributeError: 'WebChrome' object has no attribute 'driver'

Here is my question: Where should I call self.driver = webdriver.Chrome("C:\Drivers\chromedriver_win32\chromedriver.exe") so it will run only once when I run both the connect and find_string functions? And is there a better way I should be calling the WebDriver?


Solution

  • Define self.driver in __init__ and for only once.
    You can use __init__ as connect function assuming you need to connect only once.
    You are creating a new object every time. You must define WebChrome just once for a single test.
    As of now, there is no need to pass exe path simply use webdriver.Chrome() or webdriver.Edge()

    Different code for edge and chrome

    chrome.py

    import time
    
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    class WebChrome:
        def __init__(self, username: str, password: str):
            self.driver = webdriver.Chrome()
            self.driver.get("https://localhost/homepage")
            time.sleep(1)
            
            get_source = self.driver.page_source
            not_private = "Your connection is not private"
            if (not_private in get_source):
                # NET::ERR_CERT_COMMON_NAME_INVALID
                self.driver.find_element(By.ID, "details-button").click()
                self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # Scrolls to the bottom of the page
                time.sleep(1)
                self.driver.find_element(By.ID, "proceed-link").click()
                time.sleep(1)
            
            get_source = self.driver.page_source
            login_page = "Login Page"
            if (login_page in get_source):
                self.driver.find_element(By.ID, "userNameInput").send_keys(username)
                self.driver.find_element(By.ID, "passwordInput").send_keys(password)
                self.driver.find_element(By.ID, "submitButton").click()
                time.sleep(1)
    
        def find_string(self, search_text: str):
            get_source = self.driver.page_source
            self.driver.close()
    
            try:
                if (search_text in get_source):
                    assert True
                    print("Chrome Test: Passed")
                else:
                    assert False
            except:
                print("Chrome Test: Failed")
    

    test_homepage.py

    from libraries.chrome import WebChrome
    from selenium import webdriver
    
    # ----------- Connection Test (Chrome) ---------------------------------------------------------------
    test_obj = WebChrome("TestUser", "Password123")
    test_obj.find_string("Welcome to the Homepage!")
    

    One Code for both edge and chrome

    I recommend this

    chrome_and_edge.py
    (Change just the __init__ function in this way)

    class WebBrowser:
        def __init__(self, username: str, password: str,driver_name: str):
            if driver_name == "chrome":
                self.driver = webdriver.Chrome()
            elif driver_name == "edge":
                self.driver = webdriver.Edge()
            self.driver.get("https://localhost/homepage")
            time.sleep(1)
            else:
               print("Enter either chrome or edge only!")
               #raise some error
    

    test_homepage.py

    from libraries.chrome import WebChrome
    from selenium import webdriver
    
    # ----------- Connection Test (Chrome) ---------------------------------------------------------------
    test_obj = WebChrome("TestUser", "Password123","chrome")
    test_obj.find_string("Welcome to the Homepage!")
    
    # ----------- Connection Test (Edge) ---------------------------------------------------------------
    test_obj = WebChrome("TestUser", "Password123","edge")
    test_obj.find_string("Welcome to the Homepage!")