I am running selenium on remotewebdriver that connects to browser stack to run tests on different browsers. the thing is i have three #Test in my code and at the end of each test the URL is loaded again so I land on the home page again. In Chrome, the first test passes, the second test fails as the previous selection from the first test is remembered in the local storage. Then the 3rd test passes again as the local storage is cleared. In firefox all tests are passing.
I have tried with the code i have pasted in this ticket - i have put it #AfterMethod class in my setup. it clears the local storage in all the tests except no.2 in chrome. without this code, all of the tests are failing except the first one. someone please advise and sorry if it doesn't make sense.
final RemoteExecuteMethod executeMethod = new RemoteExecuteMethod((RemoteWebDriver) driver);
final RemoteWebStorage webStorage = new RemoteWebStorage(executeMethod);
final LocalStorage storage = webStorage.getLocalStorage();
storage.removeItem("sessionState");
I am not sure how to make the code more stable. Any ideas.
Related
I'm trying to make my selenium test as atomic and independent of each other as possible so I decided to quit the browser and create a new Webdriver instance after each test runs. This approach made the more sense to me and was reinforced by several threads discussing this issue.
e. g. This answer to a related question:
You are closing the webdriver after one particular test. This is a good approach but you will need to start a new webdriver for each new test that you want to run.
However, I've also come across the opinion that quitting the browser after each test is unnecessary and ineffective.
e. g. Part of this blog about Selenium:
It’s not good practice to load a browser before each test. Rather, it is much better to load a browser before all tests and then close it after all tests are executed, as this will save resources and test execution time.
As I'm pretty new to all of this, I'm struggling to choose between these two. So far the execution time of my tests is not a real concern (as I only have a handful of them) but as I begin to expand my test suite I'm worried that it might become an issue.
Answering straight, factually there is no definite rules to quit or reuse the same browser client while executing the tests using Selenium. Perhaps the decision would be based on the pre-requisites of the testcases.
If your tests are independent, it would be wise to to quit() the current Webdriver and Browser Client instance and create a new instance of the Webdriver and Browser Client after each test runs which will initiate a new and clean WebDriver / Browser Client combination as discussed in closing browser after test pass.
Albeit it would induce some overhead to spawn the new WebDriver / Browser Client combination but that may provide the much needed cushion from CPU and Memory usage as discussed in:
Limit chrome headless CPU and memory usage
Selenium using too much RAM with Firefox
Incase, the tests are not independent and the tests are based on the same session, cookies, etc parameters, reusing the same WebDriver / Browser Client makes sense.
DebanjanB has a great answer.
I am of the cloth that there is no one-sized-fits-all answer.
There is some fun balance to be had. Depending on what framework you are using, you could get fancy. I like pytest for it's unique use of fixtures.
To this end, you could do tests, or sets of tests either way depending on what you need. You could balance browser load times vs execution for what makes sense.
As an example in pytest:
conftest.py:
import pytest
from selenium import webdriver
#pytest.fixture(scope='module')
def module_browser(request):
"""Fixture lasts for an entire file of tests."""
driver = webdriver.Chrome()
def fin():
driver.quit()
request.addfinalizer(fin())
return driver
#pytest.fixture(scope='function')
def function_browser(request):
"""Fixture lasts for just a test function."""
driver = webdriver.Chrome()
def fin():
driver.quit()
request.addfinalizer(fin())
return driver
Now module_browser() lets you get a browser for a whole test module.
funtion_browser() gives you a new browser per test function.
Lets get fancy.. you have a bunch of tests that need to be logged in, and they are doing cosmetic checks on a standard account:
conftest.py continued...
#pytest.fixture(scope='module')
def logged_in_browser(request):
"""Provide a logged in browser for simple tests."""
driver = webdriver.Opera()
# Now go and log this browser in,
# so we can use the logged in state for tests.
log_in_browser(username='RedMage', password='masmune')
def fin():
driver.quit()
request.addfinalizer(fin())
return driver
This is about the same, but lets you have a browser stay open for a few tests, and it's logged in. If logging in takes say 5 seconds, and you have 30 tests that atomically check cosmetic things, you can shave a few minutes.
This flexibility will let you run some tests faster, and some tests in a more clean state. We might need some of each to run a suite and still be able to get efficiency gains on the time. There is no one-sized-fits-all answer.
Utilizing fixture in pytest lets you choose what you want for each test.. if it should be a clean browser, or if it needs to be faster.
Then in the tests we see stuff like this:
test_things.py
def test_logged_out_assets(function_browser):
driver = function_browser # just for clarity here.
driver.get('http://example.com/')
check_some_stuff(driver)
language_subdomain_list = ['www', 'es', 'de', 'ru', 'cz']
#pytest.parametrize(language_subdomain, language_subdomain_list)
def test_logged_out_assets_multlingual(module_browser, language_subdomain):
"""
Check the assets come up on each language subdomain.
This test will run for each of the subdomains as separate tests.
5 in all.
"""
driver = module_browser # for clarity in example.
url = "http://{}.example.com".format(language_subdomain)
driver.get(url)
check_some_stuff(driver)
def test_logged_in_assets(logged_in_browser):
"""
Check specific assets while logged in.
Remember, our web browser already is logged in when we get it!
"""
driver = logged_in_browser # for clarity in example.
check_some_assets(driver)
Py.test Fixtures: https://docs.pytest.org/en/latest/fixture.html
I have an app that uses Service Workers and Cache API. The cache's name used in Service Worker contains GIT revision (hash) so that with every release, new cache is used and the old one removed. This is to make 100% sure users will always get latest sources (this case is fine for intended release schedule).
I'm using Selenium Java (WebDriver) tests that run few times a day (let's say when there is a change in GIT repo) and I'd like to make sure that the worker's cache is being correctly wiped with every new GIT revision.
By default, Selenium is creating a new temporary profile directory for each browser session, which means there is always no cache when the tests start. I'd like to use cache though, my idea is (let's talk about Firefox for now):
keep some model profile directory
when Selenium starts Firefox, pass the model profile to the new temporary profile, e.g. new FirefoxProfile(new File(PROFILE_MODEL))
this would ensure that some cache exists prior starting browser
once tests are finished, back up the temporary profile (as it contains updated cache) and replace the (now older) PROFILE_MODEL with the latest profile so that next test run would use this updated cache again
The "model profile update step" at the end of test run would look like this in pseudocode
File modelDir = new File(PROFILE_MODEL);
// copy current model for backup
bckPath = Files.createTempDirectory("bckProfile");
Util.copy(modelDir, bckPath);
// remove the now obsolete PROFILE_MODEL
Util.deleteDirectory(modelDir);
// copy current profile to the model dir
File profileSnapshot = currentProfile.layoutOnDisk();
Util.copy(profileSnapshot.toPath(), modelPath);
The problem is though that the call currentProfile.layoutOnDisk(); doesn't seem to contain any cache related information and I have no idea how to get path of the currently being used temporary profile (in Linux, typically something like /tmp/anonymous6209009552324183685webdriver-profile
So basically my question is, how to preserve and control browser (Firefox) cache across multiple test runs? I know it is often desired to start browser with fresh cache in tests but I think for this particular case of testing Service Workers it is quite useful to have some control over it.
Please note that I'm running the tests in CI server, so some manual solution could be quite difficult (but hey, at least it could point me to some direction...)
Update: I can initiate Firefox profile with
profile = new ProfilesIni().getProfile("test")
and then knowing the actual path to "test" model profile (model, not the copy created by getProfile call), I could replace all its files with the ones from calling ProfilesIni().getProfile("test") at the end of tests, but this does not seem to e.g. copy history of visited pages.
Update 2: This is how I start browser:
caps = DesiredCapabilities.firefox();
FirefoxProfile sampleProfile = new ProfilesIni().getProfile("test");
caps.setCapability(FirefoxDriver.PROFILE, sampleProfile);
browser = new FirefoxDriver(caps);
and I can see it creates 2 profile temporary folders:
one is created by the call new ProfilesIni().getProfile("test") and it won't get updated "ever" during the test
second one is created from FirefoxDriver.startClient method which calls NewProfileExtensionConnection.start which then calls FirefoxProfile.layoutOnDisk
Now during the tests, only the second one profile is being updated which I guess makes kind of sense. The problem is how to get the actual profile dir that is created from the capabilities...
You could override the FirefoxProfile.layoutOnDisk method to always use the same folder for the profile:
public class FirefoxProfileEx extends FirefoxProfile {
File profileDir;
public FirefoxProfileEx(File profileDir){
super(profileDir);
this.profileDir = profileDir;
}
public File layoutOnDisk() {
try {
File userPrefs = new File(profileDir, "user.js");
installExtensions(profileDir);
deleteLockFiles(profileDir);
deleteExtensionsCacheIfItExists(profileDir);
updateUserPrefs(userPrefs);
return profileDir;
} catch (IOException e) {
throw new UnableToCreateProfileException(e);
}
}
}
Usage:
FirefoxProfileEx profile = new FirefoxProfileEx(new File("C:\\temp\\profile"));
WebDriver driver= new FirefoxDriver(profile);
Known layoutOnDisk() will used to call current profile and we write or save to disk. We need to use this saved profile or dir mostly early as possible because once execution is completed then saved profile by using layoutOnDisk() is not useful. They don't work.
For more information please see here
So for firefox only thing is just saved all cookies by using "driver.Manage().Cookies.AllCookies;" use these in next execution.
I hope it is prefer to use named profile instead of taking profile from directory. Here the way to create profile
ProfilesIni profile = new ProfilesIni();
FirefoxProfile myprofile = profile.getProfile("myProfilewhichIsSaved");
WebDriver driver = new FirefoxDriver(myprofile);
I hope IE helps by not clearing before starting. here is link helps you
Also you can try by chrome profile
Thank You,
Murali
I would like to run tests with pybot, then run more tests with pybot using the same browser window that the first pybot opened.
So…
pybot test1.txt
#opens browser window and runs test1.txt and doesn't close the window
#pybot completes execution
pybot test2.txt
#uses the same browser window from test1
#pybot completes execution
pybot test3.txt
#uses the same browser window from test1
#pybot completes execution
can't figure out how to do that….
I've tried Open Browser www.mysite.com alias=1 in the first test and then Switch Browser 1 in the others, but they just error with No browser is open
A selenium driver instance has two properties characterizing its connection to a selenium webdriver - a connection url, and session id. By setting those to the values of an already running one, you effectively "hijack" it, and can use freely.
Disclaimer - the solution uses internal SE structures, so can break on newer versions. Also, as you are connecting to the running webdriver as to aRemote one, you cannot close it even if you want to - thus this can lead to resources leakage on the machine that it runs on; e.g. that webdriver has to be eventually terminated manually by a task manager.
So first things first - you have a running browser instance, and you need to get its properties for future connections. They are 2 - driver.command_executor._url, and driver.session_id where driver is the object name of the running instance. This python code will do just that:
from robot.libraries.BuiltIn import BuiltIn
def return_driver_props()
seLib = BuiltIn().get_library_instance('SeleniumLibrary')
# the driver is instantiated in the SeleniumLibrary, but not provided publicly, thus accessing it through this py code
remote_url = seLib.driver.command_executor._url # for local instance, this is a value in the form 'http://localhost:57856'
session_id = seLib.driver.session_id
return remote_url, session_id
Importing that file as a Library, by calling the function/method you'll have the 2 props:
${conn_url} ${session_id}= Return Driver Props
# and do whatever is needed to make them known - log, store in a file, DB, etc.
Now in the second run that needs to reattach, and with the 2 values in hand, you just use the keyword Open Browser and specify a remote connection:
Open Browser about:about remote_url=${that_known_url} browser=${the_used_browser_type} # the last args - chrome|firefox|edge - whatever you're connecting two
The tricky part - the moment you connect to a remote server, selenium automatically starts a new session - which is a second browser instance (this started somewhere around selenium3, though I'm not sure on the exact timing). E.g. if you start using it right now - that is not the browser you wanted, but a brand new. That's also the reason why I gave as target address "about:about" - so it loads a dummy page, very fast.
Two things must happen at this point - a) you have to get rid of the "dummy" SE session, and b) switch to the previous one:
def set_driver_session_id(sesion_id):
""" Sets the sessoin_id of the current driver insance to the provided one. """
seLib = BuiltIn().get_library_instance('SeleniumLibrary')
if seLib.driver.session_id != sesion_id: # this is pretty much guaranteed to be the case
seLib.driver.close() # this closes the session's window
seLib.driver.quit() # for remote connections (like ours), this deletes the session, but doesn't stop the SE
# set to the session that's already running
seLib.driver.session_id = sesion_id
This function/keyword is called with the known session id:
Set Driver Session ID ${session_id}
,and voilà, you are now in control of the previous browser, with its full state - the url it was at, cookies, localStorage, etc.
I'm leaving as an exercise to the reader how to automatically pass the url and the session id.
What I myself am doing is storing them in a file in a temp folder after running the first piece, and reading from there in the follow-up runs, with some error handling around it - missing or bad file, the connection cannot happen, and so on, with fallbacks to new instance creation.
Actually it is absolute possible to do however you have to organise your tests in testsuites
testsuites/
__init__.robot
test1.robot
test2.robot
test3.robot
in __init__.robot you have to open browser in suite setup and destroy it in suite teardown f.e.
*** Settings ***
Suite Setup Open Browser
Suite Teardown Close Browser
and run tests pybot ./testsuites
I don't know how effcient it is but I needed the same process and I used code like this to complete this...
open browser ${HOMEPAGE} ${BROWSER}
#opens the browser to the homepage using the browser of my choice
maximize browser window
#maximizes the window
(DOES STUFF)
#completes some processes
select window title=calendar
#selects the window with the name calendar
(DOES MORE STUFF)
This worked for me, try it out.
If you need any information on 'select window' look here: http://rtomac.github.io/robotframework-selenium2library/doc/Selenium2Library.html#Select%20Window
Or you can always try
switch browser 1
I'm new to robotframework, but I hope this helped.
There's an open issue for new functionality to re-use existing browser session. There are some workaround mentions and custom code modifications that seem to achieve this.
In my case, I was setting off warning emails from the target website, about logging in from a new device, every time I logged in during testing. Instead, I wanted to log in a single time and then resume the same (authenticated) browser session during subsequent runs.
To do this, the key is that you need to point the webdriver to the same user data directory so that subsequent runs can resume the browser session. For my needs, I created a local directory called user-data.
I then defined:
Open Browser Profiled
[Arguments] ${url}
${options}= Evaluate sys.modules['selenium.webdriver'].ChromeOptions() sys, selenium.webdriver
Call Method ${options} add_argument --user-data-dir\=${./user-data}
Create WebDriver Chrome chrome_options=${options}
Go To ${url}
And:
Log In
Open Browser Profiled ${LOGIN_URL}
Input Text email ${EMAIL}
Input Password password ${password}
Click Button Log in
Then, on the first execution, I run:
Do The Things
Log In
# Open Browser Profiled ${AFTER_LOGIN_URL}
...
And, on subsequent executions:
Do The Things
# Log In
Open Browser Profiled ${AFTER_LOGIN_URL}
...
For extra points, you can also make this more dynamic and detect whether a log in is needed so that you do not have to modify the script, e.g.:
Do The Things
Log In or Open
...
Log In or Open
Open Browser Profiled ${AFTER_LOGIN_URL}
Sleep 2 # Wait for page to settle
${logged_in}= Run Keyword And Return Status Title Should Be ${AFTER_LOGIN_TITLE}
Run Keyword Unless ${logged_in} Log In
Special thanks to this post, which outlined the method I used to resume the browser session.
I am using Selenium 2.X with JUnit 4.X for automation testing. There are several test cases in the test class. However the for each test cases the a new session is created.
That is for each test case,
a new browser window is opened,
login mechanism is carried out,
generic steps gets executed,
test steps gets executed,
the browser get closed.
Is there any possibility for the below mentioned?
a new browser window is opened,
login mechanism is carried out,
generic steps gets executed,
The above steps are carried out only once
all test steps (methods with #Test) gets executed,
Finally the browser gets closed?
PS: I do not want to club all the test case in a single one?
Thanks,
With every new browser session, Selenium creates a new instance of the browser test profile - so re-invoking will cause you to start afresh.
You requirement, though, appears to be more organizational.
Try working with TestNG. It enables the creation of test suites, which can be executed via a testng.xml. You should be able to script tests in different classes and then call them sequentially, without having to necessarily re-invoke the browser
in a continuous integration build environment when running several Selenium tests in parallel (using Firefox driver) for different applications and each tests records its screenshots after every "action" (e.g. navigating to a page, submitting a form etc.) it seems like that whichever application window pops up that one gets on the top of the z-axis and will have the focus.
So using the method getScreenshotAs() from the Selenium API to record images results in mixed up screenshots sometimes showing one application and sometimes the other application.
Recording the HTML responses with getPageSource() on the other hand seems to work correctly using the Firefox driver instance "bound" to the test.
Is there any solution how to deal with the mixed up image screenshots? Is there a possibility how to ensure that getScreenshotAs() only consideres its own Firefox driver instance? Thanks for any hints!
Peter
I don't know what flavor of selenium you are using but here is a reference to the API that looks like it would fix your problem, but I have never tested it.
http://selenium.googlecode.com/svn/trunk/docs/api/dotnet/index.html
What that link shows is the IWrapDriver which according to the documentation Gets the IWebDriver used to find this element.
So from my understanding you could set your IWebDriver in your method and then wrapit with the IWrapDriver and then use that to reference for you getScreenShotAs();