Where we learn technology

Month: May 2020 (Page 2 of 3)

11. Page Object Model(POM) and MobileBy in Appium

In our previous blog, we have seen how to create a Base class(we named it as TestEngine.java). In this session we will see about POM and how to create .java file for each screen and manage our Mobile Elements.

Page Object Model(POM):

Guys, if you are new to Automation world, it is must for you to know about POM. I will explain the POM logic using simple examples in this session, so that you can understand it well. Most importantly POM is a very easy concept to understand and its one of a Best Practice to implement it in our project/framework.

In simple words, POM means creating java files based on “Pages/Screens”. For example let’s consider “RedBus” mobile application and its pages, (listed few pages for reference)  

  1. Login page
  2. Home page for Bus search
  3. Home page for Train search
  4. Home page for Flight search
  5. Home page for Hotel search
  6. Bus seat selection page
  7. Payment Page
  8. Confirmation page and so on….

Like this we can have up to some 20 pages. Imagine each page are having approximately 70 elements.

In our framework, do you think it’s really a good idea to declare and maintain all 1400 elements in a single java file? No definitely not!!!

To overcome this issue we are going for POM design. In POM, each pages are considered as a java file, like below

Mobile Pages/Screens/ Activity Corresponding Java file  Number of Elements 
Login page Login.java 10
Home page for Bus search HomePage_Bus.java 50
Home page for Train search HomePage_Train.java 70
 Home page for Flight search HomePage_Flight.java 65
 Home page for Hotel search HomePage_Hotels.java 80
 Bus seat selection page BusSelection.java 55
 Payment Page PaymentPage.java 35
 Confirmation page and so on…. ConfirmationPage.java 90

Quick Tips: Java class file name should start with a Capital letter.

Valid class name: Login.java

Invalid class name: login.java  

We can have all POM files under our parent project folder “Src/test/java” with a package named “com.projectName.pages”. This picture will definitely enhance your understanding.


Hope you guys are now clear with what is “POM”, our next step is creating java files based on POM and declaring the MobileElements. Please follow the steps and understand how it works. 

I'm using an app called "Invoice Manager", please refer the blog "Connect to Appium using Java / Python" for getting the app details and desired capabilities.

Step 1: Create a new Package and name it as “pages” under src/java/test.

Step 2: Once Package is created, start adding java files under those package, File name should be the name of Mobile page/activity. For example, “Loginscreen.java”

Step 3: Created a java file and named it as “Company_Setup.java” because I’m going to work in “Company setup” page in my mobile application.

Now, our java file is created successfully. Here the question comes, How can I connect my Base class “Testengine” to this “Company_Setup” class? the answer is using Inheritance concept in Java.

Guys, If you are not clear with OOPS concept, please understand it from our video

https://www.youtube.com/watch?v=g3r5KK2Acx8

Using the keyword “extends” we can inherit the properties of our Base class, like below. Please make sure to import the correct package of Base class.

All set guys, now java will allow us to use the variables and methods from my “Testengine” class in “Company_Setup” class using inheritance.

 

Before starting with element declaration in our class, please take a look on this small video to understanding how to Inspect element in Appium and adding it in to our class file.

 

Video on Inspecting element in Appium and declaring the element variable in java file.

Below image describes how to declare our elements using By class. Also created two methods, One for clicking the Logo button another for Signature button.

Quick Tip: Method name in java should always starts with a small letter. Best practice is using camel case, we can use underscore(_) to make it readable

Valid method name: clickOnLoginButton() or clickOn_LoginButton()

Invalid method name: ClickOnloginbutton()  

Here comes the Important rule, How to declare my Elements in Java file?

There are lot of ways we can declare an element. Here I demonstrate 3 most commonly used approaches, (please scroll down to understand what is By and MobileBy)

Approach #1: Using locator string directly in findElement() method using By class,

driver.findElement(MobileBy.id("loginbutton")).click();

Approach #2: Using String class to save the locator string and declaring in findElement() method,

String loginbtn = "loginbutton";
driver.findElement(MobileBy.id(loginbtn)).click();

Approach #3: Using “By” class to declare the element in findElement() method.

By addLogo = MobileBy.id("loginbutton");
driver.findElement(addLogo).click();

All approaches does the same action of clicking the “loginbutton” element, but the way of declaring the element is important here. Lets see the advantages and disadvantages of each,

Approach# 1, in this case, no re-usability concept . If there is a change in locator string, then we need to find and update everywhere. One of the worst way of declaring our elements.

Approach# 2, this approach is okay to use because we have reusability concept here. But the problem is, we don’t know what locator strategy to use in driver.findElement() method. Whether loginButton is an “ID”, or “name” or “tagname”. Also we are wasting the memory by declaring lot of String variables.         

Approach# 3: It is one of a best method to declare our element. Using “By” class we are directly declaring our locator string. We have reusability concept, Ease of maintenance and we know the strategy as well.

So, for now I prefer to use Approach 3 in our framework.

Note: Best practice and industry standard approach is using POM with “PageFactory”. We will see about PageFactory in upcoming blogs.

What is “By” and “MobileBy”?

Guys this is little tricky to understand, Please understand this carefully. Lot of questions may comes from this in Interview point of view

  1. Both “By” and “MobileBy” are abstract class, which hold the locator strategy methods.
  2. “By” class comes from the package “org.openqa.selenium” and “MobileBy” comes from the package “io.appium.java_client.MobileBy”.
  3. All methods inside “By” and “MobileBy” are static in nature. That is why java is allowing the methods “id”, “xpath”, “classname” to use directly with By or MobileBy without creating any class reference.
  4. “MobileBy” extends “By” class(inheritance). It means we can use all methods of “By” class using “MobileBy” class.
  5.  Using “By” class we cannot use methods belongs to “MobileBy”. For example if you want to use the MobileBy method like “AndroidUIAutomator()”, “AccessibilityId()”, “iOSNsPredicateString()” ect… are not allowed.
  6. “MobileBy” supports platform (iOS & Android) based location strategy for mobiles.
List of available methods in By and MobileBy,
By MobileBy Inherited from By
public static By id(String) public static By id(String) Yes
public static By linkText(String) Not applicable for Appium N/A
public static By partialLinkText(String) Not applicable for Appium N/A
public static By name(String) public static By name(String) Yes
public static By tagName(String) Not applicable for Appium N/A
public static By xpath(String) public static By xpath(String) Yes
public static By className(String) public static By className(String) Yes
public static By cssSelector(String) public static MobileBy.AndroidUIAutomator(String) No
  public static MobileBy.iOSNsPredicateString(String) No
  public static MobileBy.iOSClassChain(String) No
  public static MobileBy.IosUIAutomation(String) No
  public static MobileBy.ByAccessibilityId(String) No
 

Guys, in our next session we will see how to create a simple test case which will call our methods as a test step using TestNG…

I’m so excited about the next topic because, we are going to create a java files for our “Test cases” and handle multiple methods as a steps in our test case. Stay focused…

 

I will commit the codes discussed here in my Github repo. You can clone it and start modifying as per your idea. 

https://github.com/Karthickragu/Appium_Blog

 

Cheers!

Naveen AutomationLab

Blog Contributors:

Author:  Ragavendran

Ragav, having 10+ years of testing experience on which 7 years of rich experience in automation using UFT, Selenium (Java/Python). Expertise in Web and Mobile automation testing using Appium.

