I need help with creating Java automation with Selenium Webdriver to Pom or Pomm factory.
I've read how to create pom without any success.
Please help.
I need help on how to create java automation in pom. strong textHow to conver it?
String baseUrl = "https:amazon.com/";
WebDriver driver;
NavigationPom navigationPom;
private final boolean useFirefoxbrowser = false;
#BeforeClass
public static void setupClass() {
WebDriverManager.chromedriver().setup();
WebDriverManager.firefoxdriver().setup();
}
#Before
public void setUp() {
if (useFirefoxbrowser == false) {
FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.addArguments("--width=1240", "--height=720");
driver = new FirefoxDriver(firefoxOptions);
} else {
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--window-size=1920,1080");
driver = new ChromeDriver(chromeOptions);
}
}
#Test
public void MacbookTest1() {
driver.get(baseUrl);
driver.manage().window().maximize();
driver.findElement(By.xpath("//input[#id='twotabsearchtextbox']")).click();
driver.findElement(By.xpath("//input[#id='twotabsearchtextbox']")).sendKeys("macbook");
driver.findElement(By.xpath("//input[#id='nav-search-submit-button']")).click();
driver.findElement(By.xpath("//input[#id='nav-search-submit-button']")).click();
driver.findElement(By.xpath("//li[#id='p_89/Lenovo']/span/a/div/label/i")).click();
//Checkboxes
boolean enabled = driver.findElement(By.xpath("//li[#id='p_89/Lenovo']/span/a/div/label/i")).isEnabled();
Start from creating a simple implementation:
How the Page class might look:
class Page {
private WebDriver driver;
public Page(WebDriver driver) {
this.driver.driver = driver;
}
//Define locators
//Keep elements as By on the top of the class
private By someElement1 = By.xpath("...");
private By someElement2 = By.xpath("...");
//Define page methods
// Examples:
// public void clickSomeElement()
// public void fillSomeInput()
public void doSomeAction() {
WebElement element = driver.findElement(someElement1);
// do something with the element
// optionaly wait for something after action
}
// Examples:
// public boolean isPageLoaded()
// public boolean isSomeElementDisplayed()
// public String getSomeElementText()
// public int getSomeElementsCount()
public Object getSomeData() {
WebElement element = driver.findElement(someElement2);
// do something with the element and return
}
}
Use pages in your tests, do not work with WebDriver directly.
#Test
public void someTest() {
Page page = new Page(driver);
page.doStep1();
page.doStep2();
assertEquals(page.getSomeData(), "Some expected result", "Optional Error message");
}
And..
Start from creating a test scenario code, create test steps, which you like to have (methods, which will be underlined in IDE as non-existing), and think about the data, which you like to check.
Then just implement all the non-existing methods you need in Page classes.
Maybe it sounds complicated, but try to start from simple test scenarios and it should become more clear after some practice.
I had the same issue. If this is a Java project, with Eclipse and Intellij IDEA, you can right click the project and select Convert to Maven. From there, it's fine adjustments (versions) in the POM file.
Related
I have 2 similar classes.
I changed the opening of the browser to ChromeOptions so the tests can't be execute when a browser is open.
When I am execute the testNG.xml (with the 2 tests) its open immiditly both of the browsers and the suite can't be run.
What should I need to change in order to execute this well ?
Thanks alot
public class Demo2 {
public static WebDriver driver;
public static void main(String[] args)
{
initializeDriver();
print2();
}
#BeforeTest
private static void initializeDriver() {
System.setProperty("webdriver.chrome.driver","C:\\Program Files\\Selenium\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("user-data-dir=C:/Users/עמית/AppData/Local/Google/Chrome/User Data");
options.addArguments("--start-maximized");
driver = new ChromeDriver(options);
}
#Test
public static void print2()
{
driver.get("https://www.google.com");
System.out.println("1");
driver.close();
}
}
I think this path C:/Users/עמית/AppData/Local/Google/Chrome/User Data") should use alphabet letters. Even if you try to use this, please config your font type to use the popular font as UTF-8.
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
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() );
}
realise this might be a bit of a big ask, but I'm having trouble splitting my test class to use the Page Object Model.
My current class basically works as so:
#BeforeClass - startUp() Loads properties file for variables and starts ChromeDriverService
#Before - createDriver() Opens Chrome browser, and navs to homepage
#Test - desktopHappyCallback() Does some page interaction, then calls:
hideDynamicElements() Hides some elements on the page
runScreenshotValidation() Saves a screenshot and compares it by calling:
compareScreen() Compares and returns a true/false
#After - tearDown() Quits the ChromeDriver
#AfterClass - stopService() Kills the ChromeDriverService
The class is currently (have cut bits out of the methods to make it shorter):
public class desktopHappy {
private static ChromeDriverService service;
private static WebDriver driver;
private static Properties obj = new Properties();
//Set up screenshot comparison via im4java
private static boolean compareScreen(String expectedImage, String currentImage, String diffImage) {
CompareCmd compare = new CompareCmd();
compare.setErrorConsumer(StandardStream.STDERR);
IMOperation comparisonExe = new IMOperation();
comparisonExe.metric("mae"); //mae = Mean Absolute error (average of all the color differences)
comparisonExe.addImage(currentImage);
}
//Compare via ImageMajick
private void runScreenshotValidation() throws IOException, InfoException {
String current = "screenshots\\current\\Current.png";
boolean compareSuccess = compareScreen(baseline, current, difference); //Run the compare method
}
}
//Hide dynamic elements on the page (if they exist)
private void hideDynamicElements() throws IOException, InterruptedException {
List<By> criteria = Arrays.asList(
By.className("telephone-number"),
By.cssSelector("#chatContainer"),
);
for (By dynamicElement : criteria) { //Loop through the criteria
List<WebElement> elements = driver.findElements(dynamicElement);
for (WebElement hideElement : elements){ //Loop through each instance of an element
((JavascriptExecutor) driver).executeScript("arguments[0].style.visibility='hidden'", hideElement);
}
}
#BeforeClass //Pulls in Properties, and starts up the ChromeDriverService before the Tests run
public static void startUp() throws IOException {
FileInputStream propfile = new FileInputStream(System.getProperty
("user.dir") + "\\src\\main\\resources\\config.properties");
obj.load(propfile);
service = new ChromeDriverService.Builder()
.usingDriverExecutable(new File(obj.getProperty("chromeDriverLoc"))) //Driver set in properties
.usingAnyFreePort()
.build();
service.start();
}
#Before //Starts up the Chrome browser (on home page) before each Test
public void createDriver() {
driver = new RemoteWebDriver(service.getUrl(), DesiredCapabilities.chrome());
driver.get(obj.getProperty("targetENV")); //Opens home page (set in properties)
}
#Test //Checks the Callback form (modal)
public void desktopHappyCallback() throws Exception {
driver.findElement(By.cssSelector("#callbackInputPhone")).sendKeys(obj.getProperty("formsPhone"));
driver.findElement(By.xpath("//input[#value='Request a callback']")).click();
WebDriverWait waitForSuccessMessage = new WebDriverWait(driver, 5);
waitForSuccessMessage.until(ExpectedConditions.elementToBeClickable
(By.cssSelector("#callbackForm > div.success-message")));
hideDynamicElements(); //Run the hide dynamic elements method
runScreenshotValidation(); //Run the screenshot comparison method
}
#After //Quits the ChromeDriver after each Test
public void tearDown() throws Exception {
driver.quit();
}
#AfterClass //Kills the ChromeDriverService at end of Tests
public static void stopService() {
service.stop();
}}
So in IntelliJ I've tried to split up my project with packages as so:
I've been trying to move into the baseCompare class:
hideDynamicElements()
compareScreen()
runScreenshotValidation()
Then into the baseSetup class:
startUp()
createDriver()
tearDown()
stopService()
Then homePage will contain my representations and desktopHappy will contain my test assertions.
However I'm getting really stuck working out how to split things up so that they work together. Is anyone able to give me an example on how I should be splitting things up under these packages? (sorry big ask!)
I think you are dividing your logic very fairly.
The only thing that i would change, is to have your base* classes under your base package, rather than an actual physical base package.
For example:
com.salessite/
baseCompare.java
baseSetup.java
basePage.java
baseTest.java
pages/
homePage.java < basePage.java
tests/
desktopHappy.java < baseTest.java
Also by creating more base's, you give yourself more leeway for future changes.
so that they work together
IF by work you mean, compile - then you should have no problem. say for example that homePage.java extends basePage.java, then in homePage.java, you'd have the appropriate import.
import com.salessite.basePage;
Importing is how to access external classes and references. (access modifiers permitting, of course.)
I am fairly new to Selenium WebDriver and JUnit, I am testing a web app and was wondering is my class design correct in Junit for testing the UI?
As I have seen instances of where people have used composition.
Any advice would be greatly appreciated
Java Class
public class OverviewPage {
private WebDriver driver;
private String URL = "http://www.google.com";
public String searchQuery = "BBC";
OverviewPage(WebDriver driver){
this.driver = driver;
driver.get(URL);
if(!"Login".equals(driver.getTitle())){
throw new IllegalStateException("Wrong site");
}
}
By searchBox = By.id("siteSearchField");
By submitSearch = By.cssSelector("button.btn.searchIco");
public OverviewPage searchBox(String findADealer){
driver.findElement(searchBox).sendKeys(findADealer);
return this;
}
public OverviewPage searchBoxDisplayed(){
driver.findElement(searchBox);
return this;
}
public FindADealerPage searchResults(){
driver.findElement(searchBox).sendKeys(searchQuery);
driver.findElement(submitSearch).click();
String search = driver.getPageSource();
boolean searchResults = search.contains(searchQuery);
return new FindADealerPage(driver);
}
}
Junit
public class OverviewPageTest {
private WebDriver driver;
public String searchQuery = "find a dealer";
By searchBox = By.id("siteSearchField");
By submitSearch = By.cssSelector("button.btn.searchIco");
#Before
public void setUp(){
driver = new HtmlUnitDriver();
driver.get("http://www.google.com");
}
#After
public void tearDown(){
driver.quit();
}
#Test
public void checkTitle(){
Assert.assertEquals("product edit", driver.getTitle());
}
#Test
public void checkSearchBoxExists(){
boolean searchBoxes = driver.findElement(searchBox).isDisplayed();
Assert.assertTrue(searchBoxes);
}
#Test
public void searchResults(){
driver.findElement(searchBox).sendKeys(searchQuery);
driver.findElement(submitSearch).click();
String search = driver.getPageSource();
boolean searchResults = search.contains(searchQuery);
Assert.assertTrue(searchResults);
}
}
Your Java class OverviewPage suggests to me that you are wanting to use the PageObject model.
If you want to follow Google's example (https://code.google.com/p/selenium/wiki/PageObjects), you could put all the fields and methods pertaining to a particular page in the PageObject rather than the TestClass.
For example, in your TestClass, instantiate the PageObject:
OverviewPage page = new OverViewPage(driver);
and throughout your TestCalss, replace things like driver.get("http://www.google.com"); with driver.get(page.URL);
Basically what it boils down to is - you shouldn't have anything in quotes in your TestClass. The benefit of this pattern is when you have multiple tests referring to the same field in the PageObject, then when you need to update that field - you can do so easily in one place, rather than refactoring multiple lines of duplicate code throughout your tests.
Also, any given test needn't have more than two lines - a method call and an assertion.
So using your test searchResults() as an example, you could move the following lines into a method within the page object:
driver.findElement(searchBox).sendKeys(searchQuery);
driver.findElement(submitSearch).click();
String search = driver.getPageSource();
boolean searchResults = search.contains(searchQuery);
return searchResults; // added this one...
And your test becomes:
#Test
public void searchResults(){
boolean searchResults = page.searchResults();
Assert.assertTrue(searchResults);
}
That's my interpretation. Hope it helps!