From 0f72ef0584b3974d052e08f5738bcec5cf5b5924 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Mon, 25 Sep 2023 10:59:14 -0700 Subject: [PATCH] fix(streams): avoid leaking event listeners (#27291) Fixes #26998. --- .../src/server/dispatchers/streamDispatcher.ts | 16 ++++++++++------ tests/library/chromium/tracing.spec.ts | 10 +++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/playwright-core/src/server/dispatchers/streamDispatcher.ts b/packages/playwright-core/src/server/dispatchers/streamDispatcher.ts index 53f14fbfdd..4a45468389 100644 --- a/packages/playwright-core/src/server/dispatchers/streamDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/streamDispatcher.ts @@ -17,7 +17,7 @@ import type * as channels from '@protocol/channels'; import { Dispatcher } from './dispatcher'; import type * as stream from 'stream'; -import { createGuid } from '../../utils'; +import { ManualPromise, createGuid } from '../../utils'; import type { ArtifactDispatcher } from './artifactDispatcher'; export class StreamDispatcher extends Dispatcher<{ guid: string, stream: stream.Readable }, channels.StreamChannel, ArtifactDispatcher> implements channels.StreamChannel { @@ -36,11 +36,15 @@ export class StreamDispatcher extends Dispatcher<{ guid: string, stream: stream. if (this._ended) return { binary: Buffer.from('') }; if (!stream.readableLength) { - await new Promise((fulfill, reject) => { - stream.once('readable', fulfill); - stream.once('end', fulfill); - stream.once('error', reject); - }); + const readyPromise = new ManualPromise(); + const done = () => readyPromise.resolve(); + stream.on('readable', done); + stream.on('end', done); + stream.on('error', done); + await readyPromise; + stream.off('readable', done); + stream.off('end', done); + stream.off('error', done); } const buffer = stream.read(Math.min(stream.readableLength, params.size || stream.readableLength)); return { binary: buffer || Buffer.from('') }; diff --git a/tests/library/chromium/tracing.spec.ts b/tests/library/chromium/tracing.spec.ts index 07bfdec534..a39f21ba27 100644 --- a/tests/library/chromium/tracing.spec.ts +++ b/tests/library/chromium/tracing.spec.ts @@ -19,13 +19,21 @@ import fs from 'fs'; import path from 'path'; it('should output a trace', async ({ browser, server }, testInfo) => { + let warning = null; + const warningHandler = w => warning = w; + process.on('warning', warningHandler); + const page = await browser.newPage(); const outputTraceFile = testInfo.outputPath(path.join(`trace.json`)); await browser.startTracing(page, { screenshots: true, path: outputTraceFile }); - await page.goto(server.PREFIX + '/grid.html'); + for (let i = 0; i < 20; i++) + await page.goto(server.PREFIX + '/grid.html'); await browser.stopTracing(); expect(fs.existsSync(outputTraceFile)).toBe(true); await page.close(); + + process.off('warning', warningHandler); + expect(warning).toBe(null); }); it('should create directories as needed', async ({ browser, server }, testInfo) => {