Skip to content

Commit 76ee48d

Browse files
Skn0ttdgozman
andauthored
chore: followup on static annotations (#35579)
Signed-off-by: Simon Knott <[email protected]> Co-authored-by: Dmitry Gozman <[email protected]>
1 parent d79bb57 commit 76ee48d

File tree

17 files changed

+63
-81
lines changed

17 files changed

+63
-81
lines changed

docs/src/test-reporter-api/class-testcase.md

+1-7
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,7 @@
1111
- `description` ?<[string]> Optional description.
1212
- `location` ?<[Location]> Optional location in the source where the annotation is added.
1313

14-
The list of annotations applicable to the current test. Includes:
15-
* annotations defined on the test or suite via [`method: Test.(call)`] and [`method: Test.describe`];
16-
* annotations implicitly added by methods [`method: Test.skip`], [`method: Test.fixme`] and [`method: Test.fail`] prior to test execution.
17-
18-
Annotations are available during test execution through [`property: TestInfo.annotations`].
19-
20-
Learn more about [test annotations](../test-annotations.md).
14+
[`property: TestResult.annotations`] of the last test run.
2115

2216
## property: TestCase.expectedStatus
2317
* since: v1.10

docs/src/test-reporter-api/class-testresult.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ The list of files or buffers attached during the test execution through [`proper
2121
- `description` ?<[string]> Optional description.
2222
- `location` ?<[Location]> Optional location in the source where the annotation is added.
2323

24-
The list of annotations appended during test execution. Includes:
25-
* annotations implicitly added by methods [`method: Test.skip`], [`method: Test.fixme`] and [`method: Test.fail`] during test execution;
26-
* annotations appended to [`property: TestInfo.annotations`].
24+
The list of annotations applicable to the current test. Includes:
25+
* annotations defined on the test or suite via [`method: Test.(call)`] and [`method: Test.describe`];
26+
* annotations implicitly added by methods [`method: Test.skip`], [`method: Test.fixme`] and [`method: Test.fail`];
27+
* annotations appended to [`property: TestInfo.annotations`] during the test execution.
2728

2829
Annotations are available during test execution through [`property: TestInfo.annotations`].
2930

packages/html-reporter/src/testCaseView.spec.tsx

+14-12
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ const result: TestResult = {
4242
}],
4343
attachments: [],
4444
}],
45-
annotations: [],
45+
annotations: [
46+
{ type: 'annotation', description: 'Annotation text' },
47+
{ type: 'annotation', description: 'Another annotation text' },
48+
{ type: '_annotation', description: 'Hidden annotation' },
49+
],
4650
attachments: [],
4751
status: 'passed',
4852
};
@@ -53,11 +57,7 @@ const testCase: TestCase = {
5357
path: [],
5458
projectName: 'chromium',
5559
location: { file: 'test.spec.ts', line: 42, column: 0 },
56-
annotations: [
57-
{ type: 'annotation', description: 'Annotation text' },
58-
{ type: 'annotation', description: 'Another annotation text' },
59-
{ type: '_annotation', description: 'Hidden annotation' },
60-
],
60+
annotations: result.annotations,
6161
tags: [],
6262
outcome: 'expected',
6363
duration: 200,
@@ -98,16 +98,18 @@ const annotationLinkRenderingTestCase: TestCase = {
9898
path: [],
9999
projectName: 'chromium',
100100
location: { file: 'test.spec.ts', line: 42, column: 0 },
101-
annotations: [
102-
{ type: 'more info', description: 'read https://playwright.dev/docs/intro and https://playwright.dev/docs/api/class-playwright' },
103-
{ type: 'related issues', description: 'https://github.com/microsoft/playwright/issues/23180, https://github.com/microsoft/playwright/issues/23181' },
104-
105-
],
101+
annotations: [],
106102
tags: [],
107103
outcome: 'expected',
108104
duration: 10,
109105
ok: true,
110-
results: [result]
106+
results: [{
107+
...result,
108+
annotations: [
109+
{ type: 'more info', description: 'read https://playwright.dev/docs/intro and https://playwright.dev/docs/api/class-playwright' },
110+
{ type: 'related issues', description: 'https://github.com/microsoft/playwright/issues/23180, https://github.com/microsoft/playwright/issues/23181' },
111+
]
112+
}]
111113
};
112114

113115
test('should correctly render links in annotations', async ({ mount }) => {

packages/html-reporter/src/testCaseView.tsx

+12-11
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,7 @@ export const TestCaseView: React.FC<{
4646
return test.tags;
4747
}, [test]);
4848

49-
const visibleAnnotations = React.useMemo(() => {
50-
if (!test)
51-
return [];
52-
const annotations = [...test.annotations];
53-
if (test.results[selectedResultIndex])
54-
annotations.push(...test.results[selectedResultIndex].annotations);
55-
return annotations.filter(annotation => !annotation.type.startsWith('_'));
56-
}, [test, selectedResultIndex]);
49+
const visibleTestAnnotations = test?.annotations.filter(a => !a.type.startsWith('_')) ?? [];
5750

5851
return <div className='test-case-column vbox'>
5952
{test && <div className='hbox'>
@@ -77,8 +70,8 @@ export const TestCaseView: React.FC<{
7770
{test && !!test.projectName && <ProjectLink projectNames={projectNames} projectName={test.projectName}></ProjectLink>}
7871
{labels && <LabelsLinkView labels={labels} />}
7972
</div>}
80-
{!!visibleAnnotations.length && <AutoChip header='Annotations' dataTestId='test-case-annotations'>
81-
{visibleAnnotations.map((annotation, index) => <TestCaseAnnotationView key={index} annotation={annotation} />)}
73+
{test?.results.length === 0 && visibleTestAnnotations.length !== 0 && <AutoChip header='Annotations' dataTestId='test-case-annotations'>
74+
{visibleTestAnnotations.map((annotation, index) => <TestCaseAnnotationView key={index} annotation={annotation} />)}
8275
</AutoChip>}
8376
{test && <TabbedPane tabs={
8477
test.results.map((result, index) => ({
@@ -87,7 +80,15 @@ export const TestCaseView: React.FC<{
8780
{statusIcon(result.status)} {retryLabel(index)}
8881
{(test.results.length > 1) && <span className='test-case-run-duration'>{msToString(result.duration)}</span>}
8982
</div>,
90-
render: () => <TestResultView test={test!} result={result} />
83+
render: () => {
84+
const visibleAnnotations = result.annotations.filter(annotation => !annotation.type.startsWith('_'));
85+
return <>
86+
{!!visibleAnnotations.length && <AutoChip header='Annotations' dataTestId='test-case-annotations'>
87+
{visibleAnnotations.map((annotation, index) => <TestCaseAnnotationView key={index} annotation={annotation} />)}
88+
</AutoChip>}
89+
<TestResultView test={test!} result={result} />
90+
</>;
91+
},
9192
})) || []} selectedTab={String(selectedResultIndex)} setSelectedTab={id => setSelectedResultIndex(+id)} />}
9293
</div>;
9394
};

packages/playwright/src/isomorphic/teleReceiver.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -235,17 +235,16 @@ export class TeleReporterReceiver {
235235
const test = this._tests.get(testEndPayload.testId)!;
236236
test.timeout = testEndPayload.timeout;
237237
test.expectedStatus = testEndPayload.expectedStatus;
238-
// Should be empty array, but if it's not, it represents all annotations for that test
239-
if (testEndPayload.annotations.length > 0)
240-
test.annotations = this._absoluteAnnotationLocations(testEndPayload.annotations);
241238
const result = test.results.find(r => r._id === payload.id)!;
242239
result.duration = payload.duration;
243240
result.status = payload.status;
244241
result.errors = payload.errors;
245242
result.error = result.errors?.[0];
246243
result.attachments = this._parseAttachments(payload.attachments);
247-
if (payload.annotations)
244+
if (payload.annotations) {
248245
result.annotations = this._absoluteAnnotationLocations(payload.annotations);
246+
test.annotations = result.annotations;
247+
}
249248
this._reporter.onTestEnd?.(test, result);
250249
// Free up the memory as won't see these step ids.
251250
result._stepMap = new Map();

packages/playwright/src/reporters/base.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export function formatFailure(screen: Screen, config: FullConfig, test: TestCase
320320
const header = formatTestHeader(screen, config, test, { indent: ' ', index, mode: 'error' });
321321
lines.push(screen.colors.red(header));
322322
for (const result of test.results) {
323-
const warnings = [...result.annotations, ...test.annotations].filter(a => a.type === 'warning');
323+
const warnings = result.annotations.filter(a => a.type === 'warning');
324324
const resultLines: string[] = [];
325325
const errors = formatResultFailure(screen, test, result, ' ');
326326
if (!errors.length)

packages/playwright/src/reporters/html.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ class HtmlBuilder {
417417
projectName,
418418
location,
419419
duration,
420-
annotations: this._serializeAnnotations([...test.annotations, ...results.flatMap(r => r.annotations)]),
420+
annotations: this._serializeAnnotations(test.annotations),
421421
tags: test.tags,
422422
outcome: test.outcome(),
423423
path,

packages/playwright/src/reporters/junit.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,7 @@ class JUnitReporter implements ReporterV2 {
166166
children: [] as XMLEntry[]
167167
};
168168

169-
const annotations = [...test.annotations, ...test.results.flatMap(r => r.annotations)];
170-
for (const annotation of annotations) {
169+
for (const annotation of test.annotations) {
171170
const property: XMLEntry = {
172171
name: 'property',
173172
attributes: {

packages/playwright/src/runner/dispatcher.ts

+1
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ class JobDispatcher {
326326
result.error = result.errors[0];
327327
result.status = params.status;
328328
result.annotations = params.annotations;
329+
test.annotations = [...params.annotations]; // last test result wins
329330
test.expectedStatus = params.expectedStatus;
330331
test.timeout = params.timeout;
331332
const isFailure = result.status !== 'skipped' && result.status !== test.expectedStatus;

packages/playwright/src/worker/workerMain.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,6 @@ export class WorkerMain extends ProcessRunner {
293293
for (const annotation of test.annotations)
294294
processAnnotation(annotation);
295295

296-
const staticAnnotations = new Set(testInfo.annotations);
297-
298296
// Process existing annotations dynamically set for parent suites.
299297
for (const suite of suites) {
300298
const extraAnnotations = this._activeSuites.get(suite) || [];
@@ -313,7 +311,7 @@ export class WorkerMain extends ProcessRunner {
313311
if (isSkipped && nextTest && !hasAfterAllToRunBeforeNextTest) {
314312
// Fast path - this test is skipped, and there are more tests that will handle cleanup.
315313
testInfo.status = 'skipped';
316-
this.dispatchEvent('testEnd', buildTestEndPayload(testInfo, staticAnnotations));
314+
this.dispatchEvent('testEnd', buildTestEndPayload(testInfo));
317315
return;
318316
}
319317

@@ -495,7 +493,7 @@ export class WorkerMain extends ProcessRunner {
495493

496494
this._currentTest = null;
497495
setCurrentTestInfo(null);
498-
this.dispatchEvent('testEnd', buildTestEndPayload(testInfo, staticAnnotations));
496+
this.dispatchEvent('testEnd', buildTestEndPayload(testInfo));
499497

500498
const preserveOutput = this._config.config.preserveOutput === 'always' ||
501499
(this._config.config.preserveOutput === 'failures-only' && testInfo._isFailure());
@@ -615,15 +613,15 @@ function buildTestBeginPayload(testInfo: TestInfoImpl): TestBeginPayload {
615613
};
616614
}
617615

618-
function buildTestEndPayload(testInfo: TestInfoImpl, staticAnnotations: Set<TestAnnotation>): TestEndPayload {
616+
function buildTestEndPayload(testInfo: TestInfoImpl): TestEndPayload {
619617
return {
620618
testId: testInfo.testId,
621619
duration: testInfo.duration,
622620
status: testInfo.status!,
623621
errors: testInfo.errors,
624622
hasNonRetriableError: testInfo._hasNonRetriableError,
625623
expectedStatus: testInfo.expectedStatus,
626-
annotations: testInfo.annotations.filter(a => !staticAnnotations.has(a)),
624+
annotations: testInfo.annotations,
627625
timeout: testInfo.timeout,
628626
};
629627
}

packages/playwright/types/testReporter.d.ts

+9-19
Original file line numberDiff line numberDiff line change
@@ -438,21 +438,8 @@ export interface TestCase {
438438
titlePath(): Array<string>;
439439

440440
/**
441-
* The list of annotations applicable to the current test. Includes:
442-
* - annotations defined on the test or suite via
443-
* [test.(call)(title[, details, body])](https://playwright.dev/docs/api/class-test#test-call) and
444-
* [test.describe([title, details, callback])](https://playwright.dev/docs/api/class-test#test-describe);
445-
* - annotations implicitly added by methods
446-
* [test.skip([title, details, body, condition, callback, description])](https://playwright.dev/docs/api/class-test#test-skip),
447-
* [test.fixme([title, details, body, condition, callback, description])](https://playwright.dev/docs/api/class-test#test-fixme)
448-
* and
449-
* [test.fail([title, details, body, condition, callback, description])](https://playwright.dev/docs/api/class-test#test-fail)
450-
* prior to test execution.
451-
*
452-
* Annotations are available during test execution through
453-
* [testInfo.annotations](https://playwright.dev/docs/api/class-testinfo#test-info-annotations).
454-
*
455-
* Learn more about [test annotations](https://playwright.dev/docs/test-annotations).
441+
* [testResult.annotations](https://playwright.dev/docs/api/class-testresult#test-result-annotations) of the last test
442+
* run.
456443
*/
457444
annotations: Array<{
458445
/**
@@ -597,15 +584,18 @@ export interface TestError {
597584
*/
598585
export interface TestResult {
599586
/**
600-
* The list of annotations appended during test execution. Includes:
587+
* The list of annotations applicable to the current test. Includes:
588+
* - annotations defined on the test or suite via
589+
* [test.(call)(title[, details, body])](https://playwright.dev/docs/api/class-test#test-call) and
590+
* [test.describe([title, details, callback])](https://playwright.dev/docs/api/class-test#test-describe);
601591
* - annotations implicitly added by methods
602592
* [test.skip([title, details, body, condition, callback, description])](https://playwright.dev/docs/api/class-test#test-skip),
603593
* [test.fixme([title, details, body, condition, callback, description])](https://playwright.dev/docs/api/class-test#test-fixme)
604594
* and
605-
* [test.fail([title, details, body, condition, callback, description])](https://playwright.dev/docs/api/class-test#test-fail)
606-
* during test execution;
595+
* [test.fail([title, details, body, condition, callback, description])](https://playwright.dev/docs/api/class-test#test-fail);
607596
* - annotations appended to
608-
* [testInfo.annotations](https://playwright.dev/docs/api/class-testinfo#test-info-annotations).
597+
* [testInfo.annotations](https://playwright.dev/docs/api/class-testinfo#test-info-annotations) during the test
598+
* execution.
609599
*
610600
* Annotations are available during test execution through
611601
* [testInfo.annotations](https://playwright.dev/docs/api/class-testinfo#test-info-annotations).

packages/trace-viewer/src/ui/uiModeTraceView.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ export const TraceView: React.FC<{
8888
};
8989
}, [outputDir, item, setModel, counter, setCounter, pathSeparator]);
9090

91-
const annotations = item.testCase ? [...item.testCase.annotations, ...(item.testCase.results[0]?.annotations ?? [])] : [];
92-
9391
return <Workbench
9492
key='workbench'
9593
model={model?.model}
@@ -98,7 +96,7 @@ export const TraceView: React.FC<{
9896
fallbackLocation={item.testFile}
9997
isLive={model?.isLive}
10098
status={item.treeItem?.status}
101-
annotations={annotations}
99+
annotations={item.testCase?.annotations ?? []}
102100
onOpenExternally={onOpenExternally}
103101
revealSource={revealSource}
104102
/>;

tests/bidi/csvReporter.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ class CsvReporter implements Reporter {
4646
for (const file of project.suites) {
4747
for (const test of file.allTests()) {
4848
// Report fixme tests as failing.
49-
const annotations = [...test.annotations, ...test.results.map(r => r.annotations).flat()];
50-
const fixme = annotations.find(a => a.type === 'fixme');
49+
const fixme = test.annotations.find(a => a.type === 'fixme');
5150
if (test.ok() && !fixme)
5251
continue;
5352
const row = [];

tests/playwright-test/access-data.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ test('should access annotations in fixture', async ({ runInlineTest }) => {
6060
});
6161
expect(exitCode).toBe(0);
6262
const test = report.suites[0].specs[0].tests[0];
63-
expect(test.results[0].annotations).toEqual([
63+
expect(test.annotations).toEqual([
6464
{ type: 'slow', description: 'just slow', location: { file: expect.any(String), line: 10, column: 14 } },
6565
{ type: 'myname', description: 'hello' }
6666
]);

tests/playwright-test/playwright-test-fixtures.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ export function expectTestHelper(result: RunResult) {
434434
for (const test of tests) {
435435
expect(test.expectedStatus, `title: ${title}`).toBe(expectedStatus);
436436
expect(test.status, `title: ${title}`).toBe(status);
437-
expect([...test.annotations, ...test.results.flatMap(r => r.annotations)].map(a => a.type), `title: ${title}`).toEqual(annotations);
437+
expect(test.annotations.map(a => a.type), `title: ${title}`).toEqual(annotations);
438438
}
439439
};
440440
}

tests/playwright-test/retry.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,5 +260,5 @@ test('failed and skipped on retry should be marked as flaky', async ({ runInline
260260
expect(result.failed).toBe(0);
261261
expect(result.flaky).toBe(1);
262262
expect(result.output).toContain('Failed on first run');
263-
expect(result.report.suites[0].specs[0].tests[0].results[1].annotations).toEqual([{ type: 'skip', description: 'Skipped on first retry', location: expect.anything() }]);
263+
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'Skipped on first retry', location: expect.anything() }]);
264264
});

0 commit comments

Comments
 (0)