Where we learn technology

Month: June 2020

Configuring Email Notification in Jenkins

In this blog, let’s learn setting up Email Notification in Jenkins.

In real time, we build jobs periodically for Jobs that we create in Jenkins. As and when job is completed, if we want to be notified to know about job execution status [Success or Failure or Unstable] then it is a good feature to be added into Jenkins Job Configuration.

To achieve Email Notification in Jenkins, now let’s see how can we do it.

We need to install below plugins:

1. Email Extension Plugin.                                                           

2. Email Extension Template Plugin.

Go to Jenkins Dashboard.                                                         

1. Click on Manage Jenkins.                                                     

2. Click on Manage Plugins. 

In Manage Plugins, go to Available section and search by “Email” and install suggested email plugins related to Email Notification that are Email Extension Plugin and Email Extension Template Plugin.

In my case, as Email Extension and Email Extension Template Plugins are already installed, both plugins are appearing in installed section.

Once plugins are installed, then we are good to configure job for Email Notifications in Jenkins.

Let’s now see configuring job for Email Notifications in Jenkins after plugins are installed.

Go to Manage Jenkins.

Click on Configure System.

Scroll down to E-mail Notification in Configure System Section.

 

Follow above simple steps to do Email Notification Configuration.

Here I’m using Gmail for achieving Email Notification in Jenkins.   

1. SMTP server – For gmail, it is mandatory to provide as smtp.gmail.com.                                                                     

2. Use SMTP Authentication should be checked – Only then we should be able to see User Name and Password sections.             

3. Provide your Gmail Credentials in User Name and Password Fields. 

4. Use SSL should be checked.

5. Give SMTP Port Number as 465. [If 465 doesn’t work for you, try with 587]

Once setup is done for Email Notification.

Let’s do Test Configuration by Sending Test Email.

Once Test configuration by sending test e-mail is Checked, you should be able to see Test e-mail recipient option as shown below.

Now enter Gmail ID to which you want to send out a Test Mail and click on Test Configuration. 

If everything configured as expected then a Test Mail to should be triggered into given Gmail ID and followed message should be displayed “Email was successfully sent” as shown below.

Test E-Mail Recipient could be any Gmail ID – Now you can Check for Test Mail in Given Mail Account.

If in case, Test Configuration is Failed.                                        Go to your Gmail Account for which Email Notification was configured.             

Click on Security.                                                                   

Now Go to Less secure app access and Allow Turn on Access to Less secure app access. [By default it should be selected to Off]

Now Go to Manage Jenkins.                                                    

Click on Configure System.                                                  

Scroll down to Extended E-mail Notification in Configure System Section.     

Enter all Required Fields as shown in below Screenshots.

Note:

In Extended E-mail Notification section, you just need to provide SMTP server details as smtp.gmail.com.   

Do not change anything from Default Subject and Default Content Fields that are suggested by Jenkins. 

Now Click on Apply and Save.

Wow, now we are all set to use Email Notification Feature in Jobs.

Now go to Jenkins Job. 

Click on Configure. 

 Go to Build Settings section and provide Email IDs as shown below to which Email Notifications has to be sent.

Note:

Here Email Notifications will be sent only and only for Unstable and Failed Builds.

Surprise:   

 If you want to achieve Email Notification through Jenkins Pipeline. Follow below simple steps.       

 1. Configurations for E-mail Notification and Extended E-mail Notification should be done in Configure System section. 

2. Add below code inside Jenkins Pipeline Step.

stage('Gmail')
{
	steps
	{
		emailext body: "*${currentBuild.currentResult}:* Job Name: 
                ${env.JOB_NAME} || Build Number: ${env.BUILD_NUMBER}\n More 
                information at: ${env.BUILD_URL}",
		subject: 'Declarative Pipeline Build Status',
		to: 'Pavankrishnan1993@gmail.com'
	}
}

Above code will send a Mail with followed information as below:

1. emailext body:     

A. Current Build Status [Success or Failure or Unstable]. 

B. Job Name as specified in Jenkins Job.

C. Build Number that is executed in Jenkins.   

2. Subject: In this section, you can provide Subject name as per your Requirement.       

