diff --git a/packages/playwright-core/src/client/channelOwner.ts b/packages/playwright-core/src/client/channelOwner.ts index 89f3edced3..a5d753507b 100644 --- a/packages/playwright-core/src/client/channelOwner.ts +++ b/packages/playwright-core/src/client/channelOwner.ts @@ -168,7 +168,7 @@ export abstract class ChannelOwner(func: (apiZone: ApiZone) => Promise, isInternal = false): Promise { + async _wrapApiCall(func: (apiZone: ApiZone) => Promise, isInternal?: boolean): Promise { const logger = this._logger; const apiZone = zones.zoneData('apiZone'); if (apiZone) @@ -178,7 +178,8 @@ export abstract class ChannelOwner implements ap } async group(name: string, options: { location?: { file: string, line?: number, column?: number } } = {}) { - await this._channel.tracingGroup({ name, location: options.location }); + await this._wrapApiCall(async () => { + await this._channel.tracingGroup({ name, location: options.location }); + }, false); } async groupEnd() { - await this._channel.tracingGroupEnd(); + await this._wrapApiCall(async () => { + await this._channel.tracingGroupEnd(); + }, false); } private async _startCollectingStacks(traceName: string) { diff --git a/packages/playwright-core/src/server/trace/recorder/tracing.ts b/packages/playwright-core/src/server/trace/recorder/tracing.ts index 0184c1a2a5..927aa9c646 100644 --- a/packages/playwright-core/src/server/trace/recorder/tracing.ts +++ b/packages/playwright-core/src/server/trace/recorder/tracing.ts @@ -214,8 +214,9 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps startTime: metadata.startTime, apiName: name, class: 'Tracing', - method: 'group', + method: 'tracingGroup', params: { }, + stepId: metadata.stepId, stack: stackFrames, }; if (this._state.groupStack.length) diff --git a/packages/playwright/src/index.ts b/packages/playwright/src/index.ts index add1661502..a7be5ec533 100644 --- a/packages/playwright/src/index.ts +++ b/packages/playwright/src/index.ts @@ -20,7 +20,7 @@ import type { APIRequestContext, BrowserContext, Browser, BrowserContextOptions, import * as playwrightLibrary from 'playwright-core'; import { createGuid, debugMode, addInternalStackPrefix, isString, asLocator, jsonStringifyForceASCII } from 'playwright-core/lib/utils'; import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, VideoMode } from '../types/test'; -import type { TestInfoImpl } from './worker/testInfo'; +import type { TestInfoImpl, TestStepInternal } from './worker/testInfo'; import { rootTestType } from './common/testType'; import type { ContextReuseMode } from './common/config'; import type { ClientInstrumentation, ClientInstrumentationListener } from '../../playwright-core/src/client/clientInstrumentation'; @@ -255,20 +255,28 @@ const playwrightFixtures: Fixtures = ({ const artifactsRecorder = new ArtifactsRecorder(playwright, tracing().artifactsDir(), screenshot); await artifactsRecorder.willStartTest(testInfo as TestInfoImpl); + + let tracingGroupSteps: TestStepInternal[] = []; const csiListener: ClientInstrumentationListener = { onApiCallBegin: (apiName: string, params: Record, frames: StackFrame[], userData: any, out: { stepId?: string }) => { const testInfo = currentTestInfo(); if (!testInfo || apiName.includes('setTestIdAttribute')) return { userObject: null }; + if (apiName === 'tracing.groupEnd') { + tracingGroupSteps.pop(); + return { userObject: null }; + } const step = testInfo._addStep({ location: frames[0] as any, category: 'pw:api', title: renderApiCall(apiName, params), apiName, params, - }); + }, tracingGroupSteps[tracingGroupSteps.length - 1]); userData.userObject = step; out.stepId = step.stepId; + if (apiName === 'tracing.group') + tracingGroupSteps.push(step); }, onApiCallEnd: (userData: any, error?: Error) => { const step = userData.userObject; diff --git a/packages/playwright/src/worker/testInfo.ts b/packages/playwright/src/worker/testInfo.ts index 378b32524f..5041e4f389 100644 --- a/packages/playwright/src/worker/testInfo.ts +++ b/packages/playwright/src/worker/testInfo.ts @@ -237,15 +237,15 @@ export class TestInfoImpl implements TestInfo { } } - _addStep(data: Omit): TestStepInternal { + _addStep(data: Omit, parentStep?: TestStepInternal): TestStepInternal { const stepId = `${data.category}@${++this._lastStepId}`; - let parentStep: TestStepInternal | undefined; if (data.isStage) { // Predefined stages form a fixed hierarchy - use the current one as parent. parentStep = this._findLastStageStep(this._steps); } else { - parentStep = zones.zoneData('stepZone'); + if (!parentStep) + parentStep = zones.zoneData('stepZone'); if (!parentStep) { // If no parent step on stack, assume the current stage as parent. parentStep = this._findLastStageStep(this._steps);