Planet Jaspersoft

September 13, 2022

This post outlines about - how to integrate Extent Report for cucumber 7 that is integrated with TestNG, Selenium Java and Maven. 

You can clone the complete example from this GitHub repo or down load the zip archive file here

This code has two cucumber scenarios independent of each other but uses the same Background in the feature files. And, I've deliberately failing these scenarios to view the screen shot attachments in Extent Report(Spark Report). 
Update this piece of yellow highlighted string from this statement in HRMLoginPage.java so both the scenarios will get succeeded. 

driver.findElement(By.xpath("BAD//body/div[@id='app']/div[1]/div[1]/div[1]/div[1]/div[2]/div[2]/form[1]/div[1]/div[1]/div[2]/input[1]")).sendKeys(cells.get(0).get(0));



You could also refer this no voice video walkthrough tutorial. 

NOTE :
The best practice is to keep the code under src/test/java or src/test/resources but this makes hard to have the executable jar crated, so code should reside under src/main/java or src/main/resources. 

Project outline:



Step 1: Add the following dependency to the pom.xml file
<dependency>
<groupId>tech.grasshopper</groupId>
<artifactId>extentreports-cucumber7-adapter</artifactId>
<version>1.7.0</version>
</dependency>

Step 2 :  Add the extent cucumber adapter as plugin in the @CucumberOptions
 Cucumber options are normally given in the Cucumber Test Runner class, for instance in RunCucumberTest. java

plugin = { "pretty", 
"json:target/cucumber-reports/cucumber.json",
"html:target/cucumber-reports/cucumberreport.html",
"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"},

 Step 3 : Create extent.properties file in src/main/resources and add below properties
extent.reporter.spark.start=true 
extent.reporter.spark.out=target/SparkReport/Spark.html
screenshot.dir=target/screenshots/
screenshot.rel.path=../screenshots/

If we want to generate the extent report(say Spark report)  in an executable jar file, add the plugin in main method as shown in below BasePage.java. 
When run the cucumber scenarios from jar file , the jar generates "target" folder and inside it we can find the Extent Report that is Spark.html
BasePage.java
package com.sadakar.common;

import org.openqa.selenium.WebDriver;

import io.cucumber.core.cli.Main;

public class BasePage {

public static WebDriver driver;
public static void main(String args[]) throws Throwable {
try {
Main
.main(new String[] {


"-g","com.sadakar.common",
"-g","com.sadakar.stepdefinitions",
"-g","com.sadakar.testng.runner",

"classpath:features",

"-t","@SmokeTest",


"-p", "pretty",
"-p", "json:target/cucumber-reports/cucumber.json",
"-p", "html:target/cucumber-reports/cucumberreport.html",
"-p","com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:",

"-m"
}
);
} catch (Exception e) {
e
.printStackTrace();
System
.out.println("Main method exception : " + e);
}
}

}


Save the project and run it as TestNG from eclipse or you could run the scenarios from the executable jar file and analyze the reports generated in "target" folder. 

The Extent Report(Spark.html) with successful execution should look as shown in below image. 






Now, what if you want to attach screen shots for the failed scenarios ? 
The location is given the extent.properties file 
screenshot.dir=target/screenshots/ 
screenshot.rel.path=../screenshots/

In order to get the screen shots , add below piece of code in Cucumber @After hook with order=2 since the order=1 is used to quit the driver after each scenario. This order plays a vital role in terms of attaching screen short after a failed scenario. 

if ((scenario.isFailed())) {
final byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", scenario.getName());
}

package com.sadakar.common;

import java.time.Duration;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.chrome.ChromeDriver;

import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

public class Hooks extends BasePage {

@Before //Cucumber hook - runs for each scenario
public static void setupDriver() throws InterruptedException {

System
.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
driver
= new ChromeDriver();
driver
.manage().window().maximize();
driver
.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");

driver
.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));
}

@After(order=1) //Cucumber hook - runs for each scenario
public static void quitDriver() throws Exception {
driver
.quit();
}
@After(order = 2) // Cucumber After Hook with order 1
public void takeScreenShotOnFailedScenario(Scenario scenario) {

System
.out.println("Taking screenshot from Cucumber After hook with order=2 if the scenario fails");
if ((scenario.isFailed())) {
final byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", scenario.getName());
}

}

}