3. to: In this section, you can provide Mail IDs to which Email Notification should be sent.

Note: 

The above code can be used in different steps for Job Success, Failure or Unstable..!!

Conclusion: In this blog, we have seen how can we configure Email Notification in Jenkins for Jobs with simple steps for Builds and Pipeline.

Cheers!

Naveen AutomationLabs

13. Implementing Page Factory in Appium based Framework


In our previous blog we have seen how to create a POM and with the help of POM and TestNG we executed our first test case in our Appium automation framework. Now we are taking our next step in the ladder that is “Page Factory”.

We all knows that POM is a pattern or style in other words it acts like a “Object Repository” i.e.  Declaring a Page and page objects/elements in our java class. Page Factory is also same like POM but in addition it comes with lot of predefined notations and attributes to help the automation tester to initiate or declare an element in more standard and robust way.

Let me show an example of POM and Page Factory for better understanding,

Imagine, I have a Login test case to be executed and using POM I have a Login class which is having the below method,

Public void verify_Login() {
//my code goes here
}

Using the above method, my intension is to verify login functionality using a valid username and Password. For this I can go with 4 types of approaches,

  1. Without defining the Locator and Locator strategy as a variable seperately, instead directly implementing the locator in driver.findElement() method.

public void verify_Login() {		 
    driver.findElement(MobileBy.AccessibilityId("username")).sendKeys("Admin");		 
    driver.findElement(MobileBy.AccessibilityId("password")).sendKeys("Admin123");
    driver.findElement(MobileBy.AccessibilityId("login_button")).click();
}

2. Defining the Locator and Locator strategy as a “String” variable

String loc_Username = "username";
String loc_Password = "password";
	
public void verify_Login() {		 
    driver.findElement(MobileBy.AccessibilityId(loc_Username)).sendKeys("Admin");		 
    driver.findElement(MobileBy.AccessibilityId(loc_Password)).sendKeys("Admin123");
    driver.findElement(MobileBy.AccessibilityId("login_button")).click();
}

3. Defining the Locator using “By” variable (‘By’ from selenium or ‘MobileBy’ from Appium using POM)

public static By loc_Username = MobileBy.AccessibilityId("username");
	public static By loc_Password = MobileBy.AccessibilityId("password");
	public static By loc_login_btn = MobileBy.AccessibilityId("login_button");
	
	public void verify_Login() {
		driver.findElement(loc_Username).sendKeys("Admin");
		driver.findElement(loc_Password).sendKeys("Admin123");
		driver.findElement(loc_login_btn).click();
	}

4. Defining each Locator directly as a “MobileElement“ with the help of Page Factory. This is what we gonna see in this session.

We have already covered till point #3 in our previous blogs, in this blog we will see point #4 which is nothing but Page Factory model.

I will give you a sample code snippet below for Page Factory to discuss and for better understanding

public class LoginPage_PF extends Testengine {
	
	private AppiumDriver<?> driver;
	
	public LoginPage_PF(AppiumDriver<?> driver) {
		this.driver = driver;
		PageFactory.initElements(new AppiumFieldDecorator(driver), this);
	}	
}

In the above code, it is very clear that we have a Constructor and using this keyword we are declaring the driver. What is the next line means?

PageFactory.initElements(new AppiumFieldDecorator(driver), this);

This is the point we initiated the Page Factory. Here PageFactory is a class which is having a static method “public static <T> T initElements(WebDriver driver, Class<T> pageClassToProxy)” this method is used to initiate the driver instance of a given class and which will return an instantiated instance of the class with WebElement.

AppiumFieldDecorator() which is one of an overridden constructor of the class “AppiumFieldDecorator”. This constructor is used to decorate/initiate each mobile element directly as a “MobileElement” variable.

In combination of PageFactory.initElements and AppiumFieldDecorator we can initiate a variable/element with the help of @FindBy annotations.

Remember, one of the main advantage using Page Factory is declaring locators/elements directly as a “MobileElement”. To do so it is important to initiate the driver as soon as the class is invoked this is one of a main reason why we are initiating page factory in Constructor.

Quick Hint: “this” keyword is a reference variable which refers to the current object, so instead of using this keyword in the below line, we can directly mention the class name as well.

