Forgive me if this is a stupid question (new to coding) but I haven't been able to find documentation that explains how to do this in python. All I want is to be able to execute x number of concurrent tests for either the same browser or across different browsers.
I've setup my hub and node with maxInstance and maxSession = 5 so I was expecting that 5 browser windows would show up when I execute the test but only 1 opens and executes. Am I missing something?
I've seen examples in java where ppl set the DesiredCapabilites as a variable but I get errors when I try this - I can't figure out how to specify more than a single browser to execute my test.
How would I set something like this up to open and run on 2 chrome instances and 3 internet explorer instances?
import unittest
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
class GridTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Remote(command_executor='http://localhost:4444/wd/hub',desired_capabilities=DesiredCapabilities.CHROME)
def test01_GridTest(self):
driver = self.driver
driver.get("http://www.google.com")
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
Related
I'd like pytest to take screenshots at specified intervals of time while running tests. It's like I want to force the webdriver to make these two operations concurrently.
from pytest import fixture
#fixture(scope="function")
def drv(app_config):
options = app_config.browser[0]
service = app_config.browser[1]
drv = browser(options=options, service=service)
yield drv
#fixture(scope="function", autouse=True)
def recorder(drv):
while True:
drv.save_screenshot(f"./recordings/{str(time())}.png")
At the moment. The setup creates a webdriver and then bogs down to take screenshots indefinitely.
I want the webdriver to take screenshots until the driver closes WHILE doing other operations like opening the browser, finding and clicking elements etc.
Pytest is a testing framework and doesn't have any context of what happens in your browser. You'll need to either send the webdriver object to the method in a separate thread and loop till the webdriver is not destroyed or implement the behaviour in your driver.
There are two ways in which you can achieve this :
You can use the EventFiringWebDriver that comes with the selenium webdriver. You can basically tell selenium to print something before/after navigation.
from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener
class MyListener(AbstractEventListener):
def before_navigate_to(self, url, driver):
print("Before navigate to %s" % url)
def after_navigate_to(self, url, driver):
print("After navigate to %s" % url)
driver = Firefox()
ef_driver = EventFiringWebDriver(driver, MyListener())
ef_driver.get("http://www.google.co.in/")
There are tones of event that can be used, you can refer to this source
Use the Decorator pattern and decorate the webdriver to have the methods takes the screenshot for your particular action after a given interval.
I am fairly new to programming so please be patient, but to the point.
I am creating few test cases using Selenium Web Driver, I have to check functionality of webpage to which I have to login using password and later with SMS code that I receive on my phone. I want to do this ONE TIME ONLY, so I want to use ONE instance of Web Driver for all my test cases (I know it is not recommended, but it will save a lot of time and sending 30 SMS, code from SMS is entered manually via Terminal).
My code looks something like this:
import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
class LoginTest(unittest.TestCase):
def setUp(self):
self.browser = webdriver.Safari()
def test_LoginIn(self):
browser = self.browser
(Here I am looking for buttons and clicking on them)
def test_MyDevices(self):
browser.find_element_by_xpath('Some XPATH').click()
if __name__ == '__main__':
unittest.main()
And here is my problem after performing test_LoginIn I want to start another test test_MyDevices because MyDevice tab is right after logging in on the same page as first test is ended, but I can't because next test want to create new Web Driver Instance instead of doing test in the same instance.
In current version I receive this error:
Error after running script
I read a lot about this issue but couldn't find any satisfactory answer.
I'd be grateful for your help.
You can use the same instance of the webdriver for all of your tests. You will just need to instantiate the webdriver once, and then use it throughout your tests.
I'm currently trying to run multiple browsers at the same time with Selenium.
All processes start but don't execute passed functions correctly.
My Code:
from multiprocessing import Pool
# function that creates driver
driver = self.create_driver()
pool.apply_async(launcher.launch_browser, driver)
The launch_browser function is a different Python script that is supposed to run but only a Browser window is opened. (yes, I imported the external script as a module)
You can simply open new browser windows the same way you open the first one, with the same or different browsers:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
class Bot:
def __init__(self):
self.firstBrowser = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
self.secondBrowser = webdriver.Firefox()
def gotopage(self):
self.firstBrowser.get("https://www.google.com/")
self.secondBrowser.get("https://stackoverflow.com/")
bot = Bot()
bot.gotopage()
Found many topics about this problem, but didn't find any easy described problem solving, so creating new topic with this problem and maybe will get much better answer to this problem.
I have created test case for LoginTest and test case for LegalPersonSearchTest. Both these test cases are in separate files login.py and legalPersonSearch.py
from utils.utils import *
from selenium import webdriver
from locators.locators import Locators
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import unittest
from pages.loginPage import LoginPage
class LoginTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
cls.driver.implicitly_wait(10)
cls.driver.maximize_window()
cls.driver.get(URL)
def test_valid_login(self):
driver = self.driver
login = LoginPage(driver)
login.fill_login_form(adminUsername, adminPassword)
login.click_login_button()
if __name__ == '__main__':
unittest.main()
I think the reason why new browser opens between tests, is declaring driver in second file.
from selenium import webdriver
import unittest
from pages.legalPersonSearchPage import LegalPersonSearchPage
class LegalPersonSearchTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
def test_valid_organization_search(self):
driver = self.driver
legal = LegalPersonSearchPage(driver)
legal.open_legal_person_search_page()
#classmethod
def tearDown(cls):
cls.driver.quit()
if __name__ == '__main__':
unittest.main()
How to modify LoginTest that browser open only one time, instead between tests?
I need to modify it, because after login (which is 1/2 of test) comes second part of test. It will complete and then browser closes and open new and start again with login.
As someone told me, then best practice is to keep login test part out of whole test.
To answer one of your questions -- driver gets opened twice because you have two different setUp() methods, one for each of your classes - LoginTest and LegalPersonSearchTest. When you run test_valid_login, your setUpClass() method gets called, which initializes the driver. Then, test runs. This driver instance never gets torn down, so window remains open.
Then, test_valid_organization_search runs. This class ALSO has its own setUpClass() method, which initializes another driver instance. So now you have two drivers, both of which are opened in the setUpClass() method of each class file.
This set up is producing results that you have not intended. I think you are slightly misunderstanding what "best practice is to keep login test part out of whole test" means here.
This does not mean you need to write two separate tests -- one that logs in, and one that tests the rest of the functionality. This is actually bad practice, because you want your test cases to run independently of one another -- test cases should not rely on previous test cases to execute properly.
I think the solution you are looking for here is to write the login functionality into your setUp() method so that login is always performed before a test case starts.
This approach will prevent you from having the login part in with the test -- that's the original goal you mentioned here.
You can adjust your classes by removing the duplicate setUp() method, and inheriting LoginTest into your LegalPersonSearchTest so that you are only setting up once:
from utils.utils import *
from selenium import webdriver
from locators.locators import Locators
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import unittest
from pages.loginPage import LoginPage
# this is our "base" class
class LoginTest(unittest.TestCase):
driver = None # driver instance that we will inherit into LegalPersonSearchTest
# initialize driver, go to testing URL, etc.
def setUp(cls):
cls.driver = webdriver.Firefox()
cls.driver.implicitly_wait(10)
cls.driver.maximize_window()
cls.driver.get(URL)
# call login here to login before test
login_page = LoginPage(cls.driver)
login_page .fill_login_form(adminUsername, adminPassword)
login_page .click_login_button()
# move teardown into same class as setUp()
def tearDown(cls):
cls.driver.quit()
We have declared a class variable for driver that you can pass into LegalPersonSearchTest. We have also removed the __main__ call, because the only entry point we need is the test_ method in LegalPersonSearchTest:
from selenium import webdriver
import unittest
from pages.legalPersonSearchPage import LegalPersonSearchPage
from login_test import LoginTest # unsure of file name containing LoginTest class
class LegalPersonSearchTest(LoginTest): # inherit LoginTest here so we can use driver
def test_valid_organization_search(self):
legal_page = LegalPersonSearchPage(self.driver)
legal_page .open_legal_person_search_page()
if __name__ == '__main__':
unittest.main()
We have changed a few things here:
Entry point for main method designated by __main__ -- we only need this in one place, on the test case level (LegalPersonSearchTest)
Removed duplicate setUp() method calls that were resulting in multiple driver instances getting created (mentioned in your problem description)
Created single class instance of driver in LoginTest class to be passed into LegalPersonSearchTest class
Modified setUp() method on LoginTest to initialize the driver and login -- so that you do not have to include login code for any test!
Update: Changes made following comments:
Removed login method from LoginTest class and moved login code under setUp() -- this will get performed before every test case now
Modified test_valid_organization_search to use self.driver instead of driver when initializing PageObject
I've made many of these changes based on this sample Python test architecture that I pushed to my GitHub. The files I used as templates were base_test_fixture.py (for your LoginTest), and test_web_driver.py for your LegalPersonSearchTest.
You may notice that base_test_fixture.py also contains def _testInitialize() and def _testCleanup() -- these are methods that you can override in your LegalPersonSearchTest class to perform additional steps to be run before your test_ method. The idea here is that if you have multiple .py files containing test cases, but each .py file requires slightly different setup, and you need to do more than just setUp() method calls for. You can override the testInitialize() and testCleanup() methods in the test case class, and these methods will execute after setUp() and before the actual test_ method.
Let me know if you have any questions about this -- it's quite a bit to explain, but once you learn this architecture, you have a very powerful way of organizing and executing your test cases.
I am testing a native iOS app and need to wait for some elements to load in some of my testing. Appium is going too fast on some screens right now.
Can someone please point me to an example of using a WebDriverWait style of waiting for Appium iOS testing? There was a question that was answered for Ruby here: Wait for element to load when testing an iOS app using Appium and Ruby?. Looking for something similar in Python.
The Python client documentation doesn't seem to document the wait functions.
Thanks.
At the top of the test import these.
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
TL/DR is this should work, you may have to change self.driver to just driver in the wait = section depending on how you're doing things. Also, obviously change the By.XPath to whatever locator you're using:
wait = WebDriverWait(self.driver, 20)
currently_waiting_for = wait.until(EC.element_to_be_clickable((By.XPATH,'//UIAApplication[1]/UIAWindow[1]/UIAButton[#text="example text"]')))
Or you could just tell the driver to use implicit waits.
self.driver.implicitly_wait(10)
myElement = driver.find_element_by_id("fakeid")
myElement.click()
Most of this is explained here.
Here's an example of using wait to log into an Android App (Haven't used it on ios but it should be the similar) using the default account selector then asserting the right text appeared. During the setup, I'm loading my desired capabilities from another file.
class TrainUpSmokeTests(unittest.TestCase):
def setUp(self):
desired_caps = desired_capabilities.get_desired_capabilities('app-debug.apk')
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
def tearDown(self):
self.driver.quit()
def example_test(self):
wd = self.driver
## Depending on how you're running the test the first variable may just be driver. Or in my case self.driver which I shortened above. The number is how many seconds it should wait before timing out.
wait = WebDriverWait(wd, 20)
## Waiting for account selector to be clickable.
currently_waiting_for = wait.until(EC.element_to_be_clickable((By.XPATH,'//android.widget.CheckedTextView[#text="FakeEmail#example.com"]')))
## Locating test account and selecting it.
account = wd.find_element_by_android_uiautomator('text("FakeEmail#example.com")')
account.click()
ok_button = wd.find_element_by_android_uiautomator('text("OK")')
ok_button.click()
## Waiting for an Element on the home screen to be locatable.
currently_waiting_for = wait.until(EC.presence_of_element_located((By.XPATH,'//android.widget.RelativeLayout[#resource-id="com.name.app:id/overview"]')))
hero_headline = wd.find_element_by_android_uiautomator('new UiSelector().description("Example Header")')
self.assertIsNotNone(hero_headline)
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(TrainUpSmokeTests)
unittest.TextTestRunner(verbosity=2).run(suite)
It's a your testings a website using appium (instead of an app). Change the setup so self.driver opens a browser.
self.driver = webdriver.Firefox()
And then use By selectors like class, name, id, e.g. the example below.
currently_waiting_for = wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'search-results')))
This article also helped. Also if you don't know how to find xpaths, look into setting up uiautomatorviewer that comes with appium.
The python usage is:
driver.implicitly_wait(timeToWaitSec)
Selenium sourcecode(Py)
You can use WaitForElement class:
class WaitForElement:
#staticmethod
def wait(driver, id, time_out=100):
try:
WebDriverWait(driver, time_out).until(
lambda driver: driver.find_element(*id))
except TimeoutException:
print('Not able to find ID:' + id)
You can find all you need in selenium.webdriver.support.expected_conditions
Then from it you can do something like:
def wait_for_element_visible(self, by=By.XPATH, value=None, text=None, wait_time=20):
if text is not None:
value = value % text
wait = WebDriverWait(self.driver, wait_time)
return wait.until(EC.visibility_of_element_located((by, value)))
You can use implicitWait. Something like remoteWebDriver.implicitlyWait(time, timeUnit) This of course is for java. Something similar should be available for python.