cypress-xray-plugin
Version:
A Cypress plugin for uploading test results to Xray (test management for Jira)
190 lines (181 loc) • 9.17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConvertCypressTestsCommand = void 0;
const node_path_1 = require("node:path");
const semver_1 = require("semver");
const status_1 = require("../../../../../types/cypress/status");
const base64_1 = require("../../../../../util/base64");
const dedent_1 = require("../../../../../util/dedent");
const errors_1 = require("../../../../../util/errors");
const files_1 = require("../../../../../util/files");
const time_1 = require("../../../../../util/time");
const command_1 = require("../../../../command");
const converter_1 = require("./util/converter");
const status_conversion_1 = require("./util/status-conversion");
class ConvertCypressTestsCommand extends command_1.Command {
constructor(parameters, logger, results) {
super(parameters, logger);
this.results = results;
}
async computeResult() {
const results = await this.results.compute();
const version = (0, semver_1.lt)(results.cypressVersion, "13.0.0") ? "<13" : ">=13";
const convertedTests = this.convertTestRuns(results, version);
const runsByKey = new Map();
for (const convertedTest of convertedTests) {
if (convertedTest.issueKey === null) {
this.logger.message("warning", (0, dedent_1.dedent)(`
${convertedTest.spec.filepath}
Test: ${convertedTest.title}
Skipping result upload.
Caused by: ${(0, errors_1.errorMessage)((0, errors_1.missingTestKeyInTestTitleError)(convertedTest.title, this.parameters.projectKey))}
`));
}
else {
const runs = runsByKey.get(convertedTest.issueKey);
if (runs) {
runs.push(convertedTest);
}
else {
runsByKey.set(convertedTest.issueKey, [convertedTest]);
}
}
}
const xrayTests = [];
for (const [issueKey, testRuns] of runsByKey) {
xrayTests.push(this.getTest(testRuns, issueKey));
}
if (xrayTests.length === 0) {
throw new Error("Failed to convert Cypress tests into Xray tests: No Cypress tests to upload");
}
return [xrayTests[0], ...xrayTests.slice(1)];
}
convertTestRuns(runResults, version) {
const cypressRuns = runResults.runs.filter((run) => !this.parameters.featureFileExtension ||
!run.spec.relative.endsWith(this.parameters.featureFileExtension));
if (cypressRuns.length === 0) {
throw new Error("Failed to extract test run data: Only Cucumber tests were executed");
}
const converter = version === "<13"
? new converter_1.RunConverterV12(this.parameters.projectKey, cypressRuns)
: new converter_1.RunConverterLatest(this.parameters.projectKey, cypressRuns, this.parameters.screenshotCollection.getScreenshots());
const conversions = converter.getConversions({
onlyLastAttempt: this.parameters.uploadLastAttempt,
});
const testRunData = [];
for (const conversion of conversions) {
if (conversion.kind === "error") {
this.logger.message("warning", (0, dedent_1.dedent)(`
Test: ${conversion.title}
Skipping result upload.
Caused by: ${(0, errors_1.errorMessage)(conversion.error)}
`));
}
else {
testRunData.push(conversion);
}
}
if (this.parameters.uploadScreenshots) {
this.addScreenshotEvidence(testRunData, converter);
}
return testRunData;
}
addScreenshotEvidence(conversions, converter) {
const testIssueKeys = conversions
.map((conversion) => conversion.issueKey)
.filter((key) => key !== null);
for (const issueKey of new Set(testIssueKeys)) {
const screenshots = converter.getScreenshots(issueKey, {
onlyLastAttempt: this.parameters.uploadLastAttempt,
});
for (const screenshot of screenshots) {
let filename = (0, node_path_1.basename)(screenshot);
if (this.parameters.normalizeScreenshotNames) {
filename = (0, files_1.normalizedFilename)(filename);
}
this.parameters.evidenceCollection.addEvidence(issueKey, {
contentType: `image/${(0, node_path_1.extname)(screenshot).replace(".", "")}`,
data: (0, base64_1.encodeFile)(screenshot),
filename: filename,
});
}
}
for (const screenshot of converter.getNonAttributableScreenshots({
onlyLastAttempt: this.parameters.uploadLastAttempt,
})) {
const screenshotName = (0, node_path_1.parse)(screenshot).name;
this.logger.message("warning", (0, dedent_1.dedent)(`
${screenshot}
Screenshot cannot be attributed to a test and will not be uploaded.
To upload screenshots, include test issue keys anywhere in their name:
cy.screenshot("${this.parameters.projectKey}-123 ${screenshotName}")
`));
}
}
getTest(runs, issueKey) {
const xrayTest = {
finish: (0, time_1.truncateIsoTime)((0, time_1.latestDate)(...runs.map((test) => new Date(test.startedAt.getTime() + test.duration))).toISOString()),
start: (0, time_1.truncateIsoTime)((0, time_1.earliestDate)(...runs.map((test) => test.startedAt)).toISOString()),
status: this.getXrayStatus(runs),
testKey: issueKey,
};
const evidence = this.getXrayEvidence(issueKey);
if (evidence.length > 0) {
xrayTest.evidence = evidence;
}
if (runs.length > 1) {
const iterations = [];
for (const iteration of runs) {
const definedParameters = this.parameters.iterationParameterCollection.getIterationParameters(issueKey, iteration.title);
iterations.push({
parameters: [
{
name: "iteration",
value: (iterations.length + 1).toString(),
},
...Object.entries(definedParameters).map(([key, value]) => {
return {
name: key,
value: value,
};
}),
],
status: (0, status_conversion_1.getXrayStatus)(iteration.status, this.parameters.useCloudStatusFallback === true, this.parameters.xrayStatus),
});
}
xrayTest.iterations = iterations;
}
return xrayTest;
}
getXrayStatus(tests) {
const statuses = tests.map((test) => test.status);
if (statuses.length > 1) {
const passed = statuses.filter((s) => s === status_1.CypressStatus.PASSED).length;
const failed = statuses.filter((s) => s === status_1.CypressStatus.FAILED).length;
const pending = statuses.filter((s) => s === status_1.CypressStatus.PENDING).length;
const skipped = statuses.filter((s) => s === status_1.CypressStatus.SKIPPED).length;
if (this.parameters.xrayStatus.aggregate) {
return this.parameters.xrayStatus.aggregate({ failed, passed, pending, skipped });
}
if (passed > 0 && failed === 0 && skipped === 0) {
return (0, status_conversion_1.getXrayStatus)(status_1.CypressStatus.PASSED, this.parameters.useCloudStatusFallback === true, this.parameters.xrayStatus);
}
if (passed === 0 && failed === 0 && skipped === 0 && pending > 0) {
return (0, status_conversion_1.getXrayStatus)(status_1.CypressStatus.PENDING, this.parameters.useCloudStatusFallback === true, this.parameters.xrayStatus);
}
if (skipped > 0) {
return (0, status_conversion_1.getXrayStatus)(status_1.CypressStatus.SKIPPED, this.parameters.useCloudStatusFallback === true, this.parameters.xrayStatus);
}
return (0, status_conversion_1.getXrayStatus)(status_1.CypressStatus.FAILED, this.parameters.useCloudStatusFallback === true, this.parameters.xrayStatus);
}
return (0, status_conversion_1.getXrayStatus)(statuses[0], this.parameters.useCloudStatusFallback === true, this.parameters.xrayStatus);
}
getXrayEvidence(issueKey) {
const evidence = [];
this.parameters.evidenceCollection
.getEvidence(issueKey)
.forEach((item) => evidence.push(item));
return evidence;
}
}
exports.ConvertCypressTestsCommand = ConvertCypressTestsCommand;