The same code base above is given to have bad login so it will fail both the scenarios and so the Sprak.html look like below with the screen shot attached. 





References: 
https://github.com/grasshopper7/extentreports-cucumber7-adapter

That's all we have to do to integrate Extent Report with cucumber 7. 
I hope you found this demo is useful! Keep an eye on this space for interesting automation updates and do subscribe the YouTube channel. 


September 13, 2022

September 10, 2022

 In this blog post , we will learn majorly the following topics. 

1. How to create an executable jar for cucumber+selenium+testng+maven project ?
2. How to run scenarios from generated jar ? 

To create an executable jar for maven project there are many jar plug-in's available in the maven space. 
In this example, I'd like to demonstrate it using maven-assembly-plugin. 

The demo project for HRM application can  be found at GitHub  or download this maven zip file

You could also watch this no voice video tutorial for quick references
(Pls do subscribe for more automation updates)



Now, let's see the core part that we start with pom.xml
We need to have the maven-assembly-plugin is given the pom file, i.e., add below piece of code in the pom.xml file. 

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.sadakar.common.BasePage</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>

In a java class, using "main" method, we need to pass the glue code, tags, plug-ins and etc that are related to cucumber as arguments. 
For example, I've used, BasePage.java class that should contain normal "main" method and  inside it use Main.main(....) to pass cucumber arguments so the scenarios based on tags would be runnable from command line. 
import package : import io.cucumber.core.cli.Main; in the BasePage.java class and the passing of arguments are shown in below class.  

BasePage.java
package com.sadakar.common;

import org.openqa.selenium.WebDriver;

import io.cucumber.core.cli.Main;

public class BasePage {

public static WebDriver driver;
public static void main(String args[]) throws Throwable {
try {
Main.main(new String[] {


"-g","com.sadakar.common",
"-g","com.sadakar.stepdefinitions",
"-g","com.sadakar.testng.runner",

"classpath:features",

"-t","@HRMLogin",


"-p", "pretty",
"-p", "json:target/cucumber-reports/cucumber.json",
"-p", "html:target/cucumber-reports/cucumberreport.html",

"-m"
}
);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Main method exception : " + e);
}
}

}

In eclipse, build the project using below command: 

Ensure that any open folders, command prompts, chrome drivers in task manager are all closed.
Clean the project and then build it. 

clean package assembly:single -Dmaven.test.skip=true

Using -Dmaven.test.skip=true option we can skip the tests while the project builds! 


Click on the images to view them in gallery mode so the content provided is clear! 


