WeDriver FirefoxDriver cannot be used after quit() was called - java

i am having issues in acquiring correct driver instance.
following is my setup
public class SeleniumBase{
public static WebDriver driver;
public static void setUp(url,browser,port){
driver = new FirefoxDriver();
}
public static void tearDown(){
driver.manage().deleteAllCookies();
driver.close();
driver.quit();
}
}
public class BuildTest extends SeleniumBase{
#BeforeClass
public static void seleniumSetup(){
try{
// read properties
url = prop.getProp("baseUrl");
browser = prop.getProp("browser");
port = prop.getProp("port");
}
SeleniumBase.setUp(url,browser,port);
waitForLoginPage();
App.login();
}
#AfterClass
public static void seleniumTearDown(){
App.logOut();
SeleniumBase.tearDown();
}
}
#RunWith(Suite.class)
#Suite.SuiteClasses(
{
Test1.class,
Test2.class
})
public class SmokeSuite {
}
now, for Test1.class everything works fine but when Test2.class is invoked from the suite, new driver instance is created with the setUp method, but App.Login() throws error saying "The FirefoxDriver cannot be used after quit() was called"
is anything going wrong in my setup/teardown..?

As the comments on your question already mention, your setUp() and tearDown() methods as well as your WebDriver instance are static. So once you call driver.quit(), your driver couldn't be used any more. A new driver needs to be acquired.
However, you do not use JUnit's #Before and #After annotations but rather #BeforeClass and #AfterClass. So I guess you have multiple tests in your Test2 class, the driver quits after the first one and is not reinitialized before the second test.
Better make WebDriver, setUp() and tearDown not static and use #Before and #After in your test-classes. Then your problems should go away.

When you use driver.quit(); you close all open browsers and quit the driver. However, your driver is not set to null but remains in the void between WebDriver instance to null.
Why does this matter? Because when you call driver = new FirefoxDriver(); the constructor is "cheating" and hands you the old WebDriver instance, which considered viable because it doesn't see null, instead of initializing new instance.
Assigning null after calling quit should solve the problem.
public void tearDown() {
driver.quit();
driver = null;
}

Related

Java selenium - Second method is not included in test

