I like to test my site in a lot of threads. But when I trying to do that, I see one problem. All motions when I like are happening in last opened window. So, the first window just stuck in background.
public class Core extends Thread{
private static FirefoxDriver firefoxDriver;
public Core(){
firefoxDriver = new FirefoxDriver();
}
#Override
public void run() {
firefoxDriver.get("https://google.com/");
firefoxDriver.close();
}
}
public class Main {
public static void main(String[] args) throws AWTException {
System.setProperty("webdriver.gecko.driver", "/home/riki/Downloads/geckodriver-v0.30.0-linux64/geckodriver");
Core core = new Core();
Core core2 = new Core();
core.start(); // This thread is stuck in back
core2.start(); // This thread goes to google.com twice
}
}
I really don't understand why it happens. You can see it here. After that the code has run, the first window keeps hanging in back. It don't close. When the second thread closes after executing code
This is because of you using static field for Forefox driver.
Static means the one per all instances. So remove static here.
private FirefoxDriver firefoxDriver;
and after, each thread will use it's own firefoxDriver field.
Static fields should be used carefully if you going to modify them.
Related
I'm working on a BDD project.
Sometimes the tests go too fast for the developers to see what is happening when they run them.
At the moment I'm solving it placing something like
Thread.sleep(humanWaitTime)
before each method but it defeats the purpose of writing efficient code.
Is there any way to set this globally so that it can easily be taken out when doing a regression test and not clutter my code?
Thank you!
You can use WebDriverEventListener and fake wait for not existing element,
you should:
create class: public class CustomDriverListener implements
WebDriverEventListener and implement all methods
in this class add next method:
private void fakeWaiter(WebDriver driver) {
WebDriverWait wait = new WebDriverWait(driver, 20);
try {
wait.until(listenerDriver -> listenerDriver.findElement(By.xpath("//[.='it'sFakeElement']")));
} catch (org.openqa.selenium.TimeoutException e) {
//ignore it
}
}
add invocation of this method to methods that you need, like:
#Override
public void afterFindBy(By by, WebElement element, WebDriver driver) {
fakeWaiter(driver);
}
#Override
public void afterClickOn(WebElement element, WebDriver driver) {
fakeWaiter(driver);
}
#Override
public void afterChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysToSend) {
fakeWaiter(driver);
}
#Override
public void afterScript(String script, WebDriver driver) {
fakeWaiter(driver);
}
Create EventFiringWebDriver object and register your
CustomDriverListener:
WebDriver webDriver = new ChromeDriver();
EventFiringWebDriver driver = new EventFiringWebDriver(webDriver);
driver.register(new CustomDriverListener());
Now if you use "driver" in your tests all operations will be slower(depend on timer in fakeWaiter method)
P.S. sorry for bad formatting =(
You can probably use Implicit wait,
driver.manage().timeouts().implicitlyWait(TimeOut, TimeUnit.SECONDS);
Lets say on top of your code block, you write:-
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
Then, before each line of your code, the webdriver instance will wait for 15 seconds, you don't have to give wait times after each statement.
The implicit wait will tell to the web driver to wait for certain amount of time before it throws a "No Such Element Exception". The default setting is 0. Once we set the time, web driver will wait for that time before throwing an exception.
I'm using cucumber-jvm picocontainer to share selenium driver between classes. I have ShareDriver and WebDriverFactory class.
My problem is the following:
1. If I run 2 test cases, the driver/browser instance is closed after the first test case, new browser instance is created and run the second one. I would like to use only 1 browser instance and run the tests, then close it.
IEDriverServer.exe and one java.exe are stucked on task manager after the test, however the browser is closed. I need to kill them manually. Every run creates a new one from these tasks. I tried all ideas from stackoverflow, but none of them could solve this problem.
Thanks!
My SharedDriver class:
public class SharedDriver extends EventFiringWebDriver implements Startable {
public SharedDriver() {
super(WebDriverFactory.localInternetExplorerWebDriver());
}
#After
public void embedScreenshot(Scenario scenario) {
try {
byte[] screenshot = getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
} catch (WebDriverException somePlatformsDontSupportScreenshots) {
System.err.println(somePlatformsDontSupportScreenshots.getMessage());
}
}
#Override
public void start() {
}
#Override
public void stop() {
quit();
}
}
My WebDriverFactory class:
class WebDriverFactory {
static {
System.setProperty("webdriver.ie.driver", "src/test/resources/webDrivers/IEDriverServer.exe");
}
static WebDriver localInternetExplorerWebDriver() {
DesiredCapabilities returnCapabilities = DesiredCapabilities.internetExplorer();
System.setProperty("webdriver.ie.driver", "src/test/resources/webDrivers/IEDriverServer.exe");
//returnCapabilities.setCapability("nativeEvents", false);
returnCapabilities.setCapability("requireWindowFocus", true);
returnCapabilities.setCapability(InternetExplorerDriver.ENABLE_PERSISTENT_HOVERING, false);
returnCapabilities.setCapability(InternetExplorerDriver.IE_ENSURE_CLEAN_SESSION, true);
returnCapabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
returnCapabilities.setCapability("ignoreZoomSetting", true);
return new InternetExplorerDriver(returnCapabilities);
}
}
The implementation of SharedDriver is not correct. You need a static webdriver field in the shareddriver class, create a shutdown thread, add this thread to the jvm shutdown hook. Use this one
If you wanna kill that too use this. Add this to the shutdown hook.Add it inside the run method of the thread after call to REAL_DRIVER.quit().
I am automating web application. I want to run methods parallel , So have written code like :
public class test{
public static WebDriver driver;
public static void main(String args[])
{
driver = new FirefoxDriver();
}
public static void Login()
{
driver.get("www.example.com");
driver.findElement(By.id("uname")).sendKeys("test");
driver.findElement(By.id("pass")).sendKeys("test");
}
}
When I run the program , it just opens browser and then nothing. Why is it not going inside Login method?
Where are you calling the Login method from the main?
public static void main(String args[])
{
driver = new FirefoxDriver();
Login();
}
What do you mean by I want to run the methods in parallel?
Someone will have to call the Login() method to do the work ... Currently, its just defined but not in use ...
You need the call the Login() method inside main() to execute it.
public static void main(String args[]) {
driver = new FirefoxDriver();
Login();
}
I want to run methods parallel.
You need to create threads and launch them for running any code in parallel in java.
Main is the starting point for any java program. Once it starts executing the Main method, you can launch multiple thread by implementing Runnable interface or extending Thread class. You would need to define the parallel thread code by overriding run() method.
GlobalVariables class holds different variables which are used across my framework one of them is WebDriver instance:
public class GlobalVariables
{
public static WebDriver driver;
//Some other static global variables required across my framework
public GlobalVariables(String propertiesFile)
{
initializeVariables(propertiesFile);
}
public void initializeVariables(String propertiesFile)
{
GlobalInitializer obj=new GlobalInitializer();
obj.initialize(String propertiesFile);
}
}
GlobalInitializer contains methods to initialize all the GlobalVariables:
public class GlobalInitializer extends GlobalVariables
{
public void initialize(String propertiesFile)
{
//Some logic to read properties file and based on the properties set in it, call other initialization methods to set the global variables.
}
public void initializeDriverInstance(String Browser)
{
driver=new FireFoxDriver();
}
//Some other methods to initialize other global variables.
}
I have many GetElement classes which use the driver instance to get UI control elements E.g:
public class GetLabelElement extends GlobaleVariables
{
public static WebElement getLabel(String someID)
{
return driver.findElement(By.id(someId));
}
//Similar methods to get other types of label elements.
}
public class GetTextBoxElement extends GlobaleVariables
{
public static WebElement getTextBox(String someXpath)
{
return driver.findElement(By.xpath(someXpath));
}
//Similar methods to get other types of text box elements.
}
I have other classes which perform some actions on the UI Control(This classes too use the global variables) E.g:
public class GetLabelProperties extends GlobalVariables
{
public static String getLabelText(WebElement element)
{
return element.getText();
}
}
public class PerformAction extends GlobalVariables
{
public static void setText(String textBoxName,String someText)
{
driver.findElement(someLocator(textBoxName)).setText("someText");
}
//Some other methods which may or may not use the global variables to perform some action
}
My test class in testng looks like this:
public class TestClass
{
GlobalVariables globalObj=new GlobalVariables(String propertiesFile);
#Test(priority=0)
{
GlobalVariables.driver.get(someURL);
//Some assertion.
}
#Test(priority=1)
{
WebElement element=GetLabelElement.getLabel(someID);
String labelName=GetLabelProperties.getLabelText(element);
//Some assertion.
}
#Test(priority=2)
{
WebElement element=GetTextBoxElement.getTextBox(someXpath);
PerformAction.setText(element.getText(),someText);
//Some assertion.
}
}
I have similar multiple test classes based on scenarios.
Now this tests are running fine if i am running them individually. But when i try to run them in parallel, then this tests are failing in some weird fashion. On analyzing i found out that its the static global variables which are getting initialized by each tests thus leaving the other tests to fail. Now how should i go about achieving my objective to run multiple tests parallely with minimal changes in my framework design? i have tried searching for options, and i have come across some option i.e 1) use of synchronized. 2) Create ThreadLocal instance(Note : I have tried this solution but still same issue. tests are mixing up with each other resulting in failure. I had marked the WebDriver instance as ThreadLocal and overriden the initialValue method of ThreadLocal to initialize the driver instance. Still i am not sure whether i had implemented it correctly or not.). Now i am not sure how best to implement any one of this solution in the given scenario. Any help is appreciated. TIA!
I have found out the solution : Use of ThreadLocal is the best solution to run tests in a huge multithreaded environment.
Code snippet to use WebDriver in multithreaded environment:
public static ThreadLocal<WebDriver> driver;
driver=new ThreadLocal<WebDriver>()
{
#Override
protected WebDriver initialValue()
{
return new FirefoxDriver(); //You can use other driver based on your requirement.
}
};
Now every time a test thread is created a new browser will open. ThreadLocal will make sure that there's only one copy of static webdriver instance per thread. [NOTE: Make sure your other global variables are too ThreadLocals. In my case they were not thats why i was running into test goof up issue]. Some extra knowledge which i would like to share so that others may find it informative. In ThreadLocal whenever the ThreadLocal.get() method is called you have to make sure that there is a provision to initialize the thread local as shown above in initialValue() method or you may run into null pointer exception. Thanks everyone.
If you are going to run non-parallel, then using a static webdriver member (or a instance shared between test classes by passing by reference) is fine because it is a good way to not have to close the webdriver instance between test classes. If you want to run parallel though, you need to have one instance of webdriver for EACH thread and so in that case using a static member is the WRONG way to go. Instead you need to create or pass a webdriver instance when the test case class is invoked.
Also, you are breaking a test into separate tests for each step of the test. That is very unusual and I do not see the reason why you are doing that. You could really simplify your tests by keeping all the test steps within one singe test case like people usually do.
You are getting this because of how JVM handles static members and methods.
You can't have a static webdriver object if you are going to run in parallel.
Source: The automated regression system i implemented where I work - we had this issue.
you can try something like this
public class DriverManager {
private static final ThreadLocal<WebDriver> threadLocal = new ThreadLocal<WebDriver>();
public static WebDriver getDriver() {
return threadLocal.get();
}
public static void setDriver(WebDriver driver) {
threadLocal.set(driver);
}
public static void closeDriver() {
if (getDriver() != null) {
try {
getDriver().close();
} catch (Exception e) {
e.printStackTrace();
}
try {
getDriver().quit();
} catch (Exception e) {
e.printStackTrace();
}
}
threadLocal.remove();
}
}
I'm quite stuck right now, I don't understand why my code doesn't work as I need to. The fact is that each time there is a new test, it closes firefox and reopens it. That makes my tests take ages to realise... Could you tell me what I'm doing wrong ?
public class SeleniumTestLoginEntry extends SeleneseTestCase {
private String login="scLocator=//DynamicForm[ID=\"formulaire_login\"]/item[index=0||Class=TextItem]/element";
private String passwd="scLocator=//DynamicForm[ID=\"formulaire_login\"]/item[index=1||Class=PasswordItem]/element";
static public DefaultSelenium selenium;
public void setUp() throws Exception {
selenium = new DefaultSelenium("localhost", 4500, "*firefox", "http://localhost:9091/");
selenium.start();
}
public void testFields() throws Exception {
selenium.open("/agepro-prototype/login/Login.html");
selenium.type(login, "Unlogin");
selenium.type(passwd, "Unpassword");
Assert.assertEquals("Unlogin", selenium.getValue(login));
Assert.assertEquals("Unpassword", selenium.getValue(passwd));
selenium.click("scLocator=//ImgButton[ID=\"bouton_login\"]/");
}
public void testSameWindow() throws Exception {
selenium.open("/agepro-prototype/login/Login.html");
selenium.type(login, "truc");
Assert.assertEquals("truc", selenium.getValue(login));
}
public void tearDown() throws Exception {
selenium.stop();
}
}
I tried to put the annotations #BeforeClass and #AfterClass before the setUp() and tearDown, it doesn't change anything. Before there was an #Test before each test but this doesn't helped at all. May I ask you some help ? =)
Edit : Oh also I tried the selenium.open(blablabla) in the setUp() and not in the tests directly, same issue, doesn't change a thing.
Without using annotations, setUp() is going to run before every test (ie, twice).
It's not pretty, but you can create an initial test (which only runs once) and move the instantiation out of setUp() into the new test(). Keep in mind, though, that if that fails to create your selenium instance, then all your subsequent tests will also fail. Not great :)