This is how the log looks like when the build is in progress and is completed. 
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/softwares/Eclipse/eclipse-java-2021-09-R-win32-x86_64/eclipse/plugins/org.eclipse.m2e.maven.runtime.slf4j.simple_1.18.0.20210618-2246/jars/slf4j-simple-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [file:/D:/softwares/Eclipse/eclipse-java-2021-09-R-win32-x86_64/eclipse/configuration/org.eclipse.osgi/5/0/.cp/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/softwares/Eclipse/eclipse-java-2021-09-R-win32-x86_64/eclipse/plugins/org.eclipse.m2e.maven.runtime.slf4j.simple_1.18.0.20210618-2246/jars/slf4j-simple-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [file:/D:/softwares/Eclipse/eclipse-java-2021-09-R-win32-x86_64/eclipse/configuration/org.eclipse.osgi/5/0/.cp/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
[INFO] Scanning for projects...
[INFO]
[INFO] --< CucumberTestNGSeleniumExecutableJar:CucumberTestNGSeleniumExecutableJar >--
[INFO] Building CucumberTestNGSeleniumExecutableJar 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Deleting C:\Users\sadakarp\eclipse-workspace\CucumberTestNGSeleniumExecutableJar\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 3 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 5 source files to C:\Users\sadakarp\eclipse-workspace\CucumberTestNGSeleniumExecutableJar\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:3.0.0-M7:test (default-test) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Building jar: C:\Users\sadakarp\eclipse-workspace\CucumberTestNGSeleniumExecutableJar\target\CucumberTestNGSeleniumExecutableJar-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-assembly-plugin:3.1.1:single (default-cli) @ CucumberTestNGSeleniumExecutableJar ---
[INFO] Building jar: C:\Users\sadakarp\eclipse-workspace\CucumberTestNGSeleniumExecutableJar\target\CucumberTestNGSeleniumExecutableJar-0.0.1-SNAPSHOT-jar-with-dependencies.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 26.979 s
[INFO] Finished at: 2022-09-10T20:21:45+05:30
[INFO] ------------------------------------------------------------------------

maven-assembly-plugin generates two jar files, they are

1. CucumberTestNGSeleniumExecutableJar-0.0.1-SNAPSHOT.jar
2. CucumberTestNGSeleniumExecutableJar-0.0.1-SNAPSHOT-jar-with-dependencies.jar


The jar with the dependencies is called fat jar file and this is the one we call as "executable" or "runnable" jar. 

Make sure that this jar contains the MANIFEST.MF file containing the class that has the main method. Use jar extract tools to view the content inside the jar, I've used "Java Decompiler". 

The MANIFEST.MF file should contain all the dependencies with Main-Class:com.sadakar.common.BasePage as shown in below. 

MANIFEST.MF
Manifest-Version: 1.0
Created-By: Apache Maven 3.8.1
Built-By: sadakarp
Build-Jdk: 16.0.2
Class-Path: cucumber-java-7.1.0.jar cucumber-core-7.1.0.jar cucumber-ghe
rkin-7.1.0.jar cucumber-gherkin-messages-7.1.0.jar messages-17.1.1.jar
tag-expressions-4.1.0.jar cucumber-expressions-13.0.1.jar datatable-7.1
.0.jar cucumber-plugin-7.1.0.jar docstring-7.1.0.jar html-formatter-17.
0.0.jar create-meta-6.0.4.jar apiguardian-api-1.1.2.jar cucumber-testng
-7.1.0.jar selenium-java-4.3.0.jar selenium-api-4.3.0.jar selenium-chro
me-driver-4.3.0.jar auto-service-annotations-1.0.1.jar auto-service-1.0
.1.jar auto-common-1.2.jar guava-31.1-jre.jar failureaccess-1.0.1.jar l
istenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar jsr305-3.
0.2.jar checker-qual-3.12.0.jar error_prone_annotations-2.11.0.jar j2ob
jc-annotations-1.3.jar selenium-chromium-driver-4.3.0.jar selenium-json
-4.3.0.jar selenium-devtools-v101-4.3.0.jar selenium-devtools-v102-4.3.
0.jar selenium-devtools-v103-4.3.0.jar selenium-devtools-v85-4.3.0.jar
selenium-edge-driver-4.3.0.jar selenium-firefox-driver-4.3.0.jar seleni
um-ie-driver-4.3.0.jar selenium-opera-driver-4.3.0.jar selenium-remote-
driver-4.3.0.jar netty-buffer-4.1.78.Final.jar netty-codec-http-4.1.78.
Final.jar netty-codec-4.1.78.Final.jar netty-handler-4.1.78.Final.jar n
etty-common-4.1.78.Final.jar netty-transport-classes-epoll-4.1.78.Final
.jar netty-transport-classes-kqueue-4.1.78.Final.jar netty-transport-na
tive-epoll-4.1.78.Final.jar netty-transport-native-kqueue-4.1.78.Final.
jar netty-transport-native-unix-common-4.1.78.Final.jar netty-transport
-4.1.78.Final.jar netty-resolver-4.1.78.Final.jar opentelemetry-api-1.1
5.0.jar opentelemetry-context-1.15.0.jar opentelemetry-exporter-logging
-1.15.0.jar opentelemetry-sdk-metrics-1.15.0.jar opentelemetry-sdk-logs
-1.15.0-alpha.jar opentelemetry-sdk-common-1.15.0.jar opentelemetry-sdk
-extension-autoconfigure-spi-1.15.0.jar opentelemetry-sdk-extension-aut
oconfigure-1.15.0-alpha.jar opentelemetry-sdk-trace-1.15.0.jar opentele
metry-sdk-1.15.0.jar opentelemetry-semconv-1.15.0-alpha.jar jtoml-2.0.0
.jar byte-buddy-1.12.10.jar commons-exec-1.3.jar async-http-client-2.12
.3.jar async-http-client-netty-utils-2.12.3.jar netty-codec-socks-4.1.6
0.Final.jar netty-handler-proxy-4.1.60.Final.jar netty-transport-native
-epoll-4.1.60.Final-linux-x86_64.jar netty-transport-native-kqueue-4.1.
60.Final-osx-x86_64.jar reactive-streams-1.0.3.jar netty-reactive-strea
ms-2.0.4.jar slf4j-api-1.7.30.jar jakarta.activation-1.2.2.jar selenium
-http-4.3.0.jar failsafe-3.2.4.jar selenium-safari-driver-4.3.0.jar sel
enium-support-4.3.0.jar testng-7.1.0.jar jcommander-1.72.jar guice-4.1.
0-no_aop.jar javax.inject-1.jar aopalliance-1.0.jar snakeyaml-1.21.jar
.
Main-Class: com.sadakar.common.BasePage

Now, let's run the jar file: 
Double click on the executable jar, it will start executing the scenarios! 

Or use below command to run the cucumber scenarios

java -jar CucumberTestNGSeleniumExecutableJar-0.0.1-SNAPSHOT-jar-with-dependencies.jar 
-Dcucumber.filter.tags="@HRMLogin"


This execution, will generate, cucumber reports in "target" folder where the jar is located. 

The report is based on the plug-in(s) that we provide in BasePage.java file. 
For example, we gave it as 

"-p", "json:target/cucumber-reports/cucumber.json", 
"-p", "html:target/cucumber-reports/cucumberreport.html",


click on the "cucumberreport.html" file to analyze the report generated. 


That's all we have to do to create an executable cucumber, testng  jar file using maven and to run the scenarios from it. 

I hope you found this write-up useful, keep watch this blog site for more automation! 

September 10, 2022

August 23, 2022

What are Waits in selenium ?

1) Implicit wait 
2) Explicit wait

