Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 37 additions & 25 deletions src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,31 +758,43 @@ async function handleScreenshot(
const { refs } = await browser.getSnapshot({ interactive: true });

const entries = Object.entries(refs);
const results = await Promise.all(
entries.map(async ([ref, data]): Promise<Annotation | null> => {
try {
const locator = browser.getLocatorFromRef(ref);
if (!locator) return null;
const box = await locator.boundingBox();
if (!box || box.width === 0 || box.height === 0) return null;
const num = parseInt(ref.replace('e', ''), 10);
return {
ref,
number: num,
role: data.role,
name: data.name || undefined,
box: {
x: Math.round(box.x),
y: Math.round(box.y),
width: Math.round(box.width),
height: Math.round(box.height),
},
};
} catch {
return null;
}
})
);

// Process in batches to avoid saturating Chrome with CDP calls (#509)
const BATCH_SIZE = 20;
const ELEMENT_TIMEOUT = 1000;
const results: (Annotation | null)[] = [];
for (let i = 0; i < entries.length; i += BATCH_SIZE) {
const batch = entries.slice(i, i + BATCH_SIZE);
const batchResults = await Promise.all(
batch.map(async ([ref, data]): Promise<Annotation | null> => {
try {
const locator = browser.getLocatorFromRef(ref);
if (!locator) return null;
const box = await Promise.race([
locator.boundingBox(),
new Promise<null>((resolve) => setTimeout(() => resolve(null), ELEMENT_TIMEOUT)),
]);
if (!box || box.width === 0 || box.height === 0) return null;
const num = parseInt(ref.replace('e', ''), 10);
return {
ref,
number: num,
role: data.role,
name: data.name || undefined,
box: {
x: Math.round(box.x),
y: Math.round(box.y),
width: Math.round(box.width),
height: Math.round(box.height),
},
};
} catch {
return null;
}
})
);
results.push(...batchResults);
}

// When a selector is provided the screenshot is cropped to that element,
// so filter to annotations that overlap the target and shift coordinates.
Expand Down