PageFactory.initElements(new AppiumFieldDecorator(driver), this);
 Or
 PageFactory.initElements(new AppiumFieldDecorator(driver), LoginPage_PF.class);

Quick Hints:

  1. “PageFactory” class comes from the package “org.openqa.selenium.support”.
  2. “AppiumFieldDecorator” comes from the package “io.appium.java_client.pagefactory.”
  3. Any @ notations are internally referring to interfaces
  4. It is always a good practice to comment for each element or for a group of elements about its usage and how to use.

Tips: There is another ways of initiating PageFactory, is while creating an instance of the page, for example

LoginPage_PF login = PageFactory.initElements(driver, LoginPage_PF.class)

It is up to you to select any one of these ways in your framework.

Hope we are clear with the Constructor and initElements parts, Let’s move to Page Factory Annotations

What are Page Factory Annotations?

Page Factory annotations are used to provide the way of finding a MobileElement. Also it will make the user feel the code more readable and understandable.  

       @FindBy() is one of an annotation which helps user to declare a WebElement

Quick Hint: We are telling ‘@’ special key as an annotation, actually it is an interface with @infront. Example: public @interface Test, public @interface FindBy.   

About @FindBy in java docs

@FindBy is used to find and initiate WebElements, and to define MobileElements we need to use annotations like  @iOSXCUITFindBy and @AndroidFindBy

@iOSXCUITFindBy is used to declare variable as “IOSElement” which is for Apple idevices

@AndroidFindBy is used to declare variable as “AndroidElement” which is for Android based devices

List of locators available for @iOSXCUITFindBy

List of locators available for @AndroidFindBy

Sample code snippet below on @FindBy

@AndroidFindBy(id = "username")
 AndroidElement loc_Username_android;

 @iOSXCUITFindBy(accessibility = "username")
 AndroidElement loc_Username_ios;

Here, we are instructing Appium to use @AndroidFindBy to find an element using the strategy “id” and look for the text “username” in DOM, same for @iOSXCUITFindBy

Hence we already initialized our variable as a MobileElement, no need to use driver.findElement() method every time to access any element, instead we can directly use the variable name followed by selenium/Appium operations to be performed, for example

loc_Username_android.sendKeys(“Admin”);

Cool right!!! the background is, “driver.findElement(By.ID(“username”))” will convert any given locator as a MobileElement/WebElement in runtime and uses the selenium/Appium operations like click(), sendKeys() etc.. Since we already declared our variables as a MobileElement no need to use the findElement() method.

Please find below for the code snippet, which includes explicit wait just to let you know how to use the MobileElement.

package com.invoiceapp.pages;

import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import invoiceapp.base.Testengine;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;

public class LoginPage_PF extends Testengine {
	
	protected AppiumDriver<?> driver;
	public WebDriverWait wait;
	
	
	/**
	 * Constructor with a parameter 
	 * @param driver as an instance of AppiumDriver<?>
	 */
	public LoginPage_PF(AppiumDriver<?> driver) {
		this.driver = driver;
		PageFactory.initElements(new AppiumFieldDecorator(driver), this);
	}
	
	// Looking for the text field "Username" in Login page
	@AndroidFindBy(id = "username")
	AndroidElement loc_Username_txt;

	// Looking for the text field "Password" in Login page
	@AndroidFindBy(id = "password")
	AndroidElement loc_Password_txt;
	
	// Looking for the Button field "Username" in Login page
	@AndroidFindBy(id = "login_button")
	AndroidElement loc_login_btn;
	
	public void verify_Login() {
		wait = new WebDriverWait(driver, 10);
		wait.until(ExpectedConditions.visibilityOf(loc_Username_txt));
		loc_Username_txt.sendKeys("Admin");
		
		wait.until(ExpectedConditions.visibilityOf(loc_Password_txt));
		loc_Password_txt.sendKeys("Admin123");
		
		wait.until(ExpectedConditions.visibilityOf(loc_login_btn));
		loc_login_btn.click();
	}

}

Hope we are very clear till this level. Now the question comes, How to call this class from our Test class?