1) Implicit wait
a) implicitlyWait()
b) pageLoadTimeout()
c) setScriptTimeout()

2) Explicit wait 
a) WebDriverWait
b) Fluent

Implicit wait | implicitlyWait()

  • implicitlyWait is applied to all the web elements on the web page.
  • It will throw "No Such Element Exception" after reaching the time. 
  • Implicit wait stays in place for the entire duration for which the browser is open.
  • The default value of implicit wait is 0.
  • Implicit wait is applied for the lifetime of the Webdriver, it can extend the test execution times to a large value depending on the number of elements on which it is being called.
  •  When to use implicitlyWait? 
  •   It is recommended to use implicit wait only when you are in complete control of the script.
  • Example: 
    import this package : import java.time.Duration;
    driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(60))

Implicit wait | pageLoadTimeout()

  • It waits for the page to load completely for the specified number of seconds. 
  • Default value is : 0 
  • Example:

    WebDriver driver = new ChromeDriver();
    driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
    driver.get("https://demoqa.com/login");
  • WebDriver will wait for a maximum of 30 seconds before moving ahead with the interaction with the element.

Implicit wait | setScriptTimeout()

  • The setScriptTimeout command waits for the asynchronous parts of the web page to finish loading for a specified number of seconds.
  • Example:
    driver.manage().timeouts().setScriptTimeout(15, TimeUnit.SECONDS);
    ((JavascriptExecutor) driver).executeScript("alert('hello world');");
    ((JavascriptExecutor) driver).executeAsyncScript("window.setTimeout(arguments[arguments.length - 1], 500);");
  • WebDriver will wait for a maximum of 15 seconds before moving ahead with the interaction with the element.

Explicit wait | WebDriverWait

  • It is a conditional wait strategy 
  • Wait until the the condition specified becomes true or the time duration is elapsed. 
  • Explicit wait is only applied on the specified element. 
  • Commonly used conditions are : 
    presenceOfElementLocated()
       elementToBeClickable()
       visibilityOfElementLocated()
  • WebDriverWait class and ExpectedConditions specifies the time and condition for which the WebDriver needs to wait.

  • Example-1 : 
      WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(30));
     wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//input[@id='searchBox']")));
  • Example-2: 
    WebElement searchBox = new WebDriverWait(driver, Duration.ofSeconds(10))
    .until(ExpectedConditions.presenceOfElementLocated(By.xpath("//input[@id='searchBox']")));
  • Example-3: 
    WebElement searchBox = new WebDriverWait(driver, Duration.ofSeconds(30))
    .until(driver -> driver.findElement(By.name("//input[@id='searchBox']")));

