From ef67b52d6d98fac73ce6bf99ecd509c665c5397b Mon Sep 17 00:00:00 2001 From: Peter Hedenskog Date: Mon, 24 Feb 2025 15:47:55 +0100 Subject: [PATCH] Replace the junit-report-builder package --- lib/plugins/budget/junit.js | 128 ++++++++++++++++++++++-------------- npm-shrinkwrap.json | 33 +--------- package.json | 1 - 3 files changed, 79 insertions(+), 83 deletions(-) diff --git a/lib/plugins/budget/junit.js b/lib/plugins/budget/junit.js index 4c300a904b..915115d496 100644 --- a/lib/plugins/budget/junit.js +++ b/lib/plugins/budget/junit.js @@ -1,69 +1,95 @@ import path from 'node:path'; -import { parse } from 'node:url'; - -import jrp from 'junit-report-builder'; - +import fs from 'node:fs'; +import merge from 'lodash.merge'; import { getLogger } from '@sitespeed.io/log'; + const log = getLogger('sitespeedio.plugin.budget'); -import merge from 'lodash.merge'; +/** + * Escapes XML special characters. + * + * @param {string} str - The text to escape. + * @returns {string} The escaped text. + */ +function xmlEscape(str) { + return String(str) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +/** + * Wraps a string in a CDATA block. + * + * @param {string} str - The string to wrap. + * @returns {string} The CDATA-wrapped string. + */ +function cdata(str) { + return ``; +} +/** + * Writes a JUnit XML report mimicking the original output. + * + * @param {object} results - Object containing `failing` and `working` results. + * @param {string} dir - Directory where `junit.xml` will be written. + * @param {object} options - Options (expects `options.budget.friendlyName`). + */ export function writeJunit(results, dir, options) { - // lets have one suite per URL - const urls = Object.keys(merge({}, results.failing, results.working)); + const failing = results.failing || {}; + const working = results.working || {}; + const urls = Object.keys(merge({}, failing, working)); - for (const url of urls) { - // The URL can be an alias - let name = url; - if (url.startsWith('http')) { - const parsedUrl = parse(url); - name = url.startsWith('http') ? url : url; - parsedUrl.hostname.replaceAll('.', '_') + - '.' + - parsedUrl.path.replaceAll('.', '_').replaceAll('/', '_'); - } + let totalTests = 0; + let totalFailures = 0; + let suitesXml = ''; - const suite = jrp - .testSuite() - .name(options.budget.friendlyName || 'sitespeed.io' + '.' + name); + for (const url of urls) { + const suiteName = `${options.budget.friendlyName || 'sitespeed.io'}.${url}`; + let suiteTests = 0; + let suiteFailures = 0; + let testCasesXml = ''; - if (results.failing[url]) { - for (const result of results.failing[url]) { - suite - .testCase() - .className(name) - .name(result.type + '.' + result.metric) - .failure( - result.metric + ' is ' + result.friendlyValue || - result.value + - ' and limit ' + - result.limitType + - ' ' + - result.friendlyLimit || - result.limit + ' ' + url - ); + if (failing[url]) { + for (const result of failing[url]) { + suiteTests++; + totalTests++; + suiteFailures++; + totalFailures++; + const testCaseName = `${result.type}.${result.metric}`; + const failureMessage = `${result.metric} is ${result.friendlyValue || result.value}`; + testCasesXml += ` \n`; + testCasesXml += ` \n`; + testCasesXml += ` \n`; } } - if (results.working[url]) { - for (const result of results.working[url]) { - suite - .testCase() - .className(name) - .name(result.type + '.' + result.metric) - .standardOutput( - result.metric + ' is ' + result.friendlyValue || - result.value + - ' and limit ' + - result.limitType + - ' ' + - result.friendlyLimit || - result.limit + ' ' + url - ); + if (working[url]) { + for (const result of working[url]) { + suiteTests++; + totalTests++; + const testCaseName = `${result.type}.${result.metric}`; + const systemOutMessage = `${result.metric} is ${result.friendlyValue || result.value}`; + testCasesXml += ` \n`; + testCasesXml += ` ${cdata(systemOutMessage)}\n`; + testCasesXml += ` \n`; } } + + suitesXml += ` \n`; + suitesXml += testCasesXml; + suitesXml += ` \n`; } + + const xml = + `\n` + + `\n` + + suitesXml + + `\n`; + const file = path.join(dir, 'junit.xml'); log.info('Write junit budget to %s', path.resolve(file)); - jrp.writeTo(file); + fs.writeFileSync(file, xml); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 5ecaa9a4a9..9494be036a 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -25,7 +25,6 @@ "fast-stats": "0.0.7", "import-global": "1.1.1", "influx": "5.9.3", - "junit-report-builder": "3.2.1", "lodash.get": "4.4.2", "lodash.merge": "4.6.2", "lodash.set": "4.3.2", @@ -4091,14 +4090,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/date-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", - "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/date-time": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", @@ -6793,28 +6784,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/junit-report-builder": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-3.2.1.tgz", - "integrity": "sha512-IMCp5XyDQ4YESDE4Za7im3buM0/7cMnRfe17k2X8B05FnUl9vqnaliX6cgOEmPIeWKfJrEe/gANRq/XgqttCqQ==", - "dependencies": { - "date-format": "4.0.3", - "lodash": "^4.17.21", - "make-dir": "^3.1.0", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/junit-report-builder/node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "engines": { - "node": ">=8.0" - } - }, "node_modules/jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -7088,6 +7057,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, "dependencies": { "semver": "^6.0.0" }, @@ -7102,6 +7072,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "bin": { "semver": "bin/semver.js" } diff --git a/package.json b/package.json index c6796ff1b5..e2c623b3c9 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,6 @@ "fast-stats": "0.0.7", "import-global": "1.1.1", "influx": "5.9.3", - "junit-report-builder": "3.2.1", "lodash.get": "4.4.2", "lodash.merge": "4.6.2", "lodash.set": "4.3.2",