Skip to content

Commit 459fb7b

Browse files
authored
feat(dashboard): add openDashboardForContext entry point (#40506)
1 parent 26d198e commit 459fb7b

8 files changed

Lines changed: 495 additions & 229 deletions

File tree

packages/dashboard/src/dashboardChannel.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ export interface DashboardChannel {
4747
closeTab(params: { browser: string; context: string; page: string }): Promise<void>;
4848
newTab(params: { browser: string; context: string }): Promise<void>;
4949
closeSession(params: { browser: string }): Promise<void>;
50-
deleteSessionData(params: { browser: string }): Promise<void>;
5150
setVisible(params: { visible: boolean }): Promise<void>;
52-
reveal(params: { path: string }): Promise<void>;
5351

5452
navigate(params: { url: string }): Promise<void>;
5553
back(): Promise<void>;

packages/dashboard/src/dashboardModel.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,6 @@ export class DashboardModel {
9292
void this._client.closeSession({ browser: descriptor.browser.guid });
9393
}
9494

95-
deleteSessionData(descriptor: BrowserDescriptor) {
96-
void this._client.deleteSessionData({ browser: descriptor.browser.guid });
97-
}
98-
9995
setVisible(visible: boolean) {
10096
void this._client.setVisible({ visible });
10197
}

packages/playwright-core/src/tools/dashboard/dashboardApp.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ import { findChromiumChannelBestEffort, registryDirectory } from '../../server/r
2828
import { minimist } from '../cli-client/minimist';
2929
import { saveOutputFile } from '../trace/traceUtils';
3030
import { DashboardConnection } from './dashboardController';
31+
import { RegistrySessionProvider } from './registrySessionProvider';
32+
import { IdentitySessionProvider } from './identitySessionProvider';
3133

3234
import type * as api from '../../..';
3335
import type { AnnotationData } from '@dashboard/dashboardChannel';
36+
import type { SessionProvider } from './sessionProvider';
3437

3538
// HMR: build-time flag — `true` in watch builds, `false` in release. esbuild
3639
// replaces the identifier via `define`, so the static branch pays zero runtime
@@ -42,9 +45,10 @@ type DashboardServer = {
4245
reveal: (options: DashboardOptions) => void;
4346
triggerAnnotate: () => void;
4447
registerAnnotateWaiter: (socket: net.Socket) => void;
48+
close: () => Promise<void>;
4549
};
4650

47-
async function startDashboardServer(options: DashboardOptions): Promise<DashboardServer> {
51+
async function startDashboardServer(provider: SessionProvider, options: DashboardOptions): Promise<DashboardServer> {
4852
const httpServer = new HttpServer();
4953
const dashboardDir = libPath('vite', 'dashboard');
5054

@@ -67,7 +71,7 @@ async function startDashboardServer(options: DashboardOptions): Promise<Dashboar
6771
httpServer.createWebSocket(() => {
6872
let connection: DashboardConnection;
6973
// eslint-disable-next-line prefer-const
70-
connection = new DashboardConnection(() => connections.delete(connection), () => {
74+
connection = new DashboardConnection(provider, () => connections.delete(connection), () => {
7175
if (currentReveal.pageId)
7276
connection.revealPage(currentReveal.pageId);
7377
else if (currentReveal.sessionName)
@@ -131,7 +135,8 @@ async function startDashboardServer(options: DashboardOptions): Promise<Dashboar
131135
socket.on('error', cleanup);
132136
};
133137

134-
return { url: httpServer.urlPrefix('human-readable'), reveal, triggerAnnotate, registerAnnotateWaiter };
138+
const close = () => httpServer.stop();
139+
return { url: httpServer.urlPrefix('human-readable'), reveal, triggerAnnotate, registerAnnotateWaiter, close };
135140
}
136141

137142
function attachDashboardStaticServer(httpServer: HttpServer, dashboardDir: string) {
@@ -157,13 +162,13 @@ async function attachDashboardDevServer(httpServer: HttpServer) {
157162
// HMR end
158163

159164
async function innerOpenDashboardApp(options: DashboardOptions): Promise<{ page: api.Page; server: DashboardServer }> {
160-
const server = await startDashboardServer(options);
161-
const { page } = await launchApp('dashboard');
165+
const server = await startDashboardServer(new RegistrySessionProvider(), options);
166+
const { page } = await launchApp('dashboard', { onClose: () => gracefullyProcessExitDoNotHang(0) });
162167
await page.goto(server.url);
163168
return { page, server };
164169
}
165170

166-
async function launchApp(appName: string) {
171+
async function launchApp(appName: string, options?: { onClose?: () => void }) {
167172
const channel = findChromiumChannelBestEffort('javascript');
168173
const context = await playwright.chromium.launchPersistentContext('', {
169174
ignoreDefaultArgs: ['--enable-automation'],
@@ -192,9 +197,7 @@ async function launchApp(appName: string) {
192197
});
193198
}
194199

195-
page.on('close', () => {
196-
gracefullyProcessExitDoNotHang(0);
197-
});
200+
page.on('close', () => options?.onClose?.());
198201

199202
const image = await fs.promises.readFile(libPath('tools', 'dashboard', 'appIcon.png'));
200203
// This is local Playwright, so I can access private methods.
@@ -299,7 +302,7 @@ export async function openDashboardApp() {
299302
console.error('Unhandled promise rejection:', error);
300303
});
301304
if (options.port !== undefined) {
302-
const { url } = await startDashboardServer(options);
305+
const { url } = await startDashboardServer(new RegistrySessionProvider(), options);
303306
// eslint-disable-next-line no-console
304307
console.log(`Listening on ${url}`);
305308
selfDestructOnParentGone();
@@ -352,6 +355,22 @@ export async function openDashboardApp() {
352355
await statePromise;
353356
}
354357

358+
export async function openDashboardForContext(context: api.BrowserContext): Promise<void> {
359+
const server = await startDashboardServer(new IdentitySessionProvider(context), {});
360+
361+
let closed = false;
362+
const close = async () => {
363+
if (closed)
364+
return;
365+
closed = true;
366+
await server.close();
367+
};
368+
369+
const { page } = await launchApp('dashboard', { onClose: () => { void close(); } });
370+
context.on('close', () => { void close(); });
371+
await page.goto(server.url);
372+
}
373+
355374
async function runKillClient(): Promise<void> {
356375
const socketPath = dashboardSocketPath();
357376
await new Promise<void>(resolve => {

0 commit comments

Comments
 (0)