Skip to content

Commit 1dd35a6

Browse files
committed
PRO-13138 feat: group steps in HTML report
1 parent 48a5777 commit 1dd35a6

35 files changed

Lines changed: 726 additions & 231 deletions

autotests/packs/allTests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export const pack: Pack = {
8080
skipTests,
8181
takeFullPageScreenshotOnError: false,
8282
takeViewportScreenshotOnError: true,
83-
testFileGlobs: ['**/autotests/tests/**/exists.ts'],
83+
testFileGlobs: ['**/autotests/tests/**/*.ts'],
8484
testIdleTimeout: 8_000,
8585
testTimeout: 15_000,
8686
userAgent,

autotests/pageObjects/pages/E2edReportExample/E2edReportExample.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class E2edReportExample extends Page<CustomPageParams> {
6565
* List of test runs of retry.
6666
*/
6767
get testRunsList(): Selector {
68-
return locator('column-2');
68+
return locator('column1');
6969
}
7070

7171
/**

src/types/events.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export type LogEvent = Readonly<{
1919
type: LogEventType;
2020
}>;
2121

22+
/**
23+
* Log event with children (for groupping of `TestRun` steps).
24+
*/
25+
export type LogEventWithChildren = LogEvent & Readonly<{children: readonly LogEventWithChildren[]}>;
26+
2227
/**
2328
* EndTestRun event (on closing test).
2429
* @internal

src/types/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export type {ConsoleMessage, ConsoleMessageType} from './console';
1616
export type {UtcTimeInMs} from './date';
1717
export type {DeepMutable, DeepPartial, DeepReadonly, DeepRequired} from './deep';
1818
export type {E2edPrintedFields, JsError} from './errors';
19-
export type {LogEvent, Onlog, TestRunEvent} from './events';
19+
export type {LogEvent, LogEventWithChildren, Onlog, TestRunEvent} from './events';
2020
export type {Fn, MergeFunctions} from './fn';
2121
export type {
2222
FullMocksConfig,

src/types/internal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export type {E2edEnvironment} from './environment';
3131
export type {E2edPrintedFields, JsError} from './errors';
3232
/** @internal */
3333
export type {GlobalErrorType, MaybeWithIsTestRunBroken} from './errors';
34-
export type {LogEvent, Onlog, TestRunEvent} from './events';
34+
export type {LogEvent, LogEventWithChildren, Onlog, TestRunEvent} from './events';
3535
/** @internal */
3636
export type {EndTestRunEvent, FullEventsData} from './events';
3737
export type {Fn, MergeFunctions} from './fn';

src/utils/getDurationWithUnits.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Should be a pure function without dependencies in the form of a function declaration,
55
* because it is used in the JS client code of HTML report.
66
*/
7-
export function getDurationWithUnits(durationInMs: number): string {
7+
export const getDurationWithUnits = (durationInMs: number): string => {
88
const msInSecond = 1_000;
99
const timeMultiplicator = 60;
1010

@@ -37,4 +37,4 @@ export function getDurationWithUnits(durationInMs: number): string {
3737
}
3838

3939
return parts.slice(0, 2).join(' ') || '0ms';
40-
}
40+
};

src/utils/report/client/addOnClickOnClass.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ declare const reportClientState: ReportClientState;
77
* This base client function should not use scope variables (except other base functions).
88
* @internal
99
*/
10-
export function addOnClickOnClass(className: string, onclick: (event: HTMLElement) => void): void {
10+
export const addOnClickOnClass = (
11+
className: string,
12+
onclick: (element: HTMLElement) => void,
13+
): void => {
1114
let {clickListeners} = reportClientState;
1215

1316
if (!clickListeners) {
@@ -34,4 +37,4 @@ export function addOnClickOnClass(className: string, onclick: (event: HTMLElemen
3437
}
3538

3639
clickListeners[className] = onclick;
37-
}
40+
};

src/utils/report/client/chooseTestRun.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function chooseTestRun(runHash: RunHash): void {
5050

5151
if (
5252
!(previousHash in testRunDetailsElementsByHash) &&
53-
!previousTestRunDetailsElement.classList.contains('test-details-empty')
53+
!previousTestRunDetailsElement.classList.contains('empty-state')
5454
) {
5555
testRunDetailsElementsByHash[previousHash] = previousTestRunDetailsElement;
5656
}

src/utils/report/client/clickOnRetry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
* This base client function should not use scope variables (except other base functions).
44
* @internal
55
*/
6-
export function clickOnRetry(element: HTMLElement): void {
7-
const chosenRetryId = element.getAttribute('aria-controls');
6+
export const clickOnRetry = (element: HTMLElement): void => {
7+
const chosenRetryId = element.dataset['retry'];
88
const retry = Number(chosenRetryId?.match(/\d+/)?.[0]);
99
const allRetryElements: NodeListOf<HTMLElement> = document.querySelectorAll('.retry');
1010

@@ -26,4 +26,4 @@ export function clickOnRetry(element: HTMLElement): void {
2626
if (leftSection) {
2727
leftSection.ariaLabel = `Retry ${retry}`;
2828
}
29-
}
29+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Handler for click on screenshot in step details.
3+
* This base client function should not use scope variables (except other base functions).
4+
* @internal
5+
*/
6+
export const clickOnScreenshot = (element: HTMLElement): void => {
7+
const image = element.firstElementChild as HTMLImageElement | null;
8+
9+
if (image === null || image.tagName !== 'IMG') {
10+
// eslint-disable-next-line no-console
11+
console.error('Cannot find element <image> in clicked button', element);
12+
13+
return;
14+
}
15+
16+
const screenshotDialogImage = document.getElementById(
17+
'screenshotDialogImage',
18+
) as HTMLImageElement | null;
19+
const screenshotDialogTitle = document.getElementById('screenshotDialogTitle');
20+
21+
if (screenshotDialogImage) {
22+
screenshotDialogImage.alt = image.title;
23+
screenshotDialogImage.src = image.src;
24+
screenshotDialogImage.title = image.title;
25+
}
26+
27+
if (screenshotDialogTitle) {
28+
screenshotDialogTitle.textContent = image.title;
29+
}
30+
31+
(document.getElementById('screenshotDialog') as HTMLDialogElement | null)?.showModal();
32+
};

0 commit comments

Comments
 (0)