I'm new in automation testing so I would really appreciate your help. When I run the test only firs method (mainPage) is executed. If I add #Test prefix before second method (monitors), test will be run in a new window and I want test to continue in same window after first method ends.
public class comtradeShop {
WebDriver driver;
String URL = "https://www.ctshop.rs/";
#BeforeMethod
public void init() {
System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver_91.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.get(URL);
}
#AfterMethod
// public void quit(){}
#Test
public void mainPage() throws InterruptedException {
WebElement menu = driver.findElement(By.cssSelector(".am-opener.sharkskin-collapse"));
Actions actions = new Actions(driver);
actions.moveToElement(menu).build().perform();
driver.findElement(By.cssSelector(".sharkskin-megamenu.megamenu-v.megamenu-am>li:nth-child(6)")).click();
Thread.sleep(5000);
WebElement popup = driver.findElement(By.cssSelector(".soundest-form-background-image-wrapper"));
if (popup.isDisplayed()) {
driver.findElement(By.cssSelector(".soundest-form-background-image-close-holder > a")).click();
} else {
System.out.println("Popup is not shown");
}
}
public void monitors(){
WebElement monitors = driver.findElement(By.cssSelector(".row.categories-big >div:nth-child(1)"));
monitors.click();
}
}
use #BeforeClass to initiate the browser
use #AfterClass to quit the driver
Marking the second test as #Test makes sense, if you think it's a separate thing to test. I understand wanting to pick up where the first left off and not wanting any test to get too large. Then you may want to explore skipping subsequent tests after an earlier one fails (or how to adapt to not being where you think you are).
What are you bumping into, though, is that your #BeforeMethod runs before each test. That is why the second test, when marked as a test, is staring in a new window. If you want to get setup and get that url once at the beginning, make it #BeforeClass instead (and similarly #AfterClass for totally closing up).
Each annotation had its own meaning, definition and functionality.
#BeforeMethod
The #BeforeMethod annotated method will be invoked before the execution of each test method. In your case, it will be going to execute before each test method ie. mainPage() and monitors(). And the same reason why the other test will be runnning in a new window or in the new session.
There is two solutions or annotation to solve your problem and by replacing the #BeforeMethod with them you can achieve the desired result:
#BeforeClass: The #BeforeClass annotated method runs before the execution of the first test methods in a current class.
#BeforeTest: The method which comes under the #BeforeTest annotation will be executed first before any test belonging to that folder.
you can also use priority on #Test annoted method to set the sequence and can also use #AfterMethod annotation to take screenshots for each failure test case.
Complete Fix Code:
public class comtradeShop {
WebDriver driver;
String URL = "https://www.ctshop.rs/";
#BeforeClass
public void init() {
System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver_91.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.get(URL);
}
#Test(priority = 0)
public void mainPage() throws InterruptedException {
WebElement menu = driver.findElement(By.cssSelector(".am-opener.sharkskin-collapse"));
Actions actions = new Actions(driver);
actions.moveToElement(menu).build().perform();
driver.findElement(By.cssSelector(".sharkskin-megamenu.megamenu-v.megamenu-am>li:nth-child(6)")).click();
Thread.sleep(5000);
WebElement popup = driver.findElement(By.cssSelector(".soundest-form-background-image-wrapper"));
if (popup.isDisplayed()) {
driver.findElement(By.cssSelector(".soundest-form-background-image-close-holder > a")).click();
} else {
System.out.println("Popup is not shown");
}
}
#Test(priority = 1)
public void monitors(){
WebElement monitors = driver.findElement(By.cssSelector(".row.categories-big >div:nth-child(1)"));
monitors.click();
}
#AfterMethod
public void takeScreenshot(ITestResult testResult) {
if (testResult.getStatus() == ITestResult.FAILURE){
//TAKE SCREENSHOTT ON FAILURE
}
}
#AfterClass
public void quit(){
if(driver!=null)
driver.quit();
}
}

Cucumber picocontainer/SharedDriver doesn't handle browser instance properly

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().

Java Selenium close browser after assertTrue

