Cucumber #Before hook opening multiple browser windows - java

I'm not clear why I am getting 3 chrome browsers opening for the following example. I have an #Before (cucumber version) annotation to simply setup a chrome webdriver instance before the scenario runs. As far as I can see, it should open one browser, run scenario (step defs) then close using the #After cucumber hook. What happens is 2 windows open before a third and final window actually executes the steps:
Scenario:
Given I am on the holidays homepage
When I select the departure location "LON"
And I select the destination location "PAR"
And I submit a search
Then search results are displayed
Step Def:
public class FindAHolidayStepDefs {
private WebDriver driver;
#Before
public void setup() {
System.setProperty("webdriver.chrome.driver",
System.getProperty("user.dir") + "\\drivers\\chromedriver.exe");
driver = new ChromeDriver();
}
#Given("^I am on the Holidays homepage$")
public void IAmOnTheThomasCookHomepage() {
driver.get("http://uat7.co-operativetravel.co.uk/");
driver.manage().window().maximize();
String pageTitle = driver.getTitle();
assertEquals("the wrong page title was displayed !", "Holidays - welcome", pageTitle);
}
#When("^I select the departure location \"([^\"]*)\"$")
public void ISelectTheDepartureLocation(String departureAirport) {
WebElement dropDownContainer = driver.findElement(By.xpath("(//div[#class=\"custom-select departurePoint airportSelect\"])[1]"));
dropDownContainer.click();
selectOption(departureAirport);
}
#When("^I select the destination location \"([^\"]*)\"$")
public void ISelectTheDestinationLocation(String destinationAirport) {
WebElement destinationField = driver.findElement(By.xpath(("(//div[#class=\"searchFormCol destinationAirport\"]/div[#class=\"combinedInput searchFormInput\"]/span/input)[1]")));
destinationField.sendKeys(destinationAirport);
selectOption("(" + destinationAirport + ")");
}
#When("^I submit a search$")public void iSubmitASearch() throws Throwable {
WebElement submitButton = driver.findElement(By.xpath("(.//*[#type='submit'])[1]"));
submitButton.click();
}
#Then("^search results are displayed$")
public void searchResultsAreDisplayed() throws Throwable {
waitForIsDisplayed(By.xpath(".//*[#id='container']/div/div[3]/div/div[1]/div/h3"), 30);
assertThat(checkPageTitle(), equalTo("Package Results"));
}
#After
public void tearDown() {
driver.quit();
}
}
When I step through the code in Intellij, the following method is called:
private void runHooks(List<HookDefinition> hooks, Reporter reporter, Set<Tag> tags, boolean isBefore)
and Intellij reports that hooks paramter = 3 at this point.
hooks: size=3 reporter: "null" tags: size = 0 isBefore: true

Do you have more then one scenario in your feature? -> The #Before method will be executed before each scenario.
Do you have a different stepdef class with #Before annotated method that opens chrome? -> All #Before methods will be called before a scenario is executed.

Related

How do I close() and quit() Selenium driver without affecting other steps in Cucumber and Selenium?