Explicit wait| Fluent wait

  • Fluent wait is similar to Explicity wait 
  • It takes an additional argument frequency i.e., polling time. 
  • frequency number tells the WebDriver to keep on checking for the element at regular time intervals wait till the maximum of "Duration.ofSeconds"
  • If the element becomes avaialble earlier, we proceed with the  test execution and finish quickly. 
  • Example: 
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
    .withTimeout(Duration.ofSeconds(30))
    .pollingEvery(Duration.ofSeconds(5))
    .ignoring(NoSuchElementException.class);

    • Maximum waiting time is 30 seconds 
    • polling time is 5 seconds 
    • WebDriver keeps on checking for the element for every 5 seconds to a maximum of 30 seconds ignoring will ignore the exception NoSuchElementException while the driver finds the element in the maximum time.

  • When to use ? 
    When dealing with AJAX elements 


Which is best wait ? When to use which wait ? 

Explicit wait : 
  • Saves the time and is not applicable for all elements.
  • Wait only based on condition and time for a specified element. 

Implicit wait : 
  • It is applied once for all the elements and the next wait cycle starts once the previous one completes. 
  • Implicitly waits needs a better understanding of scripts.
There is no best type of wait, based on the demand of the element find strategy we use any of the waits above.  


NOTE:
  Do not mix implicit and explicit waits! Doing so can cause unpredictable wait times. 
  For example, setting an implicit wait of 20 seconds and an explicit wait of 35 seconds could cause a timeout to occur after 25 seconds.


What is polling time ? 
The polling time (or polling interval) is the time interval in which Selenium starts searching again after the last failed try. 
  • It depends on the type of browser driver you are working on. 
  • Some may have 500 milliseconds while some may have 1 second as polling time. 
  • The polling time is inbuild in implicitlyWait and there is no way to modify the time interval. 
  • The default pooling period for implicit and explicit wait is 250 ms.
  •  During implicitlyWait, the WebDriver will poll the DOM for certain specified time units while trying to find any element. 
  •  If the element is found earlier, the test executes at that point otherwise the WebDriver waits for the specified duration.

Thread.sleep()
  • Thread.sleep() pauses the execution
  • Sleep is a static method that belongs to the ‘Thread’ class of Java.
  • Thread.sleep() sets the condition to an exact time period to wait.
What is the difference between sleep and selenium waits ? 
  • Thread.sleep() will stop the execution of the script for the time specified in the script, irrespective of the fact that the element on the web page has been found.
  • Selenium waits do not wait for the complete duration of time. If the WebDriver is able to find the element before the specified time duration, it moves on to the next line of code. 
  • This helps in reducing the overall time of script execution by a considerable margin.
Selenium setSpeed()
setSpeed() sets the desired speed of execution or delays execution by a specified amount of time before each operation.

August 23, 2022

August 17, 2022

How to configure postman/newman API tests in Azure DevOps 
  1. Export the postman collection and environment 
  2. Push the collection/environment to "Azure Repos Git" repository
  3. Navigate to Pipeline page in Azure DevOps and click on "New pipeline" button on the top right corner. 
  4. Click on "Use the classic editor" link in the bottom to create a pipeline without YAML.
  5. Select the source for the postman tests
  6. Select a template > Click on "Empty job"
  7. A new pipe line is created with default name 
  8.  Add the tasks
    • Install newman 
    • Newman command to run the tests
    • Publish Test results
  9.  Save the pipe line and Queue(run the pipeline) 
  10.  Analysis of Junit Report
  11. Analysis of published report

Let's look into each of the steps above in detail. 