https://www.linkedin.com/in/Ragavendran-Ragav

Reviewer: Naveen Khunteta 

https://www.linkedin.com/in/naveenkhunteta

Handling Browser Window PopUp in Selenium WebDriver

1. Overview

In this article, we will discuss the concept of browser window popup also the practical implementation to handle the browser window popup with selenium web driver.

2. Browser window Popup

  • Browser window popup is a window popup that suddenly pops up on after clicking on some link or on selecting an option. It just likes another web page where maximization and minimization of the web page can be done.
  • This is having its own title and url or it could be an advertisement pop up also.
  • When do we need to handle this browser window popup: if the scenario is something like: you click on some link on the main window (parent window) and some other screen pops out just another webpage (child window ), now child window demands to submit some important information and press OK once information is filled.
  • Let’s see how the browser window appears:

Browser window popup Example

3. Steps to deal with browser window popup

1. Operate on the main window that opens the popup window. For instance, click on some link on the main window.

2. Need to know the name or id of the popup window. The window Id can be fetched from Window Handler API available in selenium. it uniquely identifies the address of all the windows open at a time. Below are the methods to handle the windows:

Syntax:

driver.getWindowHandle();

  • This function allows the handling of the current window by getting the current window Handle.
  • It returns the type String.
  • On the selenium official site, this is defined as


String parentWindowObj = driver.getwindowhandle();

driver.getwindowhandles();

  • As the method name suggests windowHandles, that means there are multiple windows and to handle all these opened windows we have to use this function.
  • It returns the Set of String.
    • Set<String> handles = driver.getwindowhandles();
  • Set stores the unique values and handle of all the windows that will be unique.
  • Below description clearly says the same:
  • Set values are not stored based on the index, so to iterate over the set, we need to use the Iterator to get the handler values and this method will give you an iterator of string.
  • This Iterator will be available in java. util package.
Iterator<String> it = handler.iterator();

//get the window ID for Parent a& Child now
String parentWindowID = it.next();
String childWindowID = it.next();

3. switch the driver to the popup window

driver.switchTo.window(childWindowID);

4. Perform some actions in the popup window such as get the title or close the button/tab etc.

driver.switchTo().window(childWindowID);
String title = driver.getTitle();
System.out.println("child window title is : " + title);

//close the pop up window now by using driver.close() method.
driver.close();

tip: Make sure, you are using close() to close the pop up. If you use quit() it will close parent and child both.
This is the basic difference between close() & quit().

5. Switch back to the parent window by passing the parentWindowID.

driver.switchTo().window(parentWindowID);
String title = driver.getTitle();
System.out.println("parent window title is : " + title);

//close the parent window by using quit:
driver.quit();

Let’s see the below code for a complete understanding of the concept:

Full code to handle Browser window popup:
package SeleniumSessions;

import java.util.Iterator;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;

