diff --git a/packages/playwright-test/src/util.ts b/packages/playwright-test/src/util.ts index 11da8cc48b..5f7a33cf00 100644 --- a/packages/playwright-test/src/util.ts +++ b/packages/playwright-test/src/util.ts @@ -20,7 +20,7 @@ import url from 'url'; import type { TestError, Location } from './types'; import { default as minimatch } from 'minimatch'; import debug from 'debug'; -import { isRegExp } from 'playwright-core/lib/utils/utils'; +import { calculateSha1, isRegExp } from 'playwright-core/lib/utils/utils'; export function serializeError(error: Error | any): TestError { if (error instanceof Error) { @@ -83,7 +83,7 @@ export function createFileMatcher(patterns: string | RegExp | (string | RegExp)[ }; } -export function createTitleMatcher(patterns: RegExp | RegExp[]): Matcher { +export function createTitleMatcher(patterns: RegExp | RegExp[]): Matcher { const reList = Array.isArray(patterns) ? patterns : [patterns]; return (value: string) => { for (const re of reList) { @@ -144,6 +144,16 @@ export function sanitizeForFilePath(s: string) { return s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-'); } +export function trimLongString(s: string, length = 100) { + if (s.length <= length) + return s; + const hash = calculateSha1(s); + const middle = `-${hash.substring(0, 5)}-`; + const start = Math.floor((length - middle.length) / 2); + const end = length - middle.length - start; + return s.substring(0, start) + middle + s.slice(-end); +} + export function addSuffixToFilePath(filePath: string, suffix: string, customExtension?: string, sanitize = false): string { const dirname = path.dirname(filePath); const ext = path.extname(filePath); diff --git a/packages/playwright-test/src/workerRunner.ts b/packages/playwright-test/src/workerRunner.ts index fe93cf4a1d..f4e80505ff 100644 --- a/packages/playwright-test/src/workerRunner.ts +++ b/packages/playwright-test/src/workerRunner.ts @@ -21,7 +21,7 @@ import * as mime from 'mime'; import util from 'util'; import colors from 'colors/safe'; import { EventEmitter } from 'events'; -import { monotonicTime, serializeError, sanitizeForFilePath, getContainedPath, addSuffixToFilePath, prependToTestError } from './util'; +import { monotonicTime, serializeError, sanitizeForFilePath, getContainedPath, addSuffixToFilePath, prependToTestError, trimLongString } from './util'; import { TestBeginPayload, TestEndPayload, RunPayload, TestEntry, DonePayload, WorkerInitParams, StepBeginPayload, StepEndPayload } from './ipc'; import { setCurrentTestInfo } from './globals'; import { Loader } from './loader'; @@ -232,7 +232,8 @@ export class WorkerRunner extends EventEmitter { const relativeTestFilePath = path.relative(this._project.config.testDir, test._requireFile.replace(/\.(spec|test)\.(js|ts|mjs)$/, '')); const sanitizedRelativePath = relativeTestFilePath.replace(process.platform === 'win32' ? new RegExp('\\\\', 'g') : new RegExp('/', 'g'), '-'); const fullTitleWithoutSpec = test.titlePath().slice(1).join(' ') + (test._type === 'test' ? '' : '-worker' + this._params.workerIndex); - let testOutputDir = sanitizedRelativePath + '-' + sanitizeForFilePath(fullTitleWithoutSpec); + + let testOutputDir = sanitizedRelativePath + '-' + sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)); if (this._uniqueProjectNamePathSegment) testOutputDir += '-' + this._uniqueProjectNamePathSegment; if (retry) diff --git a/tests/playwright-test/test-output-dir.spec.ts b/tests/playwright-test/test-output-dir.spec.ts index 393f67773f..3b533b007b 100644 --- a/tests/playwright-test/test-output-dir.spec.ts +++ b/tests/playwright-test/test-output-dir.spec.ts @@ -429,6 +429,21 @@ test('should allow nonAscii characters in the output dir', async ({ runInlineTes expect(outputDir).toBe(path.join(testInfo.outputDir, 'test-results', 'my-test-こんにちは世界')); }); +test('should allow shorten long output dirs characters in the output dir', async ({ runInlineTest }, testInfo) => { + const result = await runInlineTest({ + 'my-test.spec.js': ` + const { test } = pwt; + test.describe('this is a really long description that would be too long for a file path', () => { + test('and this is an even longer test name that just keeps going and going and we should shorten it', async ({}, testInfo) => { + console.log('\\n%%' + testInfo.outputDir); + }); + }); + `, + }); + const outputDir = result.output.split('\n').filter(x => x.startsWith('%%'))[0].slice('%%'.length); + expect(outputDir).toBe(path.join(testInfo.outputDir, 'test-results', 'my-test-this-is-a-really-long-description-that-would-b-6d724--keeps-going-and-going-and-we-should-shorten-it')); +}); + test('should not mangle double dashes', async ({ runInlineTest }, testInfo) => { const result = await runInlineTest({ 'my--file.spec.js': `