Export the postman collection and environment as .json files 

  • Create a Collection, create a GET request, write tests for the request
  • Here is a sample request created : https://learning.postman.com/docs/getting-started/sending-the-first-request/
  • Tests written for the above GET request are as follows
  • NOTE: For the demonstration purposes, I've not taken environment for this example.  
    pm.test("Status code is 200 OK", function () {
    pm.response.to.have.status(200);
    });
    pm.test("Response time is less than 10s", function () {
    pm.expect(pm.response.responseTime).to.be.below(10000);
    });

    pm.test("Body contains url",() => {
    pm.expect(pm.response.text()).to.include("http://postman-echo.com/get");
    });
  • Collection Name : 00Test.postman_collection.json

Push the collection/environment to "Azure Repos Git" repository
  • Use git commit and push the code to Azure Git repository
  • Click on the image below to get the best view. 

Navigate to Pipeline page in Azure DevOps and click on "New pipeline" button on the top right corner. 

                    


Click on "Use the classic editor" link in the bottom to create a pipeline without YAML.

Select the source for postman tests

  • Select the "Team Project", "Repository", "Branch" and click on Continue button 



Select a template > Click on "Empty job"


A new pipe line is created with default name 
Set the below basic properties and the remaining are optional and can be configured on demand basis. 

Display name : Agent job1
Agent pool : <inherit from pipeline>


 

Add the tasks
To add the tasks click on + button on the Agent job. 
I am taking 3 tasks for the tests to run, they are as follows. 
  1. Install newman 
  2. Newman command to run the tests 
  3. Publish Test results

Install newman

Search for the command line plugin at the top right corner and then Add the command line task. 

Fill the required properties for the task added, for instance, we install postman command line tool that is newman using npm package. 

Display name : Install newman
Script : npm install -g newman 


The corresponding YAML script to install the newman is 
steps:
- script: |
npm install -g newman

displayName: 'Install newman'

Newman command to run the tests
Add one more command line plug-in to run the postman API tests (This we can do in the previous step itself, I wanted to separate out the installation task to the test execution task so the second command line plugin). 

Use below script command to run the collection

Display name : Newman command to run tests
Script: newman run 00Test.postman_collection.json --reporters cli,junit --reporter-junit-export Results\junitReport.xml

Format/Syntax: Postman collection with environment 

newman run <PostmanCollection.json> -e <Environment.json> --reporters cli,junit --reporter-junit-export Results\junitReport.xml



Ensure that the working directory has the code path populated. 
Default Working Directory format is : $(System.DefaultWorkingDirectory)


Corresponding YAML script
steps:
- script: 'newman run 00Test.postman_collection.json --reporters cli,junit --reporter-junit-export Results\junitReport.xml'
displayName: 'Newman command to run tests'


Publish test results:
  • Search for Publish Test Results plugin and add it as next task for the job. 
  • Configure the below basic properties 
  • Display Name : Publish Test Results **/TEST-*.xml  ( It could be any name, I used the generated name)
  • Test result format : Junit
  • Test results files: $(System.DefaultWorkingDirectory)\Results\*.xml 
  • Search folder : $(System.DefaultWorkingDirectory)




Save the pipe line and Queue(run the pipeline) 
Save the pipe line

Queue and run the pipe line 


As the pipe line queued we navigate to the run console of the pipe line, from this console click on "Agent job1" in the bottom which is in process. 


Agent job1 displays the tasks to perform by the pipeline as shown in below image. This includes the default tasks along with the tasks configured by us. 


All the tasks in the job has successfully ran so the next thing is to analyze the junit report. 
 
Analysis of Junit Report

Be on the pipe line run console to view the report. 
If there are any unexpected blockers while executing the tasks, the junit report will not be generated. 
If there are any failures in the asserstions/tests for the postman junit report will be generated. 

The report can be analyzed in the Tests tab as shown in below image.



Analysis of Published Report
Click on Publish Test Results task from the pipe line execution and the console make note of the URL where the results are published. 
Open the URL in a new tab and start analyzing the results. 



Go to the Runs section from Azure DevOps wizard as shown in below and start analyzing the published report. 


In case of any test failures, Create bug or update the result to to the test case! 

This is how we integrate postman/newman API tests in Azure DevOps pipe line for the continuous integration (CI) .

I hope this helped a bit, keep an eye on this portal for more automation updates.

August 17, 2022

