How to check page was loaded in __init__? - python

I have base class init
class BasePage:
def __init__(self, context):
self.driver = context.driver
and later when create any new Page I used inheritance:
class LandingPage(BasePage):
def __init__(self, context):
super().__init__(context)
what I want is to check that every next page is loaded using init
def __init__(self, context, is_loaded_check=True):
self.driver = context.driver
if is_loaded_check:
self.page_was_loaded()
else:
raise Exception('page was not loaded!!')
def page_was_loaded(self):
self.elem = context.driver.find_elem_by_xpath(locator)
but tests are stuck on the white screen even when I put time.sleep 30sec

Related

How to change self.driver.get() to only self.get() in class?

I've been looking for an answer but cant find one
Let's say I have this,
self.driver = webdriver.Chrome(options=self.options)
and then I use,
self.driver.get('http://www.google.com/')
Is there a way for me to use just 'self.' on the next method where everything from self.driver pops up? Like so,
self.get('http://www.google.com/')
Create get-method for your class that calls driver.get. Then you can refer to it inside the class as self.get.
class CustomDriver:
def __init__(self, driver):
self.driver = driver
def get(self, url):
self.driver.get(url)
def another_method(self):
self.get("<some_url>")
# do some other stuff here...
# initiate driver first
driver = ...
drv = CustomDriver(driver)
drv.get("<some_url>")
self in Python class
self represents the instance of the class. By using the self keyword
we can access the attributes and methods of the class in python. It
binds the attributes with the given arguments.
In short, self is always pointing to current object.
But get() is method from the WebDriver implementation. So to access get() you have to invoke it through the instance of the WebDriver i.e. driver which you have already initialized through:
self.driver = webdriver.Chrome(options=self.options)

Quit driver instance in pytest after all the tests are executed

Below is the pytest class used to run 2 tests. Want to quit driver after both the tests are executed. used Teardown but it quits the driver after each test execution is completed
class FlightTest(unittest.TestCase):
driver = webdriver.Chrome(direct_path+'/resources/chromedriver.exe')
startup = StartUpPage(driver)
register = RegisterPage(driver)
def test_flight_registration(self):
dat = self.json_reader.read_from_file("testdata.json")
self.startup.navigate_to_url(dat['url'])\
.click_on_register_button()
self.register.create_user(dat['uid'], dat['pwd'], dat['con_pwd'])
def test_flight_sign_in(self,):
dat = self.json_reader.read_from_file("testdata.json")
self.startup.click_sign_in_link()
def tearDown(self):
self.driver.quit()
In unittest terms, you would need to use the setUpClass and tearDownClass class methods:
class FlightTest(unittest.TestCase):
#classmethod
def setUpClass(cls)
cls.driver = webdriver.Chrome()
cls.startup = StartUpPage(driver)
cls.register = RegisterPage(driver)
#classmethod
def tearDownClass(cls):
cls.driver.quit()
...
In pytest terms, you would create a class-scoped fixture:
import pytest
#pytest.fixture(scope="class")
def driver(request):
# code before 'yield' is executed before the tests
request.cls.driver = webdriver.Chrome()
request.cls.startup = StartUpPage(request.cls.driver)
request.cls.register = RegisterPage(request.cls.driver)
yield
# code after 'yield' is executed after the tests
request.cls.driver.quit()
#pytest.mark.usefixtures('driver')
class FlightTest(unittest.TestCase):
def test_spam(self):
self.driver.get('https://www.google.de')
def test_eggs(self):
self.driver.get('https://www.facebook.com')
An even better solution would be using the context manager property of the webdriver so it is automatically closed no matter what:
import pytest
#pytest.fixture(scope="class")
def driver(request):
with webdriver.Chrome() as driver:
request.cls.driver = driver
request.cls.startup = StartUpPage(driver)
request.cls.register = RegisterPage(driver)
yield
#pytest.mark.usefixtures('driver')
class FlightTest(unittest.TestCase):
def test_spam(self):
self.driver.get('https://www.google.de')
def test_eggs(self):
self.driver.get('https://www.facebook.com')

How can I access base class elements using inheritance

