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.
Related
Main Block:
public class test3 extends utility {
public WebDriver driver;
#BeforeTest
public void invokeBrowser() throws IOException {
driver = base();
driver.get(resource.getProperty("url"));
}
#Test
public class thirdPage {
public void main() {
actionTest test3 = new actionTest();
test3.executeTest();
}
}
}
Code performing mouse Actions:
public class actionTest {
public void executeTest() {
Actions execute = new Actions();
execute.moveToElement(driver.findElement(By.id("header-search-input"))).click().keyDown(Keys.SHIFT).sendKeys("Cricket").build().perform();
driver.findElement(By.id("header-desktop-search-button")).click();
}
}
Above code results in "NullPointerException" stating driver = null while executing block test3.executeTest();
Restructuring your codebase might help you to fix this issue. Create a base test class. Add the code related to web driver initialization and other main things there. Then create another class for your tests. Inherit it from the base test class. Then you can use the initialized driver in your all test classes.
I am using Testng for parallel execution of my web testcase. Totally i am having 5 classes.
BaseClass - for initializing and closing of my browser
Core class - Mediator for all drivers initialized
Reusable methods - Click, settext, gettext... [extends Step #2 Core class, so driver comes from there only]
Page Object Class - To store all locators like name,ID,xpath.Uses all those reusable methods like click, gettext,settext.
Main Test Class.
Base Class
public class TestNGBase {
ThreadLocal<WebDriver> localdriver = new ThreadLocal<>();
#BeforeMethod
public void initialize(){
System.setProperty("webdriver.chrome.driver","C:\\SeleniumTest\\chromedriver.exe");
localdriver.set(new ChromeDriver());
}
public WebDriver driver(){
Core.setDriver(localdriver.get());
return localdriver.get();
}
#AfterMethod
public void teardown(){
localdriver.get().close();
localdriver.remove();
}
}
Core Class:
public class Core {
protected static WebDriver driver;
public static void setDriver(WebDriver driverr) {
driver = driverr;
}
}
Reusable Class:
public class WebMethods extends Core {
public WebMethods() {
}
public static void Click(By by) {
driver.findElement(by).click();
}
PageObject Class
public class pagemethods(){
By login = By.name("login");
public void login(){
WebMethods.click(login);}
}
MainTestclass1 : Will use above Pageobject
MainTestclass2 : Will use above Pageobject
MainTestclass3 : Will use above Pageobject
So in above 3 testcase when i trigger all those using testng.xml file. 3 new browser gets initialized and it successfully opens the url. But when i start using the all those reusable methods such as click(). Out of 3 Testcase, any of the two testcase is always getting failed.
I think problem starts Core class as it receives all drivers at the same time. It's collapsing something.
Can some one help me to solve this parallel execution failure problem.
Thanks
Try to not make the main class static. Create a class that makes an instance of the class and then executes. When you make a static class, the method is hanging off of that class, not an instance.
E.g.
public WebDriver
{
WebDriver myWebDriver = new WebDriver();
myWebDriver.whateverMethod();
}
When using threads avoid static. Try that first.
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 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