Python Forum
Selenium Page Object Model with Python
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Selenium Page Object Model with Python
#1
I am currently working with selenium and some boilerplatte code from github: https://github.com/gunesmes/page-object-python-selenium
After changing the code to work with a diffrent site I need to make a new function and I encoutererd a problem.


after using "click_sign_in_button" function in MainPage class I return the LoginPage instance to the Unittest and then try to login in the Website. If get an error I need to restart the page with BasePage class and again use the MainPage class function for the "click_sign_in_button", but if I try to import the class in LoginPage Class file I get an error and cant use the "click_sign_in_button" function.

I need to access parent class function to use a specific function again.
Reply
#2
Can you provide the code with the errors as well? It's kind of hard to help you without it.
Reply
#3
test_sign_in_page.py
from tests.base_test import BaseTest
from pages.main_page import MainPage


class TestSignInPage(BaseTest):


    def test_sign_in_with_in_valid_user(self):
        main_page = MainPage(self.driver)
        login_page = main_page.login_click()
        result = login_page.login()
main_page.py
from pages.base_page import BasePage
from pages.login_page import LoginPage
from utils import users
from utils.locators import *


class MainPage(BasePage):
    def __init__(self, driver):
        print("user_page __init__")
        self.locator = UserPageLocators
        self.user = users.get_user("google")
        super().__init__(driver)  # Python3 version

    def check_page_loaded(self):
        return True if self.find_element(*self.locator.LOGO) else False

    def click_sign_in_button(self):
        self.find_element(*self.locator.LOGIN).click()

    def click_facebook_login_button(self):
        self.find_element(*self.locator.FACEBOOK_LOGIN).click()

    def click_google_login_button(self):
        self.find_element(*self.locator.GOOGLE_LOGIN).click()

    def click_apple_login_button(self):
        self.find_element(*self.locator.APPPLE_LOGIN).click()

    def switch_to_login_iframe(self):
        self.iframe = self.find_element(*self.locator.IFRAME)
        self.switch_iframe(self.iframe)

    def login_click(self):
        self.click_sign_in_button()
        self.switch_to_login_iframe()

        if self.user["provider"] == "google":
            self.click_google_login_button()
        elif self.user["provider"] == "facebook":
            self.click_facebook_login_button()
        elif self.user["provider"] == "apple":
            self.click_apple_login_button()

        return LoginPage(self.driver, self.user)
login_page.py
import time

from utils.locators import *
from pages.base_page import BasePage


class LoginPage(BasePage):
    def __init__(self, driver, user):
        self.user = user
        if self.user["provider"] == "google":
            self.locator = GoogleLoginPageLocators
        elif self.user["provider"] == "facebook":
            self.locator = FacebookLoginPageLocators
        elif self.user["provider"] == "apple":
            self.locator = AppleLoginPageLocators

        super().__init__(driver)

    def enter_email(self, email):
        self.find_element(*self.locator.EMAIL).send_keys(email)

    def enter_password(self, password):
        self.find_element(*self.locator.PASSWORD).send_keys(password)

    def click_login_button(self):
        self.find_element(*self.locator.SUBMIT).click()

    def click_continue_button(self):
        self.find_element(*self.locator.CONTINUE).click()

    def switch_window(self, x):
        self.driver.switch_to.window(self.driver.window_handles[x])


    def login(self):
        if self.user["provider"] == "google":
            self.login_google()
        elif self.user["provider"] == "facebook":
            self.login_facebook()
        elif self.user["provider"] == "apple":
            self.login_apple()

        if self.check_element(*self.locator.IFRAME):
            self.age_gender_verification()
        else:
            print("wtf")

    def age_gender_verification(self):
        #change frame for verification
        self.iframe = self.find_element(*self.locator.IFRAME)
        self.switch_iframe(self.iframe)

        #enter age
        self.find_element(*self.locator.AGE).send_keys(self.user["age"])

        #enter gender
        self.find_element(*self.locator.GENDER_SELECT).click()
        if self.user["gender"] == "male":
            self.find_element(*self.locator.GENDER_MALE).click()
        else:
            self.find_element(*self.locator.GENDER_FEMALE).click()

        #Click Validation Continue
        self.find_element(*self.locator.VALIDATION_CONTINUE).click()

        #If error then restart the login proccess
        if self.check_element(*self.locator.VALIDATION_ERROR):
            from pages.main_page import MainPage
            #switch back from iframe
            self.driver.switch_to.default_content()
            #click close
            self.find_element(*self.locator.VALIDATION_CLOSE).click()
            #relogin
            MainPage(self).login_click()
        else:
            print("fail")


    def login_facebook(self):
        self.switch_window(1)
        print(self.user)
        self.enter_email(self.user["email"])
        self.enter_password(self.user["password"])
        self.click_login_button()
        self.switch_window(0)

    def login_google(self):
        self.switch_window(1)
        print(self.user)
        self.enter_email(self.user["email"])
        self.click_continue_button()
        time.sleep(1)
        self.enter_password(self.user["password"])
        self.click_login_button()
        self.switch_window(0)

    def login_apple(self):
        self.switch_window(1)
        print(self.user)
        self.enter_email(self.user["email"])
        self.enter_password(self.user["password"])
        self.click_login_button()
        self.switch_window(0)