I have two feature files in Cucumber that are linked to corresponding step files. The problem is that when one of the step file finishes execution then it closes all the browser windows (because of driver.quit()) whereby killing the execution of other step file which hasn't done processing yet.
Here each step file opens a new browser window, executes the tests within it and then closes and quits the browser. Currently I have just two step files but in the future there are going to be many more.
Is there anything in Cucumber that would always get executed after all the steps are executed?
How do I solve this problem?
HelpStep.java
#Ignore
public class HelpStep {
private WebDriver driver;
#Before
public void setup() {
System.out.println("Into the setup method of HelpStep...");
this.driver = BrowserConfig.getIEWebDriver();
}
#Given("^The user is on the Help page$")
public void onPage() {
System.out.println("The user is on the Help page");
}
#When("^The user clicks on the links within the Help page$")
public void clickLinks() {
System.out.println("The user clicks on the links within the Help page");
}
#Then("^The user is navigated to that section$")
public void validate() {
System.out.println("The user is navigated to that section");
}
#After
public void cleanUp() {
System.out.println("Into the cleanUp method of HelpStep...");
//FOLLOWING METHOD CALL KILLS ALL THE OPEN BROWSERS ALSO :(
BrowserConfig.releaseResources(this.driver);
}
}
LinkStatsStep.java
#Ignore
public class LinkStatsStep {
private WebDriver driver;
#Before
public void setup() {
System.out.println("Into the setup method of LinkStatsStep...");
this.driver = BrowserConfig.getIEWebDriver();
}
#Given("^The user is on the Link Statistics page$")
public void onPage() {
System.out.println("The user is on the Link Statistics page");
}
#When("^The user does a search$")
public void clickLinks() {
System.out.println("The user does a search");
}
#Then("^The user is displayed search result$")
public void validate() {
System.out.println("The user is displayed search result");
}
#After
public void cleanUp() {
System.out.println("Into the cleanUp method of LinkStatsStep...");
BrowserConfig.releaseResources(this.driver);
}
}
TestRunner.java
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty", "json:target/cucumber-reports/cucumber.json"},
features = {"src/test/resources/features"})
public class TestRunner extends ApplicationTests {
}
BrowserConfig.java
public class BrowserConfig {
private static final String IE_DRIVER_EXE = "drivers/IEDriverServer.exe";
private static final String WEBDRIVER_IE_DRIVER = "webdriver.ie.driver";
private static final String BASE_URL = "https://www.google.com";
public static WebDriver getIEWebDriver() {
String filePath = ClassLoader.getSystemClassLoader().getResource(IE_DRIVER_EXE).getFile();
System.setProperty(WEBDRIVER_IE_DRIVER, filePath);
InternetExplorerOptions options = new InternetExplorerOptions().requireWindowFocus();
options.setCapability(INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
options.setCapability(ENABLE_ELEMENT_CACHE_CLEANUP, true);
options.setCapability(IE_ENSURE_CLEAN_SESSION, true);
options.setCapability(ACCEPT_SSL_CERTS, true);
options.setCapability("nativeEvents", false);
options.setCapability(INITIAL_BROWSER_URL, BASE_URL);
System.out.println("Initializing IE Driver now...........");
WebDriver driver = new InternetExplorerDriver(options);
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
return driver;
}
public static void releaseResources(WebDriver driver) {
System.out.println("Releasing resources now.....");
if (null != driver) {
driver.close();
driver.quit(); //CLOSES ALL THE OPEN BROWSER SESSIONS LEAVING OTHER STEP EXECUTIONS INCOMPLETE
}
}
}
help.feature
Feature: Check that the user is able to navigate to Help page
Scenario:
Given The user is on the Help page
When The user clicks on the links within the Help page
Then The user is navigated to that section
link-stats.feature
Feature: Check that the user is able to navigate to Link Statistics page
Scenario:
Given The user is on the Link Statistics page
When The user does a search
Then The user is displayed search result
System.outs
Initializing IE Driver now...........
Listening on port 47613
Into the setup method of LinkStatsStep...
Initializing IE Driver now...........
Listening on port 5009
The user is on the Help page
The user clicks on the links within the Help page
The user is navigated to that section
Into the cleanUp method of HelpStep...
Releasing resources now.....
Into the cleanUp method of LinkStatsStep...
Releasing resources now.....
Into the setup method of HelpStep...
Initializing IE Driver now...........
Listening on port 17291
Into the setup method of LinkStatsStep...
Initializing IE Driver now...........
Listening on port 23793
The user is on the Link Statistics page
The user does a search
The user is displayed search result
Into the cleanUp method of HelpStep...
Releasing resources now.....
Into the cleanUp method of LinkStatsStep...
Releasing resources now.....
Looking at your code it would appear to be correct.
Calling quit should close all open windows associated with that webdriver session. It should not close windows of other webdriver sessions. So I think you are facing a problem in the IEDriverServer.
If this is the case and if you are running your tests in a JVM that shuts down after all tests have been executed. Then as a work around you can use shut down hooks to call quite and close all web driver sessions. For example:
private static final Thread CLOSE_THREAD = new Thread() {
#Override
public void run() {
// Start a new webdriver to call quit on
// For IE this will terminate all webdriver sessions
getIEWebDriver().quit();
}
};
static {
Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
}
Posted the answer here as this question is more or less similar earlier one.
https://stackoverflow.com/a/55836832/2325154
It is because driver management not done properly. I would suggest to use qaf which does driver and resource management. With QAF your step file will look like below:
public class HelpStep {
//setup or tear-down not required here...
#Given("^The user is on the Help page$")
public void onPage() {
//you can access driver any where like below:
//WebDriver driver = new WebDriverTestBase().getDriver();
System.out.println("The user is on the Help page");
}
#When("^The user clicks on the links within the Help page$")
public void clickLinks() {
System.out.println("The user clicks on the links within the Help page");
}
#Then("^The user is navigated to that section$")
public void validate() {
System.out.println("The user is navigated to that section");
}
}
To access driver object any where in the code you can get it from test base.
WebDriver driver = new WebDriverTestBase().getDriver();
Below are examples of interacting with element anywhere in the code:
Using findBy
driver.findElement("name=q").click();
Using element factory
import static com.qmetry.qaf.automation.ui.webdriver.ElementFactory.$;
...
$("name=q").click();
Using inbuilt step library
import static com.qmetry.qaf.automation.step.CommonStep.*;
...
click("name=q");
in example above name=q is element locator using name as locator strategy, which will automatically converted to By.name.
LinkStatsStep
import static com.qmetry.qaf.automation.step.CommonStep.*;
...
public class LinkStatsStep {
#Given("^The user is on the Link Statistics page$")
public void onPage() {
get("/");
}
#When("^The user does a search$")
public void clickLinks() {
System.out.println("The user does a search");
click("elementlocator");
//$("elementlocator").click();
}
#Then("^The user is displayed search result$")
public void validate() {
verifyLinkWithPartialTextPresent("link text");
//$("partialLink=link text").verifyPresent();
}
}
Your gherkin file will remain same. To run your gherkin file use GherkinScenarioFactory
You can specify browser to use using driver.name property. You don't need to write code for creating or tearing down driver. You can set behavior of driver session by using selenium.singletone property.
#this will tear down driver after each testcase/scenario
selenium.singletone=method
#this will tear down driver after each xml test node in configuration file
selenium.singletone=test
#this will tear down driver after each xml test node in configuration file and will reuse same driver session for testcases/scenario configured under same xml test node.
selenium.singletone=test
#this will tear down driver after each xml suite node in configuration file.
selenium.singletone=suite

Could not getting correct text in output after refresh of search results

This is a site related to find shoe costs. Initially I have entered the text and performed the search and output the number of results obtained.
After selecting a criteria, the search result refresh according to new criteria.
but the output still shows the previous result. I tried with implicit wait but it still shows old result.
This is the code:
public void openBrowser()
{
StaticData.driver.get("http://laceup.io/phase2");
}
public void homeSearchAndClick()
{
System.out.println("In home search");
StaticData.driver.findElement(By.xpath(".//*[#id='search_field']")).sendKeys("Nike");
StaticData.driver.findElement(By.xpath("html/body/div[1]/div/div[1]/div[1]/div[1]/div/button")).click();
}
// Function to search by FEMALE gender
public void searchForFemale()
{
System.out.println("Gender: Female clicked");
StaticData.driver.findElement(By.xpath("html/body/div[1]/div/section/div[1]/div[1]/div/div[1]/div/div[2]/label/span")).click();
}
public void filterSearchCount()
{
StaticData.driver.manage().timeouts().implicitlyWait(500, TimeUnit.SECONDS);
String searchCount = StaticData.driver.findElement(By.xpath(".//*[#id='show_query']/h2")).getText();
System.out.println("Filter search count: " + searchCount);
}
I discovered that a driver.navigate().refresh(); used in the method filterSearchCount() do the trick. Even so, I've noticed that the Nike checkbox for filter isn't checked. In this way, the program will display Filter search count: 1919 RESULTS (1918 from Nike + 1 from Warrior)
If you want the exact result for Nike- woman you should check also Nike in the filer area, as I've told you before that the site doesn't check it automatically even if you have been written Nike in the Search Textbox.
If your objective is to fetch the number of results for "Nike" for Women gender there is another way to do it. You can toggle the Ladies beforehand on the homepage itself.
FYI, I'm using PageObjectFactory to simplify your code
Phase2Page.java - Page Object Factory for your Home Page
public class Phase2Page {
WebDriver driver;
public Phase2Page(WebDriver driver){
this.driver = driver;
PageFactory.initElements(driver, this);
}
#FindBy(xpath = "//*[#id='search_field']")
WebElement searchField;
#FindBy (xpath = "html/body/div[1]/div/div[1]/div[1]/div[1]/div/button")
WebElement searchBtn;
#FindBy(xpath = ".//*[#id='filter_gender_ul']/li[2]")
WebElement LadiesToggle;
public void homeSearchAndClick() {
System.out.println("In home search");
LadiesToggle.click();
searchField.sendKeys("Nike");
searchBtn.click();
}
}
SearchPage.java - Page Object Factory for Search Page
public class SearchPage {
WebDriver driver;
#FindBy(xpath = ".//*[#id='show_query']/h2")
WebElement searchCount;
public SearchPage(WebDriver driver){
this.driver = driver;
PageFactory.initElements(new AjaxElementLocatorFactory(driver, 50),this);
}
#FindBy(xpath = "html/body/div[1]/div/section/div[1]/div[1]/div/div[1]/div/div[2]/label/span")
WebElement femaleCheckbox;
// Function to search by FEMALE gender
public void searchForFemale() {
System.out.println("Gender: Female clicked");
femaleCheckbox.click();
}
public void filterSearchCount() {
String count = searchCount.getText();
System.out.println("Filter search count: " + count);
}
}
Test1.java - Your Actual Test for execution
public class Test1 {
WebDriver driver;
public void openBrowser() {
driver.get("http://laceup.io/phase2");
}
#Test
public void testSearch(){
System.setProperty("webdriver.chrome.driver", "D:\\Selenium Webdriver/chromedriver.exe");
driver = new ChromeDriver();
openBrowser();
Phase2Page objHome = new Phase2Page(driver);
SearchPage objSearch = new SearchPage(driver);
objHome.homeSearchAndClick();
objSearch.filterSearchCount();
driver.quit();
}
}
My code worked when i used thread.sleep in filterSearchCount().

Selenium : Automating LinkedIn - Profile Icon

I am new to Selenium and trying to use Actions class to mouseover on the Profile icon available on linked in site to open the menu that appears on Mouseover of profile image.
Below is my code and when it reaches on to those lines the error comes : Unable to locate element..
This is happening with all the icons available on Linked on top bar ( messages / Flag icon etc.
Code :
public class LinkedIn {
WebDriver driver = new FirefoxDriver();
#BeforeTest
public void setUp() throws Exception {
String baseUrl = "http://www.linkedin.com/";
driver.get(baseUrl);
}
#Test
public void login() throws InterruptedException
{
WebElement login = driver.findElement(By.id("login-email"));
login.sendKeys("*****#gmail.com");
WebElement pwd = driver.findElement(By.id("login-password"));
pwd.sendKeys("*****");
WebElement in = driver.findElement(By.name("submit"));
in.click();
Thread.sleep(10000);
}
#Test
public void profile() {
// here it gives error to me : Unable to locate element
Actions action = new Actions(driver);
WebElement profile = driver.findElement(By.xpath("//*[#id='img-defer-id-1-25469']"));
action.moveToElement(profile).build().perform();
driver.quit();
}
}
It seems you have used incorrect xpath , Kindly check below example to mouse hover on Message button :
Thread.sleep(5000);
Actions action = new Actions(driver);
WebElement profile = driver.findElement(By.xpath("//*[#id='account-nav']/ul/li[1]"));
action.moveToElement(profile).build().perform();
Correct Xpaths are :
For Message Icon : "//*[#id='account-nav']/ul/li[1]"
For Connection Icon : //*[#id='dropdowntest']
Above code I just tested and working fine so will work for you.

The selenium webdriver always pickup the second result from google search suggestion

Use below simple test code but selenium always like to choose second google suggestion result as the search text:
For example:
I input "Selenium", google will give suggestion list like below:
Selenium
Selenium WebDriver
Then webdriver will always pick up "Selenium WebDriver". But I used webdriver to sendKeys as "Selenium".
Is it a bug to webdriver?
public class HelloWorld {
private WebDriver driver;
#Before
public void setUp() {
System.setProperty("webdriver.ie.driver", "D:\\IEDriverServer.exe");
DesiredCapabilities caps = DesiredCapabilities.internetExplorer();
caps.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
driver = new InternetExplorerDriver(caps);
driver.get("http://www.google.com");
}
#After
public void tearDown() {
driver.quit();
}
#Test
public void testLitianyiNewsIsExisting() throws InterruptedException {
WebElement inputField = driver.findElement(By.name("q"));
inputField.sendKeys("selenium");
//Thread.sleep(5000);
driver.findElement(By.name("btnK")).submit();
}
}
I'm pretty sure googles immediate results are bugging you here. Once you are halfway typing your query, Google will start showing you the results already and the "btnK" button will no longer be visible. Try this in stead:
#Test
public void testLitianyiNewsIsExisting() throws InterruptedException {
WebElement inputField = driver.findElement(By.name("q"));
inputField.sendKeys("selenium");
inputField.sendKeys(Keys.ENTER);
}

How to verify a page title using WebDriver and page object?

I am trying to write a method to verify page title using page objects but I am unable to do it. Could you please help me out how to write a method to verify page title after searching something in the google page.
Here is my 2 classes.
Class 1
public class GoogleSearchPage {
protected WebDriver driver;
#FindBy(name="q")
private WebElement SearchBox;
#FindBy(name="btnG")
private WebElement SearchButton;
public void SearchFor(String SearchTerm)
{
SearchBox.sendKeys(SearchTerm);
SearchButton.click();
}
}
Class2
public class TestSearchResults {
WebDriver driver;
GoogleSearchPage page;
#BeforeClass
public void Launch() throws Exception
{
driver = new FirefoxDriver();
driver.get("http://google.com");
}
#AfterClass
public void Close()
{
driver.quit();
}
#Test
public void ResultPage() {
System.out.println(page);
page=PageFactory.initElements(driver, GoogleSearchPage.class);
page.SearchFor("selenium");
}
}
Could you please help how to verify the title after displaying the Search results
Note: I am using TestNG.
Thanks in Advance,
Shiva Oleti.
Try this:
assertEquals("Your Page Title" , driver.getTitle());
driver.getTitle() - Returns Title of your current page.
You can get & verify title of page using python webdriver. See below codes
driver.title('title name')
assert 'title name' in driver.title('title name')
It will verify the title name. if it is there title name test case pass else through assert error.
Create a constructor in each page object. The constructor:
sets the instance driver value
waits for page load to complete (e.g. loading spinner not visible, jQuery.active == 0, document.readyState == 'complete')
verifies the page title (see other answers)
Issue PageFactory.initElement(driver, this);
Therefore you don't need a separate method to verify title. In each step you will have a new YourPageObjectPage() which checks the title automatically. Think DRY.

Categories

Resources