playwright-trx-reporter
Version:
TRX reporter for playwright
209 lines (208 loc) • 8.16 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiTrxsBuilder = exports.SingleTrxBuilder = void 0;
const fs_1 = __importDefault(require("fs"));
const TestRunBuilder_1 = require("./TestRunBuilder");
const trxModel_1 = require("./trxModel");
const assert_1 = require("./assert");
const utils_1 = require("./utils");
function mergeAllSuitesToTestRunBuilder(testRunsBuilder, suite, options) {
for (const projectSuite of suite.suites) {
for (const fileSuite of projectSuite.suites) {
mergeFileOrGroupSuite(testRunsBuilder, fileSuite, options);
}
}
}
function mergeFileOrGroupSuite(testRunsBuilder, suite, options) {
if (suite.allTests().length === 0) {
return;
}
suite.tests.forEach((test) => {
mergeTestCase(testRunsBuilder, test, options);
});
suite.suites.forEach((subSuite) => {
mergeFileOrGroupSuite(testRunsBuilder, subSuite, options);
});
}
function mergeTestCase(testRunsBuilder, test, options) {
const { ownerAnnotation, priorityAnnotation } = options;
const trxUnitTestResults = buildTrxUnitTestResultByPwTestCase(test);
// TODO: use `formatTestTitle`?
// remove root title, which is just empty
// remove current test name
const classNameForJs = test.titlePath().slice(1).slice(0, -1).join(TestRunBuilder_1.NAME_SPLITTER);
const owner = getFromAnnotationByType(test.annotations, ownerAnnotation);
const priority = Number(getFromAnnotationByType(test.annotations, priorityAnnotation)) || undefined;
trxUnitTestResults.forEach((trxResult, index) => {
const testRunBuilder = testRunsBuilder.getOrCreateTestRunBuilder(index);
testRunBuilder.addTestResult(trxResult, {
testDefinitionAdditionalInfo: {
owner,
priority,
fileLocation: test.location.file,
className: classNameForJs,
},
});
});
}
function buildTrxUnitTestResultByPwTestCase(test) {
// TODO: assert test.results is sorted by retry index.
return test.results.map((result) => buildTrxUnitTestResultByPwTestResult(test, result));
}
// TODO: copy from playwright implementation, so that it would be easy to migrate
function formatMs2TimeSpanString(ms) {
return new Date(ms).toISOString().slice(11, 23);
}
function buildTrxUnitTestResultByPwTestResult(test, result) {
const endTime = new Date(result.startTime);
endTime.setMilliseconds(result.startTime.getMilliseconds() + result.duration);
const unitTestResult = new trxModel_1.UnitTestResultType({
$computerName: utils_1.computerName,
$testId: (0, utils_1.convertPwId2Uuid)(test.id),
$testListId: TestRunBuilder_1.RESULT_NOT_IN_A_LIST_ID,
$testName: test.titlePath().slice(1).join(TestRunBuilder_1.NAME_SPLITTER),
$testType: trxModel_1.UNIT_TEST_TYPE,
$duration: formatMs2TimeSpanString(result.duration),
$startTime: result.startTime.toISOString(),
$endTime: endTime.toISOString(),
$executionId: (0, utils_1.createUuid)(),
$outcome: pwOutcome2TrxOutcome(result.status),
});
bindAttachment(unitTestResult, test, result);
bindOutput(unitTestResult, test, result);
return unitTestResult;
}
function bindOutput(unitTestResult, test, result) {
var _a, _b;
// TODO: in which condition errors will have multi errors?
// the test catch the error?
let errorInfoMessage;
let errorInfoStackTrace;
if ((_a = result.error) === null || _a === void 0 ? void 0 : _a.stack) {
const { stack } = result.error;
const firstStackLine = stack.indexOf('\n at ');
errorInfoMessage = `${stack.slice(0, firstStackLine)}`;
errorInfoStackTrace = `\n${(_b = result.error.snippet) !== null && _b !== void 0 ? _b : ''}\n${stack.slice(firstStackLine)}`;
}
const stdOutString = getStringFromStdStream(result.stdout);
const stdErrString = getStringFromStdStream(result.stderr);
const errorInfo = (errorInfoMessage || errorInfoStackTrace) ? {
Message: errorInfoMessage,
StackTrace: errorInfoStackTrace,
} : undefined;
if (stdOutString || stdErrString || errorInfo) {
unitTestResult.Output = {
StdOut: stdOutString,
StdErr: stdErrString,
ErrorInfo: errorInfo,
};
}
}
function bindAttachment(unitTestResult, test, result) {
const attachmentPaths = [];
for (const attachment of result.attachments) {
const attachmentPath = attachment.path;
if (attachmentPath) {
if (fs_1.default.existsSync(attachmentPath)) {
attachmentPaths.push(attachmentPath);
}
else {
console.warn(`File path "${attachmentPath}" is not found for Attachment "${attachment.name}"`);
}
}
}
if (attachmentPaths.length !== 0) {
unitTestResult.ResultFiles = {
ResultFile: attachmentPaths.map((p) => ({ $path: p })),
};
}
}
function getStringFromStdStream(stdStream) {
return stdStream.map((i) => i.toString()).join();
}
function pwOutcome2TrxOutcome(outcome) {
switch (outcome) {
case 'failed':
return trxModel_1.TestOutcome.Failed;
case 'interrupted':
return trxModel_1.TestOutcome.Aborted;
case 'passed':
return trxModel_1.TestOutcome.Passed;
case 'timedOut':
return trxModel_1.TestOutcome.Timeout;
case 'skipped':
return trxModel_1.TestOutcome.NotExecuted;
default:
(0, assert_1.assertNever)(outcome);
}
}
function getFromAnnotationByType(annotations, type) {
for (let index = annotations.length - 1; index >= 0; index -= 1) {
const annotation = annotations[index];
if (annotation.type === type) {
return annotation.description;
}
}
}
function createDummyTestRunBuilderOption(options) {
return Object.assign(Object.assign({}, options), { id: (0, utils_1.createUuid)(), startTime: (new Date()).toISOString(), endTime: (new Date()).toISOString() });
}
class SingleTrxWriterTestRunsBuilder {
constructor(_options) {
this._options = _options;
this._builders = [];
}
getOrCreateTestRunBuilder(testResultIndex) {
if (!this._builders[0]) {
const finalOption = this._options;
const newBuilder = new TestRunBuilder_1.TestRunBuilder(finalOption);
this._builders[0] = newBuilder;
}
return this._builders[0];
}
build() {
return this._builders.map((b) => b.build());
}
}
class MultiTrxWriterTestRunsBuilder {
constructor(_options) {
this._options = _options;
this._builders = [];
}
getOrCreateTestRunBuilder(testResultIndex) {
if (!this._builders[testResultIndex]) {
const finalOption = testResultIndex === 0 ? this._options : createDummyTestRunBuilderOption(this._options);
const newBuilder = new TestRunBuilder_1.TestRunBuilder(finalOption);
this._builders[testResultIndex] = newBuilder;
}
return this._builders[testResultIndex];
}
build() {
return this._builders.map((b) => b.build());
}
}
/**
* The test cases are written into only one trx file.
*/
class SingleTrxBuilder {
analytics(rootSuite, options) {
const b = new SingleTrxWriterTestRunsBuilder(options.testRunBuilderOptions);
mergeAllSuitesToTestRunBuilder(b, rootSuite, options);
return b.build();
}
}
exports.SingleTrxBuilder = SingleTrxBuilder;
/**
* The trx cases might be written into multi trx files.
*/
class MultiTrxsBuilder {
analytics(rootSuite, options) {
const b = new MultiTrxWriterTestRunsBuilder(options.testRunBuilderOptions);
mergeAllSuitesToTestRunBuilder(b, rootSuite, options);
return b.build();
}
}
exports.MultiTrxsBuilder = MultiTrxsBuilder;