public class BrowserWindowPopUp {

public static void main(String[] args) {

WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();

driver.get(“http://www.popuptest.com/goodpopups.html”);

driver.findElement(By.linkText(“Good PopUp #3”)).click();

Set<String> handles = driver.getWindowHandles();

Iterator<String> it = handles.iterator();

String parentWindowID = it.next();
System.out.println(“parent window id is : ” + parentWindowID);

String childWindowID = it.next();
System.out.println(“child pop up window id is : ” + childWindowID);

driver.switchTo().window(childWindowID);

System.out.println(“child window title is ” + driver.getTitle());

driver.close();

driver.switchTo().window(parentWindowID);
System.out.println(“parent window title is ” + driver.getTitle());

}

}

Important Tip:

One thing to notice here is that we have to come back to parent window if any further actions have to performed on Parent window. Without switching to parent window will not allow us to perform any action on parent window page.

Let’s add another example to get more understanding of the concept:

Suppose four windows are open and we want to switch to the third window.  

  • First Approach: using Set and iterator we have already seen above.
  • Second Approach: Using ArrayList. The benefit of this approach is you can easily deal with any window. The parent window will start with an index 0.

Let’s see the code with ArrayList:

package SeleniumSessions;

import java.util.ArrayList;

import java.util.Set;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

public class BrowserWindowHandleList {

public static void main(String[] args) {

System.setProperty(“webdriver.chrome.driver”, “/Users/NaveenKhunteta/Downloads/chromedriver”);

WebDriver driver = new ChromeDriver();

driver.get(“http://www.popuptest.com/goodpopups.html”);

driver.findElement(By.linkText(“Good PopUp #3”)).click();

Set<String> handles = driver.getWindowHandles();

ArrayList<String> ar = new ArrayList<String>(handles);

System.out.println(ar);

String parentWindowID = ar.get(0);

System.out.println(parentWindowID);

String childWindowID = ar.get(1);

System.out.println(childWindowID);

driver.switchTo().window(childWindowID);

System.out.println(“child window title is “ + driver.getTitle());

driver.close();

driver.switchTo().window(parentWindowID);

System.out.println(“parent window title is “ + driver.getTitle());

}

}

 

And we’ll get the output as following:

As can be seen through the above code, you can easily browse through the windows following this approach.

6. Conclusion

We have learnt to handle  browser window popup using windowhandler API in Selenium WebDriver. We have solved this use cases by using Set and List both.

That’s about it.



Cheers!!

Naveen AutomationLabs

Blog Contributors:

Author:  Mandeep Kaur

Mandeep, having 5+ years of Testing experience in automation using Selenium (Java). Expertise in API and Performance testing using JMeter.
https://www.linkedin.com/in/mandeepkaur93
 
Reviewer: Naveen Khunteta 
https://www.linkedin.com/in/naveenkhunteta

Steps to Configure Maven Profile with Maven Project

Let us see how to configure Maven Profile for a Maven Project.

What is a Maven Profile..??                                                               

It is a feature that can be defined in a pom.xml file which allows developers and testers to configure and customize builds based on requirement. 

What is the advantage of implementing Maven Profile in our Automation Projects..??                                                                 

As shown below, In real time we generally maintain different testng.xml files in frameworks that are designed either for Web Applications, Backend APIs or Mobile Applications like Smoke Suite, Regression Suite, Sanity Suite etc. for executing test cases based on requirement.             

Based on business requirement, we will be required to execute testng.xml files from Eclipse IDE, Command Prompt or from Jenkins etc.

In general, if we do not use Maven Profiling. Each time when we need to execute testng.xml file. We need to go to pom.xml file and change the name of testng.xml inside Maven Surefire Plugin which needs to be executed and that is a very tedious task to do every time.  Now the question is, how can we avoid changing testng.xml file name in pom.xml every time. when we need to execute test suite.

Now let us see configuring Maven Profile with Maven Project.

1. Project should be a Maven Project. 

2. Maven Jar files should be downloaded and path must be set for the same in Environment Variables and ensure that you are able to execute Maven Project from Command Line prompt before implementing Maven Profile. 

Refer below blog with respect to above points to Install Maven Jars and to execute Maven Project from Command Prompt:  http://naveenautomationlabs.com/executing-maven-project-in-windows-from-command-prompt/

Below is Maven Surefire Plugin where we mention which testng.xml file needs to be executed from project.

Code for Maven Surefire Plugin:                                                     

<build>
 <pluginManagement>
 <plugins>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-surefire-plugin</artifactId>
 <version>2.18.1</version>
 <configuration>
 <suiteXmlFiles>
 <suiteXmlFile>src/main/resources/testng_smoke.xml</suiteXmlFile>
 </suiteXmlFiles>
 </configuration>
 </plugin>
 </plugins>
 </pluginManagement>
 </build>

Now, let us see how can we build Maven Profile using Maven Surefire Plugin.

We can build Maven Profile for each testng.xml file in pom.xml as shown below, for each Maven Profile we can give Id/Name as highlighted in below screenshot.

All we need to add is followed tags with Maven Surefire Plugin <profiles> </profiles>, <profile> </profile> and <id> </id>.

All we need to do is that providing Id/Name for each Profile. For example, if we have multiple testng.xml files like Smoke, Sanity and Regression then we can build 3 Maven Profiles.       

One-One Profile for each suite, so that we can avoid changing testng.xml file name inside Maven Surefire Plugin whenever we need to execute test suite.

In my case, I have 2 testng.xml files. One is for Smoke and other one is for Regression.

You can refer below screenshots for giving Maven Profile Names for Test Suites.

Note: Profile Name should always be written inside <id> tag.

Refer below pom.xml to build Maven Profile for each testng.xml file.    https://github.com/PavanReddy77/MavenSurefirePlugin/blob/master/pom.xml

Once Maven Profiles are built for all testng.xml files then we are good to execute from Command Prompt or from Jenkins.

Maven Commands to be followed when executing testng.xml files. 

mvn test –P followed by Maven Profile Id like below:

mvn test –PSmoke     

mvn test –PRegression

Well, we are now good to execute our testng.xml file based on our requirement.

Refer below repository for implementing Maven Surefire Plugin and Maven Profile.  

https://github.com/PavanReddy77/MavenSurefirePlugin

Conclusion: In this blog, we have seen implementing Maven Surefire Plugin and Maven Profile in a Maven Project.

Blog Contributors:

Author:  Pavan K

Pavan, having good knowledge in Selenium Web UI and API Automation frameworks. Also, he is helping QA community with his knowledge along with Naveen AutomationLabs!!

LinkedIn

Reviewer: Naveen Khunteta 

https://www.linkedin.com/in/naveenkhunteta

10. How to create a Mobile automation framework that supports both Android and iOS?

In previous blog, We created a method in our parent class to declare our driver as “AndroidDriver”. Here comes another scenario, suppose I need to automate both iOS and Android application using the same framework.  

 

Is it possible?, How can I do this ?

Please read the blog carefully, this is little tricky in term of understanding the driver, but very easy to implement

How to create a Mobile automation framework supports both Android and iOS?

Nowadays it is common that, most of the applications are being developed for both Android and iOS. So when creating a test framework we need to think and create a flexible and reliable framework for supporting both the applications.

One good thing is that for most of the applications, user flow/architecture will not change based on the Operating system. For example, if you take any application which supports both Android/iOS like “RedBus” or “Linkedin”, you can see that the screens and UI will be same for both OS. May be the look and feel of UI’s can change depends on the SDK’s like XCode/Android studio.

Quick Tip: I suggest you to take a look of few softwares like Xamrin and ReactNative. These softwares are used to create a unique code which executes in both iOS and Android with the help of inbuild SDK libraries.    

Being said that, screens and UI’s are same for both the apps, Our job is now easy to create class and maintain using POM for each screens. Because we can create a single .java file with elements supporting for both iOS and Android. For example,

By android_login_button = By.id("login");
By ios_login_button = By.id("XCUIlogin");

or
AndroidElement button_Login_android = (AndroidElement) driver.findElement(By.id("Login_button"));

IOSElement button_Login ios = (IOSElement) driver.findElement(By.id("XCUIlogin"));

The above example is just for your understanding. We should not create or initiate any elements like this in framework. Do you know why?

Because, consider a page having 50 elements, so we need to declare 50 variables for android and 50 variables for iOS. In total we declared 100 variables in a single java file. Do you think it is easy to manage like this? Also think about the amount of memory we are consuming because of these variables.

So to create a flexible and easily manageable framework we have lot of existing stuffs to declare our variables. For example we can use @FindBy annotations, for example,

@AndroidFindBy(id = "Login")
@iOSXCUITFindBy(id = "XCUILogin")
MobileElement login_Button;

By using @FindBy we can create a common variable for both OS. Remember, “Login_Button” variable is now common for both Android and IOS,

driver instance will automatically detects the identifier based on OS,

If, driver is an AndroidDriver then it will consider @AndroidFindBy.

If driver is IOSDriver, then it will consider @XCUITFindBy.

Did you notice?, “Login_Button” variable is declared as a type “MobileElement”, so in our code no need to use “driver.findElement” or “By” class to declare/identify the UI.

We can directly perform element operations like .click(), .sendKeys() and all other conditions[same like WebElement], For example,

Boolean visible = login_button.isDisplayed();
login_button.click();
String button_text = login_button.getText();

Always remember, Coding is not only about writing and executing the code, we need to give priority for “Best practices” like code Optimization, Memory optimization, lesser LOC etc…  

 

How to Implement and declare driver in our Class?

Now, we are going to see how to create a method in “TestEngine.java” file that handles condition and supports for both iOS and Android.

As I already said, AppiumDriver<?> is a parent class for  “AndroidDriver” and “iOSDriver”. So to make our driver to support both OS, we need to declare our driver as AppiumDriver.

// Initiating Appium Driver
	public static AppiumDriver<?> driver;

Okay, our driver is now “AppiumDriver”, how to assign the “Android” or “iOS” driver to our Appiumdriver?

//driver As an AndroidDriver
driver = new AndroidDriver<AndroidElement>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

//driver As an IOSDriver
driver = new IOSDriver<IOSElement>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); 

Our driver is now compatible to handle both OS. Still confused? Please find sample code below,

package invoiceapp.base;

import java.net.URL;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.BeforeMethod;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.ios.IOSElement;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;

public class OS {
	public static AppiumDriver<?> driver;
	
	@BeforeMethod
	public static void startTest(String platform) {
		if(platform.equalsIgnoreCase("Android")) {
			driver = startAppium_Android();
		} else {
			driver = startAppium_IOS();
		}
		}
	
	/*
	 * This method is used for initiate the AppiumDriver with caps and connection protocol
	 */
	public static AndroidDriver<?> startAppium_Android() {
		// Initializing the Appium driver
		try {
			DesiredCapabilities cap = new DesiredCapabilities();
			cap.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
			cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, "9");
			cap.setCapability(MobileCapabilityType.DEVICE_NAME, "5642c6b9");
			cap.setCapability("appActivity", "com.invoiceapp.InvoiceLaunchScreenAct");
			cap.setCapability("appPackage", "com.invoiceapp");
			cap.setCapability("autoLaunch", false);
			cap.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 500);
			cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
// driver is declared as an AndroidDriver, which supports AndroidElements
			driver = new AndroidDriver<AndroidElement>(new URL("http://127.0.0.1:4723/wd/hub"), cap);
		} catch (Exception e) {
			e.printStackTrace();
		}	
		//Returning the instance of the driver to the parent method
		return (AndroidDriver<?>) driver;
	}
	
	/*
	 * This method is used for initiate the IOSDriver with caps and connection protocol
	 */
	public static IOSDriver<?> startAppium_IOS() {
		// Initializing the Appium driver
		try {
			DesiredCapabilities cap = new DesiredCapabilities();
			cap.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
			cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, "12.0.1");
			cap.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone 8");
			cap.setCapability(MobileCapabilityType.UDID, "3jtn3j4n3ijn3ji4nrj34inrj34nr34nrk");
			cap.setCapability("bundleId", "com.invoiceapp");
			cap.setCapability("autoLaunch", false);
			cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.IOS_XCUI_TEST);
// driver is declared as an IOSDriver, which supports IOSElements
			driver = new IOSDriver<IOSElement>(new URL("http://127.0.0.1:4723/wd/hub"), cap);
		} catch (Exception e) {
			e.printStackTrace();
		}	
		//Returning the instance of the driver to the parent method
		return (IOSDriver<?>) driver;
	}	
}

Note: This is just an example for understanding how to declare both the drivers in same class. Again, in lot of ways we can declare and initiate the drivers. In upcoming blog’s, I will defiantly let you know how to implement this in our “TestEngine.java” file and pass the “platform” parameter from TestNG xml file.

Points to Remember:

