I don't know why I am getting 2 firefox browsers opened for the follwoing example. Can some one please tell me what is wrong in below code. I am new to cucumber and I am trying to develop cucumber poc with page object model.
Feature file:
Scenario: Smoke test for application
Given I am on home page
Step Defination file:
public class HomePageSteps {
CustomerDetails customerDetails;
HomePage homePage=new HomePage();
public HomePageSteps(CustomerDetails customerDetails){
this.customerDetails=customerDetails;
}
#Before
public void environmentSteup(){
homePage.envSetup();
}
#Given("^I am on home page$")
public void i_am_on_home_page() throws Throwable {
homePage.openURL();
}
}
Actual implementation of Step definition file:(HomePage.java)
public class HomePage extends BasePage{
public void openURL() {
driver.get("https://applicationURL.aspx");
System.out.println("I am on home page executed");
}
public void envSetup() {
driver=new FirefoxDriver();
driver.manage().window().maximize();
}
}
BasePage.java
public abstract class BasePage {
protected WebDriver driver=new FirefoxDriver();
}
CustomerDetails.java
public class CustomerDetails {
private String mdn=null;
private String Fname=null;
private String Lname=null;
public String getMdn() {
return mdn;
}
public void setMdn(String mdn) {
this.mdn = mdn;
}
}
2 firefox browsers are opened:
First it opens a blank browser. Later it opens another browser and in this browser it opens the application URL.
You have two calls to open browser windows...
Once in the sub-class in envSetup() - driver=new FirefoxDriver();
And in the super class driver variable declaration with initialization - protected WebDriver driver=new FirefoxDriver();
You have to remove one of them, no need for the super class one... This is the one giving you the blank window
Refer to this page. Your maximize() call in envSetup() might be doing more than you think
In selenium webdriver what is manage() [driver.manage()]
edit:
You also do not need to instantiate a new FirefoxDriver() outside of BasePage as you have already instantiated a driver field with that object. Anything extending BasePage will have access to that driver field. It is not a problem that you're doing this, it is just extraneous code that doesn't need to be there
Related
Please help me with my Selenium project.
Link for GIT repository: https://kodov#bitbucket.org/kodov/addressbook5.git
I have an application Addressbook ( https://sourceforge.net/projects/php-addressbook/ ) which I want to test.
I made several tests for Login page and page for creating a new contact.
The case is to make:
Negative test for login
Positive test for login
Then I don't need to close the browser but to run tests for creating a contact.
The problem is that I made POM and my tests and pages are in different classes, so I don't know how to quit the
Webdriver just after all tests, but not after the first one.
Maybe I need to change annotations.
You can create a Base Test class and make the other tests class extend that class.
For example:
public class BaseTest {
public static WebDriver driver;
private static boolean isTestsStarted;
public static WebDriverWait wait;
#BeforeClass
public static void setup() {
// To run setup method before all tests that extends this base class
if(!isTestsStarted) {
System.setProperty("webdriver.chrome.driver", ConfProperties.getProperty("chromedriver_path"));
driver = new ChromeDriver();
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.get(ConfProperties.getProperty("base_url"));
isTestsStarted = true;
}
}
// To quit driver after all tests run
// This will run only once, after all tests ran
// Another advantage of this is, it will quit driver even though you stop the program manually
static {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
driver.quit();
}));
}
}
Then extend this base class in your test classes
for your loginTest class
public class LoginTest extends BaseTest {
public static LoginPage loginPage;
public static MainPage mainPage;
#BeforeClass
public static void setup() {
// You can call driver object since you initialized it in your parent class
loginPage = new LoginPage(driver);
mainPage = new MainPage(driver);
driver.get(ConfProperties.getProperty("base_url"));
}
#Test
public void testUserCanNotLoginWithInvalidCredentials() {
loginPage.clearUsernameField().clearPasswordField()
.enterUsername(ConfProperties.getProperty("invalid_username"))
.enterPassword(ConfProperties.getProperty("invalid_password"))
.clickLoginButton();
assertThat(loginPage.getLoginButton().isDisplayed()).isTrue();
}
#Test
public void testUserCanLoginWithValidCredentials() {
loginPage.clearUsernameField().clearPasswordField()
.enterUsername(ConfProperties.getProperty("valid_username"))
.enterPassword(ConfProperties.getProperty("valid_password"))
.clickLoginButton();
assertThat(mainPage.getUserName())
.isEqualTo(ConfProperties.getProperty("valid_username"));
}
}
With the same way, you can use your driver object in other classes if you make those classes extend BaseTest class
You need to login no matter what, so you have to include the login part in both of your tests.
You can also try #Test(dependsOnMethods = { "testName" }) but I am not sure not if this works when your test is in another file.
I`m trying to implement cucumber with Page Object Model and i faced couple problems and have lots of questions.
My iOS app is not that complex, but i still want to orginize all stepdefs and features to correspond with pages from POM. So i will have multiple stepdefs and runners. What is best practice to organize all of it ? I tried Pico DI, but wasn`t even able to pass my driver instance through it.( If you can, please provide structure solution)
Since its native iOS - Im not going to close app after every scenario( it will take forever). But I still want to keep features DRY for re-usability
What would be the best way to create one appium driver instance and never create another until feature is executed? I understand i just need to add driver.quit in the last step. What i`m straggling with is to use same driver throughout all project(Pages, Stepdefs) (see code)
Im going to run tests with TestNg and wonder if #Before #After annotations still work in stepdefs or it`s better to avoid them ?
The MAIN question : Dependency Injection with pico. Since all my tests are acceptance (end to end feature tests) i wonder if it is good idea to create one InjectionSetUp class which will contain all my pages AND driver
Driver manager
public class IOSDriverManager {
public static ThreadLocal<IOSDriver<IOSElement>> webDriver = new ThreadLocal<IOSDriver<IOSElement>>();
public static DesiredCapabilities getIOSCapsLocal() {
DesiredCapabilities caps = new DesiredCapabilities();
//My caps
return caps;
public static void createThreadLocalWebDriver() {
IOSDriver<IOSElement> driver = null;
//try catch
driver = new IOSDriver<IOSElement>(new URL(APPIUM_SERVER_URL), getIOSCapsLocal());
//try catch
webDriver.set(driver);
}
public static IOSDriver<IOSElement> getThreadLocalDriver() {
IOSDriver<IOSElement> driver = webDriver.get();
if (driver == null) {
createThreadLocalWebDriver();
driver = webDriver.get();
}
return driver;
}
BasePage
public class BasePage {
IOSDriver<IOSElement> Driver;
public BasePage(IOSDriver<IOSElement> driver) {
initElements();
Driver = driver;
}
private void initElements() {
PageFactory.initElements(new AppiumFieldDecorator(getDriver()),this);
}
protected IOSDriver<IOSElement> getDriver() {
return IOSDriverManager.getThreadLocalDriver();
}
}
AnyPage
public class BiosurveyPage extends BasePage {
public BiosurveyPage(IOSDriver<IOSElement> driver) {
super(driver); // Appiumfield decorator is applied by BasePage constructor
//Is it better to just use getDriver() method throughout all pages instead of declaring driver again ?
}
Finaly StepDefs
public class newSignUpFlowTest{
protected IOSDriver<IOSElement> getDriver() {
return IOSDriverManager.getThreadLocalDriver();
}
LoginPage poLogin = new LoginPage(getDriver());
SignUpPage poSignup = new SignUpPage(getDriver());
// 10+ pages
#Given("I am on Login Page")
public void iAmOnLoginPage() {
assertThat("ON LOGIN PAGE",poLogin.isLoginScreen(),equalTo(true));
}
#When("I tap on Sign Up Link")
public void iTapsOnSignUpLink() {
poLogin.clickSignUp();
}
// 20+ methods for this feature
UPDATE
I fixed everything and able to run tests. Now my question is - does my framework look decent ? I dont have any real life experience prior to this. So can someone just approve me and suggest enhancements to keep up with best industry practices ? I know this post might piss some people off, but i dont know where else to communicate this as i don`t have any friends in the QA field and working remotely
When using dependency injection you want to let your DI system do all the heavy lifting. So your step definitions have a constructor dependency on your page objects.
public class NewSignUpFlowStepDefinitions {
private final LoginPage poLogin;
private final SignUpPage poSignup;
NewSignUpFlowStepDefinitions(LoginPage poLogin, SignUpPage poSignup) {
this.poLogin = poLogin;
this.poSignup = poSignup;
}
#Given("I am on Login Page")
public void iAmOnLoginPage() {
assertThat("ON LOGIN PAGE", poLogin.isLoginScreen(), equalTo(true));
}
#When("I tap on Sign Up Link")
public void iTapsOnSignUpLink() {
poLogin.clickSignUp();
}
}
You page objects can't have a constructor dependency on IOSDriver<IOSElement> because PicoContainer can only create dependency chains that don't end with empty constructors. So instead we use the IOSDriverManager here.
public class BiosurveyPage extends BasePage {
public BiosurveyPage(IOSDriverManager driverManager) {
super(driverManager);
}
}
In your BasePage you then unpack the webdriver from the driver manager.
public abstract class BasePage {
private IOSDriverManager driverManager;
public BasePage(IOSDriverManager driverManager) {
this.driverManager = driverManager;
initElements();
}
private void initElements() {
PageFactory.initElements(new AppiumFieldDecorator(driverManager.getDriver()), this);
}
protected IOSDriver<IOSElement> getDriver() {
return driverManager.getDriver();
}
}
Then in the IOSDriverManager you can keep a reference to the webdriver and create it as needed. If you are certain it is safe to share your webdriver between scenarios you can still use a ThreadLocal here.
public class IOSDriverManager implements Disposable{
private IOSDriver<IOSElement> webDriver;
private DesiredCapabilities getIOSCapsLocal() {
DesiredCapabilities caps = new DesiredCapabilities();
return caps;
}
private void createWebDriver() {
webDriver = new IOSDriver<IOSElement>(new URL(APPIUM_SERVER_URL), getIOSCapsLocal());
}
public IOSDriver<IOSElement> getDriver() {
if (webDriver == null) {
createThreadLocalWebDriver();
}
return webDriver;
}
#Override
public void dispose() {
// Stop webdriver ehre
}
}
Note that Disposable adds the dispose method which will let you clean up your driver a after each scenario. Either to dispose it entirely or to reset it to some known state.
http://picocontainer.com/lifecycle.html
Just pitching into Java! Trying to implement BDD style framework...
I'm running into this issue
My Driver.java looks like this:
public class Driver {
public static WebDriver Instance;
#Before
public void InitializeTest() {
System.setProperty("webdriver.chrome.driver", "C://chromedriver.exe");
Instance = new ChromeDriver();
}
#After
public void TearDownTest(Scenario scenario) {
//close the browser
if (scenario.isFailed()) { //take Screenshot
System.out.println(scenario.getName());
}
Instance.close();
}
}
And my Step-definition file:
public class MyStepdefs {
public static String Url = "https://ebay.com/staging/";
LoginPage loginPage = new LoginPage();
#Given("^I login to Ebay as \"([^\"]*)\"$")
public void iLoginToEbayAs(String username) throws Throwable {
Driver.Instance.navigate().to(Url);
loginPage.setUserName().sendKeys(username);
loginPage.setPassword().sendKeys("seeeev");
}
Receiving this error:
java.lang.NullPointerException
at Steps.MyStepdefs.iLoginToEbayAs(MyStepdefs.java:4)
MyStepdefs.java:4 == Driver.Instance.navigate().to(Url);
Help me pass through this!
Your Driver class never gets initialized, I'm betting Instance is null. I think you have at least 2 options, possibly more ways but this is what i'm thinking.
Instead of using #Before, which never gets executed because you don't have any test methods in that class, just make that a static "Init" method that you call in order to initialize your Instance variable
Make your Driver class an abstract class that your MyStepDefs class extends from. When you run your method iLoginToEbayAs() it will by default call the #Before method in the parent class and initialize your Instance variable as you expected.
Currently if you set a breakpoint in your #Before method I'm betting it's never getting executed hence NPE.
You are missing the argument in the step definition. it should be given below.
#Given("^I login to Ebay as \"([^\"]*)\"$")
public void iLoginToEbayAs(String role) throws Throwable {
Driver.Instance.navigate().to(Url);
}
have you imported the driver class?
I implemented a framework with POM and Page Factory approach. I have a baseTest class with lots of init e.g: (every other test class extends it)
Registration regPage = PageFactory.initelements(driver,Registration.class);
Login loginPage = PageFactory.initelements(driver,login.class);
Details detailsPage = PageFactory.initelements(driver,details.class);
.. (more than 10)
It is working fine but I would like to find more elegant/structured way to handle it.
I tried the build it into the constructor:
public Registeration(WebDriver driver) {
super(driver);
PageFactory.initelements(driver,Registration.class(or can be this));
}
It this case, I got a huge heapmemory error however it would be very nice because I could use an assert to validate every pageObject in the constructor using title or whatever element on the page, right?
How can I structure my inits and how can I handle it with PageFactory using constructor?
Thanks!
Its because initElements stuck in infinite loop. PageFactory's InitElement function looks first for page's constructor with webdriver argument. Its like Page Creation call by your runner --> initElements (2nd line)--> Page Constructor called by initElements and this keeps circling around. So, you cannot initiate the page class within constructor of page using pagefactory. You may structure something like this
public class MyTest{
#Test
public void test(){
TestFactory.invokeBrowser();
MyPage page = TestFactory.getPage(MyPage.class);
}
}
//TestFactory class
public class TestFactory{
private static WebDriver driver;
public static void invokeBrowser(){
WebDriver driver = new ChromeDriver();
//invokes the browser
this.driver = driver;
}
public static <T> T getPage(Class<T> page){
return PageFactory.initElements(driver,page);
}
}
I browsed through the site but did not find the answer I am looking.
I have
Superbase class- here I just create object of a webdriver
Baseclass- In this class I extend Superbase class, invoke the driver, and open the URL.
Clicklink class- In this class, I again extend the Superbase Class but only to find a null pointer exception. I think I am getting the exception as the driver object is not initialized.
I am just a beginner, and have not tried the browserfactory and other options, as I want to start with simple flow.
Superclass
Public class Superclass
{
public webdriver Driver;
}
Baseclass
public class Baseclass extends Superclass
{
setting capabilities and launching the browser
}
ClickLink
public class Clicklink extends Superclass
{
here I want to click on a link
driver.findelement(by.xpath("xpath").click());
// after this statement I get a null pointer exception
}
Can you please guide me here? how can I achieve the same.
Thanks much!
SuperClass and BaseClass are very poor names. Do not use the language of coding to name your classes use the language of the problem. In this case, web site application testing, use LoginPage, CartPage, ProfilePage, etc. Use the Page Object Pattern.
I suggest you use the Factory Pattern to provide the instances of WebDriver for each test. Since all those fit the idea is a page, use class extension from a standard PageObject to provide this capability. When navigating, have the current page construct an instance of the new page and pass it the current webDriver connection instance. Then any manipulations you apply to that PageObject will be automatically applied to that webDriver instance and its associated browser instance. You should also use a PageFactory to provide instances of the pageObject.
public abstract class PageObject {
public WebDriver driver;
PageObject() {
// Page can initialise its self
this.driver = BrowserFactory.webDriver();
}
PageObject(final WebDriver webDriver) {
this.driver = webDriver;
}
}
This is lot of guesswork done from my side, but please make sure, that your Superclass actually sets the driver and returns it. You can actually make it in both methods:
public class Superclass
{
public WebDriver driver;
public Superclass(){
driver = new FirefoxDriver();
}
public WebDriver getdriver(){
if (driver == null){
driver = new FirefoxDriver();
return driver;
}else{
return driver;
}
}
}
And later in methods you call it by:
public class Clicklink extends Superclass
{
getdriver().findelement(by.xpath("xpath").click());
}
If you doesn't want pass driver instance to Page Objects constructor you could create some container class for driver and put it before test and remove it after run. For example:
class Driver {
public static ThreadLocal<IWebDriver> driverInstance = new ThreadLocal<IWebDriver>();
public static IWebDriver GetDriver() {
return driverInstance.Value;
}
public static void SetDriver(IWebDriver driver) {
driverInstance.Value = driver;
}
}
and make this container field ThreadLocal to avoid problems with parallel run.
I have taken a slightly different approach than most on this thread. When I start a test session, I pass the browser name as an argument (i.e. -Dbrowser=chrome) in order to be able to test my web application with different browsers. Then I used the "browser" system property to obtain the browser name when setup() is called by my test framework. In my case, I use JUnit annotations in order to JUnit to setup all needed dependencies prior to running any tests.
#BeforeClass
public static void setup() throws Exception {
// Set up other stuff
String browser = System.getProperty("browser");
try {
SessionDataProvider.driver = TestUtils.createDriver(browser);
} catch (Exception e) {
...
}
}
The createDriver(String) is a factory method that instantiates the correct driver.
public static WebDriver createDriver(String browserName) throws Exception {
WebDriver driver = null;
try {
switch(browserName) {
case "firefox":
// code to system props and instantiate the driver
break;
case "chrome":
// code to system props and instantiate the driver
break;
case "ibrowser":
// code to system props and instantiate the driver
break;
case "edge":
// code to system props and instantiate the driver
break;
case "safari":
// code to system props and instantiate the driver
break;
default:
throw new Exception("Unsupported browser: " + browserName);
}
return driver;
}
Then, when I execute a step definition, I simply obtain the driver from the data provider class:
#And("(I click)/Click on {string}")
public void click(String arg) {
// Parse String arg and create web element locator...
try {
By locator = ...;
WebElement element = new WebDriverWait(SessionDataProvider.driver, 2)
.until(ExpectedConditions.elementToBeClickable(locator));
element.click();
} catch (Exception e) {
// handle exception
}
}
I did use below code in utility class like below
public static WebDriver setup(WebDriver driver)
{
if(driver == null) {
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
return driver;
}else
return driver;
//System.out.println("in method "+ driver.getTitle() );
}