Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/playwright/src/reporters/perfetto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { once } from 'events';
import fs from 'fs';
import path from 'path';
import zlib from 'zlib';
Expand Down Expand Up @@ -298,6 +299,10 @@ class ChunkWriter {
const gzip = file.endsWith('.gz') ? zlib.createGzip() : undefined;
gzip?.pipe(fileStream);
this._stream = gzip ?? fileStream;
// pipe() only unpipes on a destination error, so the gzip stream would never
// emit 'drain' or 'error' again. Destroy it to wake up the pending write.
if (gzip)
fileStream.on('error', error => gzip.destroy(error));
// The file is only complete once the destination closes, which is later than
// the gzip stream ending.
this._closed = new Promise(resolve => fileStream.on('close', resolve));
Expand All @@ -309,7 +314,7 @@ class ChunkWriter {
if (this._error)
throw this._error;
if (!this._stream.write(chunk))
await new Promise<void>(resolve => this._stream.once('drain', () => resolve()));
await once(this._stream, 'drain'); // Rejects if 'error' is emitted first.
}

async close() {
Expand Down
20 changes: 20 additions & 0 deletions tests/playwright-test/reporter-perfetto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
import * as zlib from 'zlib';
Expand Down Expand Up @@ -215,6 +216,25 @@ test('should report step params', async ({ runInlineTest }, testInfo) => {
expect(findSlice(events, 'my step')!.args.params).toEqual({ foo: 'bar', count: 7 });
});

for (const fileName of ['trace.json', 'trace.json.gz']) {
test(`should fail when ${fileName} output is a directory`, async ({ runInlineTest }, testInfo) => {
const outputFile = testInfo.outputPath(fileName);
await fs.promises.mkdir(outputFile);
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { reporter: [['perfetto', { outputFile: ${JSON.stringify(outputFile)} }]] };
`,
'a.test.ts': `
import { test } from '@playwright/test';
test('one', async () => {
test.info().annotations.push({ type: 'blob', description: ${JSON.stringify(crypto.randomBytes(256 * 1024).toString('base64'))} });
});
`,
});
expect(result.exitCode).not.toBe(0);
});
}

test('should respect outputFile option', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
'playwright.config.ts': `
Expand Down
Loading