  1. We can run both the drivers under same Host but not under same PROXY. Proxy should be unique for both the drivers.
  2. Executing IOS application using Windows machine is not possible, I will share the code for both the drivers, you can check IOS if you have Mac machine
  3. By getting and using the driver instance, we can run both iOS and Android in parallel. I will share the code in future blogs.

 

I’m very excited to create POM. Hope you too, follow us and stay focused…

 

I will commit the codes discussed here in my Github repo. You can clone it and start modifying as per your idea. 

 

 

https://github.com/Karthickragu/Appium_Blog

 

Cheers!

Naveen AutomationLab

Blog Contributors:

Author:  Ragavendran

Ragav, having 10+ years of testing experience on which 7 years of rich experience in automation using UFT, Selenium (Java/Python). Expertise in Web and Mobile automation testing using Appium.

https://www.linkedin.com/in/Ragavendran-Ragav

Reviewer: Naveen Khunteta 

https://www.linkedin.com/in/naveenkhunteta

9. Creating a Framework [Maven project] for Appium – III

We are now in “Configuration section” in our framework creation procedure. So far we have seen and created a maven project, discussed about the folder structure in Maven, Discussed about the importance of Log and config.properties file. Also created a POM file by adding the dependencies.

As a next step we will create a Base file, to access Log and Config.properties.

It’s time to know how a typical framework works with TestNG, What comes first? And how to maintain the flow?

We all know the importance of TestNG annotations and how to use it. Below listed are the most used TestNG annotations,

@BeforeSuite and @AfterSuite

@BeforeTest and @AfterTest

@BeforeClass and @AfterClass

@BeforeMethod and @AfterMethod

@Test

We will see TestNG in a separate session, now let me give you some important tips to understand the usage, this may change as per the design, but in common we can have an understand like this,

@BeforeSuite will execute first and only once in the hierarchy, so we are going to initialize Log4 under this annotation/method. It is must to start the logging as soon as the execution started that’s why log4j is initialized in Beforesuite.

@BeforeTest will execute second and only once in the hierarchy, so we are going initialize “Config.properties” and “WebDriver” under this annotation/method. To get the must needed values for the execution to proceed further.

@BeforeClass will execute third and only once in the hierarchy, so we are going initialize “Pagefactory” and “Data Utility” under this annotation/method.

@BeforeMethod will execute in an iteration with @Test, i.e. once for each test, so we are going to add our prerequisites for testcase here. Example: creating a test in extent report

@Test, here we will add our test case

@AfterMethod: Post processing of test case, example: Flushing the extent report ect.. and rest of the @After we will see while progressing

Creating a Base File:

Base file is an important file in our framework. This acts as a parent class for most of the class files in our framework. Being said that we need to design this carefully and in most efficient way.

Base class holds the initialization of WebDriver, any properties file, reporting and so on, also in this class we are going to implement TestNG annotations like @BeforeSuite, @BeforeTest, @BeforeMethods and @AfterSuite, @AfterTest, @AfterMethods.

Create a package under “src/main/java” and name it as “invoiceapp.base” (our test application name)

Create a new class in the base package and name it as “Testengine”

I just created a Base class now and named as “TestEngine.java” going forward we are going to use the name “TestEngine” instead of Base class for easy understanding., Its time to add TestNG annotations and methods in to TestEngine class.

Since, Log and Config.properties are important and those needs to be initialized first, I’m adding some codes for log4j adn Config.

Just placed our config.properties file under “src/main/resources” with desired capability value so it’s time to configure the file in TestEngine class

Declared Log4j , config.properties and Extent reports. (Complete code is available in the bottom of this page). [skipping to explain code for log4j, Extent report and .properties as we are well aware of these]. If not, please take a look at the videos form Naveen AutomationLabs for better understanding and follow the below code.

Added code for Extent report.

All Set, now we will add our Appium driver in our TestEngine class.

AppiumDriver is a Class with a parent “RemoteWebDriver” having “AndroidDriver” and “iOSDriver” as its direct subclass. It means if we declare our driver as an AppiumDriver we can either initiate it as an AndroidDriver or iOSDriver based on our need.

For executing Android based devices we will use “AndroidDriver<?>”  can be “AndroidElement”

For executing iOS based devices we will use “IOSDriver<?>”  can be “IOSElement”

We have our AppiumDriver declared as a public and static variable, this is because to inherit the properties of this driver in to inherited classes.

We can also declare the driver as “AndroidDriver” instead of “AppiumDriver”, if we are automating only Android devices.

// Initiating Appium Driver
	public static AppiumDriver<?> driver;

Using a method(user defined) startAppium(), we are invoking the AppiumDriver. We are getting the values for our capabilities from Config.properties file.

public static AppiumDriver<?> startAppium() {
 try {
       DesiredCapabilities cap = new DesiredCapabilities();
	// All Capability values are retrieved from Config.properties file.
	cap.setCapability(MobileCapabilityType.PLATFORM_NAME, properties.getProperty("PLATFORM_NAME"));
	cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, properties.getProperty("PLATFORM_VERS"));
	cap.setCapability(MobileCapabilityType.DEVICE_NAME, properties.getProperty("DEVICE_NAME"));
	cap.setCapability("appActivity", properties.getProperty("appActivity"));
	cap.setCapability("appPackage", properties.getProperty("appPackage"));
	cap.setCapability("autoLaunch", false);
	cap.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 500);
	cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);


// Declaring the driver as "Android driver" driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), cap); } catch (Exception e) { driver = null; e.printStackTrace(); } return driver; }

Here for a quick testing of whether Appium driver is initiated properly and it is communicating with Appium Desktop server, I’m using @Test annotation to execute our test.

@Test
public void test001() {
        log.info("Test case started successfully");
	log.info("Trying to launch the Application under Test");
	try{
	 driver.launchApp();
	 log.info("Application launched successfully");
	 }catch(Exception e) {
	     log.info("Unable to launch the application :" +e.getMessage());
         }
 }

Before starting with the execution, Make sure Appium Desktop is running in the background using the host and Port # same as mentioned in the Java code. For example, My Appium Desktop server is running with the Host & port “127.0.0.1:4723”.

If you are running in physical device, make sure the device is connected properly and verify it once with “ADB Devices” command.

Now, we have our localhost listening at “127.0.0.1:4723”. It’s time to run our code as a “TestNG Test”

Verifying the console, Logs and Appium desktop server

