diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ca79ec..18390ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ All notable changes to the full browser extension will be documented in this fil The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## Unreleased + +### Fixed +- Ignore events on non-visible elements, which will fail on replay. + ## 0.1.7 - 2025-11-28 ### Added diff --git a/CHANGELOG.rec.md b/CHANGELOG.rec.md index 67b2c83..a342600 100644 --- a/CHANGELOG.rec.md +++ b/CHANGELOG.rec.md @@ -3,6 +3,11 @@ All notable changes to the recorder browser extension will be documented in this The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## Unreleased + +### Fixed +- Ignore events on non-visible elements, which will fail on replay. + ## 0.1.7 - 2025-11-28 ### Added diff --git a/source/ContentScript/recorder.ts b/source/ContentScript/recorder.ts index ff6173d..e6298b4 100644 --- a/source/ContentScript/recorder.ts +++ b/source/ContentScript/recorder.ts @@ -396,10 +396,37 @@ class Recorder { }); } + isVisible(el: HTMLElement): boolean { + const style = window.getComputedStyle(el); + + if ( + style.display === 'none' || + style.visibility === 'hidden' || + style.opacity === '0' + ) { + return false; + } + + // Check layout dimensions + if (el.offsetWidth <= 0 && el.offsetHeight <= 0) { + return false; + } + + const rect = el.getBoundingClientRect(); + + // Check rendered size + if (rect.width === 0 || rect.height === 0) { + return false; + } + + // The element is rendered and visible in layout (may still be off-screen) + return true; + } + shouldRecord(element: HTMLElement): boolean { if (!this.active) return this.active; if (element.className === ZAP_FLOATING_DIV_ELEMENTS) return false; - return true; + return this.isVisible(element); } getBrowserName(): string { diff --git a/test/ContentScript/integrationTests.test.ts b/test/ContentScript/integrationTests.test.ts index 433214e..8cade97 100644 --- a/test/ContentScript/integrationTests.test.ts +++ b/test/ContentScript/integrationTests.test.ts @@ -673,6 +673,29 @@ function integrationTests( ]); }); + test('Should not record interactions on hidden element', async () => { + // Given / When + await driver.toggleRecording(); + const wd = await driver.getWebDriver(); + await wd.get(`http://localhost:${_HTTPPORT}/webpages/hiddenElement.html`); + await eventsProcessed(); + await wd.findElement(By.id('visibleButton')).click(); + await eventsProcessed(); + // Then + expect(actualData).toEqual([ + reportZestStatementComment(), + reportZestStatementLaunch( + 'http://localhost:1801/webpages/hiddenElement.html' + ), + reportZestStatementScrollTo(3, 'visibleButton'), + reportZestStatementClick(4, 'visibleButton'), + reportZestStatementScrollTo(5, 'visibleCheckBox'), + reportZestStatementClick(6, 'visibleCheckBox'), + reportZestStatementScrollTo(7, 'visibleCheckBox'), + reportZestStatementSendKeys(8, 'visibleCheckBox', 'on', 'id'), + ]); + }); + test('Should record set localStorage', async () => { // Given await enableZapEvents(server, driver); diff --git a/test/ContentScript/webpages/hiddenElement.html b/test/ContentScript/webpages/hiddenElement.html new file mode 100644 index 0000000..e24c4cf --- /dev/null +++ b/test/ContentScript/webpages/hiddenElement.html @@ -0,0 +1,29 @@ + + +
+ +