Skip to content

Instantly share code, notes, and snippets.

@MarekZeman91
Last active May 21, 2025 20:41
Show Gist options
  • Save MarekZeman91/3d66fb76b215a27fc813ccc4959f46d7 to your computer and use it in GitHub Desktop.
Save MarekZeman91/3d66fb76b215a27fc813ccc4959f46d7 to your computer and use it in GitHub Desktop.
PlaywrightStalker ... for those who like to watch. It is a button/script that always keeps the current test active and visible.
// 1. run Playwright with ui
// 2. paste this code in console
// 3. there is a new PIN button next to Playwright logo
window.PlaywrightStalker?.stop();
window.PlaywrightStalker = ((d = document) => {
const $ = (sel) => d.querySelector(sel);
const $$ = (sel) => Array.from(d.querySelectorAll(sel));
const delay = (ms = 1) => new Promise((r) => setTimeout(r, ms));
const h = (node, props) => Object.assign(d.createElement(node), props);
const refBtn = '.ui-mode-sidebar > .toolbar .toolbar-button';
const playBtn = '.ui-mode-sidebar > .toolbar .toolbar-button.play';
const selected = '.selected';
const tests = '.tests-list-view';
const actions = '.actions-list-view';
const entry = '.list-view-entry';
const loading = '.codicon-loading';
const blank = '.codicon-blank';
const right = '.codicon-chevron-right';
const content = '.list-view-content';
let isActive = false;
let runId = 0;
let $btn = $(refBtn);
const goTo = async (el) => {
el && await el.scrollIntoViewIfNeeded() && (await delay());
el && el.focus() && (await delay());
el && el.click() && (await delay());
};
const stalker = async (id) => {
if (id !== runId) return;
// testing is running and the stalker is active
const isRunning = $(playBtn).disabled;
if (isRunning && isActive) {
$(`${tests} ${entry}:has(${loading}) > ${right}`)?.click();
$(`${tests} ${entry}:has(${loading}):has(${blank}):not(${selected})`)?.click();
$$(`${actions} ${right}`).forEach((x) => x.click());
await goTo($(`${tests} ${entry}:has(${loading}):has(${blank})${selected}`));
const $content = $(`${actions} ${content}`);
$content && ($content.scrollTop = $content.scrollHeight);
}
await delay(10);
return stalker(id);
};
const start = () => {
if (isActive) return;
runId = Math.random();
isActive = true;
$btn.classList.toggle('toggled', isActive);
void stalker(runId);
};
const stop = () => {
if (!isActive) return;
runId = 0;
isActive = false;
$btn.classList.toggle('toggled', isActive);
};
const toggle = () => {
isActive ? stop() : start();
};
if ($btn.classList.contains('stalk')) {
$btn.classList.contains('toggled') && $btn.click();
$btn.onclick = toggle;
} else {
const ref = $btn;
$btn = h('button', {
className: 'toolbar-button stalk',
title: 'Stalk',
onclick: toggle,
});
$btn.append(h('span', { className: 'codicon codicon-pinned' }));
ref.before($btn);
}
return { isActive: () => isActive, start, stop };
})();
// to check if it is active to use
// PlaywrightStalker.isActive();
// to stop, click the button or use
// PlaywrightStalker.stop();
// to start, click the button or use
// PlaywrightStalker.start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment