diff --git a/packages/trace-viewer/src/ui/modelUtil.ts b/packages/trace-viewer/src/ui/modelUtil.ts index 9b494842960dc..309b210eabbd9 100644 --- a/packages/trace-viewer/src/ui/modelUtil.ts +++ b/packages/trace-viewer/src/ui/modelUtil.ts @@ -183,8 +183,8 @@ function mergeActionsAndUpdateTiming(contexts: ContextEntry[]) { if (traceFileToContexts.size > 1) makeCallIdsUniqueAcrossTraceFiles(contexts, ++traceFileId); // Align action times across runner and library contexts within each trace file. - const map = mergeActionsAndUpdateTimingSameTrace(contexts); - result.push(...map.values()); + const actions = mergeActionsAndUpdateTimingSameTrace(contexts); + result.push(...actions); } result.sort((a1, a2) => { if (a2.parentId === a1.callId) @@ -211,19 +211,26 @@ function makeCallIdsUniqueAcrossTraceFiles(contexts: ContextEntry[], traceFileId } } -function mergeActionsAndUpdateTimingSameTrace(contexts: ContextEntry[]) { +function mergeActionsAndUpdateTimingSameTrace(contexts: ContextEntry[]): ActionTraceEventInContext[] { const map = new Map(); const libraryContexts = contexts.filter(context => context.origin === 'library'); const testRunnerContexts = contexts.filter(context => context.origin === 'testRunner'); + // With library-only or test-runner-only traces there is nothing to match. + if (!testRunnerContexts.length || !libraryContexts.length) { + return contexts.map(context => { + return context.actions.map(action => ({ ...action, context })); + }).flat(); + } + // Library actions are replaced with corresponding test runner steps. Matching with // the test runner steps enables us to find parent steps. // - In the newer versions the actions are matched by explicit step id stored in the // library context actions. // - In the older versions the step id is not stored and the match is perfomed based on // action name and wallTime. - const matchByStepId = !libraryContexts.length || libraryContexts.some(c => c.actions.some(a => !!a.stepId)); + const matchByStepId = libraryContexts.some(c => c.actions.some(a => !!a.stepId)); for (const context of libraryContexts) { for (const action of context.actions) { @@ -264,7 +271,7 @@ function mergeActionsAndUpdateTimingSameTrace(contexts: ContextEntry[]) { map.set(key, { ...action, context }); } } - return map; + return [...map.values()]; } function adjustMonotonicTime(contexts: ContextEntry[], monotonicTimeDelta: number) { diff --git a/tests/assets/trace-library-1.46.zip b/tests/assets/trace-library-1.46.zip new file mode 100644 index 0000000000000..46d7d99bb49db Binary files /dev/null and b/tests/assets/trace-library-1.46.zip differ diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index a18526b09e5e2..01e68269ec9c2 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -1282,6 +1282,17 @@ test('should open snapshot in new browser context', async ({ browser, page, runA await newPage.close(); }); +test('should show similar actions from library-only trace', async ({ showTraceViewer, asset }) => { + const traceViewer = await showTraceViewer([asset('trace-library-1.46.zip')]); + await expect(traceViewer.actionTitles).toHaveText([ + /page.setContent/, + /locator.getAttributelocator\('div'\)/, + /locator.isVisiblelocator\('div'\)/, + /locator.getAttributelocator\('div'\)/, + /locator.isVisiblelocator\('div'\)/, + ]); +}); + function parseMillis(s: string): number { const matchMs = s.match(/(\d+)ms/); if (matchMs)