August 11, 2022

  •  Xpath's text() returns the text of selected element and it doesn't fit into the WebElement's findElement method. 

  • So remove the text() from the xpath and then apply the getText() method on WebElement. 

  • For example: 
    //*[@id="formsearch"]/fieldset/legend/text()
    will identify the text of the WebElement and we can't use it for findElement instead

    //*[@id="formsearch"]/fieldset/legend will identify the WebElement and then on this we can use getText() method of the element. 
org.openqa.selenium.InvalidSelectorException: invalid selector: The result of the xpath expression "//*[@id="formsearch"]/fieldset/legend/text()" is: [object Text]. It should be an element.
(Session info: chrome=104.0.5112.81)
For documentation on this error, please visit: https://selenium.dev/exceptions/#invalid_selector_exception
Build info: version: '4.3.0', revision: 'a4995e2c09*'
System info: host: 'SADAKARP', ip: '200.123.4.3', os.name: 'Windows 11', os.arch: 'amd64', os.version: '10.0', java.version: '17.0.3'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [f12f1c7e2c818403564e8712964c6af2, findElement {using=xpath, value=//*[@id="formsearch"]/fieldset/legend/text()}]
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 104.0.5112.81, chrome: {chromedriverVersion: 104.0.5112.79 (3cf3e8c8a07d..., userDataDir: C:\Users\sadakarp\AppData\L...}, goog:chromeOptions: {debuggerAddress: localhost:65004}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: WINDOWS, proxy: Proxy(), se:cdp: ws://localhost:65004/devtoo..., se:cdpVersion: 104.0.5112.81, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
Session ID: f12f1c7e2c818403564e8712964c6af2
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:200)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:133)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:53)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:184)
at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:167)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:142)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:569)
at org.openqa.selenium.remote.ElementLocation$ElementFinder$2.findElement(ElementLocation.java:162)
at org.openqa.selenium.remote.ElementLocation.findElement(ElementLocation.java:60)
at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:387)
at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:379)
at com.inovalon.cucumber.stepdef.payers.Products.routeToolPageNavigationValidation(Products.java:45)
at .Search for Medicaid Florida (FL) payer and navigate to RouteTool page(classpath:features/Products.feature:12)

August 11, 2022

August 10, 2022

When there are braces included in the cucumber step title for a word and if we miss double backward slashes in the step definition then we end up with UndefinedStepException 

This exception we generally, see when won't implement the glue code.


For this example, I had typed the @And annotation with step name and noticed that braces should be double escaped. 

For example, in below step (PR) should be given with double backward slashes  that is \\(PR) in the glue code. 

And Search for Product (PR) and navigate to Product Edit page

Step definition: 
@Then("Search for Product \\(PR) and navigate to Product Edit page")
public void search_for_product_pr_and_navigate_to_product_edit_page() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}

io.cucumber.testng.UndefinedStepException

at io.cucumber.core.runtime.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:69)
at io.cucumber.testng.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:23)
at io.cucumber.testng.TestNGCucumberRunner.lambda$runScenario$1(TestNGCucumberRunner.java:133)
at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$3(CucumberExecutionContext.java:110)
at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:110)
at io.cucumber.testng.TestNGCucumberRunner.runScenario(TestNGCucumberRunner.java:129)
at io.cucumber.testng.AbstractTestNGCucumberTests.runScenario(AbstractTestNGCucumberTests.java:35)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:134)
at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:597)
at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:173)
at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:816)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:146)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.testng.TestRunner.privateRun(TestRunner.java:766)
at org.testng.TestRunner.run(TestRunner.java:587)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1187)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1109)
at org.testng.TestNG.runSuites(TestNG.java:1039)
at org.testng.TestNG.run(TestNG.java:1007)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)


August 10, 2022

August 9, 2022

  • WebDriverManager is an open-source Java library
  • It carries out the management (i.e., download, setup, and maintenance) of the drivers required by Selenium WebDriver(e.g., chromedriver, geckodriver, msedgedriver, etc.) in a fully automated manner.
  • The primary use of WebDriverManager is the automation of driver.
  • With this we can get rid of System property to fetch the driver placed in physical drive or from the project path. 
More details : 
https://bonigarcia.dev/webdrivermanager/

GitHub @ https://github.com/bonigarcia/webdrivermanager