I have a code with many classes.
There is a class which creates the driver -
public class DriverDelegate {
private String baseURL = "someLink";
private WebDriver driver;
private WebDriverWait wait;
DriverDelegate(String url) {
System.setProperty("webdriver.chrome.driver", "${directory}");
driver = new ChromeDriver();
driver.get(baseURL + url);
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
wait = new WebDriverWait(driver, 5);
}
public WebDriver getDriver() {
return driver;
}
I create new driver for every test. And most of my lines are the ones containing assertTrue like this-
public class UserInterfaceTests extends BaseTest{
#Test
public void headerClicker() throws java.lang.Exception {
//Startup
DriverDelegate driverDelegate = new DriverDelegate("url");
WebDriver driver = driverDelegate.getDriver();
//Some random assertTrue
assertTrue("Test(HeaderClicker) - NoSuchElementException click", TestHelper.headerClicker(schedule, driver));
//I hope that it is not neccessary to put up all helper classes like TestHelper or BaseTest
Now I launch my tests from a class called Startup -
public class Startup{
#Test
public void HeaderClicker() throws Exception{ UserInterfaceTests UI = new UserInterfaceTests(); UI.headerClicker();}
My question here is how to close the browser after the assertTrue fails. Things like #AfterTest, #AfterSuite etc do not work because other methods can not use the same driver that was used in the test.
Any ideas?
Ok there are a few things I want to touch on here. First off, #shutdown -h now is correct in their comment that you shouldn't be programmatically creating test classes and running their #Test methods yourself. Let the test running framework handle that (e.g. TestNG, JUnit, etc).
To the point of your actual question, though, is that you want pre-test and post-test methods to handle behavior that occurs before and / or after your actual test method. For these to work, though, you need to let the test framework handle the running of the tests. You mentioned #AfterTest and #AfterSuite as not being correct for your use case, though not for the reason you specified (entirely). #AfterTest in TestNG only is executed once after all the test methods in all the classes inside of a <test> node specified in a suite. #AfterSuite is only executed once after all the test methods in the entire suite. What you are looking for is the #AfterMethod annotation.
Example:
public class FooTest {
private DriverDelegate driver;
#BeforeMethod
public void setup() {
try {
driver = new DriverDelegate("url");
} catch (Exception ignore) { }
}
#AfterMethod
public void tearDown() {
try {
driver.quit();
} catch (Exception ignore) { }
driver = null;
}
#Test
public void foo() {
// do test stuff
}
}
In the above code, when TestNG runs this test class, each method annotated with #Test in this class will have a corresponding #BeforeMethod execution that initializes the driver and an #AfterMethod that closes the driver even if the test fails. Couple of points to make about this type of setup with TestNG:
(1) TestNG does not create separate instances of the test class so if you save state on the class object then you cannot run the test methods themselves in parallel within a class since you would have multiple methods trying to create new drivers and save them to the same variable, corrupting the state of the other tests that are running. You can run with parallel mode of per class (e.g. have 5 threads, each running a separate test class at the same time).
(2) Why did I wrap the #BeforeMethod and #AfterMethod bodies in a try-catch block? Because TestNG takes a fail quickly on configuration method exceptions and can cause other tests that haven't run yet to be skipped so you need to deal with any code that could possibly fail. By wrapping the creating and closing of the web driver you can ignore the error and continue on running other tests. If the driver fails to be created, for instance, the driver variable will be null and that #Test method will fail but others might succeed. Ideally, you should probably have some logging of the exception so that you can investigate why the driver failed to be created, for instance.
Also, if you need to use a driver in many test classes, you can make a base class that does the creation of the driver along with the closing of it after each method and have your test classes extend that. If you have a class with a method annotated with #Test on it, it will run any #BeforeMethod methods on that test class AND on all of the super classes as well. There is guaranteed ordering of the methods between classes (though not if you have multiple #BeforeMethod methods in the same class).
public abstract class A {
#BeforeMethod
public void setupA() { }
}
public class B extends A {
#BeforeMethod
public void setupB() { }
#Test
public void foo() { }
}
In the above, when foo is run, it will have run first setupA and then setupB. After methods work in the same way, but in the reverse order.

Decreasing the speed of Selenium Webdriver

I have an selenium integration test that launches browser and checks the webstore for any broken functionality. However the entire test runs too fast and finishes before I can even see which page is getting executed. How can I decrease the execution speed from my code. Currently I have following file that actually launches the test.
AbstractSeleniumIt.java
#Before
public void setUp() throws Exception {
urlProp = GenericUtils.loadProperties("url.properties");
this.BASE_URL = urlProp.getProperty("webstoreUrl");
xpathProp = GenericUtils.loadProperties("xpath.properties");
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
#After
public void tearDown() {
driver.quit();
}
You can play with EventFiringWebDriver.
WebDriver driver = new FirefoxDriver();
EventFiringWebDriver slowDriver = new EventFiringWebDriver(driver);
slowDriver.registerListener(new ListenerThatAddsPauses(5, TimeUnit.SECONDS));
You will have to write your class ListenerThatAddsPauses which will extend AbstractEventFiringListener. In ListenerThatAddsPauses you will have to override methods from parent class and for example add needed pauses. Something like:
#Override
public void beforeClickOn(WebElement element, WebDriver driver) {
Thread.sleep(timeout);
}
Here is a great example

Selenium RC : Only one browser for all the tests?

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 :)

Categories