diff --git a/docs/src/test-reporters-js.md b/docs/src/test-reporters-js.md index 97ea0af5dd..0f96666c3e 100644 --- a/docs/src/test-reporters-js.md +++ b/docs/src/test-reporters-js.md @@ -261,10 +261,9 @@ Running 124 tests using 6 workers ### HTML reporter HTML reporter produces a self-contained folder that contains report for the test run that can be served as a web page. -It is usually used together with some terminal reporter like `dot` or `line`. ```bash -npx playwright test --reporter=html,dot +npx playwright test --reporter=html ``` By default, report is written into the `playwright-report` folder in the current working directory. One can override diff --git a/packages/playwright-test/src/reporters/base.ts b/packages/playwright-test/src/reporters/base.ts index 2e5d52aa78..240cde10d6 100644 --- a/packages/playwright-test/src/reporters/base.ts +++ b/packages/playwright-test/src/reporters/base.ts @@ -62,6 +62,11 @@ export class BaseReporter implements Reporter { fileDurations = new Map(); monotonicStartTime: number = 0; private printTestOutput = !process.env.PWTEST_SKIP_TEST_OUTPUT; + protected _omitFailures: boolean; + + constructor(options: { omitFailures?: boolean } = {}) { + this._omitFailures = options.omitFailures || false; + } onBegin(config: FullConfig, suite: Suite) { this.monotonicStartTime = monotonicTime(); @@ -113,7 +118,6 @@ export class BaseReporter implements Reporter { protected generateSummaryMessage({ skipped, expected, unexpected, flaky }: TestSummary) { const tokens: string[] = []; - tokens.push(''); if (unexpected.length) { tokens.push(colors.red(` ${unexpected.length} failed`)); for (const test of unexpected) @@ -169,7 +173,7 @@ export class BaseReporter implements Reporter { epilogue(full: boolean) { const summary = this.generateSummary(); const summaryMessage = this.generateSummaryMessage(summary); - if (full && summary.failuresToPrint.length) + if (full && summary.failuresToPrint.length && !this._omitFailures) this._printFailures(summary.failuresToPrint); this._printSlowTests(); this._printSummary(summaryMessage); @@ -191,9 +195,11 @@ export class BaseReporter implements Reporter { }); } - private _printSummary(summary: string){ - console.log(''); - console.log(summary); + private _printSummary(summary: string) { + if (summary.trim()) { + console.log(''); + console.log(summary); + } } willRetry(test: TestCase): boolean { diff --git a/packages/playwright-test/src/reporters/github.ts b/packages/playwright-test/src/reporters/github.ts index c5d344bb5e..bce679531f 100644 --- a/packages/playwright-test/src/reporters/github.ts +++ b/packages/playwright-test/src/reporters/github.ts @@ -31,11 +31,9 @@ type GitHubLogOptions = Partial<{ }>; class GitHubLogger { - private _isGitHubAction: boolean = !!process.env.GITHUB_ACTION; private _log(message: string, type: GitHubLogType = 'notice', options: GitHubLogOptions = {}) { - if (this._isGitHubAction) - message = message.replace(/\n/g, '%0A'); + message = message.replace(/\n/g, '%0A'); const configs = Object.entries(options) .map(([key, option]) => `${key}=${option}`) .join(','); diff --git a/packages/playwright-test/src/reporters/html.ts b/packages/playwright-test/src/reporters/html.ts index c3506ecc1b..07ac742df5 100644 --- a/packages/playwright-test/src/reporters/html.ts +++ b/packages/playwright-test/src/reporters/html.ts @@ -129,13 +129,11 @@ class HtmlReporter { if (!stats.ok && !process.env.CI && !process.env.PWTEST_SKIP_TEST_OUTPUT) { await showHTMLReport(reportFolder); } else { - console.log(''); console.log(''); console.log('All tests passed. To open last HTML report run:'); console.log(colors.cyan(` npx playwright show-report `)); - console.log(''); } } } diff --git a/packages/playwright-test/src/reporters/line.ts b/packages/playwright-test/src/reporters/line.ts index 1caed2c43e..108bf491b5 100644 --- a/packages/playwright-test/src/reporters/line.ts +++ b/packages/playwright-test/src/reporters/line.ts @@ -59,7 +59,8 @@ class LineReporter extends BaseReporter { const width = process.stdout.columns! - 1; const title = `[${++this._current}/${this._total}] ${formatTestTitle(this.config, test)}`.substring(0, width); process.stdout.write(`\u001B[1A\u001B[2K${title}\n`); - if (!this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected')) { + + if (!this._omitFailures && !this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected')) { process.stdout.write(`\u001B[1A\u001B[2K`); console.log(formatFailure(this.config, test, { index: ++this._failures diff --git a/packages/playwright-test/src/reporters/list.ts b/packages/playwright-test/src/reporters/list.ts index 4b855457cb..2672801655 100644 --- a/packages/playwright-test/src/reporters/list.ts +++ b/packages/playwright-test/src/reporters/list.ts @@ -32,8 +32,8 @@ class ListReporter extends BaseReporter { private readonly _liveTerminal: string | boolean | undefined; private readonly _ttyWidthForTest: number; - constructor() { - super(); + constructor(options: { omitFailures?: boolean } = {}) { + super(options); this._ttyWidthForTest = parseInt(process.env.PWTEST_TTY_WIDTH || '', 10); this._liveTerminal = process.stdout.isTTY || process.env.PWTEST_SKIP_TEST_OUTPUT || !!this._ttyWidthForTest; } diff --git a/packages/playwright-test/src/runner.ts b/packages/playwright-test/src/runner.ts index 15975eb6cf..4e897438ac 100644 --- a/packages/playwright-test/src/runner.ts +++ b/packages/playwright-test/src/runner.ts @@ -77,6 +77,13 @@ export class Runner { html: HtmlReporter, }; const reporters: Reporter[] = []; + const reporterConfig = this._loader.fullConfig().reporter; + if (reporterConfig.length === 1 && reporterConfig[0][0] === 'html') { + // For html reporter, add a line/dot report for convenience. + // Important to put html last because it stalls onEnd. + reporterConfig.unshift([process.stdout.isTTY && !process.env.CI ? 'line' : 'dot', { omitFailures: true }]); + } + for (const r of this._loader.fullConfig().reporter) { const [name, arg] = r; if (name in defaultReporters) { diff --git a/tests/playwright-test/reporter-github.spec.ts b/tests/playwright-test/reporter-github.spec.ts index 5682135ddc..e4bcef8387 100644 --- a/tests/playwright-test/reporter-github.spec.ts +++ b/tests/playwright-test/reporter-github.spec.ts @@ -31,30 +31,13 @@ test('print GitHub annotations for success', async ({ runInlineTest }) => { expect(1 + 1).toBe(2); }); ` - }, { reporter: 'github' }, { GITHUB_ACTION: 'true' }); + }, { reporter: 'github' }); const text = stripAscii(result.output); expect(text).not.toContain('::error'); - expect(text).toContain('::notice title=🎭 Playwright Run Summary::%0A 1 passed'); + expect(text).toContain('::notice title=🎭 Playwright Run Summary:: 1 passed'); expect(result.exitCode).toBe(0); }); -test('print GitHub annotations with newline if not in CI', async ({ runInlineTest }) => { - const result = await runInlineTest({ - 'a.test.js': ` - const { test } = pwt; - test('example1', async ({}) => { - expect(1 + 1).toBe(2); - }); - ` - }, { reporter: 'github' }, { GITHUB_ACTION: '' }); - const text = stripAscii(result.output); - expect(text).not.toContain('::error'); - expect(text).toContain(`::notice title=🎭 Playwright Run Summary:: - 1 passed `); - expect(result.exitCode).toBe(0); -}); - - test('print GitHub annotations for failed tests', async ({ runInlineTest }, testInfo) => { const result = await runInlineTest({ 'a.test.js': ` @@ -63,7 +46,7 @@ test('print GitHub annotations for failed tests', async ({ runInlineTest }, test expect(1 + 1).toBe(3); }); ` - }, { retries: 3, reporter: 'github' }, { GITHUB_ACTION: 'true', GITHUB_WORKSPACE: process.cwd() }); + }, { retries: 3, reporter: 'github' }, { GITHUB_WORKSPACE: process.cwd() }); const text = stripAscii(result.output); const testPath = relativeFilePath(testInfo.outputPath('a.test.js')); expect(text).toContain(`::error file=${testPath},title=a.test.js:6:7 › example,line=7,col=23:: 1) a.test.js:6:7 › example =======================================================================%0A%0A Retry #1`); @@ -72,7 +55,6 @@ test('print GitHub annotations for failed tests', async ({ runInlineTest }, test expect(result.exitCode).toBe(1); }); - test('print GitHub annotations for slow tests', async ({ runInlineTest }) => { const result = await runInlineTest({ 'playwright.config.ts': ` @@ -86,9 +68,9 @@ test('print GitHub annotations for slow tests', async ({ runInlineTest }) => { await new Promise(f => setTimeout(f, 200)); }); ` - }, { retries: 3, reporter: 'github' }, { GITHUB_ACTION: 'true', GITHUB_WORKSPACE: '' }); + }, { retries: 3, reporter: 'github' }, { GITHUB_WORKSPACE: '' }); const text = stripAscii(result.output); expect(text).toContain('::warning title=Slow Test,file=a.test.js::a.test.js took'); - expect(text).toContain('::notice title=🎭 Playwright Run Summary::%0A 1 passed'); + expect(text).toContain('::notice title=🎭 Playwright Run Summary:: 1 passed'); expect(result.exitCode).toBe(0); }); \ No newline at end of file