Example: 
This is how we set the path for chrome driver once the driver is downloaded and placed in system hard drive . 
System.setProperty("webdriver.chrome.driver", "D\chromedriver.exe");

Now, using DriverMnager we can get rid of physical drive path, that is replace the above line of code with 
WebDriverManager.chromedriver().setup();

This requires the following dependency to be added in pom.xml file. 

<!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>4.3.0</version>
</dependency>

In the Before hook of cucumber, normally we create the ChromeDriver object, prior creating the chrome driver object, we need to call the chrome driver setup() as shown in below example.

@Before(order = 0) // Cucumber Before Hook with order 0
public void before(Scenario scenario) throws IOException {

Log.info("Initiating the chrome driver from Cucumber Before hook with order=0");
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().window().maximize();
}

August 9, 2022

Using System.getProperty, we can provide relative path of AutoIT and then use Runtime.getRuntime().exec("PathToAutoITExeFile") method to do the windows based authentication in selenium. 

For instance: 
System.getProperty("user.dir")+"\\src\\test\\resources\\files\\atuoit_chrome_credentials.exe")

Tip credits: Co-Engineer 


 
	@Given("Products URL with AutoIT credentials entered")
public void givenChromeBrowser() throws Throwable {

// Get the credentials from AutoIT script file

// Absolute path
//Runtime.getRuntime().exec("C:\\Automation\\atuoit_chrome_credentials.exe.exe");

// Relative path
Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\src\\test\\resources\\files\\atuoit_chrome_credentials.exe");

// Get the login with windows based authentication
driver.get("http://www.products.com");
}


August 9, 2022

August 8, 2022

  • TestNG Assert.assertEquals compares the two strings 
  • This is one of situvations we get java.lang.AssertionError when the strings are not equal
  • For instance, 

String expectedEditProductURL = "http://sadakar.website.lab/Product?productId=89";
String actualEditProductURL = driver.getCurrentUrl();
Assert.assertEquals(actualEditProductURL, expectedEditProductURL);

java.lang.AssertionError: http://sadakar.website.lab/Product?productId=89 expected [http://sadakar.website.lab/Product?productId=899] but found [Change Product details hyperlink clicking is failed]
at org.testng.Assert.fail(Assert.java:97)
at org.testng.Assert.assertEqualsImpl(Assert.java:136)
at org.testng.Assert.assertEquals(Assert.java:118)
at org.testng.Assert.assertEquals(Assert.java:575)



August 8, 2022

io.cucumber.testng.UndefinedStepException

  • This exception, normally observed when the the steps are undefined. 

  • I have had two scenario's with same name and same tag provided then the one that has glue code defined is PASSED and the other is FAILED. 

  • Generally, we don't give the same scenario name. 
PASSED: runScenario("Validating navigation to Products Page", "Optional[Product page validations]")

FAILED: runScenario("Validating navigation to Products Page", "Optional[Product page validations]")

io.cucumber.testng.UndefinedStepException: The step 'Clicks on Edit Product  Hyperlink' and 1 other step(s) are undefined.
You can implement these steps using the snippet(s) below:

@Then("Clicks on Edit Product Hyperlink")
public void clicks_on_edit_route_overrides_hyperlink() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
@Then("Verifies the navigation to Product Edit Page")
public void verifies_the_navigation_to_trading_partner_route_overrides_page() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}

at io.cucumber.core.runtime.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:69)
at io.cucumber.testng.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:23)
at io.cucumber.testng.TestNGCucumberRunner.lambda$runScenario$1(TestNGCucumberRunner.java:133)
at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$3(CucumberExecutionContext.java:110)
at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:110)
at io.cucumber.testng.TestNGCucumberRunner.runScenario(TestNGCucumberRunner.java:129)
at io.cucumber.testng.AbstractTestNGCucumberTests.runScenario(AbstractTestNGCucumberTests.java:35)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:134)
at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:597)
at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:173)
at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:816)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:146)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.testng.TestRunner.privateRun(TestRunner.java:766)
at org.testng.TestRunner.run(TestRunner.java:587)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1187)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1109)
at org.testng.TestNG.runSuites(TestNG.java:1039)
at org.testng.TestNG.run(TestNG.java:1007)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)

August 8, 2022

Pages

Feedback