[Bug]: video show.test leaves a stale overlay behind, duplicating caption lines in the recording

Open
#42,796 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
testing-qa

Research direction

Start in packages/playwright/src/index.ts at installScreencastTitleUpdater, then reproduce the issue with the provided playwright.config.ts and a.test.ts. Trace the page-event and test.step overlay updates around page.screencast.showOverlay(...). Done means the recording and live page contain exactly one overlay throughout the step, with no stale caption line.

Written by the indexing model from the issue text.

Description

Version

1.63.0, also reproduces on main (07f1a6154, 1.64.0-next)

Steps to reproduce
// playwright.config.ts
export default defineConfig({
  use: { video: { mode: 'on', show: { test: { level: 'step' } } } },
});
// a.test.ts
test('my test', async ({ page }) => {
  await test.step('first step', async () => {
    const lines = await page.locator('.x-pw-user-overlay').evaluateAll(
        els => els.map(el => el.innerText.split('\n')));
    console.log(lines);
  });
});
Expected behavior

Exactly one annotation overlay, showing the current file / test title / step.

Image
Actual behavior

Two overlays are present in the page at once:

[ ['a.test.ts', 'my test'],                 // stale, from before the step started
  ['a.test.ts', 'my test', 'first step'] ]  // current

Both are anchored to the same edge, so they are offset by exactly one line: the last line
of the stale overlay lands on the step line of the current one. In the recorded video the
previous caption line shows through as a ghost behind the current line — visible wherever
it is longer than the text drawn over it. It appears from the first step and stays for the
whole clip.

Shortening the test title moves the ghost up one line (the file name's tail then shows
behind the shorter line), which confirms it depends on the length of adjacent lines, not
on the step itself. It is in the .webm, not an artifact of how frames are extracted —
it is equally visible during plain playback.

Image
Additional context

Possible cause

installScreencastTitleUpdater in packages/playwright/src/index.ts updates the overlay
from two places: the test.step callbacks and the page event. The page handler is
fire-and-forget (void updateOverlay()), and updateOverlay reads overlays.get(page)
before awaiting page.screencast.showOverlay(...). When a step begins while the
page-event update is still in flight, the second update finds an empty map, removes
nothing and adds a second overlay. The reference to the first one is lost, so it stays in
the page until the context closes.

This makes the bug timing-dependent: an extra round trip before the first test.step
(any page call) is enough to hide it.

Environment
System:
    OS: macOS 26.6.2
    CPU: (10) arm64 Apple M1 Pro
    Memory: 1.62 GB / 32.00 GB
  Binaries:
    Node: 24.7.0 - ~/.nvm/versions/node/v24.7.0/bin/node
    npm: 11.5.1 - ~/.nvm/versions/node/v24.7.0/bin/npm
  Languages:
    Bash: 3.2.57 - /bin/bash
Dominant language
TypeScript
Stars
96.4k
Forks
6.5k
Avg merge
1d 7h
Merged PRs (30d)
170

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/playwright

All issues in microsoft/playwright

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.