Okay, so we are using constructor in our Page class i.e. “PageFactory_Example” which expect an argument to be passed. Please find the code below to understand how to pass the driver as an argument for the PageFactory_Example.class

package test;

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.invoiceapp.pages.LoginPage_PF;
import invoiceapp.base.Testengine;

public class PageFactoryTest extends Testengine {
	
	public static LoginPage_PF login;
	
	@BeforeClass
	public static void initiateDrivers() {
		// Passing the driver as an argument to LoginPage_PF constructor 
		login = new LoginPage_PF(driver);
	}

	@Test
	public void test_TC001_verifyAppLaunch() {		
		login.verify_Login();
	}
}

That’s all folks!!! We are now good to go with the PageFactory model in our framework. In our next blog we will see how to create a separate class for PageFactory and to get the instance of that to initiate all our elements instead of initiating everytime in our Page classes.

Also we will see how to utilize Page Factory annotations to define a MobileElement in such a way it which works for both Android and iOS, also how to create a common method for both OS, and few additional topics around Page Factory annotations like @CatcheLookup and using “how” keyword ect..

Stay focused!!!

Note: Whatever code used here are basic level and its only to understand the concept of Page Factory. We are not going to use the same code in our Framework. In our next blog I will definitely demonstrate the same using our AUT.

Hope this helps understanding the concept of Page Factory. Please post your suggestion or questions in comments sections if you have any.


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

12. Executing Test case in Appium with POM

Guys, we are half a way done with our framework creation process. So far we have implemented below operations in our framework,

  1. Created a Maven project and added our dependency jars in POM
  2. Created a Base file (Testengine.java) and initiated logs, Extent report and AppiumDriver
  3. Created Pages for our mobile screens using POM method
  4. We have also seen how to add our mobile elements using MobileBy class

In this session, we are going to use all the operations mentioned above, i.e. creating a test case for our Android application and running the same. While test case is running we will capture the test logs and add the test steps in our Extent report with the help of TestNG Listeners. Going to cover pretty much in this session so please stay focused.

Guys I’m not going to focus on loggers, Extent report etc.., as we have already seen enough in our previous blogs. Please use our video tutorial to refresh your skill on reporting and also for easy understanding. 

First things first, we will define our test strategy.

What we are going to do now? Since our Base class and POM are done (please refer previous blog)

  1. Creating a new package under the folder “src/test/java” and name it as “tests”
  2. Under the test package, we will create a new java file and name it as “SmokeTest.java”
  3. In the “SmokeTest.java” file we will implement the ITestListener interface
  4. See how and where to use the ITestListener methods in our test class
  5. Create our first Test case and run the same

All set.. Time to launch….

Create a new package under the folder “src/test/java” and name it as “tests” and under the test package, create a new java file and name it as “SmokeTest.java”

In the “SmokeTest.java” file we will implement the ITestListener interface and implements all the unimplemented methods

Once all the unimplemented Methods are added, our “SmokeTest.java” file will look like this,

Listener interface is especially for “@Test” method, so it will allow us to have all our pre-requisites and post processing activities in our Listener Methods.

For example,

In the “public void onTestStart” method, I can have all the prerequisite of my Test case, because it will execute before @Test annotation. [Please don’t confuse with @BeforeMethod] both are different

I can set all the activities for my Test case in case of failure on the “public void onTestFailure” method.  Ex, Screenshot capturing, adding a failed step in our report and log ect…

Please go through our ITestListener tutorials for more ideas

Quick hint: It is not mandatory to add Listeners in the same class where our @Test methods are available, we can also have a different and dedicated class for Listeners as well. [This can be achieved using TestNG xml file]

Remember: We have Implemented @BeforeTest , @BeforeTest and @BeforeMethod in our Testengine class. Below for reference. @BeforeMethod will open the app(AUT) and makes the app ready for our test case.

package invoiceapp.base;

import org.testng.annotations.BeforeMethod;
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.By;
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.ios.IOSDriver;
import io.appium.java_client.ios.IOSElement;
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;
	}

	@BeforeMethod
	public static void openApp() {
		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());
		}
	}
	

}