I am using inheritance to access base class elements. I have defined driver object in environment class and inherited in base class. In base class I am trying to access this object.
However I am getting an error Environment has no object driver. How do I access this element?
class Environment(object):
def __init__(self):
driver = "webdriver.Chrome(D:\BrowserDriver\ChromeDriver\chromedriver.exe)"
print self.driver
class base(Environment):
def __init__(self):
drive = self.driver
def test_Home_Page(self):
# Screenshots relative paths
ss_path = "/Test_MercuryTours_HomePage/"
# Using the driver instances created in EnvironmentSetup
drive = self.driver
print drive
env=Environment()
print env.setUp()
b=base()
print b.drive
class Environment(object):
def __init__(self):
self.driver = "webdriver.Chrome(D:\BrowserDriver\ChromeDriver\chromedriver.exe)"
print self.driver
class base(Environment):
def __init__(self):
Environment.__init__(self)
self.drive = self.driver
b=base()
print b.drive
Add self to the variable driver, in the base class.
def __init__(self):
self.driver = "webdriver.C..."
ps: similarly, to access drive, you need to change it to self.drive .
In the base class, try this.
def __init__(self):
Environment.__init__(self)
self.driver = "webdriver.C..." .
Find out more about the Super keyword used for inheritance.

Define custom function in selenium python

How I can define custom function and then use it in test function, it works when I run single test case but don't work when I run multiple test cases.
class AlphaTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.driver.get("http://google.com/")
def asserTrueId(self, value):
self.assertTrue(self.driver.find_element_by_id(value))
time.sleep(1)
def test_flush_cache(self):
self.asserTrueId("block-menu-menu-menu-for-directories")
You could use unittest.setUpClass() to instantiate a class level driver instance. Similarly you can use tearDownClass() to clean up class level variables if required.
Since setUpClass() and tearDownClass() will only be run once inside your Test class you can use this to guarantee there is only one driver. Otherwise using setUp() would be run for each test method - each creating a browser instance each time - which could be slow and possibly memory inefficient.
class AlphaTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
cls.driver.implicitly_wait(30)
cls.driver.get("http://google.com/")
def asserTrueId(self, value):
self.assertTrue(self.driver.find_element_by_id(value))
time.sleep(1)
def test_flush_cache(self):
self.asserTrueId("block-menu-menu-menu-for-directories")

Pass self to decorator object

Having such decorator object
class wait_for_page_load(object):
def __init__(self, driver, time_to_wait=20):
self.driver = driver
self.time_to_wait = time_to_wait
def __call__(self, function):
#functools.wraps(function)
def wrapper(*args):
old_page = self.driver.find_element_by_tag_name('html')
function(*args)
WebDriverWait(self.driver, self.time_to_wait).until(staleness_of(old_page))
return wrapper
I want to apply it to method of another class, like this:
class VehiclePage(object):
def __init__(self, driver):
self.driver = driver
#wait_for_page_load(self.driver)
def open(self):
self.driver.get('%s/vehicles/' % BASE_URL)
This gives me an error. Is there a way to pass self.driver to decorator?
You don't have to pass self to a decorator object. If the decorator returns a function, then that function will get access to self when it is called. eg.
def pass_value(function):
def wrapper(self):
function(self, self.value)
return wrapper
class Printer(object):
def __init__(self, value):
self.value = value
#pass_value
def print_(self, v):
print v
Printer("blah").print_()
The one problem with this method is that it requires self to implement a specific interface (such as having a field called driver, rather than directly passing the driver to the decorator).
Your decorator would become:
def wait_for_page_load(time_to_wait=20):
def decorator(function):
#functools.wraps(function)
def wrapper(self, *args):
old_page = self.driver.find_element_by_tag_name('html')
function(self, *args)
WebDriverWait(self.driver, time_to_wait).until(staleness_of(old_page))
return wrapper
return decorator
Used as:
#wait_for_page_load() # brackets are needed
def open(self):
...
Short answer: No there is not.
Long answer:
The driver attribute is set when you instantiate the class. However, the decorator is run when the class is interpreted. That is, when the interpreter first reads it when loading the module. At this point, you don't have any instance ready. To do this kind of stuff you will have to refactor your code.
Also, even if that worked, you would end up using a single instance of your decorator class for all your objects. Probably not what you expected.
A simple workaround, though, could be to apply the decorator in __init__. Though not very elegant, that would work if you really need to apply the decorator.
def __init__(self, driver):
self.driver = driver
self.open = wait_for_page_load(self.driver)(self.open)
But then I believe you need to bind the wrapper to the class yourself by calling types.MethodType - honestly, it's probably better you just reorganize your code.

Categories