Skip to content

Commit d9c30ad

Browse files
committed
PRO-15806 feat: add functionality of regroupSteps in HTML reports
1 parent 0e74da9 commit d9c30ad

13 files changed

Lines changed: 85 additions & 42 deletions

File tree

autotests/configurator/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export {mapLogPayloadInConsole} from './mapLogPayloadInConsole';
77
export {mapLogPayloadInLogFile} from './mapLogPayloadInLogFile';
88
export {mapLogPayloadInReport} from './mapLogPayloadInReport';
99
export {matchScreenshot} from './matchScreenshot';
10+
export {regroupSteps} from './regroupSteps';
1011
export {skipTests} from './skipTests';
1112
export type {
1213
DoAfterPack,
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import {LogEventStatus, LogEventType} from '../../../constants/internal';
1+
import {LogEventStatus, LogEventType} from 'e2ed/constants';
22

3-
import type {LogEvent, LogEventWithChildren} from '../../../types/internal';
3+
import type {LogEvent} from 'e2ed/types';
44

55
/**
6-
* Group log events to log events with children (for groupping of `TestRun` steps).
6+
* Regroup log events (for groupping of `TestRun` steps).
77
* This base client function should not use scope variables (except other base functions).
88
* @internal
99
*/
10-
export const groupLogEvents = (logEvents: readonly LogEvent[]): readonly LogEventWithChildren[] => {
10+
export const regroupSteps = (logEvents: readonly LogEvent[]): readonly LogEvent[] => {
1111
const topLevelTypes: readonly LogEventType[] = [
1212
LogEventType.Action,
1313
LogEventType.Assert,
@@ -20,15 +20,15 @@ export const groupLogEvents = (logEvents: readonly LogEvent[]): readonly LogEven
2020
topLevelTypes.includes(logEvent.type) ||
2121
logEvent.payload?.logEventStatus === LogEventStatus.Failed;
2222

23-
const result: LogEventWithChildren[] = [];
23+
const result: LogEvent[] = [];
2424

2525
for (const logEvent of logEvents) {
2626
const last = result.at(-1);
27-
const newEvent: LogEventWithChildren = {children: [], ...logEvent};
27+
const newEvent: LogEvent = {children: [], ...logEvent};
2828

2929
if (isTopLevelEvent(logEvent)) {
3030
if (last && !isTopLevelEvent(last)) {
31-
const firstTopLevel: LogEventWithChildren = {
31+
const firstTopLevel: LogEvent = {
3232
children: [...result],
3333
message: 'Initialization',
3434
payload: undefined,
@@ -43,7 +43,7 @@ export const groupLogEvents = (logEvents: readonly LogEvent[]): readonly LogEven
4343

4444
result.push(newEvent);
4545
} else if (last && isTopLevelEvent(last)) {
46-
(last.children as LogEventWithChildren[]).push(newEvent);
46+
(last.children as LogEvent[]).push(newEvent);
4747
} else {
4848
result.push(newEvent);
4949
}

autotests/packs/allTests.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
mapLogPayloadInLogFile,
1919
mapLogPayloadInReport,
2020
matchScreenshot,
21+
regroupSteps,
2122
skipTests,
2223
} from '../configurator';
2324

@@ -74,6 +75,7 @@ export const pack: Pack = {
7475
pathToScreenshotsDirectoryForReport: './screenshots',
7576
port1: 1337,
7677
port2: 1338,
78+
regroupSteps,
7779
reportFileName: 'report.html',
7880
resourceUsageReadingInternal: 5_000,
7981
selectorTimeout: 10_000,

src/step.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,52 @@ import {LogEventType} from './constants/internal';
22
import {setCustomInspectOnFunction} from './utils/fn';
33
import {log} from './utils/log';
44

5-
import type {MaybePromise} from './types/internal';
5+
import type {LogPayload, MaybePromise} from './types/internal';
66

77
import {test as playwrightTest} from '@playwright/test';
88

9-
type Options = Readonly<{skipLogs?: boolean; timeout?: number}>;
10-
11-
const noop = (): void => {};
9+
type Options = Readonly<{runPlaywrightStep?: boolean; skipLogs?: boolean; timeout?: number}>;
1210

1311
/**
1412
* Declares a test step (calls Playwright's `test.step` function inside).
1513
*/
16-
export const step = (
14+
export const step = async (
1715
name: string,
18-
body: () => MaybePromise<void> = noop,
16+
body?: () => MaybePromise<LogPayload | undefined>,
1917
options?: Options,
2018
): Promise<void> => {
2119
if (options?.skipLogs !== true) {
22-
if (body !== noop) {
20+
if (body !== undefined) {
2321
setCustomInspectOnFunction(body);
2422
}
2523

26-
log(name, {body: body === noop ? undefined : body, options}, LogEventType.InternalCore);
24+
log(name, {body, options}, LogEventType.InternalCore);
2725
}
2826

29-
return playwrightTest.step(name, body, options);
27+
try {
28+
let payload: LogPayload | undefined;
29+
30+
if (options?.runPlaywrightStep === true) {
31+
await playwrightTest.step(
32+
name,
33+
async () => {
34+
payload = await body?.();
35+
},
36+
options,
37+
);
38+
} else {
39+
payload = await body?.();
40+
}
41+
42+
// TODO: set payload to log
43+
payload;
44+
} catch (error) {
45+
// TODO: add error to log and set logEventStatus = 'failed'
46+
47+
if (error !== null && typeof error === 'object') {
48+
Object.assign(error, {fromStep: name});
49+
}
50+
51+
throw error;
52+
}
3053
};

src/types/config/ownE2edConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {PlaywrightTestConfig} from '@playwright/test';
22

33
import type {TestRunStatus} from '../../constants/internal';
44

5+
import type {LogEvent} from '../events';
56
import type {FullMocksConfig} from '../fullMocks';
67
import type {LogTag, MapBackendResponseToLog, MapLogPayload, MapLogPayloadInReport} from '../log';
78
import type {MatchScreenshotConfig} from '../matchScreenshot';
@@ -198,6 +199,11 @@ export type OwnE2edConfig<
198199
*/
199200
pathToScreenshotsDirectoryForReport: string | null;
200201

202+
/**
203+
* Regroup tree of test steps in the HTML report.
204+
*/
205+
regroupSteps: (this: void, steps: readonly LogEvent[]) => readonly LogEvent[];
206+
201207
/**
202208
* The name of the file under which, after running the tests,
203209
* the HTML report will be saved in the `autotests/reports` directory, for example, `report.html`.

src/types/events.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@ import type {TestMetaPlaceholder} from './userland';
1313
* Log event (on log call).
1414
*/
1515
export type LogEvent = Readonly<{
16+
children?: readonly LogEvent[];
1617
message: string;
1718
payload: LogPayload | undefined;
1819
time: UtcTimeInMs;
1920
type: LogEventType;
2021
}>;
2122

22-
/**
23-
* Log event with children (for groupping of `TestRun` steps).
24-
*/
25-
export type LogEventWithChildren = LogEvent & Readonly<{children: readonly LogEventWithChildren[]}>;
26-
2723
/**
2824
* EndTestRun event (on closing test).
2925
* @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, LogEventWithChildren, Onlog, TestRunEvent} from './events';
19+
export type {LogEvent, 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, LogEventWithChildren, Onlog, TestRunEvent} from './events';
34+
export type {LogEvent, Onlog, TestRunEvent} from './events';
3535
/** @internal */
3636
export type {EndTestRunEvent, FullEventsData} from './events';
3737
export type {Fn, MergeFunctions} from './fn';

src/utils/flatLogEvents.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type {LogEvent} from '../types/internal';
2+
3+
/**
4+
* Flats array of log events with children to flat array.
5+
* @internal
6+
*/
7+
export const flatLogEvents = (logEvents: readonly LogEvent[]): readonly LogEvent[] => {
8+
const result: LogEvent[] = [];
9+
10+
for (const logEvent of logEvents) {
11+
result.push(logEvent);
12+
13+
if (logEvent.children !== undefined && logEvent.children.length > 0) {
14+
result.push(...flatLogEvents(logEvent.children));
15+
}
16+
}
17+
18+
return result;
19+
};

src/utils/report/client/render/Step.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ import {Duration as clientDuration} from './Duration';
44
import {StepContent as clientStepContent} from './StepContent';
55
import {Steps as clientSteps} from './Steps';
66

7-
import type {
8-
LogEventWithChildren,
9-
ReportClientState,
10-
UtcTimeInMs,
11-
} from '../../../../types/internal';
7+
import type {LogEvent, ReportClientState, UtcTimeInMs} from '../../../../types/internal';
128

139
const Duration = clientDuration;
1410
const StepContent = clientStepContent;
@@ -19,7 +15,7 @@ declare const reportClientState: ReportClientState;
1915

2016
type Props = Readonly<{
2117
isEnd?: boolean;
22-
logEvent: LogEventWithChildren;
18+
logEvent: LogEvent;
2319
nextLogEventTime: UtcTimeInMs;
2420
open?: boolean;
2521
}>;
@@ -32,8 +28,9 @@ type Props = Readonly<{
3228
export const Step: JSX.Component<Props> = ({isEnd = false, logEvent, nextLogEventTime, open}) => {
3329
const {children, message, payload, time, type} = logEvent;
3430
const date = new Date(time).toISOString();
31+
const baseRadix = 16;
3532
const isPayloadEmpty = !payload || Object.keys(payload).length === 0;
36-
const popoverId = Math.random().toString(16).slice(2);
33+
const popoverId = Math.random().toString(baseRadix).slice(2);
3734
const status = payload?.logEventStatus ?? LogEventStatus.Passed;
3835

3936
let pathToScreenshotOfPage: string | undefined;
@@ -54,7 +51,7 @@ export const Step: JSX.Component<Props> = ({isEnd = false, logEvent, nextLogEven
5451

5552
if (!isEnd) {
5653
content =
57-
isPayloadEmpty && children.length === 0 ? (
54+
isPayloadEmpty && (children === undefined || children.length === 0) ? (
5855
<div class="step__head">
5956
<span class="step__name">{message}</span>
6057
<span class="step__duration">

0 commit comments

Comments
 (0)