Now to initiate the AndroidDriver before our @BeforeMethod, I have added @BeforeClass in our SmokeTest.java file. This is just to make sure our driver is initiated and a new instance has been created properly before executing @BeforeMethod or @Test.

Quick hint: It is not necessary to add all the @Before and @After (methods/annotations) in the same class, based on our needs we can have it in different class as well. Please find the code below,

Hope it is clear till now, as I said we need to add our POM logic in this test case, to do so we have another package called “pages” where we have a class called “Company_Setup” with POM right, now it’s time to initiate that class using constructor.

We all know the use of Constructor in a class. For quick reference,

  1. Constructor is a default method of a class,
  2. Constructor will be executed first whenever an instance/reference has been created for a class
  3. If no constructor defined manually, a default hidden constructor will be created by JVM to execute the class. etc….

So using constructor in “Company_Setup” class we can define our Driver which will be applicable for all methods inside the class.

I’m going to add a local variable for Driver and declare it inside the constructor. Code below,

Quick hint: If driver is not declared/initiated properly we will get a “NullPointerException” 😊

Since “Company_Setup” accepts a driver as an input, we need to initiate “Company_Setup” class and pass the driver from @BeforeClass method. Simple right, code below.

Public static Company_Setup com_Setup;
@BeforeClass
	public static void initiateDrivers() {
		com_Setup = new Company_Setup(driver);
	}

Now, we are going to add test steps in our @Test method using the “com_Setup” reference to access the Company_Setup class. Like below

This looks good, but not perfect because this will simply execute the test case and we cannot make sure on the test case test case status because there is no test conditions applied. We all know without “Assert” a test case never be fulfilled.

Time to add Assert in our test case, There are lot of methods to verify and Assert a condition, here I’m going to use a classical way of Assertion. i.e. In our POM classes under method I’m gonna add a try/Catch block to execute a test case like below, (it’s a classical way found in most of the Old frameworks)

package com.invoiceapp.pages;

import org.openqa.selenium.By;

import invoiceapp.base.Testengine;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileBy;
import io.appium.java_client.android.AndroidDriver;

public class Company_Setup extends Testengine {
	
	public AppiumDriver<?> driver;
	public static Boolean assertion = false;

	public Company_Setup(AppiumDriver<?> driver) {
		this.driver = driver;
	}
	
	// Variables are declared as static to access directly in methods
	static By addLogo = MobileBy.id("frag_obup_RlAddCompLogo");
	static By addSignature = MobileBy.id("frag_obup_RlAddSignature");


	public Boolean clickOnLogobutton() {
		assertion = false;
		try {
			driver.findElement(addLogo).click();
			assertion = true;
			log.info("Add Logo, button clicked successfully");
		} catch (Exception e) {
			assertion = false;
			log.error("Unable to click on the Add Logo button, " + e);
		}
		return assertion;
	}

	public Boolean clickOnSignaturebutton() {
		assertion = false;
		try {
			driver.findElement(addSignature).click();
			assertion = true;
			log.info("Add Logo, button clicked successfully");
		} catch (Exception e) {
			assertion = false;
			log.error("Unable to click on the Add Logo button, " + e);
		}
		return assertion;
	}
}

Since methods are returning Boolean values and to capture the result of each method, we can make an Assert in our test case like below,

package test;

import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.invoiceapp.pages.Company_Setup;

import invoiceapp.base.Testengine;

public class SmokeTest extends Testengine implements ITestListener {
	
	public static Company_Setup com_Setup;
	
	@BeforeClass
	public static void initiateDrivers() {
		com_Setup = new Company_Setup(driver);
	}

	@Test
	public void test_TC001_verifyAppLaunch() {		
		Assert.assertTrue(com_Setup.clickOnLogobutton());
		Assert.assertTrue(com_Setup.clickOnSignaturebutton());
	}

	public void onTestStart(ITestResult result) {
		log.info("Test case started successfully");
		log.info("Trying to launch the Application under Test");
	}

	public void onTestSuccess(ITestResult result) {
		// TODO Auto-generated method stub

	}

	public void onTestFailure(ITestResult result) {
		// TODO Auto-generated method stub

	}

	public void onTestSkipped(ITestResult result) {
		// TODO Auto-generated method stub

	}

