← Back to microsoft/playwright
microsoft / playwright · Issue No. 42796
1.63.0, also reproduces on main (07f1a6154, 1.64.0-next)
// 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);
});
});
Exactly one annotation overlay, showing the current file / test title / step.
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.
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.
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
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.