Adaptavist’s Test Management for Jira (TM4J) is a full-featured test management solution that seamlessly integrates with Jira. Coordinate and track all testing activities in a central location, and produce real-time insights with out-of-the-box reports designed to help assess the quality of your product. ScriptRunner integrates with TM4J, allowing you to automate and customise your tests, making them more accurate and efficient.

TM4J integration allows you to:

You must have, at minimum, ScriptRunner version 5.6.8.1 installed to use the TM4J events/integration.

TM4J Event Listeners

There are currently three TM4J events available for ScriptRunner:

  • TestExecutionChangedEvent - Fires when a test execution is updated.

  • TestCaseChangedEvent - Fires when a test case is updated.

  • TestCycleChangedEvent - Fires when a test cycle is updated.

Create listeners to run scripts when these TM4J events fire.

For more information on TM4J events in ScriptRunner, see the TM4J ScriptRunner for Jira documentation.
TM4J Server version 6.8 is the minimum version required for listener events.

Workflow Examples

These examples only work with Test Management for Jira 4.5.3 and above.

Workflow Condition that Prevents an Issue Transition

The below examples show two ways of preventing an issue transition via a workflow condition using ScriptRunner’s scripted condition option. The first example uses a JQL function provided by Test Management for Jira. The second example shows the same functionality, but this time using Test Management for Jira’s Java API. Using the Java API means that this example can be extended using additional logic.

In both examples, if an epic has an associated child issue with a non-passing test, the condition also fails to pass.
See Navigating to Workflow Functions page for details on how to get access ScriptRunner workflow functions.

JQL Query that Fails if the Issue has any Outstanding Non-passing Tests

  1. Navigate to the required transition and add a new ScriptRunner condition.

  2. Select the Allows Transition if this Query Matches a JQL Query option.

    select jql condition
  3. Optionally, add a Note to identify the condition.

  4. Use the hasAllLastTestResults("Pass") JQL function provided by TM4J to write a JQL Query for the condition.

  5. Enter a Preview Issue Key to check the JQL function on before saving.

    add jql condition details

For further details on additional JQL functions provided by Test Management for Jira and how to use them, please see the Advanced Searching with JQL Functions documentation.

Script that Fails if the Issue has any Outstanding Non-passing Tests

  1. Navigate to the required transition and add a new ScriptRunner condition.

  2. Select the Custom Script Condition option.

    select custom script condition
  3. Optionally, add a Note to identify the condition.

  4. Either select a Script File that contains the code shown below, or paste the following into the Inline Script field:

package examples.docs.tm4j

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.kanoah.testmanager.service.publicservice.IssueLinkPublicService
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

//Must use @WithPlugin annotation to pick up Test Management for JIRA classes
@WithPlugin("com.kanoah.test-manager")

def issueLinkPublicService = ComponentAccessor.getOSGiComponentInstanceOfType(IssueLinkPublicService)

def checkTestStatus = { Issue targetIssue ->
    issueLinkPublicService.getTestCases(targetIssue.key, "lastTestResultStatus").each {
        if (it.get("lastTestResultStatus") != "Pass") {
            passesCondition = false
        }
    }
}

if (issue.issueType.name == "Epic") {
    ComponentAccessor.getIssueLinkManager().getOutwardLinks(issue.id).each {
        if (it.issueLinkType.name == "Epic-Story Link") {
            checkTestStatus(it.destinationObject)
        }
    }
} else {
    checkTestStatus(issue)
}
The objects returned by the TM4J Java API are key/value maps representing each object or lists of such maps. You can tailor the key/values returned in the map by specifying the keys as a comma-separated parameter value on the method call. In the above example, we are requesting that the lastTestResultStatus for each test case be returned. For further details on the structure of the returned key/value maps provided by TM4J, please see the REST API documentation.

Workflow Post Function that Creates a Test Case

The below example shows how to use a scripted post function to create a new test case using details from the issue.

  1. Navigate to the required transition and add a new ScriptRunner post function.

  2. Select the Custom Script Post Function option.

    custom scripted post function
  3. Optionally, add a Note to identify the post function.

  4. Either select a Script File that contains the code shown below, or paste the following into the Inline Script field:

package examples.docs.tm4j