	public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
		// TODO Auto-generated method stub

	}

	public void onStart(ITestContext context) {
		// TODO Auto-generated method stub

	}

	public void onFinish(ITestContext context) {
		// TODO Auto-generated method stub

	}

}

A proper test case has been added in the @SmokeTest.java file  and now we can able to execute it as a “TestNG Test”.

Guys, whatever illustrated here is a common way of adding and executing a test case. There are still plenty of ways to do this. Please elaborate your knowledge by thinking in different angles and try to put your own thoughts. We are here to help you.

Execute the scripts and add your comments, eager to see the results.

In our next blog, we will see how to implement “PageFactory” and create a common methods using POM for both Android and iOS.

I’m using the AUT version 1.10.82 committed the same in my git repo. Please download and use the app if you have any plan to clone code from my git repo.

Points to Remember:

  1. ITestListener is an interface which extends ITestNGListener
  2. Another popular interface is there called “ITestResult”
  3. @Test is a testNG annotation, not a method(I mentioned as methods in blog just for your understanding)
  4. Soft Assert and Hard Assert are two types are asserts available
  5. Some times Assert and few annotations can be driven from JUnit make sure to import the proper TestNG package
 

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

NoSuchElementException and NotFoundException in Selenium || Common Exceptions in Selenium

There is no ElementNotFoundException as such in selenium, if you are talking in #Selenium context. We have NotFoundException which is extended by :
Direct Known Subclasses as:
NoAlertPresentException, NoSuchCookieException, NoSuchElementException, NoSuchFrameException, NoSuchWindowException

Please refer this Java API Doc: https://jar-download.com/artifacts/org.seleniumhq.selenium/selenium-api/3.141.59/documentation

NoSuchElementException extends NotFoundException” 

and 

NotFoundException extends WebDriverException“. 

This is thrown when???
1. Element could not be found in the DOM – or may it never. exists.
2. The page is still being loaded and you’ve already finished your WebElement search
3) AJAX Element has not returned yet on the page

If you encounter this exception, you may want to check the following:
>Check your selector used in your find_by…
>Element may not yet be on the screen at the time of the find operation, (webpage is still loading) apply WebDriverWait() for an element to be appeared on the page. 

Exceptions that may happen in all the webdriver code.

Common Exceptions in Selenium:

exception selenium.common.exceptions.ElementClickInterceptedException

(msg=Nonescreen=Nonestacktrace=None)[source]

The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested clicked.

exception selenium.common.exceptions.ElementNotInteractableException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when an element is present in the DOM but interactions with that element will hit another element do to paint order

