playwright-tesults-reporter
Version:
Playwright Tesults Reporter
422 lines (392 loc) • 16.4 kB
JavaScript
// playwright-tesults-reporter.js
// @ts-nocheck
const fs = require('fs');
const path = require('path');
const tesults = require('tesults');
/** @implements {import('@playwright/test/reporter').Reporter} */
class tesultsReporter {
onBegin(config, suite) {
this.disabled = true
this.retries = new Map();
this.data = {
target: 'token',
results: {
cases: []
},
metadata: {
integration_name: "playwright-tesults-reporter",
integration_version: "1.3.1",
test_framework: "playwright"
}
};
this.testIndices = {}
this.caseFiles = (suite, name) => {
let files = [];
if (this.args['tesults-files'] !== undefined) {
try {
const filesPath = path.join(this.args['tesults-files'], suite, name);
fs.readdirSync(filesPath).forEach(function (file) {
if (file !== ".DS_Store") { // Exclude os files
files.push(path.join(filesPath, file));
}
});
} catch (err) {
if (err.code === 'ENOENT') {
// Normal scenario where no files present: console.log('Tesults error reading case files, check supplied tesults-files arg path is correct.');
} else {
console.log('Tesults error reading case files.')
}
}
}
return files;
}
this.startTimes = {};
this.args = {};
this.disabled = false;
this.targetKey = "tesults-target";
this.filesKey = "tesults-files";
this.configKey = "tesults-config";
this.buildNameKey = "tesults-build-name";
this.buildDescKey = "tesults-build-description";
this.buildResultKey = "tesults-build-result";
this.buildReasonKey = "tesults-build-reason";
if (config !== undefined && config !== null) {
if (config.reporter !== undefined && config.reporter !== null) {
if (Array.isArray(config.reporter)) {
for (let i = 0; i < config.reporter.length; i++) {
let reporter = config.reporter[i]
if (Array.isArray(reporter)) {
if (reporter.length > 0) {
let reporterName = reporter[0]
if (reporterName.indexOf("playwright-tesults-reporter") > -1) {
if (reporter.length > 1) {
let reportArgs = reporter[1];
if (reportArgs !== undefined && reportArgs !== null) {
this.args[this.targetKey] = reportArgs[this.targetKey]
this.args[this.filesKey] = reportArgs[this.filesKey]
this.args[this.buildNameKey] = reportArgs[this.buildNameKey]
this.args[this.buildDescKey] = reportArgs[this.buildDescKey]
this.args[this.buildResultKey] = reportArgs[this.buildResultKey]
this.args[this.buildReasonKey] = reportArgs[this.buildReasonKey]
}
}
}
}
}
}
}
}
}
/* Reserved for future use
process.argv.forEach((val, index) => {
if (val.indexOf(this.targetKey) === 0) {
this.args[this.targetKey] = val.substr(this.targetKey.length + 1);
}
if (val.indexOf(this.filesKey) === 0) {
this.args[this.filesKey] = val.substr(this.filesKey.length + 1);
}
if (val.indexOf(this.configKey) === 0) {
this.args[this.configKey] = val.substr(this.configKey.length + 1);
}
if (val.indexOf(this.buildNameKey) === 0) {
this.args[this.buildNameKey] = val.substr(this.buildNameKey.length + 1);
}
if (val.indexOf(this.buildDescKey) === 0) {
this.args[this.buildDescKey] = val.substr(this.buildDescKey.length + 1);
}
if (val.indexOf(this.buildResultKey) === 0) {
this.args[this.buildResultKey] = val.substr(this.buildResultKey.length + 1);
}
if (val.indexOf(this.buildReasonKey) === 0) {
this.args[this.buildReasonKey] = val.substr(this.buildReasonKey.length + 1);
}
});
*/
if (this.args[this.targetKey] === undefined) {
console.log(this.targetKey + " not provided. Tesults disabled.");
this.disabled = true;
}
}
onTestBegin(test, result) {
// Not used
}
onStepBegin (test, result, step) {
// Not used
}
onStepEnd (test, result, step) {
// Not used
}
onTestEnd(test, result) {
if (this.disabled === true) {
return;
}
let testCase = {};
testCase.name = test.title;
const consolidatedSuite = (entity, suite) => {
if (entity.parent !== undefined && entity.parent !== null) {
if (suite === "") {
if (entity.parent.title !== "") {
suite += entity.parent.title;
}
} else {
if (entity.parent.title !== "") {
suite += " - " + entity.parent.title;
}
}
return consolidatedSuite(entity.parent, suite);
} else {
return suite;
}
}
testCase.suite = consolidatedSuite(test, "");
try {
testCase["_Suite location"] = JSON.stringify(test.parent.location);
} catch (err) {
// Unable to handle suite location
}
testCase.rawResult = result.status;
testCase.result = "unknown";
if (result.status === "passed") {
testCase.result = "pass";
}
if (result.status === "failed") {
testCase.result = "fail";
}
if (test.expectedStatus !== "passed") { // "passed" is the default expected status
if (test.expectedStatus === result.status) {
testCase.result = "pass";
} else {
testCase.result = "fail";
}
}
try {
if (test.annotations !== undefined && test.annotations !== null) {
if (Array.isArray(test.annotations)) {
Object.keys(test.annotations).forEach((key) => {
testCase["_Annotation " + key] = test.annotations[key]
});
}
}
} catch (err) {
// Unable to capture annotations
}
testCase["_Timeout"] = test.timeout;
testCase["_Retries Configuration Setting"] = test.retries;
testCase["_Expected Status"] = test.expectedStatus;
try {
testCase["_Location"] = JSON.stringify(test.location);
} catch (err) {
// Unable to handle location
}
testCase["_Outcome"] = test.outcome();
testCase["_Ok"] = test.ok();
try {
testCase["_Test path"] = JSON.stringify(testCase.titlePath())
} catch (err) {
// Unable to capture test path
}
try {
testCase["_Repeat each index"] = test.repeatEachIndex;
} catch (err) {
// Unable to capture repeat each index
}
try {
testCase.start = result.startTime.getTime();
} catch (err) {
// Unable to capture start time
}
testCase.duration = result.duration;
if (testCase.start !== undefined) {
testCase.end = testCase.start + testCase.duration;
}
testCase["_Worker index"] = result.workerIndex;
testCase.files = [];
try {
if (result.attachments !== undefined && result.attachments !== null) {
if (Array.isArray(result.attachments)) {
for (let i = 0; i < result.attachments.length; i++) {
let attachment = result.attachments[i];
if (attachment.path !== undefined && attachment.path !== null) {
testCase.files.push(attachment.path);
}
}
}
}
} catch (err) {
// Unable to handle attachments
}
if (result.error !== undefined && result.error !== null) {
try {
testCase.reason = JSON.stringify(result.error);
} catch (err) {
// Unable to handle error
}
}
if (result.errors !== undefined && result.errors !== null) {
if (Array.isArray(result.errors)) {
try {
testCase["_Errors"] = JSON.stringify(result.errors);
} catch (err) {
// Unable to handle errors
}
}
}
if (result.stdout !== undefined && result.stdout !== null) {
if (Array.isArray(result.stdout)) {
try {
testCase["_Standard output"] = JSON.stringify(result.stdout);
} catch (err) {
// Unable to handle stdout
}
}
}
if (result.stderr !== undefined && result.stderr !== null) {
if (Array.isArray(result.stderr)) {
try {
testCase["_Standard error"] = JSON.stringify(result.stderr);
} catch (err) {
// Unable to handle stderr
}
}
}
if (result.steps !== undefined && result.steps !== null) {
testCase.steps = [];
if (Array.isArray(result.steps)) {
for (let i = 0; i < result.steps.length; i++) {
let step = result.steps[i];
let stepObj = {};
stepObj.name = step.title;
try {
stepObj.start = step.startTime.getTime();
} catch (err) {
// Unable to handle start
}
stepObj.duration = step.duration;
if (stepObj.start !== undefined) {
stepObj.end = stepObj.start + stepObj.duration;
}
try {
stepObj["_Location"] = JSON.stringify(step.location);
} catch (err) {
// Unable to handle location
}
stepObj.result = "pass";
if (step.error !== undefined && step.error !=null) {
stepObj.result = "fail";
try {
stepObj.reason = JSON.stringify(step.error);
} catch (err) {
// Unable to handle reason
}
}
if (step.titlePath() !== undefined && step.titlePath() !=null) {
if (Array.isArray(step.titlePath()))
try {
stepObj["_Path"] = JSON.stringify(step.titlePath());
} catch (err) {
// Unable to handle path
}
}
if (step.category !== undefined && step.category !== null) {
stepObj["_Category"] = step.category;
}
if (step.steps !== undefined && step.steps !== null) {
if (Array.isArray(step.steps)) {
try {
stepObj["_Steps"] = JSON.stringify(step.steps);
} catch (err) {
// Unable to handle steps
}
}
}
testCase.steps.push(stepObj);
}
}
}
if (result.retry !== undefined && result.retry !== null) {
testCase["_Retry"] = result.retry;
}
let additionalFiles = this.caseFiles(testCase.suite, testCase.name);
if (additionalFiles.length > 0) {
for (let i = 0; i < additionalFiles.length; i++) {
testCase.files.push(additionalFiles[i]);
}
}
let replace = false;
const hash = testCase.suite + " " + testCase.name;
if (this.testIndices[hash] !== undefined) {
// This is not the first run of this test case
let index = this.testIndices[hash];
if (index < this.data.results.cases.length) {
let t = this.data.results.cases[index];
if (t["_Retry"] !== testCase["_Retry"]) {
// Replacement
replace = true;
const retries = this.retries.get(hash);
testCase["_Retries"] = Array.from(retries);
retries.push(testCase);
this.retries.set(hash, retries);
this.data.results.cases[index] = testCase;
}
}
} else {
// This is the first run of this test case
testCase["_Retries"] = [];
this.retries.set(hash, [testCase]);
this.testIndices[hash] = this.data.results.cases.length
}
if (replace === false) {
this.data.results.cases.push(testCase);
}
}
onEnd (result) {
if (this.disabled === true) {
return;
}
// build case
if (this.args[this.buildNameKey] !== undefined) {
let buildCase = {suite: "[build]"};
buildCase.name = this.args[this.buildNameKey];
if (buildCase.name === "") {
buildCase.name = "-";
}
if (this.args[this.buildDescKey] !== undefined) {
buildCase.desc = this.args[this.buildDescKey];
}
if (this.args[this.buildReasonKey] !== undefined) {
buildCase.reason = this.args[this.buildReasonKey];
}
if (this.args[this.buildResultKey] !== undefined) {
buildCase.result = this.args[this.buildResultKey].toLowerCase();
if (buildCase.result !== "pass" && buildCase.result !== "fail") {
buildCase.result = "unknown";
}
} else {
buildCase.result = "unknown";
}
let files = this.caseFiles(buildCase.suite, buildCase.name);
if (files.length > 0) {
buildCase.files = files;
}
this.data.results.cases.push(buildCase);
}
// Tesults upload
this.data.target = this.args[this.targetKey];
console.log('Tesults results upload...');
return new Promise((resolve, reject) => {
tesults.results(this.data, function (err, response) {
if (err) {
console.log('Tesults library error, failed to upload.');
return reject('Tesults library error, failed to upload.');
} else {
console.log('Success: ' + response.success);
console.log('Message: ' + response.message);
console.log('Warnings: ' + response.warnings.length);
console.log('Errors: ' + response.errors.length);
resolve();
}
});
});
}
}
module.exports = tesultsReporter