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 коммит произвёл GitHub
Родитель 9a580af1e6
Коммит dcdf38f119
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 30 добавлений и 34 удалений

Просмотреть файл

@ -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:

Просмотреть файл

@ -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';

Просмотреть файл

@ -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 => {

Просмотреть файл

@ -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) => {

Просмотреть файл

@ -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'>