Error Message:
Error:
ImportError: cannot import name 'LoginPage' from partially initialized module 'pages.login_page' (most likely due to a circular import)
for the missing classes please look at the github link https://github.com/gunesmes/page-object-python-selenium
Reply
#4
try to replace imports in test_sign_in_page.py to:
from tests.base_test import BaseTest
from pages.main_page import MainPage
and then you probably will have to use local import because of circular imports -> remove
from pages.main_page import MainPage

from login_page.py and import it inside the age_gender_verification:
def age_gender_verification(self):
    from pages.main_page import MainPage
and if I were you I would try to avoid * imports
Reply
#5
It works at first but I think the inheritance gets all messed up because there is a BasePage class within MainPage and LoginPage after reusing a function which is in BasePage I get this error. Strangely only the BasePage function doesnt work and the MainPage class still does.

I updated the code in the post before that.

Error:
Error Traceback (most recent call last): File "C:\Python\Python38-32\lib\unittest\case.py", line 60, in testPartExecutor yield File "C:\Python\Python38-32\lib\unittest\case.py", line 676, in run self._callTestMethod(testMethod) File "C:\Python\Python38-32\lib\unittest\case.py", line 633, in _callTestMethod method() File "C:\MEGA\Private_Project\POM\tests\test_sign_in_page.py", line 11, in test_sign_in_with_in_valid_user result = login_page.login() File "C:\MEGA\Private_Project\POM\pages\login_page.py", line 44, in login self.age_gender_verification() File "C:\MEGA\Private_Project\POM\pages\login_page.py", line 74, in age_gender_verification MainPage(self).login_click() File "C:\MEGA\Private_Project\POM\pages\main_page.py", line 35, in login_click self.switch_to_login_iframe() File "C:\MEGA\Private_Project\POM\pages\main_page.py", line 31, in switch_to_login_iframe self.switch_iframe(self.iframe) File "C:\MEGA\Private_Project\POM\pages\base_page.py", line 46, in switch_iframe self.driver.switch_to.frame(element) AttributeError: 'LoginPage' object has no attribute 'switch_to'
base_page.py
import time

from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException,NoSuchElementException

# this Base class is serving basic attributes for every single page inherited from Page class
from utils import users


class BasePage(object):
    def __init__(self, driver, base_url='https://soundcloud.com/'):
        print("base_page __init__")
        self.base_url = base_url
        self.driver = driver
        #self.driver.get(base_url)

    def find_element(self, *locator):
        self.wait_element(locator)
        return self.driver.find_element(*locator)

    def check_element(self, *locator):
        time.sleep(1)
        try:
            return self.driver.find_element(*locator)
        except NoSuchElementException:
            return False

    def open(self, url):
        url = self.base_url + url
        self.driver.get(url)

    def get_title(self):
        return self.driver.title

    def get_url(self):
        return self.driver.current_url

    def hover(self, *locator):
        element = self.find_element(*locator)
        hover = ActionChains(self.driver).move_to_element(element)
        hover.perform()

    def switch_iframe(self, element):
        self.driver.switch_to.frame(element)

    def switch_window(self, x):
        self.driver.switch_to.window(self.driver.window_handles[x])

    def wait_element(self, *locator):
        try:
            WebDriverWait(self.driver, 10).until(EC.presence_of_element_located(*locator))
        except TimeoutException:
            print("\n * ELEMENT NOT FOUND WITHIN GIVEN TIME! --> %s" %(locator[1]))
            self.driver.quit()
Maybe the POM model I am using is wrong or am I doing something wrong?
my problem is that after intialising MainPage which clicks the login button and returns LoginPage which trys to login with email and password I sometimes need to restart the login process from the LoginPage class function and use the MainPage login click function again but this POM model from github: https://github.com/gunesmes/page-object-...-selenium/ doesnt really seem to allow it because I cant somehow easily jump between the classes with the same objects and functions.
Reply
#6
I don't understand this line:
MainPage(self).login_click()
and it seems to be the problem, as you are initializing MainPage instance and passing it an instance of LoginPage instead of a driver.

But from a quick overall look, it feels like going this direction you will have more problems, as you are trying to restart the login process from inside the LoginPage instance by creating another LoginPage instance.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Click on a button on web page using Selenium Pavel_47 7 4,565 Jan-05-2023, 04:20 AM
Last Post: ellapurnellrt
  Selenium/Helium loads up a blank web page firaki12345 0 2,008 Mar-23-2021, 11:51 AM
Last Post: firaki12345
  Saving html page and reloading into selenium while developing all xpaths Larz60+ 4 4,104 Feb-04-2021, 07:01 AM
Last Post: jonathanwhite1
  Selenium Parsing (unable to Parse page after loading) oneclick 7 5,891 Oct-30-2020, 08:13 PM
Last Post: tomalex
  Code example for entering input in a textbox with requests/selenium object peterjv26 1 1,674 Sep-26-2020, 04:34 PM
Last Post: Larz60+
  Selenium on Angular page Martinelli 3 5,598 Jul-28-2020, 12:40 PM
Last Post: Martinelli
  use Xpath in Python :: libxml2 for a page-to-page skip-setting apollo 2 3,579 Mar-19-2020, 06:13 PM
Last Post: apollo
  Selenium get data from newly accessed page hoff1022 2 2,903 Oct-09-2019, 06:52 PM
Last Post: hoff1022
  Difficult web page -- Selenium Larz60+ 2 2,588 Dec-31-2018, 06:51 PM
Last Post: Larz60+
  Web Page not opening while web scraping through python selenium sumandas89 4 10,000 Nov-19-2018, 02:47 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020