diff --git a/packages/playwright/src/worker/testInfo.ts b/packages/playwright/src/worker/testInfo.ts index 08e7972fac..6577e19d0d 100644 --- a/packages/playwright/src/worker/testInfo.ts +++ b/packages/playwright/src/worker/testInfo.ts @@ -421,8 +421,15 @@ export class TestInfoImpl implements TestInfo { private _attach(attachment: TestInfo['attachments'][0], stepId: string | undefined) { const index = this._attachmentsPush(attachment) - 1; - if (stepId) + if (stepId) { this._stepMap.get(stepId)!.attachmentIndices.push(index); + } else { + // trace viewer has no means of representing attachments outside of a step, so we create an artificial action + const callId = `attach@${++this._lastStepId}`; + this._tracing.appendBeforeActionForStep(callId, this._findLastStageStep(this._steps)?.stepId, `attach "${attachment.name}"`, undefined, []); + this._tracing.appendAfterActionForStep(callId, undefined, [attachment]); + } + this._onAttach({ testId: this.testId, name: attachment.name, diff --git a/tests/playwright-test/ui-mode-trace.spec.ts b/tests/playwright-test/ui-mode-trace.spec.ts index f3f586c57f..855d390aa4 100644 --- a/tests/playwright-test/ui-mode-trace.spec.ts +++ b/tests/playwright-test/ui-mode-trace.spec.ts @@ -426,6 +426,7 @@ test('attachments tab shows all but top-level .push attachments', async ({ runUI - treeitem /step/: - group: - treeitem /attach \\"foo-attach\\"/ + - treeitem /attach \\"bar-push\\"/ - treeitem /attach \\"bar-attach\\"/ `); await page.getByRole('tab', { name: 'Attachments' }).click(); @@ -433,6 +434,7 @@ test('attachments tab shows all but top-level .push attachments', async ({ runUI - tabpanel: - button /foo-push/ - button /foo-attach/ + - button /bar-push/ - button /bar-attach/ `); });