feat(html-report): add url fields for rendered.
This commit is contained in:
parent
e8fc8af22e
commit
68c6defbc3
|
|
@ -182,7 +182,7 @@ You can also annotate all tests in a group or provide multiple annotations:
|
||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
test.describe('report tests', {
|
test.describe('report tests', {
|
||||||
annotation: { type: 'category', description: 'report' },
|
annotation: { type: 'category', description: 'report', url: 'https://github.com/microsoft/playwright/issues/23180'},
|
||||||
}, () => {
|
}, () => {
|
||||||
test('test report header', async ({ page }) => {
|
test('test report header', async ({ page }) => {
|
||||||
// ...
|
// ...
|
||||||
|
|
@ -192,6 +192,7 @@ test.describe('report tests', {
|
||||||
annotation: [
|
annotation: [
|
||||||
{ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23180' },
|
{ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23180' },
|
||||||
{ type: 'performance', description: 'very slow test!' },
|
{ type: 'performance', description: 'very slow test!' },
|
||||||
|
{ type: 'performance', description: 'very slow test!', url: 'https://github.com/microsoft/playwright/issues/23180'},
|
||||||
],
|
],
|
||||||
}, async ({ page }) => {
|
}, async ({ page }) => {
|
||||||
// ...
|
// ...
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,10 @@ function cacheSearchValues(test: TestCaseSummary): SearchValues {
|
||||||
line: String(test.location.line),
|
line: String(test.location.line),
|
||||||
column: String(test.location.column),
|
column: String(test.location.column),
|
||||||
labels: test.tags.map(tag => tag.toLowerCase()),
|
labels: test.tags.map(tag => tag.toLowerCase()),
|
||||||
annotations: test.annotations.map(a => a.type.toLowerCase() + '=' + a.description?.toLocaleLowerCase())
|
annotations: test.annotations.map(a => {
|
||||||
|
const value = a.description?.toLocaleLowerCase() || a.url?.toLocaleLowerCase() || '';
|
||||||
|
return a.type.toLowerCase() + '=' + value;
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
(test as any)[searchValuesSymbol] = searchValues;
|
(test as any)[searchValuesSymbol] = searchValues;
|
||||||
return searchValues;
|
return searchValues;
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export type TestEndPayload = {
|
||||||
errors: TestInfoError[];
|
errors: TestInfoError[];
|
||||||
hasNonRetriableError: boolean;
|
hasNonRetriableError: boolean;
|
||||||
expectedStatus: TestStatus;
|
expectedStatus: TestStatus;
|
||||||
annotations: { type: string, description?: string }[];
|
annotations: { type: string, description?: string, url?: string }[];
|
||||||
timeout: number;
|
timeout: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,12 +221,13 @@ export class TestTypeImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof modifierArgs[0] === 'function') {
|
if (typeof modifierArgs[0] === 'function') {
|
||||||
suite._modifiers.push({ type, fn: modifierArgs[0], location, description: modifierArgs[1] });
|
suite._modifiers.push({ type, fn: modifierArgs[0], location, description: modifierArgs[1], url: modifierArgs[1] });
|
||||||
} else {
|
} else {
|
||||||
if (modifierArgs.length >= 1 && !modifierArgs[0])
|
if (modifierArgs.length >= 1 && !modifierArgs[0])
|
||||||
return;
|
return;
|
||||||
const description = modifierArgs[1];
|
const description = modifierArgs[1];
|
||||||
suite._staticAnnotations.push({ type, description });
|
const url = modifierArgs[1];
|
||||||
|
suite._staticAnnotations.push({ type, description, url });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,14 @@ export type JsonTestCase = {
|
||||||
retries: number;
|
retries: number;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
repeatEachIndex: number;
|
repeatEachIndex: number;
|
||||||
annotations?: { type: string, description?: string }[];
|
annotations?: { type: string, description?: string, url?: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type JsonTestEnd = {
|
export type JsonTestEnd = {
|
||||||
testId: string;
|
testId: string;
|
||||||
expectedStatus: reporterTypes.TestStatus;
|
expectedStatus: reporterTypes.TestStatus;
|
||||||
timeout: number;
|
timeout: number;
|
||||||
annotations: { type: string, description?: string }[];
|
annotations: { type: string, description?: string, url?: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type JsonTestResultStart = {
|
export type JsonTestResultStart = {
|
||||||
|
|
|
||||||
|
|
@ -380,7 +380,11 @@ class HtmlBuilder {
|
||||||
location,
|
location,
|
||||||
duration,
|
duration,
|
||||||
// Annotations can be pushed directly, with a wrong type.
|
// Annotations can be pushed directly, with a wrong type.
|
||||||
annotations: test.annotations.map(a => ({ type: a.type, description: a.description ? String(a.description) : a.description })),
|
annotations: test.annotations.map(a => ({
|
||||||
|
type: a.type,
|
||||||
|
description: a.description ? String(a.description) : a.description,
|
||||||
|
url: a.url ? String(a.url) : a.url
|
||||||
|
})),
|
||||||
tags: test.tags,
|
tags: test.tags,
|
||||||
outcome: test.outcome(),
|
outcome: test.outcome(),
|
||||||
path,
|
path,
|
||||||
|
|
@ -394,7 +398,11 @@ class HtmlBuilder {
|
||||||
location,
|
location,
|
||||||
duration,
|
duration,
|
||||||
// Annotations can be pushed directly, with a wrong type.
|
// Annotations can be pushed directly, with a wrong type.
|
||||||
annotations: test.annotations.map(a => ({ type: a.type, description: a.description ? String(a.description) : a.description })),
|
annotations: test.annotations.map(a => ({
|
||||||
|
type: a.type,
|
||||||
|
description: a.description ? String(a.description) : a.description,
|
||||||
|
url: a.url ? String(a.url) : a.url
|
||||||
|
})),
|
||||||
tags: test.tags,
|
tags: test.tags,
|
||||||
outcome: test.outcome(),
|
outcome: test.outcome(),
|
||||||
path,
|
path,
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ export type JsonTestEnd = {
|
||||||
testId: string;
|
testId: string;
|
||||||
expectedStatus: reporterTypes.TestStatus;
|
expectedStatus: reporterTypes.TestStatus;
|
||||||
timeout: number;
|
timeout: number;
|
||||||
annotations: { type: string, description?: string }[];
|
annotations: { type: string, description?: string, url?: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type JsonTestResultStart = {
|
export type JsonTestResultStart = {
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ export class TestInfoImpl implements TestInfo {
|
||||||
this._tracing = new TestTracing(this, workerParams.artifactsDir);
|
this._tracing = new TestTracing(this, workerParams.artifactsDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _modifier(type: 'skip' | 'fail' | 'fixme' | 'slow', modifierArgs: [arg?: any, description?: string]) {
|
private _modifier(type: 'skip' | 'fail' | 'fixme' | 'slow', modifierArgs: [arg?: any, description?: string, url?: string]) {
|
||||||
if (typeof modifierArgs[1] === 'function') {
|
if (typeof modifierArgs[1] === 'function') {
|
||||||
throw new Error([
|
throw new Error([
|
||||||
'It looks like you are calling test.skip() inside the test and pass a callback.',
|
'It looks like you are calling test.skip() inside the test and pass a callback.',
|
||||||
|
|
@ -473,19 +473,19 @@ export class TestInfoImpl implements TestInfo {
|
||||||
return path.normalize(path.resolve(this._configInternal.configDir, snapshotPath));
|
return path.normalize(path.resolve(this._configInternal.configDir, snapshotPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
skip(...args: [arg?: any, description?: string]) {
|
skip(...args: [arg?: any, description?: string, url?: string]) {
|
||||||
this._modifier('skip', args);
|
this._modifier('skip', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fixme(...args: [arg?: any, description?: string]) {
|
fixme(...args: [arg?: any, description?: string, url?: string]) {
|
||||||
this._modifier('fixme', args);
|
this._modifier('fixme', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fail(...args: [arg?: any, description?: string]) {
|
fail(...args: [arg?: any, description?: string, url?: string]) {
|
||||||
this._modifier('fail', args);
|
this._modifier('fail', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
slow(...args: [arg?: any, description?: string]) {
|
slow(...args: [arg?: any, description?: string, url?: string]) {
|
||||||
this._modifier('slow', args);
|
this._modifier('slow', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
6
packages/playwright/types/test.d.ts
vendored
6
packages/playwright/types/test.d.ts
vendored
|
|
@ -1845,6 +1845,7 @@ export type TestStatus = 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interru
|
||||||
type TestDetailsAnnotation = {
|
type TestDetailsAnnotation = {
|
||||||
type: string;
|
type: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
url?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TestDetails = {
|
export type TestDetails = {
|
||||||
|
|
@ -8175,6 +8176,11 @@ export interface TestInfo {
|
||||||
* Optional description.
|
* Optional description.
|
||||||
*/
|
*/
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional url.
|
||||||
|
*/
|
||||||
|
url?: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
7
packages/playwright/types/testReporter.d.ts
vendored
7
packages/playwright/types/testReporter.d.ts
vendored
|
|
@ -273,7 +273,7 @@ export interface JSONReportSpec {
|
||||||
|
|
||||||
export interface JSONReportTest {
|
export interface JSONReportTest {
|
||||||
timeout: number;
|
timeout: number;
|
||||||
annotations: { type: string, description?: string }[],
|
annotations: { type: string, description?: string, url?: string }[],
|
||||||
expectedStatus: TestStatus;
|
expectedStatus: TestStatus;
|
||||||
projectName: string;
|
projectName: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
|
@ -481,6 +481,11 @@ export interface TestCase {
|
||||||
* Optional description.
|
* Optional description.
|
||||||
*/
|
*/
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional url.
|
||||||
|
*/
|
||||||
|
url?: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -744,16 +744,15 @@ test.info().annotations.push({ type: 'issue', description: 'I am not interested
|
||||||
'a.test.js': `
|
'a.test.js': `
|
||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
test('annotated test', async ({ page }) => {
|
test('annotated test', async ({ page }) => {
|
||||||
test.info().annotations.push({ type: 'issue', description: 'I add URL field to annotations for hyperlink display', url: 'https://github.com/microsoft/playwright/pull/31014' });
|
test.info().annotations.push({ type: 'url', url: 'https://github.com/microsoft/playwright/pull/31014' });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { reporter: 'dot,html' }, { PLAYWRIGHT_HTML_OPEN: 'never' });
|
}, { reporter: 'dot,html' }, { PLAYWRIGHT_HTML_OPEN: 'never' });
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
|
|
||||||
await showReport();
|
await showReport();
|
||||||
await page.click('text=annotated test');
|
await page.click('text=annotated test');
|
||||||
await expect(page.locator('.test-case-annotation')).toHaveText('issue: I am not interested in this test');
|
await expect(page.locator('.test-case-annotation')).toHaveText(`url: https://github.com/microsoft/playwright/pull/31014`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render annotations as link if needed', async ({ runInlineTest, page, showReport, server }) => {
|
test('should render annotations as link if needed', async ({ runInlineTest, page, showReport, server }) => {
|
||||||
|
|
|
||||||
1
utils/generate_types/overrides-test.d.ts
vendored
1
utils/generate_types/overrides-test.d.ts
vendored
|
|
@ -68,6 +68,7 @@ export type TestStatus = 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interru
|
||||||
type TestDetailsAnnotation = {
|
type TestDetailsAnnotation = {
|
||||||
type: string;
|
type: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
url?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TestDetails = {
|
export type TestDetails = {
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ export interface JSONReportSpec {
|
||||||
|
|
||||||
export interface JSONReportTest {
|
export interface JSONReportTest {
|
||||||
timeout: number;
|
timeout: number;
|
||||||
annotations: { type: string, description?: string }[],
|
annotations: { type: string, description?: string, url?: string }[],
|
||||||
expectedStatus: TestStatus;
|
expectedStatus: TestStatus;
|
||||||
projectName: string;
|
projectName: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue