From e5d7268006ed8c9a839e8650628c8739bc88a5a9 Mon Sep 17 00:00:00 2001 From: Devon Powell Date: Fri, 15 Nov 2024 16:36:55 -0500 Subject: [PATCH] fix: escape some special characters if present in test name (#386) --- src/helpers/report-builder.cjs | 3 +- src/helpers/strings.cjs | 11 +++ .../data/tests/mocha/reporter-1.test.js | 2 + .../data/tests/mocha/reporter-2.test.js | 2 + .../data/tests/mocha/reporter-3.test.js | 2 + .../data/tests/playwright/reporter-1.test.js | 2 + .../data/tests/playwright/reporter-2.test.js | 2 + .../data/tests/playwright/reporter-3.test.js | 2 + .../tests/web-test-runner/reporter-1.test.js | 2 + .../tests/web-test-runner/reporter-2.test.js | 2 + .../tests/web-test-runner/reporter-3.test.js | 2 + .../data/validation/test-report-mocha.js | 25 +++-- .../data/validation/test-report-playwright.js | 77 +++++++++++++-- .../validation/test-report-web-test-runner.js | 95 +++++++++++-------- 14 files changed, 174 insertions(+), 55 deletions(-) create mode 100644 src/helpers/strings.cjs diff --git a/src/helpers/report-builder.cjs b/src/helpers/report-builder.cjs index 5df7420..2eae798 100644 --- a/src/helpers/report-builder.cjs +++ b/src/helpers/report-builder.cjs @@ -4,6 +4,7 @@ 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 = [ @@ -186,7 +187,7 @@ class ReportDetailBuilder extends ReportBuilderBase { } setName(name, options) { - this._setProperty('name', name, options); + this._setProperty('name', escapeSpecialCharacters(name), options); return this; } diff --git a/src/helpers/strings.cjs b/src/helpers/strings.cjs new file mode 100644 index 0000000..c6f076a --- /dev/null +++ b/src/helpers/strings.cjs @@ -0,0 +1,11 @@ +const escapeSpecialCharacters = (str) => { + return str + .replace(/[\\]/g, '\\\\') + .replace(/[\b]/g, '\\b') + .replace(/[\f]/g, '\\f') + .replace(/[\n]/g, '\\n') + .replace(/[\r]/g, '\\r') + .replace(/[\t]/g, '\\t'); +}; + +module.exports = { escapeSpecialCharacters }; diff --git a/test/integration/data/tests/mocha/reporter-1.test.js b/test/integration/data/tests/mocha/reporter-1.test.js index ab064bb..a98f62e 100644 --- a/test/integration/data/tests/mocha/reporter-1.test.js +++ b/test/integration/data/tests/mocha/reporter-1.test.js @@ -27,6 +27,8 @@ describe('reporter 1', () => { it('failed', () => { throw new Error('fail'); }); + it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + afterEach(async() => { await delay(250); }); after(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 a8d256b..692b779 100644 --- a/test/integration/data/tests/mocha/reporter-2.test.js +++ b/test/integration/data/tests/mocha/reporter-2.test.js @@ -27,6 +27,8 @@ describe('reporter 2', () => { it('failed', () => { throw new Error('fail'); }); + it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + afterEach(async() => { await delay(250); }); after(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 156eda7..5c6ff79 100644 --- a/test/integration/data/tests/mocha/reporter-3.test.js +++ b/test/integration/data/tests/mocha/reporter-3.test.js @@ -27,6 +27,8 @@ describe('reporter 3', () => { it('failed', () => { throw new Error('fail'); }); + it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + afterEach(async() => { await delay(250); }); after(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 6536a2c..ad7abfe 100644 --- a/test/integration/data/tests/playwright/reporter-1.test.js +++ b/test/integration/data/tests/playwright/reporter-1.test.js @@ -55,6 +55,8 @@ test.describe('reporter 1', () => { throw new Error('fail'); }); + test('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + test.afterEach(async() => { await delay(250); }); test.afterAll(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 2f76aad..8254dd0 100644 --- a/test/integration/data/tests/playwright/reporter-2.test.js +++ b/test/integration/data/tests/playwright/reporter-2.test.js @@ -55,6 +55,8 @@ test.describe('reporter 2', () => { throw new Error('fail'); }); + test('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + test.afterEach(async() => { await delay(250); }); test.afterAll(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 4d8ace3..4b00ed4 100644 --- a/test/integration/data/tests/playwright/reporter-3.test.js +++ b/test/integration/data/tests/playwright/reporter-3.test.js @@ -55,6 +55,8 @@ test.describe('reporter 3', () => { throw new Error('fail'); }); + test('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + test.afterEach(async() => { await delay(250); }); test.afterAll(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 1bd0599..cb452f2 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,6 +13,8 @@ describe('reporter 1', () => { it('failed', () => { throw new Error('fail'); }); + it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + afterEach(async() => { await delay(250); }); after(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 836eb5f..7af0698 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,6 +13,8 @@ describe('reporter 2', () => { it('failed', () => { throw new Error('fail'); }); + it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + afterEach(async() => { await delay(250); }); after(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 1beeb38..20f22f3 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,6 +13,8 @@ describe('reporter 3', () => { it('failed', () => { throw new Error('fail'); }); + it('special/characters "(\n\r\t\b\f)"', async() => { await delay(); }); + afterEach(async() => { await delay(250); }); after(async() => { await delay(250); }); diff --git a/test/integration/data/validation/test-report-mocha.js b/test/integration/data/validation/test-report-mocha.js index 2fe38de..cb3b7a4 100644 --- a/test/integration/data/validation/test-report-mocha.js +++ b/test/integration/data/validation/test-report-mocha.js @@ -3,12 +3,7 @@ export const testReportV2Partial = { summary: { status: 'failed', framework: 'mocha', - count: { - passed: 2, - failed: 2, - skipped: 2, - flaky: 2 - } + count: { passed: 4, failed: 2, skipped: 2, flaky: 2 } }, details: [{ name: 'reporter 1 > passed', @@ -82,5 +77,23 @@ export const testReportV2Partial = { experience: 'Mocha 2 Test Framework', type: 'integration', retries: 3 + }, { + name: 'reporter 1 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { file: 'test/integration/data/tests/mocha/reporter-1.test.js' }, + timeout: 2000, + tool: 'Mocha 1 Test Reporting', + experience: 'Test Framework', + type: 'ui', + retries: 0 + }, { + name: 'reporter 2 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { file: 'test/integration/data/tests/mocha/reporter-2.test.js' }, + timeout: 2000, + tool: 'Test Reporting', + experience: 'Mocha 2 Test Framework', + type: 'integration', + retries: 0 }] }; diff --git a/test/integration/data/validation/test-report-playwright.js b/test/integration/data/validation/test-report-playwright.js index 60a75e5..c372e8c 100644 --- a/test/integration/data/validation/test-report-playwright.js +++ b/test/integration/data/validation/test-report-playwright.js @@ -3,12 +3,7 @@ export const testReportV2Partial = { summary: { status: 'failed', framework: 'playwright', - count: { - passed: 15, - failed: 5, - skipped: 30, - flaky: 5 - } + count: { passed: 20, failed: 5, skipped: 30, flaky: 5 } }, details: [{ name: '[chromium] > reporter 1 > skipped static, fixme', @@ -780,5 +775,75 @@ export const testReportV2Partial = { experience: 'Playwright 2 Test Framework', type: 'visual diff', retries: 0 + }, { + name: '[chromium] > reporter 1 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { + file: 'test/integration/data/tests/playwright/reporter-1.test.js', + line: 58, + column: 2 + }, + browser: 'chromium', + timeout: 30000, + tool: 'Playwright 1 Test Reporting', + experience: 'Playwright 1 Test Framework', + type: 'integration', + retries: 0 + }, { + name: '[chromium] > reporter 2 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { + file: 'test/integration/data/tests/playwright/reporter-2.test.js', + line: 58, + column: 2 + }, + browser: 'chromium', + timeout: 30000, + tool: 'Test Reporting', + experience: 'Playwright 2 Test Framework', + type: 'visual diff', + retries: 0 + }, { + name: '[firefox] > reporter 2 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { + file: 'test/integration/data/tests/playwright/reporter-2.test.js', + line: 58, + column: 2 + }, + browser: 'firefox', + timeout: 30000, + tool: 'Test Reporting', + experience: 'Playwright 2 Test Framework', + type: 'visual diff', + retries: 0 + }, { + name: '[webkit] > reporter 1 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { + file: 'test/integration/data/tests/playwright/reporter-1.test.js', + line: 58, + column: 2 + }, + browser: 'webkit', + timeout: 30000, + tool: 'Playwright 1 Test Reporting', + experience: 'Playwright 1 Test Framework', + type: 'integration', + retries: 0 + }, { + name: '[webkit] > reporter 2 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { + file: 'test/integration/data/tests/playwright/reporter-2.test.js', + line: 58, + column: 2 + }, + browser: 'webkit', + timeout: 30000, + tool: 'Test Reporting', + experience: 'Playwright 2 Test Framework', + type: 'visual diff', + retries: 0 }] }; diff --git a/test/integration/data/validation/test-report-web-test-runner.js b/test/integration/data/validation/test-report-web-test-runner.js index f2c22ae..e2b90fa 100644 --- a/test/integration/data/validation/test-report-web-test-runner.js +++ b/test/integration/data/validation/test-report-web-test-runner.js @@ -3,19 +3,12 @@ export const testReportV2Partial = { summary: { status: 'failed', framework: '@web/test-runner', - count: { - passed: 4, - failed: 4, - skipped: 4, - flaky: 0 - } + count: { passed: 8, failed: 4, skipped: 4, flaky: 0 } }, details: [{ name: 'reporter 1 > passed', status: 'passed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, browser: 'chrome', timeout: 120000, tool: 'WebTestRunner 1 Test Reporting', @@ -25,9 +18,7 @@ export const testReportV2Partial = { }, { name: 'reporter 1 > skipped', status: 'skipped', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, browser: 'chrome', timeout: 120000, tool: 'WebTestRunner 1 Test Reporting', @@ -37,9 +28,7 @@ export const testReportV2Partial = { }, { name: 'reporter 1 > failed', status: 'failed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, browser: 'chrome', timeout: 120000, tool: 'WebTestRunner 1 Test Reporting', @@ -49,9 +38,7 @@ export const testReportV2Partial = { }, { name: '[group 1] > reporter 2 > passed', status: 'passed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, browser: 'chromium', timeout: 120000, tool: 'Test Reporting', @@ -61,9 +48,7 @@ export const testReportV2Partial = { }, { name: '[group 1] > reporter 2 > skipped', status: 'skipped', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, browser: 'chromium', timeout: 120000, tool: 'Test Reporting', @@ -73,9 +58,7 @@ export const testReportV2Partial = { }, { name: '[group 1] > reporter 2 > failed', status: 'failed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, browser: 'chromium', timeout: 120000, tool: 'Test Reporting', @@ -85,9 +68,7 @@ export const testReportV2Partial = { }, { name: '[group 1] > reporter 2 > passed', status: 'passed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, browser: 'firefox', timeout: 120000, tool: 'Test Reporting', @@ -97,9 +78,7 @@ export const testReportV2Partial = { }, { name: '[group 1] > reporter 2 > skipped', status: 'skipped', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, browser: 'firefox', timeout: 120000, tool: 'Test Reporting', @@ -109,9 +88,7 @@ export const testReportV2Partial = { }, { name: '[group 1] > reporter 2 > failed', status: 'failed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, browser: 'firefox', timeout: 120000, tool: 'Test Reporting', @@ -121,9 +98,7 @@ export const testReportV2Partial = { }, { name: '[group 2] > reporter 1 > passed', status: 'passed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, browser: 'webkit', timeout: 120000, tool: 'WebTestRunner 1 Test Reporting', @@ -133,9 +108,7 @@ export const testReportV2Partial = { }, { name: '[group 2] > reporter 1 > skipped', status: 'skipped', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, browser: 'webkit', timeout: 120000, tool: 'WebTestRunner 1 Test Reporting', @@ -145,9 +118,47 @@ export const testReportV2Partial = { }, { name: '[group 2] > reporter 1 > failed', status: 'failed', - location: { - file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' - }, + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, + browser: 'webkit', + timeout: 120000, + tool: 'WebTestRunner 1 Test Reporting', + experience: 'WebTestRunner 1 Test Framework', + type: 'integration', + retries: 0 + }, { + name: 'reporter 1 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, + browser: 'chrome', + timeout: 120000, + tool: 'WebTestRunner 1 Test Reporting', + experience: 'WebTestRunner 1 Test Framework', + type: 'integration', + retries: 0 + }, { + name: '[group 1] > reporter 2 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, + browser: 'chromium', + timeout: 120000, + tool: 'Test Reporting', + experience: 'WebTestRunner 2 Test Framework', + type: 'accessibility', + retries: 0 + }, { + name: '[group 1] > reporter 2 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { file: 'test/integration/data/tests/web-test-runner/reporter-2.test.js' }, + browser: 'firefox', + timeout: 120000, + tool: 'Test Reporting', + experience: 'WebTestRunner 2 Test Framework', + type: 'accessibility', + retries: 0 + }, { + name: '[group 2] > reporter 1 > special/characters "(\\n\\r\\t\\b\\f)"', + status: 'passed', + location: { file: 'test/integration/data/tests/web-test-runner/reporter-1.test.js' }, browser: 'webkit', timeout: 120000, tool: 'WebTestRunner 1 Test Reporting',