import com.atlassian.jira.component.ComponentAccessor
import com.kanoah.testmanager.model.activeobjects.TestScriptEntity
import com.kanoah.testmanager.service.model.StepDTO
import com.kanoah.testmanager.service.model.TestCaseDTO
import com.kanoah.testmanager.service.model.TestScriptDTO
import com.kanoah.testmanager.service.publicservice.TestCasePublicService
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

//Must use @WithPlugin annotation to pick up Test Management for JIRA classes
@WithPlugin("com.kanoah.test-manager")

def testCasePublicService = ComponentAccessor.getOSGiComponentInstanceOfType(TestCasePublicService)

def newTestCase = new TestCaseDTO(
    name: issue.summary,
    projectKey: issue.projectObject.key,
    objective: issue.description,
    testScript: new TestScriptDTO(
        type: TestScriptEntity.Type.STEP_BY_STEP.toString(),
        steps: [
            new StepDTO(
                description: "This is the first test step",
                testData: "First test step test data",
                expectedResult: "First test step expected result"
            ),
            new StepDTO(
                description: "This is the second test step",
                testData: "Second test step test data",
                expectedResult: "Second test step expected result"
            )
        ]
    ),
    issueLinks: [issue.key]
)

testCasePublicService.createTestCase(newTestCase)

Once done, the below code creates a new test case with the issue’s details every time the issue is transitioned with the post function’s corresponding workflow transition.

Scripted Fields Examples

This example only works with Test Management for Jira 4.5.3 and above.

Scripted Field for Displaying the Percentage of Passing Tests

The below example shows the creation of a scripted field which is used to display the percentage of passing tests. The script either displays the percentage of passing tests for an issue (or 100% in the case of issues with no tests) or, for an epic, displays the percentage of passing tests across all issues within that epic.

  1. Create a new ScriptRunner custom script field.

    For more information on how to create a custom script field, see our Scripted Fields documentation.
  2. Enter a Field Name (for example, Tests Passed) and Field Description.

  3. Optionally, add a Note.

  4. Set the Template to Custom. This allows us to control how we want to display the calculated field.

  5. Type $value% into the Custom Template field. $value represents the calculated result. While % is the unit of measurement, we want to display in this example.

    create passing tests custom field
  6. Either select a Script File that contains the code shown below or paste the following into the Inline Script field:

package examples.docs.tm4j

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.kanoah.testmanager.service.publicservice.IssueLinkPublicService
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

//Must use @WithPlugin annotation to pick up Test Management for JIRA classes
@WithPlugin("com.kanoah.test-manager")

def numberOfTests = 0
def numberOfPassingTests = 0

def issueLinkPublicService = ComponentAccessor.getOSGiComponentInstanceOfType(IssueLinkPublicService)

def countTestsInIssue = { Issue targetIssue ->
    issueLinkPublicService.getTestCases(targetIssue.key, "lastTestResultStatus").each {
        numberOfTests++
        if (it.get("lastTestResultStatus") == "Pass") {
            numberOfPassingTests++
        }
    }
}

if (issue.issueType.name == "Epic") {
    ComponentAccessor.getIssueLinkManager().getOutwardLinks(issue.id).each {
        if (it.issueLinkType.name == "Epic-Story Link") {
            countTestsInIssue(it.destinationObject)
        }
    }
} else {
    countTestsInIssue(issue)
}

if (numberOfTests == 0) {
    return 100
}
return (double) (numberOfPassingTests * 100) / numberOfTests

Once you have added the scripted field, you should have the below scripted field configuration:

resulting custom field config

Notice that the Searcher is listed as being a Free Text Searcher. This is the default. However, in order to make our scripted field more versatile and in order to run issue searches such as Percentage Of Tests Passing < 50 we need to change this to a Number Searcher. Now your config should look like the one below.

edited custom field config

TM4J Event Listeners Examples

To view example scripts for each TM4J event listener see the Creating Listeners in Scriptrunner for TM4J Events documentation.

Have questions? Visit the Atlassian Community to connect, share, and learn with other Atlassian users and experts, including Adaptavist staff.

Ask a question about ScriptRunner for JIRA, Bitbucket Server, or Confluence.

Want to learn more? Check out courses on Adaptavist Learn, an online platform to onboard and train new users for Atlassian solutions.