Integrating Jira with your Selenium framework can be helpful for managing issues that occur during automated testing. If a script fails generated by algoQA, Jira can be used to create a defect ticket automatically, which can then be assigned for resolution. This integration streamlines the defect management process and ensures that issues are addressed promptly.
Jira Overview
Jira is a tool primarily used for bug and issue tracking. It also supports project management features for all kinds of use cases, from requirements and test case management to Agile software development.
Jira is free to use for up to 20 users. However, if any organization requires additional features, such as support, storage, and a large user limit, must choose the commercial version. Since Jira is a bug/issue tracking tool, it enables the assignment, resolution, and implementation of bug life cycle management.
Setting up Jira Software with Google Account
Perform the following:
- Enter the URL Products | Atlassian into the browser bar.
- Select Jira Software. In this page, select Get it free button on the right-top corner.
- Get started with Jira page appears. Click Google account button to create your account.
- Follow the on-screen prompts to create your first project.
Creating an API Token for Secure Integration with Jira
To enable secure connections between various software tools or automation scripts and your Jira account, you can create an API token. This token allows these tools to interact with Jira on your behalf without requiring your Jira password. This approach ensures security while facilitating smooth collaboration between different tools.
Perform the following to create an API token in Jira for use in Selenium Jira integration:
- Open a web browser and go to your organization's Jira website. For example, if your organization's Jira website is https://example.atlassian.net/, enter this URL in the address bar and press Enter.
- Log in to your Jira account using your credentials (username and password).
- After logging in, click icon next to your profile and settings icon or username on the top-right corner of the Jira dashboard.
- Select the Account Settings option.
- Navigate to the Security tab and then, click Create and manage API tokens link.
- In the API Tokens screen, click the Create API token button.
- Enter the Label and click Create button.
- Upon creating the API token, click Copy button to copy the token to the clipboard and save it to appropriate location.
Integrating Selenium with Jira and logging defects in Jira using algoQA Project
Applies to JUnit, Selenium, Maven framework and Java as a programming language |
Prerequisites
- Click here to download Eclipse IDE packages.
- Maven Project must be configured.
To automatically create a Jira ticket when a Selenium test fails, and skip ticket creation if the same ticket has already been created in the project, perform the following:
- Add required dependencies in pom.xml
- In order to Integrate Jira with Selenium, use rcarz Jira-client. This is the wrapper built on top of the Jira Rest API Client. This file enables communication between Selenium and Jira, allowing Selenium tests to interact with Jira's features like creating and updating issues, and querying issue details.
- Scripts generated by algoQA follow structured folder structure. Navigate to pom.xml in the project, and add the following dependency:
<dependency>
<groupId>net.rcarz</groupId>
<artifactId>Jira-client</artifactId>
<version>0.5</version>
<scope>compile</scope>
</dependency>
- Create basic tests using Selenium and Java
In the com.demo.project package, two basic Selenium tests have been created: one designed to pass and one to fail.
These tests can serve as examples for understanding Selenium test creation and execution. - Create a utility to handle Jira issue
Custom annotations can be used to mark specific test methods or classes to indicate that they should create Jira issues when certain conditions are met, such as a test failure. This allows you to automate the process of creating Jira issues for failed tests, making it easier to track and manage issues related to your test automation.
To create a package inside the main folder of your project, for example com.demo.utility create a package to hold the utility classes related to Jira integration as shown.
- Create the JiraServiceProvider class: This class will handle the creation of Jira issues.
Code snippet:package JiraUtility;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
@Retention(RetentionPolicy.RUNTIME)
public @interface JiraCreateIssue {
boolean isCreateIssue();
} - Create the JiraCreateIssue annotation: This annotation will be used to mark specific test methods or classes that should create Jira issues.
Code snippet:package JiraUtility;
import net.rcarz.jiraclient.BasicCredentials;
import net.rcarz.jiraclient.Field;
import net.rcarz.jiraclient.Issue;
import net.rcarz.jiraclient.Issue.FluentCreate;
import net.rcarz.jiraclient.JiraClient;
import net.rcarz.jiraclient.JiraException;
public class JiraServiceProvider {
private JiraClient Jira;
private String project;
private String JiraUrl;
public JiraServiceProvider(String JiraUrl, String username, String password, String project) {
this.JiraUrl=JiraUrl;
// create basic authentication object
BasicCredentials creds = new BasicCredentials(username, password);
// initialize the Jira client with the url and the credentials
Jira = new JiraClient(JiraUrl, creds);
this.project = project;
}
public void createJiraIssue(String issueType, String summary, String description, String reporterName) {
try {
//Avoid Creating Duplicate Issue
Issue.SearchResult sr = Jira.searchIssues("summary ~ \""+summary+"\"");
if(sr.total!=0) {
System.out.println("Same Issue Already Exists on Jira");
return;
}
//Create issue if not exists
FluentCreate fleuntCreate = Jira.createIssue(project, issueType);
fleuntCreate.field(Field.SUMMARY, summary);
fleuntCreate.field(Field.DESCRIPTION, description);
Issue newIssue = fleuntCreate.execute();
System.out.println("********************************************");
System.out.println("New issue created in Jira with ID: " + newIssue);
System.out.println("New issue URL is :"+JiraUrl+"/browse/"+newIssue);
System.out.println("*******************************************");
} catch (JiraException e) {
e.printStackTrace();
}
}
}
- Create the JiraServiceProvider class: This class will handle the creation of Jira issues.
Configure the Hooks File
In a script generated folder structure, the 'hooks' file contains code that runs before or after scenarios in your test suite. If there is a failure in a scenario, you can use the 'hooks' file to perform certain actions, such as logging the failure, taking screenshots, or notifying team members.
In the script folder structure, navigate to the Hooks file and update the code as shown in the following screenshot.
Code snippet:package common; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Paths; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.hamcrest.CoreMatchers; import org.junit.ClassRule; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.asserts.SoftAssert; import com.aventstack.extentreports.ExtentReports; import com.aventstack.extentreports.ExtentTest; import com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter; //import com.cucumber.listener.Reporter; import com.google.common.io.Files; import JiraUtility.JiraServiceProvider; //import org.testng.asserts.SoftAssert; //vish commented following 3 lines //import cucumber.api.Scenario; //import cucumber.api.java.After; //import cucumber.api.java.Before; import common.CommonUtil; import common.TFSUtil; import common.WebBrowser; import io.cucumber.java.*; import ScreenRecorder.ScreenRecorderUtil; import org.monte.screenrecorder.ScreenRecorder; public class Hooks { public WebDriver driver; public static String userName; public static String password; private static List<Map<String, Object>> tstSteps = new ArrayList<>(); final static Logger log = Logger.getLogger(Hooks.class); public static boolean closeBrowser=true; public static SoftAssert softAssertions=new SoftAssert(); public static List<String> tagsExecuted=new ArrayList<String>(); public static int passCount=0; public static int failCount=0; public static int skipCount=0; public static String JiraIntegration; private static String path = System.getProperty("user.dir"); String EnableVideoCaptureForSuccess = CommonUtil.GetXMLData( Paths.get(path.toString(), "src", "test", "java", "ApplicationSettings.xml").toString(), "EnableVideoCaptureForSuccess"); String EnableVideoCaptureForFailure = CommonUtil.GetXMLData( Paths.get(path.toString(), "src", "test", "java", "ApplicationSettings.xml").toString(), "EnableVideoCaptureForFailure"); @Before public void init(Scenario scenario) { log.info("*********************************Execution started*******************************"); String node=System.getProperty("Node"); if(node == null || node.isEmpty()) { node="Node1"; } String url=System.getProperty("Url"); System.out.println("Url-----------"+url); if(url != null && !url.isEmpty()) { CommonUtil.appUrl=url; } String apiurl=System.getProperty("apiUrl"); System.out.println("apiurl-----------"+apiurl); if(apiurl != null && !apiurl.isEmpty()) { RestAssuredUtil.apiCmdUrl=apiurl; } String browserName=System.getProperty("browserName"); System.out.println("browserName-----------"+browserName); if(browserName != null && !browserName.isEmpty()) { CommonUtil.browserName=browserName; } YMLUtil.loadYML("src/test/java/", node); YMLUtil.loadObjectRepoYML("src/test/java/ObjectRepository.yml"); YMLUtil.PayloadYML("src/test/java/Payload.yml", node); Timestamp timestamp = new Timestamp(System.currentTimeMillis()); // Reporter.addScenarioLog("Start Time : "+timestamp); ExtentCucumberAdapter.addTestStepLog(""+scenario.getSourceTagNames()); ExtentCucumberAdapter.addTestStepLog("Start Time : "+timestamp); if(EnableVideoCaptureForSuccess.toUpperCase().equals("TRUE")||EnableVideoCaptureForFailure.toUpperCase().equals("TRUE")) { try { ScreenRecorderUtil.startRecord("TestCase"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } JiraIntegration = CommonUtil.GetXMLData( Paths.get(path.toString(), "src", "test", "java", "ApplicationSettings.xml").toString(), "JiraIntegration"); //extent = new ExtentReports(System.getProperty("user.dir") + "/test-output/ExtentScreenshot.html", true); } //Method to wait for 2 minutes before executing the test case //This method is used to handle LRS execution so that execution will happen without locking the user to Login @Before("@waitinminutes") public void beforeScenario()throws Throwable { log.info("*********************************Scenario started*******************************"); Thread.sleep(120000); CommonUtil.setCopiedCount(0); } @BeforeStep public void storeScenario(Scenario scenario) { WebBrowserUtil.sce=scenario; } @AfterStep public void addScreenshot(Scenario scenario) { WebBrowserUtil.takeEachStepScrenshot(scenario); } @After(order = 1) public void afterScenario(Scenario scenario) { if(EnableVideoCaptureForSuccess.toUpperCase().equals("TRUE")||EnableVideoCaptureForFailure.toUpperCase().equals("TRUE")) { try { ScreenRecorderUtil.stopRecord(); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if(EnableVideoCaptureForSuccess.toUpperCase().equals("TRUE")&&EnableVideoCaptureForFailure.toUpperCase().equals("FALSE")) { if(scenario.isFailed()) ScreenRecorderUtil.deleteRecordedFile(); } else if(EnableVideoCaptureForSuccess.toUpperCase().equals("FALSE")&&EnableVideoCaptureForFailure.toUpperCase().equals("TRUE")) { if(!scenario.isFailed()) ScreenRecorderUtil.deleteRecordedFile(); } } if(JiraIntegration.toUpperCase().equals("TRUE")) if (scenario.isFailed()) { //scenario.getName()=>name of the failing scenario; scenario.getLine=>the line(s) in the feature file of the Scenario; scenario.getStatus()=>scenario Status String JiraIntegrationParameters = CommonUtil.GetXMLData( Paths.get(path.toString(), "src", "test", "java", "ApplicationSettings.xml").toString(), "JiraIntegrationParameters"); String[] JiraPara = JiraIntegrationParameters.split("[,]", 0); // String description = "Scenario " + scenario.getName() + " is failed at line(s) " + scenario.getLine() + " with status " + scenario.getStatus(); // String Summary = "summary1" + CommonUtil.error.substring(0, Math.min(CommonUtil.error.length(), 255)); String description = CommonUtil.error; String Summary ="Scenario2 " + scenario.getName() + " is failed"; // To limit the size of the summary to 255 characters Summary = Summary.substring(0, Math.min(Summary.length(), 255)); // To remove special characters Summary = Summary.replaceAll("[^a-zA-Z0-9 ]", ""); JiraServiceProvider JiraServiceProvider = new JiraServiceProvider(JiraPara[0], JiraPara[1], JiraPara[2],JiraPara[3]); JiraServiceProvider.createJiraIssue(JiraPara[4],Summary,description,JiraPara[5]); } log.info("*********************************Scenario ended*******************************"); Timestamp timestamp = new Timestamp(System.currentTimeMillis()); ExtentCucumberAdapter.addTestStepLog("End Time: "+timestamp); CommonUtil.setCopiedCount(0); CommonUtil.setCopiedCountTextNull(); softAssertions=new SoftAssert(); boolean semiAuto=false; String scenarioStatusLowercase = new String(); scenarioStatusLowercase = scenario.getStatus().toString().toLowerCase(); if(scenarioStatusLowercase.equals("skipped")) { skipCount++; } if (scenario.isFailed()||(scenarioStatusLowercase.equals("passed"))) { if(scenarioStatusLowercase.equals("passed")) { passCount++; } else if(scenarioStatusLowercase.equals("failed")) { failCount++; AutoHealUtil.SaveConfigDeatils(); } String screenshotName = "Image_"+new Date().getTime(); boolean flag=true; for(String tag : scenario.getSourceTagNames()) { tagsExecuted.add(tag); if(tag.toLowerCase().contains("api")) { flag=false; break; } } if(flag) { driver = WebBrowser.getBrowser(); WebBrowserUtil.takeScrenshot(scenario); } } for(String tag : scenario.getSourceTagNames()) { closeBrowser=true; if (tag.contains("usesamesession")) { closeBrowser=false; break; } } String testcaseId=""; for(String tag : scenario.getSourceTagNames()) { if (tag.contains("set2") || tag.contains("semiauto") || tag.contains("set3") || tag.contains("set21") || tag.contains("set22") || tag.contains("set23")) { if(closeBrowser) { WebBrowser.closeBrowserInstance(); } } if (tag.contains("semiauto")) { semiAuto = true; } if (scenario.isFailed() && semiAuto) { semiAuto = false; throw new CustomException("Semi Auto test cases may fail due to OTP / Captcha."); } if(tag.contains("test")) { testcaseId=tag; } String SubmitTfsResult = CommonUtil.GetXMLData(Paths.get( System.getProperty("user.dir").toString(), "src", "test", "java", "ApplicationSettings.xml").toString(), "SubmitResultToTFS"); boolean tfsResult= Boolean.parseBoolean(SubmitTfsResult); if(tfsResult) { int testPointId=0, testPlanId=0, testRunId=0,testCaseId=0; TFSUtil tfsUtil = new TFSUtil(); testPointId = tfsUtil.getTestPointId(testCaseId)[0]; testPlanId= tfsUtil.getTestPointId(testCaseId)[1]; testRunId = tfsUtil.getTestRunId(testCaseId, testPointId, testPlanId); System.out.println(tstSteps); tfsUtil.updateResultsToTFS(testCaseId,testPointId, testRunId, tstSteps, userName, password); tstSteps.clear(); } } softAssertions=new SoftAssert(); } @After(order = 0) public void closeBrowser() { log.info("*********************************Execution ended*******************************"); System.out.println("------------------------------"); System.out.println(" Status - "); System.out.println("------------------------------"); if (WebBrowser.isBrowserOpened() && closeBrowser) { WebBrowser.closeBrowserInstance(); } String abc=System.getProperty("user.dir"); File dir = new File(abc+"//output//"); File[] files = dir.listFiles(); File lastModified = Arrays.stream(files).filter(File::isDirectory).max(Comparator.comparing(File::lastModified)).orElse(null); System.out.println(lastModified); try { int totalCount = passCount+failCount+skipCount; String json = "{\"TotalTest\":"+String.valueOf(totalCount)+","+"\"passed\":"+passCount+","+"\"failed\":"+failCount+","+"\"skipped\":"+skipCount+"}"; String path= lastModified+"//Execution_status.json"; System.out.println("PATH :"+path); BufferedWriter writer = new BufferedWriter(new FileWriter(new File(path))); writer.write(json); writer.close(); FileWriter myWriter = new FileWriter(lastModified+"//ExexutedTagDetails.txt"); Set<String> uniqueTag = new HashSet<String>(tagsExecuted); String test=""; String set=""; String otherTags=""; for (String tag : uniqueTag) { if(tag.contains("@test")) { test+= test=="" ? tag: ","+tag; } else if(tag.contains("@set")) { set+= set=="" ? tag: ","+tag; } else { otherTags+= otherTags=="" ? tag: ","+tag; } } myWriter.write("Test Tags:\n"); myWriter.write(test+"\n\n"); myWriter.write("Set Tags:\n"); myWriter.write(set+"\n\n"); myWriter.write("Other Tags:\n"); myWriter.write(otherTags+"\n"); myWriter.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Project folder structure is displayed similar to the example shown in the following screenshot:- Get the Project Key
Perform the following:- Navigate to Projects Main Menu and select View All Projects as follows:
- Choose the respective project.
- In the Project page, Key will be displayed next to the corresponding project name.
- Navigate to Projects Main Menu and select View All Projects as follows:
- Configure Applications.XML file
- Navigate to the Application Settings. XML file in your script generated folder
- Set the Jira Integration parameter to true and add all the required parameters as shown:
When you create a JiraServiceProvider object, consider the following parameters:Field Description JiraUrl Indicates company's Jira URL. If you are working on Jira cloud, then URL will be: https://<organisation>.atlassian.net Username User is a parameter used for authentication, but its format can vary based on configuration. For example, format is <Username>@gmail.com Password When using Jira Cloud, it is necessary to pass the API Token as the password. Using your login password might not work. For example, the API token could be lorelimpusm12uijk. Project Key This refers to the project key, which is typically a short, two-letter identifier (e.g., "AS") assigned by Jira. Using the full project name, such as "Algoshack Project," might not work, so it's important to always use the short version. Issue Type Indicates the category of an issue. For example, Bug. Reporter Name Name of the person in the project who is reporting the bug.
- Configure the testng.xml file
After all the required set up, testng.xml file must be configured to run the tests.
The following code displays sample xml file. (You can use your existing testng.xml file to run your tests).
Code snippet:?xml version="1.0" encoding="UTF-8"?>
<suite name="Default suite" parallel="methods" verbose="3">
<listeners>
<listener class-name="com.demo.listener.TestListener" />
</listeners>
<test name=" First test" skipfailedinvocationcounts="false">
<classes>
<class name="com.demo.project.HomePageTest">
</class>
</classes>
</test>
</suite> - Execute your tests
Upon completing the setup, execute the tests. After test execution, any failures must automatically trigger the creation of a Jira ticket. Results will be visible in the console section for further analysis and verification.
The following screenshot represents sample console output:
Successful completion of Selenium tests triggers automatic creation of a Jira Issue, with the console displaying the Issue ID and providing a URL to navigate to the specific issue. - Verifying Jira ticket creation
Navigate to the Jira dashboard to check whether an issue has been created or not. In the Jira dashboard, click on the project dashboard to see if a new issue has been created along with a particular test step failure details and Issue details as shown:
Most of the operations performed through the Jira user interface can be run using the REST API client. The Jira REST API client allows testers to automate the issue tracking and logging process, reducing the need for manual effort and attention.
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article