Log:

Logs are printed as expected, You can see the driver instance printed in Line: 4

Appium Desktop server logs:

App launched as expected in my Physical device. You can use the same code to run using emulator. (Make sure device name is changed to emulator name). 

CompleteCode:

package invoiceapp.base;

import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.openqa.selenium.remote.DesiredCapabilities;

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;

/***
 * 
 * @author Ragav
 * @date May 10, 2020
 * 
 */

/**
 * 
 * @Usage: This class is used to initiate the Appium Driver and all other
 *         reporting stuffs. All static variables are declared here and
 *         inherited by other classes.
 *
 */

public class Testengine {

	public static Logger log;
	public static ExtentHtmlReporter htmlReporter;
	public static ExtentReports extent;
	public static ExtentTest test;
	public static FileInputStream fInputStream;
	protected static Properties properties;

	// Initiating Appium Driver
	public static AppiumDriver<?> driver;

	/*
	 * This method is used for initializing the Log4j and Config.properties
	 */
	@BeforeSuite
	public static void startSuite() {
		log = Logger.getLogger("devpinoyLogger");
		log.info("Test Started successfully");

		log.info("Initializing the Config.properties file");
		// Path where Config.properties file is placed
		String propertyFilePath = "src//main//resources//config.properties";

		BufferedReader reader;
		try {
			reader = new BufferedReader(new FileReader(propertyFilePath));
			properties = new Properties();
			try {
				properties.load(reader);
				reader.close();
				log.info("Properties file loaded successfully:");
				// Config file is loaded successfully, now with the help of
				// properties.getProperty(key) we can retrieve the value.
			} catch (IOException ioE) {
				ioE.printStackTrace();
			}
		} catch (FileNotFoundException fnfE) {
			fnfE.printStackTrace();
			log.fatal("Unable to find/Load the Properties file ");
			throw new RuntimeException("Configuration.properties not found at " + propertyFilePath);
		}
	}

	

	/*
	 * This method is used for init the Appium Driver and Extent report
	 */
	@BeforeTest
	public static void startTest() {

		// Getting the driver declared using our Capabilities
		try {
			driver = startAppium();
		} catch (Exception e) {
			log.fatal("Driver is not Initiated as Expected" + e.getMessage());
		}
		// LOC for initializing the Extent Report
		log.info("Initializing the Extent Report");
		try {
			log.info("Extent report is available under the directory " + System.getProperty("user.dir") + "/Reports/");
			// starting the HTML report
			htmlReporter = new ExtentHtmlReporter(System.getProperty("user.dir") + "/Reports/testReport.html");
			// To Initialize the reporters
			extent = new ExtentReports();
			// attach only HtmlReporter
			extent.attachReporter(htmlReporter);
			// Providing internal name for the report
			htmlReporter.config().setReportName("Test Report");
			// To create a test case and steps, we need to use reference variable for
			// "ExtentTest" class.
			// This test reference will help us to create test.
			test = extent.createTest("testcase Name");
		} catch (Exception e) {
			log.error("Unable to Initialize the Extent Report" + e.getMessage());
		}
	}


	/*
	 * This method is used for initiate the AppiumDriver with caps and connection protocol
	 */
	public static AppiumDriver<?> startAppium() {
		// Initializing the Appium driver
		try {
			DesiredCapabilities cap = new DesiredCapabilities();
			// All Capability values are retrieved from Config.properties file.
			cap.setCapability(MobileCapabilityType.PLATFORM_NAME, properties.getProperty("PLATFORM_NAME"));
			cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, properties.getProperty("PLATFORM_VERS"));
			cap.setCapability(MobileCapabilityType.DEVICE_NAME, properties.getProperty("DEVICE_NAME"));
			cap.setCapability("appActivity", "com.invoiceapp.InvoiceLaunchScreenAct");
			cap.setCapability("appPackage", "com.invoiceapp");
			cap.setCapability("autoLaunch", true);
			cap.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 500);
			cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);

			// Declaring the driver as "Android driver" with the Host and Port number to communicate with Appium desktop
			driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), cap);
			//Printing the driver details in Log file
			log.info("Driver declared successfully : " +driver);
		} catch (Exception e) {
			driver = null;
			log.fatal("Driver declaration failed : " +driver);
			log.fatal(e.getStackTrace());
		}
		//Returning the instance of the driver to the parent method
		return driver;
	}

	@Test
	public void test001() {
		log.info("Test case started successfully");
		
		log.info("Trying to launch the Application under Test");
		try{
		driver.launchApp();
		log.info("Application launched successfully");
		}catch(Exception e) {
			log.info("Unable to launch the application :" +e.getMessage());
		}
	}

}

Guys, hope now it is clear on the usage of our base (TestEngine) class. In next blog we will see how to inherit the variables from TestEngine class to our child classes and creating a POM for different activies (screens) using AndroidElement and iOSElement. 

I’m very excited to create POM. Hope you too, follow us and stay focused, 

I will commit the codes discussed here in my Github repo. You can clone it and start modifying as per your idea. 

https://github.com/Karthickragu/Appium_Blog

Cheers!

Naveen AutomationLab

Blog Contributors:

Author:  Ragavendran

Ragav, having 10+ years of testing experience on which 7 years of rich experience in automation using UFT, Selenium (Java/Python). Expertise in Web and Mobile automation testing using Appium.

https://www.linkedin.com/in/Ragavendran-Ragav

Reviewer: Naveen Khunteta 

https://www.linkedin.com/in/naveenkhunteta

Steps to Configure Maven Project with Jenkins

Jenkins is an Open Source Continuous integration tool that is written in Java which is often used in Devops.

It is mainly used by Developers and Testers, whenever Developers/Testers does any changes in Source Code then Jenkins will automatically pull the code and continuously build and test code that has been added.           

Step 1: Installing Jenkins War File.

Follow below steps to install Jenkins War File. 

Go to any browser and search by Jenkins Download as shown below and click on  below highlighted link.

After clicking on above highlighted link, you will be navigated to below page.      

Click on “Permalink to the latest” – Latest and Stable version of Jenkins War File will be installed into your local system.

Now you are good to execute your Jenkins War File from Command Prompt.

Step 2: Executing Jenkins War File from Command Prompt.

Create a separate folder in your local system and place Jenkins War file once it is downloaded. Note: We must run Jenkins.war file through Command Line Prompt.

Step 3: Use below command to Run Jenkins.war file

Note:  By default, Jenkins will always run in localhost:8080. Make sure nothing else is running on port 8080. If localhost:8080 is already occupied then you won’t be able to execute Jenkins.war file.                    In such case you can execute your Jenkins.war file in other port using below command.

Once Jenkins is successfully launched, user should be able to see below message in
Command Prompt.

“Jenkins is Fully Up and Running”.

Step 4: Now, go to browser and open localhost:8084 where you have run your Jenkins.               
In my case, I have run Jenkins in port 8084.                                                                            

When launching it for first time, you have to set username and password and install default plug-ins that suggests etc and then you will be landed on to Jenkins Dashboard Page. 

Step 5: Configure your system for Java and Maven in Jenkins as shown below                

Go to Manage Jenkins >> Global Tool Configuration.

Step 6: Install Required Plug-ins >> Go to Manage Jenkins >> Manage Plug-ins and install from Available Section.

