jest-spiratest
Version:
This reporter will integrate JestJS with Inflectra's ALM suite. It will create a test run in Spira for each test executed in Jest. ### Don't have Spira? If you haven't tried out one of our products, you can get a 30 day free trial for our flagship ALM pro
207 lines (180 loc) • 7.53 kB
JavaScript
const http = require('http');
const https = require('https');
const spiraServiceUrl = "/Services/v5_0/RestService.svc/";
const runnerName = "JestJS"
/**
* Remove the spaces, special characters, and punctuation from the given string.
* Used for assigning test cases to individual specs (the it call)
* @param {string} name
*/
function compressName(name) {
return name.toLowerCase().replace(/[^a-z0-9]/ig, "")
}
class SpiraReporter {
constructor(globalConfig, options) {
/* Where all executed test runs are put before they are posted to Spira. Here is the format:
{
TestCaseId: int
TestName: string
RunnerStackTrace: string
ExecutionStatusId: int
StartDate: string
RunnerMessage: string
ReleaseId: int
TestSetId: int
} */
this.allTestRuns = [];
this.credentials = {};
//make sure user has given all the essentials
if (options.hasOwnProperty("url") && options.hasOwnProperty("username")
&& options.hasOwnProperty("token") && options.hasOwnProperty("projectId")) {
this.credentials.url = options.url;
this.credentials.username = options.username;
this.credentials.token = options.token;
this.credentials.projectId = options.projectId;
}
else {
//'yell' at them
console.error("-- SPIRA ERROR --");
console.error("Please make sure you have the 'url', 'username'," +
" 'token', and 'projectId' fields defined. This integration" +
" will not work without them.");
}
//make sure the user has test cases taken care of
if (options.hasOwnProperty("testCases")) {
this.credentials.testCases = {};
if (options.testCases.hasOwnProperty("default")) {
this.credentials.testCases.default = options.testCases.default;
}
else {
console.error("-- SPIRA ERROR --");
console.error("Please Make sure you have the 'default'" +
" field within the 'testCases' object. ");
}
//process unique test case names
for (var property in options.testCases) {
if (property != "default" && options.testCases.hasOwnProperty(property)) {
//remove special characters and spaces and assign to the credentials
this.credentials.testCases[compressName(property)] = options.testCases[property];
}
}
}
else {
console.error("-- SPIRA ERROR --");
console.error("Please make sure you have a field called 'testCases'");
}
//nonessential properties
if (options.hasOwnProperty("releaseId")) {
this.credentials.releaseId = options.releaseId;
}
if (options.hasOwnProperty("testSetId")) {
this.credentials.testSetId = options.testSetId;
}
}
async onRunComplete(contexts, results) {
await this.postTestRuns();
}
onTestResult(test, testResult, aggregatedResult) {
var results = testResult.testResults;
results.forEach(e => {
var newTestRun = {
TestCaseId: this.credentials.testCases.default,
RunnerName: runnerName,
RunnerTestName: e.title,
RunnerStackTrace: "",
ExecutionStatusId: -1,
StartDate: "/Date(" + new Date().getTime() + "-0000)/",
RunnerMessage: "",
}
//assign an individual test case
for (var property in this.credentials.testCases) {
if (property != "default" && this.credentials.testCases.hasOwnProperty(property)) {
if (compressName(e.title) == property) {
newTestRun.TestCaseId = this.credentials.testCases[property];
}
}
}
//Add up all the error messages
e.failureMessages.forEach(fail => {
newTestRun.RunnerStackTrace += fail + "\n";
})
if (e.status == "passed") {
//2 is passed in Spira
newTestRun.ExecutionStatusId = 2;
newTestRun.RunnerMessage = "Test Succeeded";
}
else if (e.status == "pending") {
//3 is Not Run in Spira
newTestRun.ExecutionStatusId = 3;
newTestRun.RunnerMessage = "Test Not Run";
}
else {
//1 is failed in Spira
newTestRun.ExecutionStatusId = 1;
newTestRun.RunnerMessage = "Test Failed"
}
//handle optional release and test set id's
if (this.credentials.hasOwnProperty("releaseId")) {
newTestRun.ReleaseId = this.credentials.releaseId;
}
if (this.credentials.hasOwnProperty("testSetId")) {
newTestRun.TestSetId = this.credentials.testSetId;
}
this.allTestRuns.push(newTestRun);
})
}
async postTestRuns() {
return new Promise(resolve => {
//we will submit all test runs at once
var url = this.credentials.url + spiraServiceUrl + "projects/" + this.credentials.projectId
+ "/test-runs/record?username=" + this.credentials.username
+ "&api-key=" + this.credentials.token;
var protocol = http.request;
if (url.startsWith("https")) {
protocol = https.request;
//cut the https:// out of the url
url = url.substring(8);
}
else if (url.startsWith("http")) {
//cut out the http:// out of the url
url = url.substring(7);
}
var path = url.substring(url.indexOf("/"));
url = url.substring(0, url.length - path.length);
var options = {
host: url,
path: path,
method: "POST",
headers: {
"Content-Type": "application/json",
"accept": "application/json"
}
}
//used to tell how many POST requests were actually made
var numRequestsMade = 0;
//tabulate our data into something Spira can read and POST it
this.allTestRuns.forEach(e => {
//open the POST request
var request = protocol(options, (res) => {
// console.log(res.statusCode + " : " + res.statusMessage);
res.on('data', chunk => {
numRequestsMade++;
// console.log("RETURN: " + chunk)
if (numRequestsMade == this.allTestRuns.length) {
//empty array for next suite.
this.allTestRuns = [];
resolve();
}
})
});
request.on("error", e => {
// console.log("Error " + e);
})
//actually send the data
request.write(JSON.stringify(e));
request.end();
});
});
}
}
module.exports = SpiraReporter;