diff --git a/eslint.config.js b/eslint.config.js index f17f1d6..64e3ee9 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -49,7 +49,8 @@ const playwrightConfigs = addExtensions( rules: { 'playwright/expect-expect': 'off', 'playwright/no-skipped-test': 'off', - 'playwright/no-conditional-in-test': 'off' + 'playwright/no-conditional-in-test': 'off', + 'playwright/valid-title': 'off' } } ], diff --git a/src/helpers/report-builder.cjs b/src/helpers/report-builder.cjs index 2eae798..6823ee7 100644 --- a/src/helpers/report-builder.cjs +++ b/src/helpers/report-builder.cjs @@ -4,7 +4,6 @@ const { randomUUID } = require('node:crypto'); const { resolve } = require('node:path'); const { ReportConfiguration } = require('./report-configuration.cjs'); const { writeFileSync } = require('node:fs'); -const { escapeSpecialCharacters } = require('./strings.cjs'); const defaultReportPath = './d2l-test-report.json'; const reportMemberPriority = [ @@ -58,7 +57,7 @@ class ReportBuilderBase { this._data = {}; } - toJSON() { + get data() { return this._data; } @@ -187,7 +186,7 @@ class ReportDetailBuilder extends ReportBuilderBase { } setName(name, options) { - this._setProperty('name', escapeSpecialCharacters(name), options); + this._setProperty('name', name, options); return this; } @@ -350,8 +349,8 @@ class ReportBuilder extends ReportBuilderBase { let countSkipped = 0; let countFlaky = 0; - for (const [, detail] of this._data.details) { - const { status, retries } = detail.toJSON(); + for (const [, { data: detail }] of this._data.details) { + const { status, retries } = detail; if (status === 'passed') { if (retries !== 0) { @@ -366,7 +365,7 @@ class ReportBuilder extends ReportBuilderBase { } if (this._verbose) { - const { name, location, type, tool, experience } = detail.toJSON(); + const { name, location, type, tool, experience } = detail; const prefix = `Test '${name}' at '${location}' is missing`; if (!type) { @@ -393,12 +392,12 @@ class ReportBuilder extends ReportBuilderBase { } toJSON() { - const data = super.toJSON(); + const { summary, details } = this.data; return { - ...data, - summary: data.summary.toJSON(), - details: [...data.details].map(([, detail]) => detail.toJSON()) + ...this.data, + summary: summary.data, + details: [...details.values()].map(({ data }) => data) }; } diff --git a/src/helpers/strings.cjs b/src/helpers/strings.cjs index c6f076a..fa9315e 100644 --- a/src/helpers/strings.cjs +++ b/src/helpers/strings.cjs @@ -1,11 +1,13 @@ const escapeSpecialCharacters = (str) => { return str .replace(/[\\]/g, '\\\\') + .replace(/[\0]/g, '\\0') .replace(/[\b]/g, '\\b') - .replace(/[\f]/g, '\\f') .replace(/[\n]/g, '\\n') .replace(/[\r]/g, '\\r') - .replace(/[\t]/g, '\\t'); + .replace(/[\t]/g, '\\t') + .replace(/[\v]/g, '\\v') + .replace(/[\f]/g, '\\f'); }; module.exports = { escapeSpecialCharacters }; diff --git a/src/reporters/mocha.cjs b/src/reporters/mocha.cjs index 4c6ddee..e53ac2b 100644 --- a/src/reporters/mocha.cjs +++ b/src/reporters/mocha.cjs @@ -1,4 +1,5 @@ const { reporters: { Base, Spec }, Runner: { constants } } = require('mocha'); +const { escapeSpecialCharacters } = require('../helpers/strings.cjs'); const { ReportBuilder } = require('../helpers/report-builder.cjs'); const { consoleLog, color } = Base; @@ -19,7 +20,10 @@ class MochaLogger { } const makeDetailName = (test) => { - return test.titlePath().join(' > '); + return test + .titlePath() + .map(titlePart => escapeSpecialCharacters(titlePart).trim()) + .join(' > '); }; const makeDetailId = (file, name) => { diff --git a/src/reporters/playwright.js b/src/reporters/playwright.js index 510a0a4..399242f 100644 --- a/src/reporters/playwright.js +++ b/src/reporters/playwright.js @@ -1,5 +1,6 @@ import { createRequire } from 'node:module'; import { colors } from 'playwright-core/lib/utilsBundle'; +import { escapeSpecialCharacters } from '../helpers/strings.cjs'; const require = createRequire(import.meta.url); @@ -18,7 +19,9 @@ const makeTestName = (test) => { const [, projectName, , ...titles] = test.titlePath(); const titlePaths = projectName ? [`[${projectName}]`, ...titles] : titles; - return titlePaths.join(' > '); + return titlePaths + .map(titlePart => escapeSpecialCharacters(titlePart).trim()) + .join(' > '); }; const getBrowser = (project) => { diff --git a/src/reporters/web-test-runner.js b/src/reporters/web-test-runner.js index 026866c..188e4b6 100644 --- a/src/reporters/web-test-runner.js +++ b/src/reporters/web-test-runner.js @@ -1,6 +1,7 @@ +import chalk from 'chalk'; +import { escapeSpecialCharacters } from '../helpers/strings.cjs'; import { ReportBuilder } from '../helpers/report-builder.cjs'; import { SESSION_STATUS } from '@web/test-runner-core'; -import chalk from 'chalk'; const { yellow, red, cyan, bold } = chalk; @@ -11,8 +12,12 @@ class WebTestRunnerLogger { location(message, location) { this.info(`${message}: ${cyan(bold(location))}`); } } +const sanitizeName = (name) => { + return escapeSpecialCharacters(name).trim(); +}; + const makeDetailName = (prefix, testName) => { - return `${prefix}${testName}`; + return `${prefix}${sanitizeName(testName)}`; }; const makeDetailId = (sessionId, file, name) => { @@ -93,7 +98,7 @@ export function reporter(options = {}) { collectTests(session, prefix, suite.tests); for (const childSuite of suite.suites) { - const newPrefix = `${prefix}${childSuite.name} > `; + const newPrefix = `${prefix}${sanitizeName(childSuite.name)} > `; collectSuite(session, newPrefix, childSuite); } @@ -105,7 +110,7 @@ export function reporter(options = {}) { for (const session of sessions) { const { passed, group: { name: groupName }, testResults } = session; const isGroupName = groupName && testConfig.groups?.some(({ name }) => groupName === name); - const prefix = isGroupName ? `[${groupName}] > ` : ''; + const prefix = isGroupName ? `[${sanitizeName(groupName)}] > ` : ''; overallPassed &= passed; diff --git a/test/integration/data/tests/mocha/reporter-1.test.js b/test/integration/data/tests/mocha/reporter-1.test.js index a98f62e..72b54c8 100644 --- a/test/integration/data/tests/mocha/reporter-1.test.js +++ b/test/integration/data/tests/mocha/reporter-1.test.js @@ -27,7 +27,7 @@ describe('reporter 1', () => { it('failed', () => { throw new Error('fail'); }); - it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + it(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/mocha/reporter-2.test.js b/test/integration/data/tests/mocha/reporter-2.test.js index 692b779..57e685a 100644 --- a/test/integration/data/tests/mocha/reporter-2.test.js +++ b/test/integration/data/tests/mocha/reporter-2.test.js @@ -27,7 +27,7 @@ describe('reporter 2', () => { it('failed', () => { throw new Error('fail'); }); - it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + it(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/mocha/reporter-3.test.js b/test/integration/data/tests/mocha/reporter-3.test.js index 5c6ff79..4eaf511 100644 --- a/test/integration/data/tests/mocha/reporter-3.test.js +++ b/test/integration/data/tests/mocha/reporter-3.test.js @@ -27,7 +27,7 @@ describe('reporter 3', () => { it('failed', () => { throw new Error('fail'); }); - it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + it(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/playwright/reporter-1.test.js b/test/integration/data/tests/playwright/reporter-1.test.js index ad7abfe..ee160a3 100644 --- a/test/integration/data/tests/playwright/reporter-1.test.js +++ b/test/integration/data/tests/playwright/reporter-1.test.js @@ -55,7 +55,7 @@ test.describe('reporter 1', () => { throw new Error('fail'); }); - test('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + test(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); test.afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/playwright/reporter-2.test.js b/test/integration/data/tests/playwright/reporter-2.test.js index 8254dd0..e811561 100644 --- a/test/integration/data/tests/playwright/reporter-2.test.js +++ b/test/integration/data/tests/playwright/reporter-2.test.js @@ -55,7 +55,7 @@ test.describe('reporter 2', () => { throw new Error('fail'); }); - test('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + test(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); test.afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/playwright/reporter-3.test.js b/test/integration/data/tests/playwright/reporter-3.test.js index 4b00ed4..0d539fc 100644 --- a/test/integration/data/tests/playwright/reporter-3.test.js +++ b/test/integration/data/tests/playwright/reporter-3.test.js @@ -55,7 +55,7 @@ test.describe('reporter 3', () => { throw new Error('fail'); }); - test('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + test(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); test.afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/web-test-runner/reporter-1.test.js b/test/integration/data/tests/web-test-runner/reporter-1.test.js index cb452f2..48ec483 100644 --- a/test/integration/data/tests/web-test-runner/reporter-1.test.js +++ b/test/integration/data/tests/web-test-runner/reporter-1.test.js @@ -13,7 +13,7 @@ describe('reporter 1', () => { it('failed', () => { throw new Error('fail'); }); - it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + it(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/web-test-runner/reporter-2.test.js b/test/integration/data/tests/web-test-runner/reporter-2.test.js index 7af0698..5691036 100644 --- a/test/integration/data/tests/web-test-runner/reporter-2.test.js +++ b/test/integration/data/tests/web-test-runner/reporter-2.test.js @@ -13,7 +13,7 @@ describe('reporter 2', () => { it('failed', () => { throw new Error('fail'); }); - it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + it(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); afterEach(async() => { await delay(250); }); diff --git a/test/integration/data/tests/web-test-runner/reporter-3.test.js b/test/integration/data/tests/web-test-runner/reporter-3.test.js index 20f22f3..644d388 100644 --- a/test/integration/data/tests/web-test-runner/reporter-3.test.js +++ b/test/integration/data/tests/web-test-runner/reporter-3.test.js @@ -13,7 +13,7 @@ describe('reporter 3', () => { it('failed', () => { throw new Error('fail'); }); - it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + it(' special/characters "(\n\r\t\b\f)" ', async() => { await delay(); }); afterEach(async() => { await delay(250); });