pw-simple-testrail-reporter
Version:
Report Playwright test results to TestRail
206 lines • 8.47 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestRailReporter = void 0;
exports.getTestCaseName = getTestCaseName;
const testrail_1 = __importDefault(require("@dlenroc/testrail"));
const logger_1 = __importDefault(require("./logger"));
const dotenv_1 = __importDefault(require("dotenv"));
// Read from default ".env" file.
dotenv_1.default.config();
/**
* Mapping status within Playwright & TestRail
*/
const StatusMap = new Map([
["failed", 5],
["passed", 1],
["skipped", 3],
["timedout", 5],
["interrupted", 5],
]);
/**
* Initialise TestRail API credential auth
*/
const api = new testrail_1.default({
host: process.env.TESTRAIL_HOST,
password: process.env.TESTRAIL_PASSWORD,
username: process.env.TESTRAIL_USERNAME,
});
const testResults = [];
// Track test case IDs that need to be added to the run
const testCasesToAdd = [];
// Track test case IDs already in the run
const existingTestCaseIds = new Set();
class TestRailReporter {
onBegin() {
return __awaiter(this, void 0, void 0, function* () {
if (!process.env.TESTRAIL_RUN_ID) {
(0, logger_1.default)("No 'TESTRAIL_RUN_ID' found, skipping reporting......");
return;
}
(0, logger_1.default)("Existing Test Run with ID " +
process.env.TESTRAIL_RUN_ID +
" will be used");
// Fetch existing test cases in the run
const runId = parseInt(process.env.TESTRAIL_RUN_ID);
try {
const tests = yield api.getTests(runId);
tests.forEach((test) => {
existingTestCaseIds.add(test.case_id);
});
(0, logger_1.default)(`Found ${existingTestCaseIds.size} test cases in run ${runId}`);
}
catch (error) {
(0, logger_1.default)(`Error fetching tests for run ${runId}: ${error}`);
}
});
}
onTestEnd(test, result) {
if (!process.env.TESTRAIL_RUN_ID) {
return;
}
(0, logger_1.default)(`Test Case Completed : ${test.title} Status : ${result.status}`);
// Return no test case match with TestRail Case ID Regex
const testCaseMatches = getTestCaseName(test.title);
if (testCaseMatches != null) {
try {
testCaseMatches.forEach((testCaseMatch) => {
const testId = parseInt(testCaseMatch.substring(1), 10);
// Check if test case is in the run
if (!existingTestCaseIds.has(testId)) {
testCasesToAdd.push(testId);
existingTestCaseIds.add(testId); // Add to set to avoid duplicates
(0, logger_1.default)(`Test case C${testId} not in run, will be added`);
}
// Update test status if test case is not skipped
if (result.status != "skipped") {
const testComment = setTestComment(result);
const payload = {
case_id: testId,
status_id: StatusMap.get(result.status),
comment: testComment,
};
testResults.push(payload);
}
});
}
catch (error) {
console.log(error);
}
}
else {
(0, logger_1.default)("Test case could not be extracted from test title!");
}
}
onEnd() {
return __awaiter(this, void 0, void 0, function* () {
if (!process.env.TESTRAIL_RUN_ID) {
return;
}
const runId = parseInt(process.env.TESTRAIL_RUN_ID);
// Add missing test cases to the run if any
if (testCasesToAdd.length > 0) {
try {
(0, logger_1.default)(`Adding ${testCasesToAdd.length} test cases to run ${runId}`);
// First get the current run to see its configuration
const currentRun = yield api.getRun(runId);
// Prepare the update payload
const updatePayload = {
case_ids: testCasesToAdd,
include_all: currentRun.include_all,
};
// If the run doesn't include all test cases, we need to add our new cases
// to the existing ones to avoid replacing them
if (!currentRun.include_all) {
// Get existing case IDs if they're not already included in all cases
const existingCaseIds = Array.from(existingTestCaseIds).filter((id) => !testCasesToAdd.includes(id));
// Combine existing and new case IDs
updatePayload.case_ids = [
...existingCaseIds,
...testCasesToAdd,
];
(0, logger_1.default)(`Preserving ${existingCaseIds.length} existing test cases in the run`);
}
// Update the run with the combined test cases
yield api.updateRun(runId, updatePayload);
(0, logger_1.default)(`Successfully added test cases to run ${runId}`);
}
catch (error) {
(0, logger_1.default)(`Error adding test cases to run ${runId}: ${error}`);
// If we can't add test cases, we should still try to update results for existing ones
}
}
// Update test results
if (testResults.length > 0) {
(0, logger_1.default)("Updating test status for the following TestRail Run ID: " +
runId);
yield updateResultCases(runId, testResults);
}
else {
(0, logger_1.default)("No test results to update");
}
});
}
onError(error) {
(0, logger_1.default)(error.message);
}
}
exports.TestRailReporter = TestRailReporter;
/**
* Get list of matching Test IDs
*/
function getTestCaseName(testname) {
const testCaseIdRegex = /\bC(\d+)\b/g;
const testCaseMatches = [testname.match(testCaseIdRegex)];
if (testCaseMatches[0] != null) {
testCaseMatches[0].forEach((testCaseMatch) => {
const testCaseId = parseInt(testCaseMatch.substring(1), 10);
(0, logger_1.default)("Matched Test Case ID: " + testCaseId);
});
}
else {
(0, logger_1.default)("No test case matches available");
}
return testCaseMatches[0];
}
/**
* Set Test comment for TestCase Failed | Passed
* @param result
* @returns
*/
function setTestComment(result) {
if (result.status == "failed" ||
result.status == "timedOut" ||
result.status == "interrupted") {
const comment = { testStatus: result.status, testError: result.error };
return JSON.stringify(comment);
}
else {
return `Test Passed within ${result.duration} ms`;
}
}
/**
* Update TestResult for Multiple Cases
* @param runId
* @param payload
*/
function updateResultCases(runId, payload) {
return __awaiter(this, void 0, void 0, function* () {
(0, logger_1.default)(payload);
yield api.addResultsForCases(runId, {
results: payload,
});
});
}
//# sourceMappingURL=reporter.js.map