exception selenium.common.exceptions.ElementNotSelectableException (msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when trying to select an unselectable element.

For example, selecting a ‘script’ element.

exception selenium.common.exceptions.ElementNotVisibleException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when an element is present on the DOM, but it is not visible, and so is not able to be interacted with.

Most commonly encountered when trying to click or read text of an element that is hidden from view.

exception selenium.common.exceptions.ErrorInResponseException

(responsemsg)[source]

Thrown when an error has occurred on the server side.

This may happen when communicating with the firefox extension or the remote driver server.

exception selenium.common.exceptions.ImeActivationFailedException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when activating an IME engine has failed.

exception selenium.common.exceptions.ImeNotAvailableException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when IME support is not available. This exception is thrown for every IME-related method call if IME support is not available on the machine.

exception selenium.common.exceptions.InsecureCertificateException

(msg=Nonescreen=Nonestacktrace=None)[source]

Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate.

exception selenium.common.exceptions.InvalidArgumentException

(msg=Nonescreen=Nonestacktrace=None)[source]

The arguments passed to a command are either invalid or malformed.

exception selenium.common.exceptions.InvalidCookieDomainException 

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when attempting to add a cookie under a different domain than the current URL.

exception selenium.common.exceptions.InvalidCoordinatesException

(msg=Nonescreen=Nonestacktrace=None)[source]

The coordinates provided to an interactions operation are invalid.

exception selenium.common.exceptions.InvalidElementStateException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when a command could not be completed because the element is in an invalid state.

This can be caused by attempting to clear an element that isn’t both editable and resettable.

exception selenium.common.exceptions.InvalidSelectorException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when the selector which is used to find an element does not return a WebElement. Currently this only happens when the selector is an xpath expression and it is either syntactically invalid (i.e. it is not a xpath expression) or the expression does not select WebElements (e.g. “count(//input)”).

exception selenium.common.exceptions.InvalidSessionIdException

(msg=Nonescreen=Nonestacktrace=None)[source]

Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it’s not active.

exception selenium.common.exceptions.InvalidSwitchToTargetException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when frame or window target to be switched doesn’t exist.

exception selenium.common.exceptions.JavascriptException

(msg=Nonescreen=Nonestacktrace=None)[source]

An error occurred while executing JavaScript supplied by the user.

exception selenium.common.exceptions.MoveTargetOutOfBoundsException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when the target provided to the ActionsChains move() method is invalid, i.e. out of document.

exception selenium.common.exceptions.NoAlertPresentException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when switching to no presented alert.

This can be caused by calling an operation on the Alert() class when an alert is not yet on the screen.

exception selenium.common.exceptions.NoSuchAttributeException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when the attribute of element could not be found.

You may want to check if the attribute exists in the particular browser you are testing against. Some browsers may have different property names for the same property. (IE8’s .innerText vs. Firefox .textContent)

exception selenium.common.exceptions.NoSuchCookieException

(msg=Nonescreen=Nonestacktrace=None)[source]

No cookie matching the given path name was found amongst the associated cookies of the current browsing context’s active document.

exception selenium.common.exceptions.NoSuchElementException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when element could not be found.If you encounter this exception, you may want to check the following:

  • Check your selector used in your find_by…
  • Element may not yet be on the screen at the time of the find operation, (webpage is still loading) see selenium.webdriver.support.wait.WebDriverWait() for how to write a wait wrapper to wait for an element to appear.

exception selenium.common.exceptions.NoSuchFrameException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when frame target to be switched doesn’t exist.

exception selenium.common.exceptions.NoSuchWindowException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when window target to be switched doesn’t exist.

To find the current set of active window handles, you can get a list of the active window handles in the following way:

exception selenium.common.exceptions.RemoteDriverServerException

(msg=Nonescreen=Nonestacktrace=None)[source]

exception selenium.common.exceptions.ScreenshotException

(msg=Nonescreen=Nonestacktrace=None)[source]

A screen capture was made impossible.

exception selenium.common.exceptions.SessionNotCreatedException

(msg=Nonescreen=Nonestacktrace=None)[source]

A new session could not be created.

exception selenium.common.exceptions.StaleElementReferenceException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when a reference to an element is now “stale”.

Stale means the element no longer appears on the DOM of the page.Possible causes of StaleElementReferenceException include, but not limited to:

  • You are no longer on the same page, or the page may have refreshed since the element was located.
  • The element may have been removed and re-added to the screen, since it was located. Such as an element being relocated. This can happen typically with a javascript framework when values are updated and the node is rebuilt.
  • Element may have been inside an iframe or another context which was refreshed.

exception selenium.common.exceptions.TimeoutException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when a command does not complete in enough time.

exception selenium.common.exceptions.UnableToSetCookieException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when a driver fails to set a cookie.

exception selenium.common.exceptions.UnexpectedAlertPresentException

(msg=Nonescreen=Nonestacktrace=Nonealert_text=None)[source]

Thrown when an unexpected alert is appeared.

Usually raised when when an expected modal is blocking webdriver form executing any more commands.

exception selenium.common.exceptions.UnexpectedTagNameException

(msg=Nonescreen=Nonestacktrace=None)[source]

Thrown when a support class did not get an expected web element.

exception selenium.common.exceptions.UnknownMethodException

(msg=Nonescreen=Nonestacktrace=None)[source]

The requested command matched a known URL but did not match an method for that URL.

exception selenium.common.exceptions.WebDriverException

(msg=Nonescreen=Nonestacktrace=None)[source] vBase webdriver exception.

 

Reference taken from: 

https://www.selenium.dev/selenium/docs/api/py/common/selenium.common.exceptions.html

Cheers!!

Naveen AutomationLabs