feat: add 'get styles' command for computed styles extraction (#142)

This commit is contained in:
Danila Poyarkov
2026-01-17 18:56:52 -06:00
committed by GitHub
parent b19ca760aa
commit e6e832d2bc
5 changed files with 145 additions and 3 deletions
+63
View File
@@ -50,6 +50,7 @@ import type {
IsCheckedCommand,
CountCommand,
BoundingBoxCommand,
StylesCommand,
TraceStartCommand,
TraceStopCommand,
HarStopCommand,
@@ -117,6 +118,7 @@ import type {
RecordingStopData,
RecordingRestartData,
InputEventData,
StylesData,
} from './types.js';
import { successResponse, errorResponse } from './protocol.js';
@@ -318,6 +320,8 @@ export async function executeCommand(command: Command, browser: BrowserManager):
return await handleCount(command, browser);
case 'boundingbox':
return await handleBoundingBox(command, browser);
case 'styles':
return await handleStyles(command, browser);
case 'video_start':
return await handleVideoStart(command, browser);
case 'video_stop':
@@ -1246,6 +1250,65 @@ async function handleBoundingBox(
return successResponse(command.id, { box });
}
async function handleStyles(
command: StylesCommand,
browser: BrowserManager
): Promise<Response<StylesData>> {
const page = browser.getPage();
// Shared extraction logic as a string to be eval'd in browser context
const extractStylesScript = `(function(el) {
const s = getComputedStyle(el);
const r = el.getBoundingClientRect();
return {
tag: el.tagName.toLowerCase(),
text: el.innerText?.trim().slice(0, 80) || null,
box: {
x: Math.round(r.x),
y: Math.round(r.y),
width: Math.round(r.width),
height: Math.round(r.height),
},
styles: {
fontSize: s.fontSize,
fontWeight: s.fontWeight,
fontFamily: s.fontFamily.split(',')[0].trim().replace(/"/g, ''),
color: s.color,
backgroundColor: s.backgroundColor,
borderRadius: s.borderRadius,
border: s.border !== 'none' && s.borderWidth !== '0px' ? s.border : null,
boxShadow: s.boxShadow !== 'none' ? s.boxShadow : null,
padding: s.padding,
},
};
})`;
// Check if it's a ref - single element
if (browser.isRef(command.selector)) {
const locator = browser.getLocator(command.selector);
const element = (await locator.evaluate(
(el, script) => {
const fn = eval(script);
return fn(el);
},
extractStylesScript
)) as StylesData['elements'][0];
return successResponse(command.id, { elements: [element] });
}
// CSS selector - can match multiple elements
const elements = (await page.$$eval(
command.selector,
(els, script) => {
const fn = eval(script);
return els.map((el) => fn(el));
},
extractStylesScript
)) as StylesData['elements'];
return successResponse(command.id, { elements });
}
// Advanced handlers
async function handleVideoStart(