fix(ui): print config and global setup errors (#30531)
Fixes: https://github.com/microsoft/playwright/issues/30513
This commit is contained in:
parent
59689c9c97
commit
ff3d3ae8f2
|
|
@ -124,9 +124,9 @@ export type JsonEvent = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type TeleReporterReceiverOptions = {
|
type TeleReporterReceiverOptions = {
|
||||||
mergeProjects: boolean;
|
mergeProjects?: boolean;
|
||||||
mergeTestCases: boolean;
|
mergeTestCases?: boolean;
|
||||||
resolvePath: (rootDir: string, relativePath: string) => string;
|
resolvePath?: (rootDir: string, relativePath: string) => string;
|
||||||
configOverrides?: Pick<reporterTypes.FullConfig, 'configFile' | 'quiet' | 'reportSlowTests' | 'reporter'>;
|
configOverrides?: Pick<reporterTypes.FullConfig, 'configFile' | 'quiet' | 'reportSlowTests' | 'reporter'>;
|
||||||
clearPreviousResultsWhenTestBegins?: boolean;
|
clearPreviousResultsWhenTestBegins?: boolean;
|
||||||
};
|
};
|
||||||
|
|
@ -140,7 +140,7 @@ export class TeleReporterReceiver {
|
||||||
private _rootDir!: string;
|
private _rootDir!: string;
|
||||||
private _config!: reporterTypes.FullConfig;
|
private _config!: reporterTypes.FullConfig;
|
||||||
|
|
||||||
constructor(reporter: Partial<ReporterV2>, options: TeleReporterReceiverOptions) {
|
constructor(reporter: Partial<ReporterV2>, options: TeleReporterReceiverOptions = {}) {
|
||||||
this._rootSuite = new TeleSuite('', 'root');
|
this._rootSuite = new TeleSuite('', 'root');
|
||||||
this._options = options;
|
this._options = options;
|
||||||
this._reporter = reporter;
|
this._reporter = reporter;
|
||||||
|
|
@ -388,7 +388,7 @@ export class TeleReporterReceiver {
|
||||||
private _absolutePath(relativePath?: string): string | undefined {
|
private _absolutePath(relativePath?: string): string | undefined {
|
||||||
if (relativePath === undefined)
|
if (relativePath === undefined)
|
||||||
return;
|
return;
|
||||||
return this._options.resolvePath(this._rootDir, relativePath);
|
return this._options.resolvePath ? this._options.resolvePath(this._rootDir, relativePath) : this._rootDir + '/' + relativePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,5 @@
|
||||||
../util.ts
|
../util.ts
|
||||||
../utilsBundle.ts
|
../utilsBundle.ts
|
||||||
../isomorphic/folders.ts
|
../isomorphic/folders.ts
|
||||||
|
../isomorphic/teleReceiver.ts
|
||||||
../fsWatcher.ts
|
../fsWatcher.ts
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import type { TraceViewerRedirectOptions, TraceViewerServerOptions } from 'playw
|
||||||
import type { TestRunnerPluginRegistration } from '../plugins';
|
import type { TestRunnerPluginRegistration } from '../plugins';
|
||||||
import { serializeError } from '../util';
|
import { serializeError } from '../util';
|
||||||
import { cacheDir } from '../transform/compilationCache';
|
import { cacheDir } from '../transform/compilationCache';
|
||||||
|
import { baseFullConfig } from '../isomorphic/teleReceiver';
|
||||||
|
|
||||||
const originalStdoutWrite = process.stdout.write;
|
const originalStdoutWrite = process.stdout.write;
|
||||||
const originalStderrWrite = process.stderr.write;
|
const originalStderrWrite = process.stderr.write;
|
||||||
|
|
@ -147,7 +148,10 @@ class TestServerDispatcher implements TestServerInterface {
|
||||||
const { reporter, report } = await this._collectingReporter();
|
const { reporter, report } = await this._collectingReporter();
|
||||||
const { config, error } = await this._loadConfig();
|
const { config, error } = await this._loadConfig();
|
||||||
if (!config) {
|
if (!config) {
|
||||||
|
// Produce dummy config when it has an error.
|
||||||
|
reporter.onConfigure(baseFullConfig);
|
||||||
reporter.onError(error!);
|
reporter.onError(error!);
|
||||||
|
await reporter.onExit();
|
||||||
return { status: 'failed', report };
|
return { status: 'failed', report };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,11 +115,7 @@ export class TeleSuiteUpdater {
|
||||||
this._options.onUpdate();
|
this._options.onUpdate();
|
||||||
},
|
},
|
||||||
|
|
||||||
onError: (error: reporterTypes.TestError) => {
|
onError: (error: reporterTypes.TestError) => this._handleOnError(error),
|
||||||
this.loadErrors.push(error);
|
|
||||||
this._options.onError?.(error);
|
|
||||||
this._options.onUpdate();
|
|
||||||
},
|
|
||||||
|
|
||||||
printsToStdio: () => {
|
printsToStdio: () => {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -133,6 +129,17 @@ export class TeleSuiteUpdater {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processGlobalReport(report: any[]) {
|
||||||
|
const receiver = new TeleReporterReceiver({
|
||||||
|
onConfigure: (c: reporterTypes.FullConfig) => {
|
||||||
|
this.config = c;
|
||||||
|
},
|
||||||
|
onError: (error: reporterTypes.TestError) => this._handleOnError(error)
|
||||||
|
});
|
||||||
|
for (const message of report)
|
||||||
|
receiver.dispatch(message);
|
||||||
|
}
|
||||||
|
|
||||||
processListReport(report: any[]) {
|
processListReport(report: any[]) {
|
||||||
// Save test results and reset all projects, the results will be restored after
|
// Save test results and reset all projects, the results will be restored after
|
||||||
// new project structure is built.
|
// new project structure is built.
|
||||||
|
|
@ -150,6 +157,12 @@ export class TeleSuiteUpdater {
|
||||||
this._receiver.dispatch(message)?.catch(() => {});
|
this._receiver.dispatch(message)?.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleOnError(error: reporterTypes.TestError) {
|
||||||
|
this.loadErrors.push(error);
|
||||||
|
this._options.onError?.(error);
|
||||||
|
this._options.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
asModel(): TestModel {
|
asModel(): TestModel {
|
||||||
return {
|
return {
|
||||||
rootSuite: this.rootSuite || new TeleSuite('', 'root'),
|
rootSuite: this.rootSuite || new TeleSuite('', 'root'),
|
||||||
|
|
|
||||||
|
|
@ -172,24 +172,29 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setWatchedTreeIds({ value: new Set() });
|
setWatchedTreeIds({ value: new Set() });
|
||||||
(async () => {
|
(async () => {
|
||||||
await testServerConnection.initialize({
|
try {
|
||||||
interceptStdio: true,
|
await testServerConnection.initialize({
|
||||||
watchTestDirs: true
|
interceptStdio: true,
|
||||||
});
|
watchTestDirs: true
|
||||||
const { status } = await testServerConnection.runGlobalSetup({});
|
});
|
||||||
if (status !== 'passed')
|
const { status, report } = await testServerConnection.runGlobalSetup({});
|
||||||
return;
|
teleSuiteUpdater.processGlobalReport(report);
|
||||||
const result = await testServerConnection.listTests({ projects: queryParams.projects, locations: queryParams.args });
|
if (status !== 'passed')
|
||||||
teleSuiteUpdater.processListReport(result.report);
|
return;
|
||||||
|
|
||||||
testServerConnection.onListChanged(updateList);
|
const result = await testServerConnection.listTests({ projects: queryParams.projects, locations: queryParams.args });
|
||||||
testServerConnection.onReport(params => {
|
teleSuiteUpdater.processListReport(result.report);
|
||||||
teleSuiteUpdater.processTestReportEvent(params);
|
|
||||||
});
|
|
||||||
setIsLoading(false);
|
|
||||||
|
|
||||||
const { hasBrowsers } = await testServerConnection.checkBrowsers({});
|
testServerConnection.onListChanged(updateList);
|
||||||
setHasBrowsers(hasBrowsers);
|
testServerConnection.onReport(params => {
|
||||||
|
teleSuiteUpdater.processTestReportEvent(params);
|
||||||
|
});
|
||||||
|
|
||||||
|
const { hasBrowsers } = await testServerConnection.checkBrowsers({});
|
||||||
|
setHasBrowsers(hasBrowsers);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(throttleTimer);
|
clearTimeout(throttleTimer);
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,17 @@ test('should teardown on sigint', async ({ runUITest, nodeVersion }) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should show errors in config', async ({ runUITest }) => {
|
||||||
|
const { page } = await runUITest({
|
||||||
|
'playwright.config.ts': `
|
||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
throw new Error("URL is empty")
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
await page.getByText('playwright.config.ts').click();
|
||||||
|
await expect(page.getByText('Error: URL is empty')).toBeInViewport();
|
||||||
|
});
|
||||||
|
|
||||||
const testsWithSetup = {
|
const testsWithSetup = {
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
import { defineConfig } from '@playwright/test';
|
import { defineConfig } from '@playwright/test';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue