mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-13 17:14:02 +03:00
fix(html): render text attachments as text (#10778)
This commit is contained in:
parent
287a2eaee8
commit
4d683cef7f
@ -22,7 +22,7 @@ import { Transform, TransformCallback } from 'stream';
|
||||
import { FullConfig, Suite, Reporter } from '../../types/testReporter';
|
||||
import { HttpServer } from 'playwright-core/lib/utils/httpServer';
|
||||
import { calculateSha1, removeFolders } from 'playwright-core/lib/utils/utils';
|
||||
import RawReporter, { JsonReport, JsonSuite, JsonTestCase, JsonTestResult, JsonTestStep, JsonAttachment } from './raw';
|
||||
import RawReporter, { JsonReport, JsonSuite, JsonTestCase, JsonTestResult, JsonTestStep } from './raw';
|
||||
import assert from 'assert';
|
||||
import yazl from 'yazl';
|
||||
import { stripAnsiEscapes } from './base';
|
||||
@ -78,7 +78,13 @@ export type TestCase = TestCaseSummary & {
|
||||
results: TestResult[];
|
||||
};
|
||||
|
||||
export type TestAttachment = JsonAttachment;
|
||||
export type TestAttachment = {
|
||||
name: string;
|
||||
body?: string;
|
||||
path?: string;
|
||||
contentType: string;
|
||||
};
|
||||
|
||||
|
||||
export type TestResult = {
|
||||
retry: number;
|
||||
@ -381,6 +387,19 @@ class HtmlBuilder {
|
||||
attachments: result.attachments.map(a => {
|
||||
if (a.name === 'trace')
|
||||
this._hasTraces = true;
|
||||
|
||||
if ((a.name === 'stdout' || a.name === 'stderr') && a.contentType === 'text/plain') {
|
||||
if (lastAttachment &&
|
||||
lastAttachment.name === a.name &&
|
||||
lastAttachment.contentType === a.contentType) {
|
||||
lastAttachment.body += stripAnsiEscapes(a.body as string);
|
||||
return null;
|
||||
}
|
||||
a.body = stripAnsiEscapes(a.body as string);
|
||||
lastAttachment = a as TestAttachment;
|
||||
return a;
|
||||
}
|
||||
|
||||
if (a.path) {
|
||||
let fileName = a.path;
|
||||
try {
|
||||
@ -404,17 +423,39 @@ class HtmlBuilder {
|
||||
};
|
||||
}
|
||||
|
||||
if ((a.name === 'stdout' || a.name === 'stderr') && a.contentType === 'text/plain') {
|
||||
if (lastAttachment &&
|
||||
lastAttachment.name === a.name &&
|
||||
lastAttachment.contentType === a.contentType) {
|
||||
lastAttachment.body += stripAnsiEscapes(a.body as string);
|
||||
return null;
|
||||
if (a.body instanceof Buffer) {
|
||||
if (isTextContentType(a.contentType)) {
|
||||
// Content type is like this: "text/html; charset=UTF-8"
|
||||
const charset = a.contentType.match(/charset=(.*)/)?.[1];
|
||||
try {
|
||||
const body = a.body.toString(charset as any || 'utf-8');
|
||||
return {
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
body,
|
||||
};
|
||||
} catch (e) {
|
||||
// Invalid encoding, fall through and save to file.
|
||||
}
|
||||
}
|
||||
a.body = stripAnsiEscapes(a.body as string);
|
||||
|
||||
fs.mkdirSync(path.join(this._reportFolder, 'data'), { recursive: true });
|
||||
const sha1 = calculateSha1(a.body) + '.dat';
|
||||
fs.writeFileSync(path.join(this._reportFolder, 'data', sha1), a.body);
|
||||
return {
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
path: 'data/' + sha1,
|
||||
body: a.body,
|
||||
};
|
||||
}
|
||||
lastAttachment = a;
|
||||
return a;
|
||||
|
||||
// string
|
||||
return {
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
body: a.body,
|
||||
};
|
||||
}).filter(Boolean) as TestAttachment[]
|
||||
};
|
||||
}
|
||||
@ -481,4 +522,8 @@ class Base64Encoder extends Transform {
|
||||
}
|
||||
}
|
||||
|
||||
function isTextContentType(contentType: string) {
|
||||
return contentType.startsWith('text/') || contentType.startsWith('application/json');
|
||||
}
|
||||
|
||||
export default HtmlReporter;
|
||||
|
@ -71,7 +71,7 @@ export type JsonTestCase = {
|
||||
|
||||
export type JsonAttachment = {
|
||||
name: string;
|
||||
body?: string;
|
||||
body?: string | Buffer;
|
||||
path?: string;
|
||||
contentType: string;
|
||||
};
|
||||
@ -245,7 +245,7 @@ class RawReporter {
|
||||
attachments.push({
|
||||
name: attachment.name,
|
||||
contentType: attachment.contentType,
|
||||
body: attachment.body.toString('base64')
|
||||
body: attachment.body
|
||||
});
|
||||
} else if (attachment.path) {
|
||||
attachments.push({
|
||||
@ -274,7 +274,7 @@ class RawReporter {
|
||||
return {
|
||||
name: type,
|
||||
contentType: 'application/octet-stream',
|
||||
body: chunk.toString('base64')
|
||||
body: chunk
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -294,3 +294,44 @@ test('should render annotations', async ({ runInlineTest, page, showReport }) =>
|
||||
await page.click('text=skipped test');
|
||||
await expect(page.locator('.test-case-annotation')).toHaveText('skip: I am not interested in this test');
|
||||
});
|
||||
|
||||
test('should render text attachments as text', async ({ runInlineTest, page, showReport }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.js': `
|
||||
const { test } = pwt;
|
||||
test('passing', async ({ page }, testInfo) => {
|
||||
testInfo.attachments.push({
|
||||
name: 'example.txt',
|
||||
contentType: 'text/plain',
|
||||
body: Buffer.from('foo'),
|
||||
});
|
||||
|
||||
testInfo.attachments.push({
|
||||
name: 'example.json',
|
||||
contentType: 'application/json',
|
||||
body: Buffer.from(JSON.stringify({ foo: 1 })),
|
||||
});
|
||||
|
||||
testInfo.attachments.push({
|
||||
name: 'example-utf16.txt',
|
||||
contentType: 'text/plain, charset=utf16le',
|
||||
body: Buffer.from('utf16 encoded', 'utf16le'),
|
||||
});
|
||||
|
||||
testInfo.attachments.push({
|
||||
name: 'example-null.txt',
|
||||
contentType: 'text/plain, charset=utf16le',
|
||||
body: null,
|
||||
});
|
||||
});
|
||||
`,
|
||||
}, { reporter: 'dot,html' });
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
await showReport();
|
||||
await page.click('text=passing');
|
||||
await page.click('text=example.txt');
|
||||
await page.click('text=example.json');
|
||||
await page.click('text=example-utf16.txt');
|
||||
await expect(page.locator('.attachment-body')).toHaveText(['foo', '{"foo":1}', 'utf16 encoded']);
|
||||
});
|
||||
|
@ -72,13 +72,13 @@ test('should save stdio', async ({ runInlineTest }, testInfo) => {
|
||||
{
|
||||
name: 'stdout',
|
||||
contentType: 'application/octet-stream',
|
||||
body: 'AQID'
|
||||
body: { data: [1, 2, 3], type: 'Buffer' }
|
||||
},
|
||||
{ name: 'stderr', contentType: 'text/plain', body: 'STDERR\n' },
|
||||
{
|
||||
name: 'stderr',
|
||||
contentType: 'application/octet-stream',
|
||||
body: 'BAUG'
|
||||
body: { data: [4, 5, 6], type: 'Buffer' }
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user