@salesforce/apex-node
Version:
Salesforce JS library for Apex
135 lines • 6.19 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JUnitFormatTransformer = void 0;
const utils_1 = require("../utils");
const node_stream_1 = require("node:stream");
const narrowing_1 = require("../narrowing");
const core_1 = require("@salesforce/core");
// cli currently has spaces in multiples of four for junit format
const tab = ' ';
const timeProperties = [
'testExecutionTimeInMs',
'testTotalTimeInMs',
'commandTimeInMs'
];
// properties not in cli junit spec
const skippedProperties = ['skipRate', 'totalLines', 'linesCovered'];
class JUnitFormatTransformer extends node_stream_1.Readable {
testResult;
logger;
buffer;
bufferSize;
constructor(testResult, options) {
super(options);
this.testResult = testResult;
this.testResult = testResult;
this.logger = core_1.Logger.childFromRoot('JUnitFormatTransformer');
this.buffer = '';
this.bufferSize = options?.bufferSize || 256; // Default buffer size is 256
}
pushToBuffer(chunk) {
this.buffer += chunk;
if (this.buffer.length >= this.bufferSize) {
this.push(this.buffer);
this.buffer = '';
}
}
_read() {
this.logger.trace('starting _read');
utils_1.HeapMonitor.getInstance().checkHeapSize('JUnitFormatTransformer._read');
this.format();
if (this.buffer.length > 0) {
this.push(this.buffer);
}
this.push(null); // Signal the end of the stream
this.logger.trace('finishing _read');
utils_1.HeapMonitor.getInstance().checkHeapSize('JUnitFormatTransformer._read');
}
format() {
const { summary } = this.testResult;
this.pushToBuffer(`<?xml version="1.0" encoding="UTF-8"?>\n`);
this.pushToBuffer(`<testsuites>\n`);
this.pushToBuffer(`${tab}<testsuite name="force.apex" `);
this.pushToBuffer(`timestamp="${summary.testStartTime}" `);
this.pushToBuffer(`hostname="${summary.hostname}" `);
this.pushToBuffer(`tests="${summary.testsRan}" `);
this.pushToBuffer(`failures="${summary.failing}" `);
this.pushToBuffer(`errors="0" `);
this.pushToBuffer(`time="${(0, utils_1.msToSecond)(summary.testExecutionTimeInMs)}">\n`);
this.buildProperties();
this.buildTestCases();
this.pushToBuffer(`${tab}</testsuite>\n`);
this.pushToBuffer(`</testsuites>\n`);
}
buildProperties() {
this.pushToBuffer(`${tab}${tab}<properties>\n`);
Object.entries(this.testResult.summary).forEach(([key, value]) => {
if ((0, narrowing_1.isEmpty)(value) || skippedProperties.includes(key)) {
return;
}
if (timeProperties.includes(key)) {
value = `${(0, utils_1.msToSecond)(value)} s`;
key = key.replace('InMs', '');
}
if (key === 'outcome' && value === 'Passed') {
value = 'Successful';
}
if (key === 'testStartTime') {
value = (0, utils_1.formatStartTime)(value);
}
this.pushToBuffer(`${tab}${tab}${tab}<property name="${key}" value="${value}"/>\n`);
// this call to setImmediate will schedule the closure on the event loop
// this action causing the current code to yield to the event loop
// allowing other processes to get time on the event loop
setImmediate(() => { });
});
this.pushToBuffer(`${tab}${tab}</properties>\n`);
}
buildTestCases() {
const testCases = this.testResult.tests;
for (const testCase of testCases) {
const methodName = JUnitFormatTransformer.xmlEscape(testCase.methodName);
this.pushToBuffer(`${tab}${tab}<testcase name="${methodName}" classname="${testCase.apexClass.fullName}" time="${(0, utils_1.msToSecond)(testCase.runTime)}">\n`);
if (testCase.outcome === "Fail" /* ApexTestResultOutcome.Fail */ ||
testCase.outcome === "CompileFail" /* ApexTestResultOutcome.CompileFail */) {
let message = (0, narrowing_1.isEmpty)(testCase.message) ? '' : testCase.message;
message = JUnitFormatTransformer.xmlEscape(message);
this.pushToBuffer(`${tab}${tab}${tab}<failure message="${message}">`);
if (testCase.stackTrace) {
this.pushToBuffer(`<![CDATA[${testCase.stackTrace}]]>`);
}
this.pushToBuffer(`</failure>\n`);
}
this.pushToBuffer(`${tab}${tab}</testcase>\n`);
// this call to setImmediate will schedule the closure on the event loop
// this action causing the current code to yield to the event loop
// allowing other processes to get time on the event loop
setImmediate(() => { });
}
}
static xmlEscape(value) {
return value
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
}
exports.JUnitFormatTransformer = JUnitFormatTransformer;
__decorate([
(0, utils_1.elapsedTime)()
], JUnitFormatTransformer.prototype, "format", null);
__decorate([
(0, utils_1.elapsedTime)()
], JUnitFormatTransformer.prototype, "buildProperties", null);
__decorate([
(0, utils_1.elapsedTime)()
], JUnitFormatTransformer.prototype, "buildTestCases", null);
//# sourceMappingURL=junitFormatTransformer.js.map