Step 7: Create Job >> New Item >> Enter Item Name >> Select Maven Project and Click on OK. After installing all Maven Plug-ins user should be able to see Maven Project Option.

Step 8:                                                                                                                                           A. Go to General >> Enter Description of your Project.

B. Go to Maven Info Plug-in Configuration >> Select None.

C. Go to Source Code Management. [You have to select any one option from it].       

Select None, if you are not using any Source Code Management tool for maintaining Code.

Select Git and provide Repository URL and Branch Name, if you are maintaining code in Git.

D. Go to Build Triggers.                                                                                                      

You can select as shown below, if you are not scheduling jobs using CRON Command and such. [In this case you have to build a job manually].

If you have to schedule jobs automatically, select Build Periodically and use CRON Command. 

If we have to build a job automatically when in any commit happens to Git then we
can select Poll SCM and use CRON Command.                                                                 

[As soon as code commit happens to Git, it will trigger a build].

E. From Build Environment, Select None

F. From Pre Steps, Select None.

G. From Build, Enter Path for your Root POM.xml and command to be executed as shown below.                                                                                                                  
Note: When in giving Maven Command to Run Test Cases in Jenkins, ignore mvn and just give commands as below.                                                                                
clean install Or test Or test -PSmoke etc.

H. From Post Steps, you can select any option as per your requirement.

I. If you want to be notified, when in any job is getting failed then you can select Build Settings and configure it.

Note: To do this we need to do other extra configuration [You can ignore for it now].

J. Post Build Actions can be used to Generate Results. [To achieve it, we need to install required plug-ins like TestNG Plug-in, HTML Report Plug-in for Generating Extent Report]

Below Configurations needs to be done for generating Extent Reports in Project Folder.

Step 9: Apply and Save, now click on Build now to trigger your Job.

Conclusion: In this blog, we have seen how to create a Job for Maven Project, Configuring Job and Executing a Job in Jenkins.


Cheers!!

Naveen AutomationLabs

Blog Contributors:

Author:  Pavan K

Pavan, having good knowledge in Selenium Web UI and API Automation frameworks. Also, he is helping QA community with his knowledge along with Naveen AutomationLabs!!

LinkedIn

Reviewer: Naveen Khunteta 

https://www.linkedin.com/in/naveenkhunteta

JS Alert Popup, Auth Pop Up and File Upload Pop Up Handling in Selenium WebDriver

1.Introduction

In this article, we’re going to illustrate how to handle alert or javascript Popup using selenium WebDriver.

2. Basics

Let’s get started by understanding what are these alerts or javascript popups.

  • Javascript Alert/popup is a notification/warning or message displayed on the User interface in box format to notify the user about some information or asks for permission to perform certain kind of operations.
  • Alert is a method in javascript and  displays an alert box with a specified message and an OK button.
  • what do we need to generate this alert on UI is simply open inspect window and click on console and type alert(“Hi this is an automation User!!”) . 
  • you will be able to see the popup similar to this:

3. Types of Alerts

  1. Simple Alert
  2. Confirmation Alert
  3. Prompt Alert

Let’s have a look at the first one:

Simple Alert:

This alert is called simple alert because it just notifies the user some information or warning with an “OK” or “Close” button as shown in the following image.

  • The above popup can not be handled with finding XPath of OK Button as we can not inspect or spy over this button.
  • So, to handle the above Popup, we need to look at Alert interface of selenium WebDriver

Alert Interface

  • Alert is an interface in selenium provide some methods to handle the alert
  • Syntax:
  • Alert alert= driver.switchTo().alert();
  • To handle the Alert, we first need to switch to alert using switchTo() method.
  • WebDriver interface contains method switchTo() which has return as interface and contains method alert() which has return type as Alert interface. 
  • RemoteAlert class in RemoteWebDriver class implement this Alert Interface
  • For complete code reference, visit over
  • RemoteWebDriver Implementation
  • alert() switches to the alert and return an alert reference and throw “NoAlertPresentException” if no alert exists.
  • Next, Let’s what actions we can perform once we switched to an alert

1.void dismiss(): This method clicks on the ‘Cancel’ button of the alert or dismiss the popup . It returns void.

Syntax:

driver.switchTo().alert().dismiss();

2.void accept(): This method click on the ‘OK’ button of the alert and returns void

Syntax:

driver.switchTo().alert().accept();

3.String getText() : This method captures the alert message and returns the String.

Syntax:

driver.switchTo().alert().getText();

4.void sendKeys(String Text):This method passes some data to alert input text and it returns void 

Syntax:

driver.switchTo().alert().sendKeys(“Text”);

Back to simple alert , let’s see following snippet code

 

Simple Alert

As can be seen, for simple Alert we just need to click on OK button and with one statement by switching to alert and accepting it we can achieve this scenario.

  • Confirmation Alert

  • Confirmation Alert is the alert which asks for confirmation from the user to perform certain actions.
  • User can opt for OK or Cancel button based on the requirements and also we can not inspect over this alert also.
  • Let’s see how it looks like

Following code snippet for the same:

package com.example.automation;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

/**
 * @author Mandeep Kaur
 * @Date 6 May,2020
 */
public class SeleniumConfig {
    public static void main(String[] args) throws InterruptedException {
        String path = System.getProperty("user.dir");
        System.setProperty("webdriver.chrome.silentOutput", "true");
        System.setProperty("webdriver.chrome.driver", path + "/chromedriver");
        WebDriver driver = new ChromeDriver();

        driver.get("https://testuserautomation.github.io/Alerts/");
        driver.findElement(By.xpath("//button[2]")).click();

       Alert alert = driver.switchTo().alert();
       System.out.println(alert.getText());
        //For OK button in alert, accept the PopUp
        alert.accept();
        Thread.sleep(2000);
        WebElement text =driver.findElement(By.xpath("//*[@id='demo']"));
        //verify the text after accepting the popUp
        System.out.println(text.getText());
        driver.close();

    }
}

As shown in the code, we have accepted the alert and verify the text we got after running the above piece of code and we get output similar to:

  • Prompt Alert

  • This Alert is to get input from the user in the form of text.
  • From the above methods, we have to use alert.sendKeys() method to send the text in an alert
  • After entering the input, the user can press the OK or Cancel Button.
  • Let’s prompt Alert on UI

 

prompt Alert

Now , see the code snippet for the same:

package com.example.automation;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;


/**
 * @author Mandeep Kaur
 * @Date 6 May,2020
 */
public class SeleniumConfig {
    public static void main(String[] args) throws InterruptedException {
        String path = System.getProperty("user.dir");
        System.setProperty("webdriver.chrome.silentOutput", "true");
        System.setProperty("webdriver.chrome.driver", path + "/chromedriver");
        WebDriver driver = new ChromeDriver();

        driver.get("https://testuserautomation.github.io/Alerts/");
        driver.findElement(By.xpath("//button[3]")).click();

       Alert alert = driver.switchTo().alert();
       System.out.println(alert.getText());
       //Send Text to the Alert
        alert.sendKeys("TestAutomationUser!!");
        //For OK button in alert, accept the PopUp
        alert.accept();
        Thread.sleep(2000);
        WebElement text =driver.findElement(By.xpath("//*[@id='test']"));
        //verify the text after accepting the popUp
        System.out.println(text.getText());
        driver.close();

    }
}

