chore: keep UI Mode running when used with browser mode (#23876)

This will keep UI Mode running in browser mode. When launched in normal
persistent context mode, we know when the persistent context closes, so
we can run the project teardown code.

Fixes https://github.com/microsoft/playwright/issues/23801
This commit is contained in:
Max Schmitt 2023-06-26 22:21:44 +02:00 committed by GitHub
parent 9a580af1e6
commit dcdf38f119
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 34 deletions

View File

@ -22,7 +22,8 @@ import path from 'path';
import type { Command } from '../utilsBundle';
import { program } from '../utilsBundle';
import { runDriver, runServer, printApiJson, launchBrowserServer } from './driver';
import { showTraceViewer } from '../server/trace/viewer/traceViewer';
import type { OpenTraceViewerOptions } from '../server/trace/viewer/traceViewer';
import { openTraceInBrowser, openTraceViewerApp } from '../server/trace/viewer/traceViewer';
import * as playwright from '../..';
import type { BrowserContext } from '../client/browserContext';
import type { Browser } from '../client/browser';
@ -297,14 +298,19 @@ program
if (options.browser === 'wk')
options.browser = 'webkit';
const openOptions = {
const openOptions: OpenTraceViewerOptions = {
headless: false,
host: options.host,
port: +options.port,
isServer: !!options.stdin,
openInBrowser: options.port !== undefined || options.host !== undefined
};
showTraceViewer(traces, options.browser, openOptions).catch(logErrorAndExit);
if (options.port !== undefined || options.host !== undefined) {
openTraceInBrowser(traces, openOptions).catch(logErrorAndExit);
} else {
openTraceViewerApp(traces, options.browser, openOptions).then(page => {
page.on('close', () => process.exit(0));
}).catch(logErrorAndExit);
}
}).addHelpText('afterAll', `
Examples:

View File

@ -29,5 +29,5 @@ export { createPlaywright } from './playwright';
export type { DispatcherScope } from './dispatchers/dispatcher';
export type { Playwright } from './playwright';
export { showTraceViewer, openTraceViewerApp } from './trace/viewer/traceViewer';
export { openTraceInBrowser, openTraceViewerApp } from './trace/viewer/traceViewer';
export { serverSideCallMetadata } from './instrumentation';

View File

@ -33,25 +33,16 @@ export type Transport = {
onclose: () => void;
};
type Options = {
export type OpenTraceViewerOptions = {
app?: string;
headless?: boolean;
host?: string;
port?: number;
isServer?: boolean;
openInBrowser?: boolean;
transport?: Transport;
};
export async function showTraceViewer(traceUrls: string[], browserName: string, options?: Options): Promise<void> {
if (options?.openInBrowser) {
await openTraceInBrowser(traceUrls, options);
return;
}
await openTraceViewerApp(traceUrls, browserName, options);
}
async function startTraceViewerServer(traceUrls: string[], options?: Options): Promise<{ server: HttpServer, url: string }> {
async function startTraceViewerServer(traceUrls: string[], options?: OpenTraceViewerOptions): Promise<{ server: HttpServer, url: string }> {
for (const traceUrl of traceUrls) {
let traceFile = traceUrl;
// If .json is requested, we'll synthesize it.
@ -134,7 +125,7 @@ async function startTraceViewerServer(traceUrls: string[], options?: Options): P
return { server, url };
}
export async function openTraceViewerApp(traceUrls: string[], browserName: string, options?: Options): Promise<Page> {
export async function openTraceViewerApp(traceUrls: string[], browserName: string, options?: OpenTraceViewerOptions): Promise<Page> {
const { url } = await startTraceViewerServer(traceUrls, options);
const traceViewerPlaywright = createPlaywright({ sdkLanguage: 'javascript', isInternalPlaywright: true });
const traceViewerBrowser = isUnderTest() ? 'chromium' : browserName;
@ -171,24 +162,21 @@ export async function openTraceViewerApp(traceUrls: string[], browserName: strin
if (isUnderTest())
page.on('close', () => context.close(serverSideCallMetadata()).catch(() => {}));
else
page.on('close', () => process.exit());
await page.mainFrame().goto(serverSideCallMetadata(), url);
return page;
}
async function openTraceInBrowser(traceUrls: string[], options?: Options) {
export async function openTraceInBrowser(traceUrls: string[], options?: OpenTraceViewerOptions) {
const { url } = await startTraceViewerServer(traceUrls, options);
// eslint-disable-next-line no-console
console.log('\nListening on ' + url);
await open(url, { wait: true }).catch(() => {});
await open(url).catch(() => {});
}
class StdinServer implements Transport {
private _pollTimer: NodeJS.Timeout | undefined;
private _traceUrl: string | undefined;
private _page: Page | undefined;
constructor() {
process.stdin.on('data', data => {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { showTraceViewer } from 'playwright-core/lib/server';
import { openTraceViewerApp, openTraceInBrowser } from 'playwright-core/lib/server';
import { isUnderTest, ManualPromise } from 'playwright-core/lib/utils';
import type { FullResult } from '../../reporter';
import { clearCompilationCache, collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache';
@ -27,7 +27,7 @@ import { chokidar } from '../utilsBundle';
import type { FSWatcher } from 'chokidar';
import { open } from 'playwright-core/lib/utilsBundle';
import ListReporter from '../reporters/list';
import type { Transport } from 'playwright-core/lib/server/trace/viewer/traceViewer';
import type { OpenTraceViewerOptions, Transport } from 'playwright-core/lib/server/trace/viewer/traceViewer';
class UIMode {
private _config: FullConfigInternal;
@ -82,7 +82,6 @@ class UIMode {
}
async showUI(options: { host?: string, port?: number }) {
const exitPromise = new ManualPromise();
let queue = Promise.resolve();
this._transport = {
@ -90,10 +89,6 @@ class UIMode {
if (method === 'ping')
return;
if (method === 'exit') {
exitPromise.resolve();
return;
}
if (method === 'watch') {
this._watchFiles(params.fileNames);
return;
@ -117,16 +112,22 @@ class UIMode {
await queue;
},
onclose: () => exitPromise.resolve(),
onclose: () => { },
};
await showTraceViewer([], 'chromium', {
const openOptions: OpenTraceViewerOptions = {
app: 'uiMode.html',
headless: isUnderTest() && process.env.PWTEST_HEADED_FOR_TEST !== '1',
transport: this._transport,
host: options.host,
port: options.port,
openInBrowser: options.host !== undefined || options.port !== undefined,
});
};
const exitPromise = new ManualPromise<void>();
if (options.host !== undefined || options.port !== undefined) {
await openTraceInBrowser([], openOptions);
} else {
const page = await openTraceViewerApp([], 'chromium', openOptions);
page.on('close', () => exitPromise.resolve());
}
if (!process.env.PWTEST_DEBUG) {
process.stdout.write = (chunk: string | Buffer) => {

View File

@ -168,7 +168,8 @@ export const UIModeView: React.FC<{}> = ({
return <div className='vbox ui-mode'>
{isDisconnected && <div className='drop-target'>
<div className='title'>Process disconnected</div>
<div className='title'>UI Mode disconnected</div>
<div><a href='#' onClick={() => window.location.reload()}>Reload the page</a> to reconnect</div>
</div>}
<SplitView sidebarSize={250} orientation='horizontal' sidebarIsFirst={true}>
<div className='vbox'>