Been trying to learn/perform some automated testing using Selenium + JUnit + Cucumber and I've spent hours browsing through the internet trying to resolve this with no success. I've written my feature, steps and runner code and the 'glue' is mapped to the correct package too. However, I run into the topic error when I try to run my Runner.java file.
Project Structure
Feature file:
Feature: Admin login
Scenario: Logging into Fleet Portal
Given user navigates to Fleet Portal
When enter credentials
Then user had logged
Runner file:
package Runner;
import org.junit.runner.RunWith;
import io.cucumber.junit.*;
#RunWith(Cucumber.class)
#CucumberOptions(
features = "Features"
,glue="Steps"
)
public class TestRunner {}
Step file:
package Steps;
import java.util.ArrayList;
import java.util.Scanner;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
class App {
private static final WebDriver driver = new ChromeDriver();
public void myMethod(String flag) {
System.out.println(flag);
}
#Given("user navigates to Fleet Portal")
public void user_navigates_to_fleet_portal() {
throw new io.cucumber.java.PendingException();
}
#When("enter credentials")
public void enter_credentials() throws InterruptedException {
throw new io.cucumber.java.PendingException();
}
#Then("user had logged in successfully")
public void user_had_logged_in_successfully() {
myMethod("yes");
throw new io.cucumber.java.PendingException();
}
}
I've tried to take JUnit out of the picture by simply running the feature file as a cucumber test but it still results in the same error, which is weird because the cucumber plugin confirms that the steps are mapped to the features -> feature mapping
POM file
Any and all help is appreciated.
In cucumber maven project.
Feature file :
Feature: Smoke Test for Home
Scenario: positive scenario
Given Open "JTMS_PORTAL"
#When application open successfully
#Then validate title as "Welcome: Mercury Tours"
#And Close Application
StepDef File :
package jtms.stepdef;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
public class LoginStepDef {
#Before
public void setup() {
System.out.println("In login stepdef");
}
#Given("^Open \"([^\"]*)\"$")
public void open(String arg1) throws Throwable {
System.out.println("In login stepdef2 with Given annotation");
}
}
TestRunner :
package jtms.testrunner;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions(features = "features/jtms/home.feature",
glue="jtms.stepdef",
dryRun=false
)
public class TestRunner {
}
Cosole output:
In login stepdef
Project structure:
Issue:
#Given from stepdef not print the print statement, but #Before is executed and print the output 'In login stepdef'. please help, thank you in advance.
can you change the value of the feature in cucumber options to below
features = {"classpath:features"}
I have written a step definition file but still its not getting identified,below is my feature,step definition,Runner file.
Feature: Google Search feature
Scenario: To verify search bar functionality
Given user is on google search page
When user enters a search keyword in a search bar
And user clicks on Enter keyboard button
Then search results are displayed
Then Close the browser
package com.mavenDemo;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class StepDefination {
WebDriver driver;
#Given("^user is on google search page$")
public void user_is_on_google_search_page() throws Throwable {
// Write code here that turns the phrase above into concrete actions
System.setProperty("webdriver.chrome.driver", "F://chromedriver.exe");
driver = new ChromeDriver();
driver.get("https://www.google.com");
}
#When("^user enters a search keyword in a search bar$")
public void user_enters_a_search_keyword_in_a_search_bar() throws Throwable {
driver.findElement(By.name("q")).sendKeys("Test");
}
#And("^user clicks on Enter keyboard button$")
public void user_clicks_on_Enter_keyboard_button() throws Throwable {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ENTER);
}
#Then("^search results are displayed$")
public void search_results_are_displayed() throws Throwable {
boolean searchText = driver.findElement(By.xpath("//span[#class='wUrVib']")).getText().contains("Test");
Assert.assertTrue(searchText);
}
#Then("^Close the browser$")
public void close_the_browser() throws Throwable {
driver.quit();
}
}
package com.mavenDemo;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions(features =
"C:/Users/BR/workspace/com.mavenDemo/src/main/java/Login.features",
glue = {
"/com.mavenDemo/src/main/java/com/mavenDemo/StepDefination" })
public class TestRunner {
}
What Might be the reason to it not to recognize step definition file?
I have double checked the code but I am unable to find the solution also tried solution provided for similar problem but even that didn't work
Please help me in resolving this.
Thanks
I have found an answer!!
mistake was in a test runner file,while specifying a step definition path in glue we need to specify folder name not the test runner path,
Changed glue to
glue = {"com.mavenDemo" }
Thanks.
Please remove /com.mavenDemo from glue path
I am a bit new to eclipse and the cucumber/selenium combo. I have three files: a feature, a TestRunner, and the stepDefintion file. I would like to be able to run these files outside of the eclipse IDE. I need to be able to run these tests on a different computer that does not have Eclipse or access to external websites, only the one that will be tested. I've included code for the three sample files (this does not include the proper URL or credentials). I would like to make this somehow executable, however I know that lacking a main method, I can't run this as a Jar.
Feature:
Feature: Login Action
Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User enters "maximo" and "source1"
Then Message displayed Login Successfully
Scenario: Successful LogOut
When User LogOut from the Application
Then Message displayed LogOut Successfully
TestRunner
package cucumberTest;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions(
features = "Feature"
,glue={"stepDefinition"}
, monochrome = true
, plugin = {"pretty"}
)
public class firstTestCase {
}
And the actual Step Definitions
package stepDefinition;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.WebDriverWait;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class Test_Steps {
public static WebDriver driver;
private String baseUrl;
static WebDriverWait wait;
#Given("^User is on Home Page$")
public void user_is_on_Home_Page() throws Throwable {
System.setProperty("webdriver.chrome.driver",
"C:\\Selenium\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
baseUrl = "https://maximo-demo76.mro.com/";
wait = new WebDriverWait(driver, 60);
driver.get(baseUrl + "/maximo/webclient/login/login.jsp?welcome=true");
}
// #When("^User Navigate to LogIn Page$")
// public void user_Navigate_to_LogIn_Page() throws Throwable {
// driver.findElement(By.xpath(".//*[#id='account']/a")).click();
// }S
#When("^User enters \"(.*)\" and \"(.*)\"$")
public void user_enters_UserName_and_Password(String realUsername, String realPassword) throws Throwable {
driver.findElement(By.id("username")).clear();
driver.findElement(By.id("username")).sendKeys(realUsername);
driver.findElement(By.id("password")).clear();
driver.findElement(By.id("password")).sendKeys(realPassword);
driver.findElement(By.id("loginbutton")).click();
}
#Then("^Message displayed Login Successfully$")
public void message_displayed_Login_Successfully() throws Throwable {
System.out.println("Login Successfully");
}
#When("^User LogOut from the Application$")
public void user_LogOut_from_the_Application() throws Throwable {
WebElement logOut =
driver.findElement(By.id("titlebar_hyperlink_8-lbsignout_image"));
Actions actions = new Actions(driver);
actions.moveToElement(logOut).click().perform();
}
#Then("^Message displayed LogOut Successfully$")
public void message_displayed_LogOut_Successfully() throws Throwable {
// Write code here that turns the phrase above into concrete actions
System.out.println("LogOut Successfully");
}
}
Basically every time I run my java code from eclipse, webdriver launches a new ie browser and executes my tests successfully for the most part. However, I have a lot of tests to run, and it's a pain that webdriver starts up a new browser session every time. I need a way to re-use a previously opened browser; so webdriver would open ie the first time, then the second time, i run my eclipse program, I want it to simply pick up the previous browser instance and continue to run my tests on that same instance. That way, I am NOT starting up a new browser session every time I run my program.
Say you have 100 tests to run in eclipse, you hit that run button and they all run, then at about the 87th test you get an error. You then go back to eclipse, fix that error, but then you have to re-run all 100 test again from scratch.
It would be nice to fix the error on that 87th test and then resume the execution from that 87th test as opposed to re-executing all tests from scratch, i.e from test 0 all the way to 100.
Hopefully, I am clear enough to get some help from you guys, thanks btw.
Here's my attempt below at trying to maintain and re-use a webdriver internet explorer browser instance:
public class demo extends RemoteWebDriver {
public static WebDriver driver;
public Selenium selenium;
public WebDriverWait wait;
public String propertyFile;
String getSessionId;
public demo() { // constructor
DesiredCapabilities ieCapabilities = DesiredCapabilities
.internetExplorer();
ieCapabilities
.setCapability(
InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,
true);
driver = new InternetExplorerDriver(ieCapabilities);
this.saveSessionIdToSomeStorage(getSessionId);
this.startSession(ieCapabilities);
driver.manage().window().maximize();
}
#Override
protected void startSession(Capabilities desiredCapabilities) {
String sid = getPreviousSessionIdFromSomeStorage();
if (sid != null) {
setSessionId(sid);
try {
getCurrentUrl();
} catch (WebDriverException e) {
// session is not valid
sid = null;
}
}
if (sid == null) {
super.startSession(desiredCapabilities);
saveSessionIdToSomeStorage(getSessionId().toString());
}
}
private void saveSessionIdToSomeStorage(String session) {
session=((RemoteWebDriver) driver).getSessionId().toString();
}
private String getPreviousSessionIdFromSomeStorage() {
return getSessionId;
}
}
My hope here was that by overriding the startSession() method from remoteWebdriver, it would somehow check that I already had an instance of webdriver browser opened in i.e and it would instead use that instance as opposed to re-creating a new instance everytime I hit that "run" button in eclipse.
I can also see that because I am creating a "new driver instance" from my constructor, since constructor always execute first, it creates that new driver instance automatically, so I might need to alter that somehow, but don't know how.
I am a newbie on both stackoverflow and with selenium webdriver and hope someone here can help.
Thanks!
To answer your question:
No. You can't use a browser that is currently running on your computer. You can use the same browser for the different tests, however, as long as it is on the same execution.
However, it sounds like your real problem is running 100 tests over and over again. I would recommend using a testing framework (like TestNG or JUnit). With these, you can specify which tests you want to run (TestNG will generate an XML file of all of the tests that fail, so when you run it, it will only execute the failed tests).
Actually you can re-use the same session again..
In node client you can use following code to attach to existing selenium session
var browser = wd.remote('http://localhost:4444/wd/hub');
browser.attach('df606fdd-f4b7-4651-aaba-fe37a39c86e3', function(err, capabilities) {
// The 'capabilities' object as returned by sessionCapabilities
if (err) { /* that session doesn't exist */ }
else {
browser.elementByCss("button.groovy-button", function(err, el) {
...
});
}
});
...
browser.detach();
To get selenium session id,
driver.getSessionId();
Note:
This is available in Node Client only..
To do the same thing in JAVA or C#, you have to override execute method of selenium to capture the sessionId and save it in local file and read it again to attach with existing selenium session
I have tried the below steps to use the same browser instance and it worked for me:
If you are having generic or Class 1 in different package the below code snippet will work -
package zgenerics;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.BeforeTest;
import org.openqa.selenium.WebDriver;
// Class 1 :
public class Generics {
public Generics(){}
protected WebDriver driver;
#BeforeTest
public void maxmen() throws InterruptedException, IOException{
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
String appURL= "url";
driver.get(appURL);
String expectedTitle = "Title";
String actualTitle= driver.getTitle();
if(actualTitle.equals(expectedTitle)){
System.out.println("Verification passed");
}
else {
System.out.println("Verification failed");
} }
// Class 2 :
package automationScripts;
import org.openqa.selenium.By;
import org.testng.annotations.*;
import zgenerics.Generics;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
public class Login extends Generics {
#Test
public void Login() throws InterruptedException, Exception {
WebDriverWait wait = new WebDriverWait(driver,25);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("")));
driver.findElement(By.cssSelector("")).sendKeys("");
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("")));
driver.findElement(By.xpath("")).sendKeys("");
}
}
If your Generics class is in the same package you just need to make below change in your code:
public class Generics {
public Generics(){}
WebDriver driver; }
Just remove the protected word from Webdriver code line. Rest code of class 1 remain as it is.
Regards,
Mohit Baluja
I have tried it by extension of classes(Java Inheritance) and creating an xml file. I hope below examples will help:
Class 1 :
package zgenerics;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.BeforeTest;
import org.openqa.selenium.WebDriver;
public class SetUp {
public Generics(){}
protected WebDriver driver;
#BeforeTest
public void maxmen() throws InterruptedException, IOException{
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
String appURL= "URL";
driver.get(appURL);
String expectedTitle = "Title";
String actualTitle= driver.getTitle();
if(actualTitle.equals(expectedTitle)){
System.out.println("Verification passed");
}
else {
System.out.println("Verification failed");
} }
Class 2 :
package automationScripts;
import org.openqa.selenium.By;
import org.testng.annotations.Test;
import zgenerics.SetUp
public class Conditions extends SetUp {
#Test
public void visible() throws InterruptedException{
Thread.sleep(5000);
boolean signINbutton=driver.findElement(By.xpath("xpath")).isEnabled();
System.out.println(signINbutton);
boolean SIGNTEXT=driver.findElement(By.xpath("xpath")).isDisplayed();
System.out.println(SIGNTEXT);
if (signINbutton==true && SIGNTEXT==true){
System.out.println("Text and button is present");
}
else{
System.out.println("Nothing is visible");
}
}
}
Class 3:
package automationScripts;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.testng.annotations.Test;
public class Footer extends Conditions {
#Test
public void footerNew () throws InterruptedException{
WebElement aboutUs = driver.findElement(By.cssSelector("CssSelector"));
aboutUs.click();
WebElement cancel = driver.findElement(By.xpath("xpath"));
cancel.click();
Thread.sleep(1000);
WebElement TermsNCond = driver.findElement(By.xpath("xpath"));
TermsNCond.click();
}
}
Now Create an xml file with below code for example and run the testng.xml as testng suite:
copy and paste below code and edit it accordingly.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestSuite" parallel="classes" thread-count="3">
<test name="PackTest">
<classes>
<class name="automationScripts.Footer"/>
</classes>
This will run above three classes. That means one browser and different tests.
We can set the execution sequence by setting the class names in alphabetical order as i have done in above classes.