chore: warn users on clashing test output and html reporter folders (#14964)
This commit is contained in:
parent
ed6b14f0f4
commit
e8070ee1b2
|
|
@ -131,9 +131,12 @@ class HtmlReporter implements Reporter {
|
||||||
private config!: FullConfigInternal;
|
private config!: FullConfigInternal;
|
||||||
private suite!: Suite;
|
private suite!: Suite;
|
||||||
private _options: HtmlReporterOptions;
|
private _options: HtmlReporterOptions;
|
||||||
|
private _outputFolder!: string;
|
||||||
|
private _open: string | undefined;
|
||||||
|
|
||||||
constructor(options: HtmlReporterOptions = {}) {
|
constructor(options: HtmlReporterOptions = {}) {
|
||||||
this._options = options;
|
this._options = options;
|
||||||
|
console.log('HTML REPORTER OPTIONS', options);
|
||||||
}
|
}
|
||||||
|
|
||||||
printsToStdio() {
|
printsToStdio() {
|
||||||
|
|
@ -142,6 +145,25 @@ class HtmlReporter implements Reporter {
|
||||||
|
|
||||||
onBegin(config: FullConfig, suite: Suite) {
|
onBegin(config: FullConfig, suite: Suite) {
|
||||||
this.config = config as FullConfigInternal;
|
this.config = config as FullConfigInternal;
|
||||||
|
const { outputFolder, open } = this._resolveOptions();
|
||||||
|
this._outputFolder = outputFolder;
|
||||||
|
this._open = open;
|
||||||
|
const reportedWarnings = new Set<string>();
|
||||||
|
for (const project of config.projects) {
|
||||||
|
if (outputFolder.startsWith(project.outputDir) || project.outputDir.startsWith(outputFolder)) {
|
||||||
|
const key = outputFolder + '|' + project.outputDir;
|
||||||
|
if (reportedWarnings.has(key))
|
||||||
|
continue;
|
||||||
|
reportedWarnings.add(key);
|
||||||
|
console.log(colors.red(`Configuration Error: HTML reporter output folder clashes with the tests output folder:`));
|
||||||
|
console.log(`
|
||||||
|
html reporter folder: ${colors.bold(outputFolder)}
|
||||||
|
test results folder: ${colors.bold(project.outputDir)}`);
|
||||||
|
console.log('');
|
||||||
|
console.log(`HTML reporter will clear its output directory prior to being generated, which will lead to the artifact loss.
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.suite = suite;
|
this.suite = suite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,26 +178,25 @@ class HtmlReporter implements Reporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
async onEnd() {
|
async onEnd() {
|
||||||
const { open, outputFolder } = this._resolveOptions();
|
|
||||||
const projectSuites = this.suite.suites;
|
const projectSuites = this.suite.suites;
|
||||||
const reports = projectSuites.map(suite => {
|
const reports = projectSuites.map(suite => {
|
||||||
const rawReporter = new RawReporter();
|
const rawReporter = new RawReporter();
|
||||||
const report = rawReporter.generateProjectReport(this.config, suite);
|
const report = rawReporter.generateProjectReport(this.config, suite);
|
||||||
return report;
|
return report;
|
||||||
});
|
});
|
||||||
await removeFolders([outputFolder]);
|
await removeFolders([this._outputFolder]);
|
||||||
const builder = new HtmlBuilder(outputFolder);
|
const builder = new HtmlBuilder(this._outputFolder);
|
||||||
const { ok, singleTestId } = await builder.build(this.config.metadata, reports);
|
const { ok, singleTestId } = await builder.build(this.config.metadata, reports);
|
||||||
|
|
||||||
if (process.env.CI)
|
if (process.env.CI)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
const shouldOpen = open === 'always' || (!ok && open === 'on-failure');
|
const shouldOpen = this._open === 'always' || (!ok && this._open === 'on-failure');
|
||||||
if (shouldOpen) {
|
if (shouldOpen) {
|
||||||
await showHTMLReport(outputFolder, singleTestId);
|
await showHTMLReport(this._outputFolder, singleTestId);
|
||||||
} else {
|
} else {
|
||||||
const relativeReportPath = outputFolder === standaloneDefaultFolder() ? '' : ' ' + path.relative(process.cwd(), outputFolder);
|
const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? '' : ' ' + path.relative(process.cwd(), this._outputFolder);
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('To open last HTML report run:');
|
console.log('To open last HTML report run:');
|
||||||
console.log(colors.cyan(`
|
console.log(colors.cyan(`
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export class TestChildProcess {
|
||||||
process: ChildProcess;
|
process: ChildProcess;
|
||||||
output = '';
|
output = '';
|
||||||
onOutput?: () => void;
|
onOutput?: () => void;
|
||||||
exited: Promise<{ exitCode: number | null, signal: string | null }>;
|
exited: Promise<{ exitCode: number, signal: string | null }>;
|
||||||
exitCode: Promise<number>;
|
exitCode: Promise<number>;
|
||||||
|
|
||||||
private _outputCallbacks = new Set<() => void>();
|
private _outputCallbacks = new Set<() => void>();
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { JSONReport, JSONReportSuite } from '@playwright/test/reporter';
|
import type { JSONReport, JSONReportSuite, JSONReportTestResult } from '@playwright/test/reporter';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
@ -102,7 +102,7 @@ async function writeFiles(testInfo: TestInfo, files: Files) {
|
||||||
const cliEntrypoint = path.join(__dirname, '../../packages/playwright-core/cli.js');
|
const cliEntrypoint = path.join(__dirname, '../../packages/playwright-core/cli.js');
|
||||||
|
|
||||||
async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], baseDir: string, params: any, env: Env, options: RunOptions): Promise<RunResult> {
|
async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], baseDir: string, params: any, env: Env, options: RunOptions): Promise<RunResult> {
|
||||||
const paramList = [];
|
const paramList: string[] = [];
|
||||||
for (const key of Object.keys(params)) {
|
for (const key of Object.keys(params)) {
|
||||||
for (const value of Array.isArray(params[key]) ? params[key] : [params[key]]) {
|
for (const value of Array.isArray(params[key]) ? params[key] : [params[key]]) {
|
||||||
const k = key.startsWith('-') ? key : '--' + key;
|
const k = key.startsWith('-') ? key : '--' + key;
|
||||||
|
|
@ -114,8 +114,9 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b
|
||||||
const args = ['node', cliEntrypoint, 'test'];
|
const args = ['node', cliEntrypoint, 'test'];
|
||||||
if (!options.usesCustomOutputDir)
|
if (!options.usesCustomOutputDir)
|
||||||
args.push('--output=' + outputDir);
|
args.push('--output=' + outputDir);
|
||||||
|
if (!options.usesCustomReporters)
|
||||||
|
args.push('--reporter=dot,json');
|
||||||
args.push(
|
args.push(
|
||||||
'--reporter=dot,json',
|
|
||||||
'--workers=2',
|
'--workers=2',
|
||||||
...paramList
|
...paramList
|
||||||
);
|
);
|
||||||
|
|
@ -181,7 +182,7 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b
|
||||||
testProcess.output += '\n' + e.toString();
|
testProcess.output += '\n' + e.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = [];
|
const results: JSONReportTestResult[] = [];
|
||||||
function visitSuites(suites?: JSONReportSuite[]) {
|
function visitSuites(suites?: JSONReportSuite[]) {
|
||||||
if (!suites)
|
if (!suites)
|
||||||
return;
|
return;
|
||||||
|
|
@ -211,6 +212,7 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b
|
||||||
type RunOptions = {
|
type RunOptions = {
|
||||||
sendSIGINTAfter?: number;
|
sendSIGINTAfter?: number;
|
||||||
usesCustomOutputDir?: boolean;
|
usesCustomOutputDir?: boolean;
|
||||||
|
usesCustomReporters?: boolean;
|
||||||
additionalArgs?: string[];
|
additionalArgs?: string[];
|
||||||
cwd?: string,
|
cwd?: string,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { test as baseTest, expect, createImage } from './playwright-test-fixtures';
|
import { test as baseTest, expect, createImage, stripAnsi } from './playwright-test-fixtures';
|
||||||
import type { HttpServer } from '../../packages/playwright-core/lib/utils/httpServer';
|
import type { HttpServer } from '../../packages/playwright-core/lib/utils/httpServer';
|
||||||
import { startHtmlReportServer } from '../../packages/playwright-test/lib/reporters/html';
|
import { startHtmlReportServer } from '../../packages/playwright-test/lib/reporters/html';
|
||||||
import { spawnAsync } from 'playwright-core/lib/utils/spawnAsync';
|
import { spawnAsync } from 'playwright-core/lib/utils/spawnAsync';
|
||||||
|
|
@ -860,3 +860,22 @@ test.describe('gitCommitInfo plugin', () => {
|
||||||
await expect.soft(page.locator('data-test-id=metadata-chip')).not.toBeVisible();
|
await expect.soft(page.locator('data-test-id=metadata-chip')).not.toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should report clashing folders', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.ts': `
|
||||||
|
module.exports = {
|
||||||
|
reporter: [['html', { outputFolder: 'test-results/html-report' }]]
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
'a.test.js': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('passes', async ({}) => {
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, {}, {}, { usesCustomReporters: true });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
const output = stripAnsi(result.output);
|
||||||
|
expect(output).toContain('Configuration Error');
|
||||||
|
expect(output).toContain('html-report');
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue