feat: add cursor-interactive element detection in snapshots (#374)
* fix: only warn about ignored flags when explicitly passed via CLI The warning about launch-time options being ignored (when daemon is already running) was incorrectly shown when options were set via environment variables like AGENT_BROWSER_EXECUTABLE_PATH, even when no CLI flag was passed. Now the warning only appears when flags are explicitly passed on the command line, not when values come solely from environment variables. Fixes #372 * feat: add cursor-interactive element detection in snapshots Add -C/--cursor flag to snapshot command that detects clickable elements that don't have proper ARIA roles but are interactive based on: - cursor: pointer CSS style - onclick attribute/handler - tabindex attribute This helps with modern web apps that use custom divs/spans as buttons. Fixes #366 * fix: add cursor option to getSnapshot type signature
This commit is contained in:
@@ -304,6 +304,86 @@ describe('BrowserManager', () => {
|
||||
// Compact should be equal or shorter
|
||||
expect(compactSnapshot.length).toBeLessThanOrEqual(fullSnapshot.length);
|
||||
});
|
||||
|
||||
it('should not capture cursor-interactive elements without cursor flag', async () => {
|
||||
const page = browser.getPage();
|
||||
await page.setContent(`
|
||||
<html>
|
||||
<body>
|
||||
<button id="standard-btn">Standard Button</button>
|
||||
<div id="clickable-div" style="cursor: pointer;" onclick="void(0)">Clickable Div</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
const { tree, refs } = await browser.getSnapshot({ interactive: true });
|
||||
|
||||
// Standard button should be captured via ARIA
|
||||
expect(tree).toContain('button "Standard Button"');
|
||||
|
||||
// Cursor-interactive elements should NOT be captured without cursor flag
|
||||
expect(tree).not.toContain('Cursor-interactive elements');
|
||||
expect(tree).not.toContain('clickable "Clickable Div"');
|
||||
|
||||
// Should only have refs for ARIA interactive elements
|
||||
const refValues = Object.values(refs);
|
||||
expect(refValues.some((r) => r.role === 'button')).toBe(true);
|
||||
expect(refValues.some((r) => r.role === 'clickable')).toBe(false);
|
||||
});
|
||||
|
||||
it('should capture cursor-interactive elements with cursor flag', async () => {
|
||||
const page = browser.getPage();
|
||||
await page.setContent(`
|
||||
<html>
|
||||
<body>
|
||||
<button id="standard-btn">Standard Button</button>
|
||||
<div id="clickable-div" style="cursor: pointer;" onclick="void(0)">Clickable Div</div>
|
||||
<span onclick="void(0)">Onclick Span</span>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
const { tree, refs } = await browser.getSnapshot({ interactive: true, cursor: true });
|
||||
|
||||
// Standard button should be captured via ARIA
|
||||
expect(tree).toContain('button "Standard Button"');
|
||||
|
||||
// Cursor-interactive elements should be captured with cursor flag
|
||||
expect(tree).toContain('Cursor-interactive elements');
|
||||
expect(tree).toContain('clickable "Clickable Div"');
|
||||
expect(tree).toContain('clickable "Onclick Span"');
|
||||
|
||||
// Should have refs for all interactive elements
|
||||
const refValues = Object.values(refs);
|
||||
expect(refValues.some((r) => r.role === 'button')).toBe(true);
|
||||
expect(refValues.some((r) => r.role === 'clickable')).toBe(true);
|
||||
});
|
||||
|
||||
it('should click cursor-interactive elements via refs', async () => {
|
||||
const page = browser.getPage();
|
||||
await page.setContent(`
|
||||
<html>
|
||||
<body>
|
||||
<div id="clickable" style="cursor: pointer;" onclick="document.getElementById('result').textContent = 'clicked'">Click Me</div>
|
||||
<div id="result">not clicked</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
const { refs } = await browser.getSnapshot({ cursor: true });
|
||||
|
||||
// Find the ref for the clickable element
|
||||
const clickableRef = Object.keys(refs).find((k) => refs[k].name === 'Click Me');
|
||||
expect(clickableRef).toBeDefined();
|
||||
|
||||
// Click using the ref
|
||||
const locator = browser.getLocator(`@${clickableRef}`);
|
||||
await locator.click();
|
||||
|
||||
// Verify click worked
|
||||
const result = await page.locator('#result').textContent();
|
||||
expect(result).toBe('clicked');
|
||||
});
|
||||
});
|
||||
|
||||
describe('locator resolution', () => {
|
||||
|
||||
Reference in New Issue
Block a user