We can see that here before accepting the Popup, we have sent the “TestAutomationUser” to the alert and verified the text after we accepted the popup and output will be like following

 
 
 
Do we have some other pop ups as well? 
Answer is YESSS…
 
 
Now, there are few other Popups such as Authentication popup and window-based  popup like file Upload , we need to have strong understanding to tackle such popups :
Let’s quickly discuss about Basic Authentication Popup First: 
 
1) Basic Authentication popup : It asks user to enter username and password to the popup  when the browser gets launched and it looks like something :
As can be comprehended from the above snapshot that we need to pass username and password and we can’t spy over this popup.
Let’s look at below code snippet to handle this popup

 

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

/**
* @author Mandeep Kaur
* @Date 6 May,2020
*/
public class SeleniumConfig {
public static void main(String[] args) throws InterruptedException {
String path = System.getProperty(“user.dir”);
System.setProperty(“webdriver.chrome.silentOutput”, “true”);
System.setProperty(“webdriver.chrome.driver”, path + “/chromedriver”);
WebDriver driver = new ChromeDriver();

//send username : admin and password: admin in url before launching the browser
driver.get(“https://admin:admin@the-internet.herokuapp.com/basic_auth”);

//validate if popup is closed successfully and capture the text

WebElement successMessage = driver.findElement(By.xpath(“//div[@class=’example’]//p”));

System.out.println(successMessage.getText());

}
}

It’s pretty clear from the above code that we just need to pass the username and password in the URL and after “@” the complete URL, after that, we can verify the success message, this is how we can achieve our goal.

2) Window-based File Upload popup :

Window-based popup interacts with window operations, selenium doesn’t provide direct support to handle this type of popup  but there is a workaround to operate on such cases. let’s look down to understand this in detail:

Window/ Mac-based popup appears like this once you click on choose file:

Let’s see the code to handle this popup:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

/**
* @author Mandeep Kaur
* @Date 6 May,2020
*/
public class SeleniumConfig {
public static void main(String[] args) throws InterruptedException {
String path = System.getProperty(“user.dir”);
System.setProperty(“webdriver.chrome.silentOutput”, “true”);
System.setProperty(“webdriver.chrome.driver”, path + “/chromedriver”);
WebDriver driver = new ChromeDriver();

//launch the url
driver.get(“https://the-internet.herokuapp.com/upload”);

//inspect over the choose file element and send File from your directory to it
WebElement uploadFile = driver.findElement(By.xpath(“//input[@name=’file’]”));
uploadFile.sendKeys(“/Users/Documents/index.html”);

//click on upload button
driver.findElement(By.xpath(” //input[@class=’button’]”)).click();

//verify the message
WebElement successMessage= driver.findElement(By.xpath(“//div[@class=’example’]//h3”));
System.out.println(successMessage.getText());

driver.close();
}
}

Explanation:

1. We first need to inspect over choose file Button and capture XPath, HTML to look like below where it should have <input> tag and type should be file:

<input id=”file-upload” type=”file” name=”file” xpath=”1″>

 

2. Next, need to send File to upload using sendKeys(String fileNameWithExtension);

3. It will upload the file and we can verify the file is uploaded or not by capturing the success message like following:

4. Conclusion

In this write-up, we have learnt about javascript alerts, a few other types of popups and various ways to handle all these popups.

 

That’s all for this post, hope you have learnt about PopUps 🙂

 

Cheers!!

Naveen AutomationLabs

 

Blog Contributors:

Author:  Mandeep Kaur
Mandeep, having 5+ years of Testing experience in automation using Selenium (Java). Expertise in API and Performance testing using JMeter.
https://www.linkedin.com/in/mandeepkaur93
 
Reviewer: Naveen Khunteta 
https://www.linkedin.com/in/naveenkhunteta

 

Image Resolution Issue in HeadLess Mode

If you have seen this strange issue while running the test in HeadLess mode. You might be getting lower resolution of the images or thumbnail png’s from the site.

Please use below code:

ChromeOptions options= new ChromeOptions();
options.addArguments(“window-size=1400,800”);
options.addArguments(“headless”);
WebDriver driver =  new ChromeDriver(options);

You can also use Dimension class from Selenium:

Dimension dim = new Dimension(width,height)
driver.manage().window().setSize(dim)

Server is checking the headless browser as not needing the higher resolution of the images. This solution will help you to set the widnow-size to “1400,800”. You can try this and take the screenshot of the page. in Headless. You should get higher resolution and clear images.

This is just a small trick 🙂


Cheers!!

Naveen AutomationLabs

.gitingore file for Java projects

Different IDE will create extra files which we really don’t want to push to Git Repo at remote side. So using the .gitignore file in the root folder of your Git repository will ignore files and patterns you have mentioned. 

I have created the git ignore list of famous Java editors like Eclipse, IntelliJ, NetBeans and Visual Studio Code.

##############################
## Java
##############################
.mtj.tmp/
*.class
*.jar
*.war
*.ear
*.nar
hs_err_pid*
##############################
## Maven
##############################
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
pom.xml.bak
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
##############################
## Gradle
##############################
bin/
build/
.gradle
.gradletasknamecache
gradle-app.setting
!gradle-wrapper.jar
##############################
## IntelliJ
##############################
out/
.idea/
.idea_modules/
*.iml
*.ipr
*.iws
##############################
## Eclipse
##############################
.settings/
bin/
tmp/
.metadata
.classpath
.project
*.tmp
*.bak
*.swp
*~.nib
local.properties
.loadpath
.factorypath
##############################
## NetBeans
##############################
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
##############################
## Visual Studio Code
##############################
.vscode/
##############################
## OS X
##############################
.DS_Store

Please comment below, if you want to have more git ignore files extensions. You can also share with other projects based out of JavaScript, NodeJS, Python, .Net etc…

References:

dedunu.info

Cheers!!

Naveen AutomationLabs

Difference between ImplicitlyWait, ExplicitWait and FluentWait in Selenium WebDriver

1.Overview

In this article, we’ll look at the most fundamental mechanism in selenium – synchronisation(wait).

2. Synchronisation in Selenium

  • Synchronisation helps the user to troubleshoot issues when launching or navigating to different web pages while executing the selenium scripts.
  • When the entire web page gets refreshed or elements are getting re-loaded there should be synchronisation between the selenium scripts, script execution speed and web application speed.
  • At times, there can be a lot of Ajax components or some images and when we want to interact with these elements it may not visible. Thus, a time fall back can be seen in such cases and we get an exception as “ElementNotVisibleException“.
  • Selenium doesn’t provide any default synchronisation but it provides synchronisation in the form of different types of waits which we will see below.

3. Different Types of waits in Selenium WebDriver

  • Implicit Wait
  • Explicit Wait
  • Fluent Wait

These waits are dynamic waits. To understand the statement let’s consider a situation when you have given a TimeOut value of 20 seconds. If the element is loaded in 5 seconds, then rest 15 seconds will be ignored.

Let’s have a look at each one of these commands:

  1. Implicit Wait

As per Selenium Documentation, An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance.

  • Implicit wait waits for a certain time till page gets loaded. After setting a particular time web driver will wait for that time before throwing an exception “No Such Element Exception“.
  • Implicitly wait is applied globally, which means it is always available for all the web elements throughout the driver instance.
  • Syntax: driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
  • Implicitly accepts two parameters the first parameter time: 10 given as timeout wait and other is TimeUnit can be given in seconds, minutes, hours days just put dot key after TimeUnit, we can see all the options available.

Implicit Wait
 

So do I need to use Implicitly Wait? Answer is really NO..

Dis-advantages of Implicitly Wait:

  • undocumented and practically undefined behaviour.
  • runs in the remote part of selenium (the part controlling the browser).
  • only works on find element(s) methods.
  • returns either element found or (after timeout) not found.
  • if checking for absence of element must always wait until timeout.
  • cannot be customised other than global timeout.

This list is gathered from observations and reading bug reports and cursory reading of selenium source code.

Let me tell you one thing : <Always use explicit wait. Forget that implicit wait exists>                                              --Naveen Khunteta

2. Explicit Wait

Explicit wait is of two types:

a) WebDriverWait (Class) : 

b) FluentWait (Class)

Both are classes and implements Wait interface.

WebDriverWait class is an extension of FluentWait class. It doesn’t have its own methods.

  • Explicit wait waits for a certain condition till specific element is not loaded.
  • Its implementation is given by WebDriverWait Class in selenium with some expected conditions.
  • This can be useful when certain elements on the webpage are not available immediately and need some time to load for e.g when you click on some submit button after you fill some registration form, then it takes some time in processing and displaying the data on UI.
  • Selenium has its predefined conditions provided in ExpectedConditions class.
  • Below is the syntax to define explicit wait and the expected conditions to be selected based on our needs:

Expected Conditions

So do I need to use Explicit Wait? Answer is YESSSS..

  • documented and defined behaviour.
  • runs in the local part of selenium (in the language of your code).
  • works on any condition you can think of.
  • returns either success or timeout error.
  • can define absence of element as success condition.
  • can customise delay between retries and exceptions to ignore.

Fluent Wait:

As per Official Selenium API Documentation, FluentWait is:

An implementation of the Wait interface that may have its timeout and polling interval configured on the fly.

Each FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition. Furthermore, the user may configure the wait to ignore specific types of exceptions whilst waiting, such as NoSuchElementExceptions when searching for an element on the page.

  • FluentWait is used when we can define the maximum time to wait for a condition, It also defines the frequency with which WebDriver will check if the condition appears before throwing the “ElementNotVisibleException”.
  • We can configure the wait to ignore specific types of exceptions while waiting, such as NoSuchElementException when searching for an element on the page.
  • The fluent wait is a class and an implementation of Wait interface and also parent class of WebDriverWait.
  • We can customise the below apply method to give any conditions based on our specifications.

Syntax:

Let’s below code snippet :

Code for Fluent Wait

package com.example.automation;

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.support.ui.*;
import java.time.Duration;
import java.util.function.Function;

/**
 * @author Mandeep Kaur
 * @Date 2 May,2020
 */
public class SeleniumConfig {
    public static void main(String[] args) {
        String path = System.getProperty("user.dir");
        System.setProperty("webdriver.chrome.silentOutput", "true");
        System.setProperty("webdriver.chrome.driver", path + "/chromedriver");
        WebDriver driver = new ChromeDriver();
        driver.get("https://www.facebook.com/");
        // Create object of WebDriverWait class

        Wait wait = new FluentWait(driver)
                //Wait for the condition
                .withTimeout(Duration.ofSeconds(10))
                //checking for its presenceonce every 5 seconds.
                .pollingEvery(Duration.ofSeconds(5))
                //Which will ignore the Exception
                .ignoring(Exception.class);

        WebElement element = wait.until(new Function<WebDriver, WebElement>() {
            @Override
            public WebElement apply(WebDriver driver) {
                return driver.findElement(By.name("lastname"));

            }
        });
        element.sendKeys("Martin");
    }
}

Explanation:

To put it simply, Fluent Wait looks for a web element repeatedly at regular intervals until timeout happens or until the object is found.

  • The above code defines time out value as 10 seconds and polling frequency as 5 seconds that means for every 5 seconds it keeps on checking for element.
  • It directs WebDriver to wait for a maximum of 10 seconds to verify a specific condition. If the condition occurs during those 10 seconds, it will perform the next step in the test script. If not, it will throw an “ElementNotVisibleException”.

So when should I use FluentWait?

  • When you do not see suitable expected wait condition in explicit wait.
  • To handle dynamic AJAX web elements with polling mechansim
  • You need to do more than just waiting along with Polling Mechanism, IgnoredException and when you want to create your own custom wait condition (in apply method) for non WebDriver use cases as well.
So can I use FluentWait features like, polling interval, ignoreAll with WebDriverWait? 
Ans
: Yes, of course you can do that, as I have explained earlier WebDriverWait is child class of FluentWait, so it has access on all parent class public methods.

Refer this WebDriver API on GIT:

https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/support/ui/FluentWait.java

Final Conclusion:

a. Wait is an Interface in Selenium and having only one method declaration:

public interface Wait {

until(Function<? super F, T> isTrue);

}

b. FluentWait is a class which is implementing Wait Interface, it’s having its own methods shown above and overridden until() method from the wait Interface. 

public class FluentWait implements Wait<T> { }

c. WebDriverWait is extending FluentWait class but has no methods init except one overridden method, that is: timeoutException(){}.

WebDriverWait can use all the methods of FluentWait class – pollingEvery(), withMessage(), ignoreAll etc..

FluentWait can be used for both WebDriver and non WebDriver use cases. It just needs a condition – waitForCondition.

3. Concept of Thread.sleep()

  • It is a static wait and execution of the scripts will be on hold till specified time configured in the function.
  • Thread is a class in JAVA and sleep is static method.
  • sleep() methods accept duration in milliseconds. ( 1 s= 1000 ms).
  • It throws  IllegalArgumentException – if the value of ms is negative.
  • sleep() throws a checked exception which we must either throw or handle it using try catch like done below
  • Syntax:

try{
Thread.sleep(5000);
}
catch(InterruptedException e){
}

Note: it’s never a good idea to use thread.sleep () as unlike dynamic waits it will wait for the entire time configured in the function till the element gets loaded.

4. PageLoadTimeOut & SetScriptTimeOut property

PageLoadTimeOut

  • PageLoadTimeOut is focused on the time a webpage needs to be loaded – the page load timeout limits the time that the script allows for a web page to be displayed.
  • If the page loads within the time, then the script continues. If the page does not load within the timeout the script will be stopped by a TimeoutException.
  • The timeout is set at the driver level. After creating the driver instance with the appropriate driver capabilities.
  • Syntax :

   driver.manage().timeouts().pageLoadTimeout(2, TimeUnit.SECONDS);

SetScriptTimeOut

  • From WebDriver documentation: setScriptTimeout(long time, java.util.concurrent.TimeUnit unit) sets the amount of time to wait for an asynchronous script to finish execution before throwing an error.
  • This works only for Async scripts (executeAsyncScript: calls which takes some time to respond back)
  • Syntax:

driver.manage().timeouts().setScriptTimeout(1, TimeUnit.SECONDS);

5. Conclusion:

In this article , we learnt about the various waits in selenium WebDriver.

Some References taken from:

 
Blog Contributors:
Author:  Mandeep Kaur
Mandeep, having 5+ years of Testing experience in automation using Selenium (Java). Expertise in API and Performance testing using JMeter.
https://www.linkedin.com/in/mandeepkaur93
 
Reviewer: Naveen Khunteta 
https://www.linkedin.com/in/naveenkhunteta
« Older posts Newer posts »