@wdio/image-comparison-core 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/base.interfaces.d.ts +7 -0
  3. package/dist/base.interfaces.d.ts.map +1 -1
  4. package/dist/clientSideScripts/injectWebviewOverlay.test.js +29 -0
  5. package/dist/clientSideScripts/scrollElementIntoView.d.ts.map +1 -1
  6. package/dist/clientSideScripts/scrollElementIntoView.js +4 -1
  7. package/dist/clientSideScripts/scrollElementIntoView.test.js +4 -2
  8. package/dist/commands/check.interfaces.d.ts +1 -1
  9. package/dist/commands/check.interfaces.d.ts.map +1 -1
  10. package/dist/commands/checkFullPageScreen.d.ts.map +1 -1
  11. package/dist/commands/checkFullPageScreen.js +7 -2
  12. package/dist/commands/checkWebElement.d.ts.map +1 -1
  13. package/dist/commands/checkWebElement.js +7 -2
  14. package/dist/commands/checkWebScreen.d.ts.map +1 -1
  15. package/dist/commands/checkWebScreen.js +10 -3
  16. package/dist/commands/checkWebScreen.test.js +43 -0
  17. package/dist/commands/fullPage.interfaces.d.ts +6 -0
  18. package/dist/commands/fullPage.interfaces.d.ts.map +1 -1
  19. package/dist/commands/save.interfaces.d.ts +3 -1
  20. package/dist/commands/save.interfaces.d.ts.map +1 -1
  21. package/dist/commands/saveElement.d.ts +1 -1
  22. package/dist/commands/saveElement.d.ts.map +1 -1
  23. package/dist/commands/saveElement.js +2 -2
  24. package/dist/commands/saveFullPageScreen.d.ts.map +1 -1
  25. package/dist/commands/saveFullPageScreen.js +23 -3
  26. package/dist/commands/saveWebElement.d.ts +1 -1
  27. package/dist/commands/saveWebElement.d.ts.map +1 -1
  28. package/dist/commands/saveWebElement.js +24 -2
  29. package/dist/commands/saveWebScreen.d.ts +1 -1
  30. package/dist/commands/saveWebScreen.d.ts.map +1 -1
  31. package/dist/commands/saveWebScreen.js +23 -3
  32. package/dist/helpers/afterScreenshot.interfaces.d.ts +2 -0
  33. package/dist/helpers/afterScreenshot.interfaces.d.ts.map +1 -1
  34. package/dist/helpers/options.d.ts.map +1 -1
  35. package/dist/helpers/options.interfaces.d.ts +10 -0
  36. package/dist/helpers/options.interfaces.d.ts.map +1 -1
  37. package/dist/helpers/options.js +1 -0
  38. package/dist/helpers/utils.d.ts +6 -0
  39. package/dist/helpers/utils.d.ts.map +1 -1
  40. package/dist/helpers/utils.interfaces.d.ts +3 -0
  41. package/dist/helpers/utils.interfaces.d.ts.map +1 -1
  42. package/dist/helpers/utils.js +95 -29
  43. package/dist/helpers/utils.test.js +121 -1
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/methods/images.d.ts.map +1 -1
  47. package/dist/methods/images.interfaces.d.ts +4 -0
  48. package/dist/methods/images.interfaces.d.ts.map +1 -1
  49. package/dist/methods/images.js +4 -2
  50. package/dist/methods/rectangles.d.ts +33 -2
  51. package/dist/methods/rectangles.d.ts.map +1 -1
  52. package/dist/methods/rectangles.interfaces.d.ts +58 -0
  53. package/dist/methods/rectangles.interfaces.d.ts.map +1 -1
  54. package/dist/methods/rectangles.js +289 -15
  55. package/dist/methods/rectangles.test.js +558 -2
  56. package/dist/methods/takeElementScreenshots.js +19 -16
  57. package/dist/methods/takeElementScreenshots.test.js +22 -22
  58. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @wdio/image-comparison-core
2
2
 
3
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 994f4da: ## #857 Support ignore regions for web screenshots
8
+
9
+ Add `ignore` support to all web screenshot methods (`saveScreen`/`checkScreen`, `saveElement`/`checkElement`, `saveFullPageScreen`/`checkFullPageScreen`) so that specified elements can be blocked out during visual comparison. This brings web parity with the native-app ignore-region support that already existed.
10
+
11
+ ### Changes
12
+
13
+ - **Ignore regions for full-page screenshots:** new `determineWebFullPageIgnoreRegions` function that calculates ignore-region rectangles for full-page screenshots, including a `fullPageCropTopPaddingCSS` correction for mobile scroll-and-stitch scenarios where the address-bar shadow padding shifts element positions
14
+ - **Consolidated `ignoreRegionPadding`:** moved `ignoreRegionPadding` into `BaseWebScreenshotOptions` so it is inherited by all web methods instead of being duplicated per method
15
+ - **Fix `isAndroidNativeWebScreenshot` type:** ensure `nativeWebScreenshot` is always a boolean (was accidentally an object for LambdaTest capabilities), preventing ignore-region DPR scaling failures
16
+ - **Fix viewport rounding for mobile:** restore `Math.round()` in `injectWebviewOverlay` and remove `Math.min` clamping in `getMobileViewPortPosition` to prevent 1-pixel crop shifts during full-page stitching
17
+ - **Fix `scrollElementIntoView` for scrolled pages:** account for `currentPosition` (existing scroll offset) when computing the target scroll position, so elements are scrolled into view correctly when the page is already scrolled
18
+ - **Dismiss Chrome Start Surface on Android:** when Chrome's tab-overview UI blocks the webview overlay, automatically press the Android Back button (up to 4 retries) to restore the active tab before measuring the viewport
19
+ - **Add hybrid status bar blockout:** on hybrid apps the statusbar was not blocked out which could result in flaky tests regarding battery and reception
20
+
21
+ # Committers: 1
22
+
23
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
24
+
3
25
  ## 1.1.4
4
26
 
5
27
  ### Patch Changes
@@ -48,6 +48,13 @@ export interface BaseWebScreenshotOptions {
48
48
  * @default true
49
49
  */
50
50
  hideScrollBars?: boolean;
51
+ /**
52
+ * Padding in device pixels added to each side of ignore regions (makes each region 2× this value wider and higher).
53
+ * Helps avoid 1px boundary differences on high-DPR / BiDi. Set to 0 to disable.
54
+ * Applies to screen, element, and full-page web methods.
55
+ * @default 1
56
+ */
57
+ ignoreRegionPadding?: number;
51
58
  /**
52
59
  * Elements to hide before taking screenshot
53
60
  * @default []
@@ -1 +1 @@
1
- {"version":3,"file":"base.interfaces.d.ts","sourceRoot":"","sources":["../src/base.interfaces.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.interfaces.d.ts","sourceRoot":"","sources":["../src/base.interfaces.ts"],"names":[],"mappings":"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"}
@@ -54,6 +54,35 @@ describe('injectWebviewOverlay', () => {
54
54
  height: 1600,
55
55
  });
56
56
  });
57
+ it('should round values to integers with non-integer DPR (Android)', () => {
58
+ Object.defineProperty(window, 'devicePixelRatio', {
59
+ value: 2.625,
60
+ configurable: true,
61
+ });
62
+ Object.defineProperty(window, 'innerWidth', {
63
+ value: 412,
64
+ configurable: true,
65
+ });
66
+ Object.defineProperty(document.documentElement, 'clientHeight', {
67
+ value: 363,
68
+ configurable: true,
69
+ });
70
+ injectWebviewOverlay(true);
71
+ const overlay = document.querySelector('[data-test="ics-overlay"]');
72
+ const event = new window.MouseEvent('click', {
73
+ clientX: 206,
74
+ clientY: 181,
75
+ bubbles: true,
76
+ });
77
+ overlay.dispatchEvent(event);
78
+ const parsedData = JSON.parse(overlay.dataset.icsWebviewData);
79
+ expect(parsedData).toEqual({
80
+ x: Math.round(206 * 2.625),
81
+ y: Math.round(181 * 2.625),
82
+ width: Math.round(412 * 2.625),
83
+ height: Math.round(363 * 2.625),
84
+ });
85
+ });
57
86
  it('should use DPR = 1 for iOS (isAndroid = false)', () => {
58
87
  injectWebviewOverlay(false);
59
88
  const overlay = document.querySelector('[data-test="ics-overlay"]');
@@ -1 +1 @@
1
- {"version":3,"file":"scrollElementIntoView.d.ts","sourceRoot":"","sources":["../../src/clientSideScripts/scrollElementIntoView.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,GAAG,MAAM,CA+B3G"}
1
+ {"version":3,"file":"scrollElementIntoView.d.ts","sourceRoot":"","sources":["../../src/clientSideScripts/scrollElementIntoView.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,GAAG,MAAM,CAkC3G"}
@@ -17,7 +17,10 @@ export default function scrollElementIntoView(element, addressBarShadowPadding)
17
17
  currentPosition = bodyNode.scrollTop;
18
18
  }
19
19
  const { top } = element.getBoundingClientRect();
20
- const yPosition = top - addressBarShadowPadding;
20
+ // BCR.top is viewport-relative, so the element's document position is
21
+ // currentPosition + top. Scroll there (minus padding) to place the
22
+ // element at the viewport top.
23
+ const yPosition = currentPosition + top - addressBarShadowPadding;
21
24
  // Scroll to the position
22
25
  if (htmlNode.scrollHeight > htmlNode.clientHeight) {
23
26
  htmlNode.scrollTop = yPosition;
@@ -56,7 +56,8 @@ describe('scrollElementIntoView', () => {
56
56
  const addressBarShadowPadding = 10;
57
57
  const result = scrollElementIntoView(mockElement, addressBarShadowPadding);
58
58
  expect(result).toBe(50);
59
- expect(mockHtmlNode.scrollTop).toBe(90);
59
+ // currentPosition (50) + BCR.top (100) - padding (10) = 140
60
+ expect(mockHtmlNode.scrollTop).toBe(140);
60
61
  });
61
62
  it('should return current scroll position when body node has scroll', () => {
62
63
  mockHtmlNode.scrollTop = 0;
@@ -65,7 +66,8 @@ describe('scrollElementIntoView', () => {
65
66
  const addressBarShadowPadding = 10;
66
67
  const result = scrollElementIntoView(mockElement, addressBarShadowPadding);
67
68
  expect(result).toBe(50);
68
- expect(mockBodyNode.scrollTop).toBe(90);
69
+ // currentPosition (50) + BCR.top (100) - padding (10) = 140
70
+ expect(mockBodyNode.scrollTop).toBe(140);
69
71
  });
70
72
  it('should not scroll when neither html nor body is scrollable', () => {
71
73
  Object.defineProperty(mockHtmlNode, 'scrollHeight', { value: 500 });
@@ -14,7 +14,7 @@ export interface CheckMethodOptions extends BaseImageCompareOptions, BaseMobileB
14
14
  /**
15
15
  * Ignore elements and or areas
16
16
  */
17
- ignore?: ElementIgnore[];
17
+ ignore?: (ElementIgnore | ElementIgnore[])[];
18
18
  }
19
19
  export interface InternalCheckMethodOptions extends InternalSaveMethodOptions {
20
20
  testContext: TestContext;
@@ -1 +1 @@
1
- {"version":3,"file":"check.interfaces.d.ts","sourceRoot":"","sources":["../../src/commands/check.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAC7F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,KAAK,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAC/F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB,EAAE,yBAAyB;IAC1F;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B;;OAEG;IACH,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA2B,SAAQ,yBAAyB;IACzE,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED,MAAM,WAAW,gCAAiC,SAAQ,0BAA0B;IAChF,kBAAkB,EAAE,kBAAkB,CAAC;CAC1C;AAED,MAAM,WAAW,iCAAkC,SAAQ,0BAA0B;IACjF,OAAO,EAAE,UAAU,GAAG,WAAW,CAAC;IAClC,mBAAmB,EAAE,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAmC,SAAQ,0BAA0B;IAClF,oBAAoB,EAAE,oBAAoB,CAAC;CAC9C;AAED,MAAM,WAAW,sCAAuC,SAAQ,0BAA0B;IACtF,oBAAoB,EAAE,oBAAoB,CAAC;CAC9C"}
1
+ {"version":3,"file":"check.interfaces.d.ts","sourceRoot":"","sources":["../../src/commands/check.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAC7F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,KAAK,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAC/F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB,EAAE,yBAAyB;IAC1F;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,CAAC;CAChD;AAED,MAAM,WAAW,0BAA2B,SAAQ,yBAAyB;IACzE,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED,MAAM,WAAW,gCAAiC,SAAQ,0BAA0B;IAChF,kBAAkB,EAAE,kBAAkB,CAAC;CAC1C;AAED,MAAM,WAAW,iCAAkC,SAAQ,0BAA0B;IACjF,OAAO,EAAE,UAAU,GAAG,WAAW,CAAC;IAClC,mBAAmB,EAAE,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAmC,SAAQ,0BAA0B;IAClF,oBAAoB,EAAE,oBAAoB,CAAC;CAC9C;AAED,MAAM,WAAW,sCAAuC,SAAQ,0BAA0B;IACtF,oBAAoB,EAAE,oBAAoB,CAAC;CAC9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"checkFullPageScreen.d.ts","sourceRoot":"","sources":["../../src/commands/checkFullPageScreen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAIzE,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,uBAAuB,CAAA;AAE/E;;GAEG;AACH,wBAA8B,mBAAmB,CAC7C,EACI,eAAe,EACf,oBAAoB,EACpB,OAAO,EACP,YAAY,EACZ,eAAuB,EACvB,GAAG,EACH,WAAW,GACd,EAAE,kCAAkC,GACtC,OAAO,CAAC,kBAAkB,GAAG,MAAM,CAAC,CAgEtC"}
1
+ {"version":3,"file":"checkFullPageScreen.d.ts","sourceRoot":"","sources":["../../src/commands/checkFullPageScreen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAIzE,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,uBAAuB,CAAA;AAE/E;;GAEG;AACH,wBAA8B,mBAAmB,CAC7C,EACI,eAAe,EACf,oBAAoB,EACpB,OAAO,EACP,YAAY,EACZ,eAAuB,EACvB,GAAG,EACH,WAAW,GACd,EAAE,kCAAkC,GACtC,OAAO,CAAC,kBAAkB,GAAG,MAAM,CAAC,CAsEtC"}
@@ -8,7 +8,7 @@ import { extractCommonCheckVariables, buildBaseExecuteCompareOptions } from '../
8
8
  export default async function checkFullPageScreen({ browserInstance, checkFullPageOptions, folders, instanceData, isNativeContext = false, tag, testContext, }) {
9
9
  // 1. Extract common variables
10
10
  const commonCheckVariables = extractCommonCheckVariables({ folders, instanceData, wicOptions: checkFullPageOptions.wic });
11
- const { disableBlinkingCursor, disableCSSAnimation, enableLayoutTesting, enableLegacyScreenshotMethod, fullPageScrollTimeout, hideAfterFirstScroll = [], hideScrollBars, hideElements = [], removeElements = [], waitForFontsLoaded, } = checkFullPageOptions.method;
11
+ const { disableBlinkingCursor, disableCSSAnimation, enableLayoutTesting, enableLegacyScreenshotMethod, fullPageScrollTimeout, hideAfterFirstScroll = [], hideScrollBars, hideElements = [], ignoreRegionPadding, removeElements = [], waitForFontsLoaded, } = checkFullPageOptions.method;
12
12
  // 2. Check if the method is supported in native context
13
13
  if (isNativeContext) {
14
14
  throw new Error('The method checkFullPageScreen is not supported in native context for native mobile apps!');
@@ -25,11 +25,13 @@ export default async function checkFullPageScreen({ browserInstance, checkFullPa
25
25
  hideAfterFirstScroll,
26
26
  hideScrollBars,
27
27
  hideElements,
28
+ ignore: checkFullPageOptions.method.ignore,
29
+ ignoreRegionPadding,
28
30
  removeElements,
29
31
  waitForFontsLoaded,
30
32
  },
31
33
  };
32
- const { devicePixelRatio, fileName, base64Image } = await saveFullPageScreen({
34
+ const { devicePixelRatio, fileName, base64Image, ignoreRegions } = await saveFullPageScreen({
33
35
  browserInstance,
34
36
  folders,
35
37
  instanceData,
@@ -45,6 +47,9 @@ export default async function checkFullPageScreen({ browserInstance, checkFullPa
45
47
  methodCompareOptions: compareOptions,
46
48
  devicePixelRatio,
47
49
  fileName,
50
+ additionalProperties: {
51
+ ignoreRegions: ignoreRegions || [],
52
+ },
48
53
  });
49
54
  // 5. Now execute the compare and return the data
50
55
  return executeImageCompare({
@@ -1 +1 @@
1
- {"version":3,"file":"checkWebElement.d.ts","sourceRoot":"","sources":["../../src/commands/checkWebElement.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAIzE,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,uBAAuB,CAAA;AAE9E;;GAEG;AACH,wBAA8B,eAAe,CACzC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,OAAO,EACP,GAAG,EACH,mBAAmB,EACnB,WAAW,EACX,eAAuB,GAC1B,EAAE,iCAAiC,GACrC,OAAO,CAAC,kBAAkB,GAAG,MAAM,CAAC,CA0DtC"}
1
+ {"version":3,"file":"checkWebElement.d.ts","sourceRoot":"","sources":["../../src/commands/checkWebElement.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAIzE,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,uBAAuB,CAAA;AAE9E;;GAEG;AACH,wBAA8B,eAAe,CACzC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,OAAO,EACP,GAAG,EACH,mBAAmB,EACnB,WAAW,EACX,eAAuB,GAC1B,EAAE,iCAAiC,GACrC,OAAO,CAAC,kBAAkB,GAAG,MAAM,CAAC,CAgEtC"}
@@ -8,7 +8,7 @@ import { extractCommonCheckVariables, buildBaseExecuteCompareOptions } from '../
8
8
  export default async function checkWebElement({ browserInstance, instanceData, folders, element, tag, checkElementOptions, testContext, isNativeContext = false, }) {
9
9
  // 1. Extract common variables
10
10
  const commonCheckVariables = extractCommonCheckVariables({ folders, instanceData, wicOptions: checkElementOptions.wic });
11
- const { disableBlinkingCursor, disableCSSAnimation, enableLayoutTesting, enableLegacyScreenshotMethod, hideScrollBars, resizeDimensions, hideElements = [], removeElements = [], waitForFontsLoaded = false, } = checkElementOptions.method;
11
+ const { disableBlinkingCursor, disableCSSAnimation, enableLayoutTesting, enableLegacyScreenshotMethod, hideScrollBars, resizeDimensions, ignoreRegionPadding, hideElements = [], removeElements = [], waitForFontsLoaded = false, } = checkElementOptions.method;
12
12
  // 2. Take the actual element screenshot and retrieve the needed data
13
13
  const saveElementOptions = {
14
14
  wic: checkElementOptions.wic,
@@ -19,17 +19,19 @@ export default async function checkWebElement({ browserInstance, instanceData, f
19
19
  enableLegacyScreenshotMethod,
20
20
  hideScrollBars,
21
21
  resizeDimensions,
22
+ ignoreRegionPadding,
22
23
  hideElements,
23
24
  removeElements,
24
25
  waitForFontsLoaded,
25
26
  },
26
27
  };
27
- const { devicePixelRatio, fileName, base64Image } = await saveWebElement({
28
+ const { devicePixelRatio, fileName, base64Image, ignoreRegions } = await saveWebElement({
28
29
  browserInstance,
29
30
  instanceData,
30
31
  folders,
31
32
  element,
32
33
  tag,
34
+ ignore: checkElementOptions.method.ignore,
33
35
  saveElementOptions,
34
36
  });
35
37
  // 3. Determine the options
@@ -41,6 +43,9 @@ export default async function checkWebElement({ browserInstance, instanceData, f
41
43
  devicePixelRatio,
42
44
  fileName,
43
45
  isElementScreenshot: true,
46
+ additionalProperties: {
47
+ ignoreRegions: ignoreRegions || [],
48
+ },
44
49
  });
45
50
  // 4. Now execute the compare and return the data
46
51
  return executeImageCompare({
@@ -1 +1 @@
1
- {"version":3,"file":"checkWebScreen.d.ts","sourceRoot":"","sources":["../../src/commands/checkWebScreen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAIzE,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAA;AAE7E;;GAEG;AACH,wBAA8B,cAAc,CACxC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,GAAG,EACH,kBAAkB,EAClB,eAAuB,EACvB,WAAW,GACd,EAAE,gCAAgC,GACpC,OAAO,CAAC,kBAAkB,GAAG,MAAM,CAAC,CAuDtC"}
1
+ {"version":3,"file":"checkWebScreen.d.ts","sourceRoot":"","sources":["../../src/commands/checkWebScreen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAIzE,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAA;AAE7E;;GAEG;AACH,wBAA8B,cAAc,CACxC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,GAAG,EACH,kBAAkB,EAClB,eAAuB,EACvB,WAAW,GACd,EAAE,gCAAgC,GACpC,OAAO,CAAC,kBAAkB,GAAG,MAAM,CAAC,CA+DtC"}
@@ -8,8 +8,10 @@ import { extractCommonCheckVariables, buildBaseExecuteCompareOptions } from '../
8
8
  export default async function checkWebScreen({ browserInstance, instanceData, folders, tag, checkScreenOptions, isNativeContext = false, testContext, }) {
9
9
  // 1. Extract common variables
10
10
  const commonCheckVariables = extractCommonCheckVariables({ folders, instanceData, wicOptions: checkScreenOptions.wic });
11
- const { disableBlinkingCursor, disableCSSAnimation, enableLayoutTesting, enableLegacyScreenshotMethod, hideScrollBars, hideElements = [], removeElements = [], waitForFontsLoaded, } = checkScreenOptions.method;
12
- // 2. Take the actual screenshot and retrieve the needed data
11
+ const { disableBlinkingCursor, disableCSSAnimation, enableLayoutTesting, enableLegacyScreenshotMethod, hideScrollBars, ignoreRegionPadding, hideElements = [], removeElements = [], waitForFontsLoaded, } = checkScreenOptions.method;
12
+ // 2. Take the actual screenshot and resolve ignore regions in one go.
13
+ // Ignore regions are resolved while the DOM is still in screenshot state
14
+ // (scrollbar hidden, elements hidden/removed) so positions match the image.
13
15
  const saveScreenOptions = {
14
16
  wic: checkScreenOptions.wic,
15
17
  method: {
@@ -18,16 +20,18 @@ export default async function checkWebScreen({ browserInstance, instanceData, fo
18
20
  enableLayoutTesting,
19
21
  enableLegacyScreenshotMethod,
20
22
  hideScrollBars,
23
+ ignoreRegionPadding,
21
24
  hideElements,
22
25
  removeElements,
23
26
  waitForFontsLoaded,
24
27
  },
25
28
  };
26
- const { devicePixelRatio, fileName, base64Image } = await saveWebScreen({
29
+ const { devicePixelRatio, fileName, base64Image, ignoreRegions } = await saveWebScreen({
27
30
  browserInstance,
28
31
  instanceData,
29
32
  folders,
30
33
  tag,
34
+ ignore: checkScreenOptions.method.ignore,
31
35
  saveScreenOptions,
32
36
  isNativeContext,
33
37
  });
@@ -39,6 +43,9 @@ export default async function checkWebScreen({ browserInstance, instanceData, fo
39
43
  methodCompareOptions,
40
44
  devicePixelRatio,
41
45
  fileName,
46
+ additionalProperties: {
47
+ ignoreRegions: ignoreRegions || [],
48
+ },
42
49
  });
43
50
  // 4. Now execute the compare and return the data
44
51
  return executeImageCompare({
@@ -189,6 +189,49 @@ describe('checkWebScreen', () => {
189
189
  expect(saveWebScreenSpy.mock.calls[0]).toMatchSnapshot();
190
190
  expect(executeImageCompareSpy.mock.calls[0]).toMatchSnapshot();
191
191
  });
192
+ it('should pass ignore elements to saveWebScreen and forward resolved regions', async () => {
193
+ const { buildBaseExecuteCompareOptions } = await import('../helpers/utils.js');
194
+ const buildBaseExecuteCompareOptionsSpy = vi.mocked(buildBaseExecuteCompareOptions);
195
+ const mockIgnoreElement = { elementId: 'ignore-el', selector: '.navbar' };
196
+ const mockIgnoreRegion = { x: 10, y: 20, width: 100, height: 50 };
197
+ const resolvedRegions = [
198
+ { x: 50, y: 60, width: 200, height: 100 },
199
+ { x: 10, y: 20, width: 100, height: 50 },
200
+ ];
201
+ // saveWebScreen returns ignoreRegions resolved during screenshot
202
+ saveWebScreenSpy.mockResolvedValueOnce({
203
+ devicePixelRatio: 2,
204
+ fileName: 'test-screen.png',
205
+ ignoreRegions: resolvedRegions,
206
+ });
207
+ const options = {
208
+ ...baseOptions,
209
+ checkScreenOptions: {
210
+ ...baseOptions.checkScreenOptions,
211
+ method: {
212
+ ...baseOptions.checkScreenOptions.method,
213
+ ignore: [mockIgnoreElement, mockIgnoreRegion],
214
+ }
215
+ }
216
+ };
217
+ await checkWebScreen(options);
218
+ // ignore is passed through to saveWebScreen
219
+ expect(saveWebScreenSpy).toHaveBeenCalledWith(expect.objectContaining({
220
+ ignore: [mockIgnoreElement, mockIgnoreRegion],
221
+ }));
222
+ // resolved regions are forwarded to the compare options
223
+ expect(buildBaseExecuteCompareOptionsSpy).toHaveBeenCalledWith(expect.objectContaining({
224
+ additionalProperties: { ignoreRegions: resolvedRegions },
225
+ }));
226
+ });
227
+ it('should pass empty array when no ignore regions are returned', async () => {
228
+ const { buildBaseExecuteCompareOptions } = await import('../helpers/utils.js');
229
+ const buildBaseExecuteCompareOptionsSpy = vi.mocked(buildBaseExecuteCompareOptions);
230
+ await checkWebScreen(baseOptions);
231
+ expect(buildBaseExecuteCompareOptionsSpy).toHaveBeenCalledWith(expect.objectContaining({
232
+ additionalProperties: { ignoreRegions: [] },
233
+ }));
234
+ });
192
235
  it('should handle all method options correctly', async () => {
193
236
  const mockHideElement = {
194
237
  elementId: 'hide-element',
@@ -2,11 +2,17 @@ import type { BaseMobileWebScreenshotOptions, BaseWebScreenshotOptions, Folders
2
2
  import type { DefaultOptions } from '../helpers/options.interfaces.js';
3
3
  import type { ResizeDimensions } from '../methods/images.interfaces.js';
4
4
  import type { CheckMethodOptions } from './check.interfaces.js';
5
+ import type { ElementIgnore } from './element.interfaces.js';
5
6
  export interface SaveFullPageOptions {
6
7
  wic: DefaultOptions;
7
8
  method: SaveFullPageMethodOptions;
8
9
  }
9
10
  export interface SaveFullPageMethodOptions extends Partial<Folders>, BaseWebScreenshotOptions, BaseMobileWebScreenshotOptions {
11
+ /**
12
+ * Elements or regions to ignore when saving/comparing full-page (desktop and mobile web).
13
+ * Same format as saveScreen / checkScreen (selectors or { x, y, width, height } in document CSS pixels).
14
+ */
15
+ ignore?: (ElementIgnore | ElementIgnore[])[];
10
16
  /**
11
17
  * The amount of milliseconds to wait for a new scroll. This will be used for the legacy
12
18
  * fullpage screenshot method.
@@ -1 +1 @@
1
- {"version":3,"file":"fullPage.interfaces.d.ts","sourceRoot":"","sources":["../../src/commands/fullPage.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC9G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,MAAM,WAAW,mBAAmB;IAChC,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,yBAAyB,CAAC;CACrC;AAED,MAAM,WAAW,yBAA0B,SAAQ,OAAO,CAAC,OAAO,CAAC,EAAE,wBAAwB,EAAE,8BAA8B;IACzH;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,WAAW,EAAE,CAAC;IACrC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;OAGG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,MAAM,WAAW,0BAA2B,SAAQ,yBAAyB,EAAE,kBAAkB;CAAI;AAErG,MAAM,WAAW,oBAAoB;IACjC,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,0BAA0B,CAAC;CACtC"}
1
+ {"version":3,"file":"fullPage.interfaces.d.ts","sourceRoot":"","sources":["../../src/commands/fullPage.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC9G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAE5D,MAAM,WAAW,mBAAmB;IAChC,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,yBAAyB,CAAC;CACrC;AAED,MAAM,WAAW,yBAA0B,SAAQ,OAAO,CAAC,OAAO,CAAC,EAAE,wBAAwB,EAAE,8BAA8B;IACzH;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,CAAC;IAC7C;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,WAAW,EAAE,CAAC;IACrC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;OAGG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,MAAM,WAAW,0BAA2B,SAAQ,yBAAyB,EAAE,kBAAkB;CAAI;AAErG,MAAM,WAAW,oBAAoB;IACjC,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,0BAA0B,CAAC;CACtC"}
@@ -1,7 +1,7 @@
1
1
  import type { InstanceData } from '../methods/instanceData.interfaces.js';
2
2
  import type { SaveFullPageOptions } from './fullPage.interfaces.js';
3
3
  import type { SaveScreenOptions } from './screen.interfaces.js';
4
- import type { SaveElementOptions, WicElement } from './element.interfaces.js';
4
+ import type { SaveElementOptions, WicElement, ElementIgnore } from './element.interfaces.js';
5
5
  import type { SaveTabbableOptions } from './tabbable.interfaces.js';
6
6
  import type { Folders } from '../base.interfaces.js';
7
7
  export interface InternalSaveMethodOptions {
@@ -12,10 +12,12 @@ export interface InternalSaveMethodOptions {
12
12
  tag: string;
13
13
  }
14
14
  export interface InternalSaveScreenMethodOptions extends InternalSaveMethodOptions {
15
+ ignore?: (ElementIgnore | ElementIgnore[])[];
15
16
  saveScreenOptions: SaveScreenOptions;
16
17
  }
17
18
  export interface InternalSaveElementMethodOptions extends InternalSaveMethodOptions {
18
19
  element: HTMLElement | WicElement;
20
+ ignore?: (ElementIgnore | ElementIgnore[])[];
19
21
  saveElementOptions: SaveElementOptions;
20
22
  }
21
23
  export interface InternalSaveFullPageMethodOptions extends InternalSaveMethodOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"save.interfaces.d.ts","sourceRoot":"","sources":["../../src/commands/save.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAEpD,MAAM,WAAW,yBAAyB;IACtC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC;IACrC,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,+BAAgC,SAAQ,yBAAyB;IAC9E,iBAAiB,EAAE,iBAAiB,CAAC;CACxC;AAED,MAAM,WAAW,gCAAiC,SAAQ,yBAAyB;IAC/E,OAAO,EAAE,WAAW,GAAG,UAAU,CAAC;IAClC,kBAAkB,EAAE,kBAAkB,CAAC;CAC1C;AAED,MAAM,WAAW,iCAAkC,SAAQ,yBAAyB;IAChF,mBAAmB,EAAE,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,qCAAsC,SAAQ,yBAAyB;IACpF,mBAAmB,EAAE,mBAAmB,CAAC;CAC5C"}
1
+ {"version":3,"file":"save.interfaces.d.ts","sourceRoot":"","sources":["../../src/commands/save.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAEpD,MAAM,WAAW,yBAAyB;IACtC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC;IACrC,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,+BAAgC,SAAQ,yBAAyB;IAC9E,MAAM,CAAC,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,CAAC;IAC7C,iBAAiB,EAAE,iBAAiB,CAAC;CACxC;AAED,MAAM,WAAW,gCAAiC,SAAQ,yBAAyB;IAC/E,OAAO,EAAE,WAAW,GAAG,UAAU,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,CAAC;IAC7C,kBAAkB,EAAE,kBAAkB,CAAC;CAC1C;AAED,MAAM,WAAW,iCAAkC,SAAQ,yBAAyB;IAChF,mBAAmB,EAAE,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,qCAAsC,SAAQ,yBAAyB;IACpF,mBAAmB,EAAE,mBAAmB,CAAC;CAC5C"}
@@ -3,5 +3,5 @@ import type { InternalSaveElementMethodOptions } from './save.interfaces.js';
3
3
  /**
4
4
  * Saves an image of an element
5
5
  */
6
- export default function saveElement({ browserInstance, element, folders, instanceData, isNativeContext, saveElementOptions, tag, }: InternalSaveElementMethodOptions): Promise<ScreenshotOutput>;
6
+ export default function saveElement({ browserInstance, element, folders, instanceData, isNativeContext, ignore, saveElementOptions, tag, }: InternalSaveElementMethodOptions): Promise<ScreenshotOutput>;
7
7
  //# sourceMappingURL=saveElement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"saveElement.d.ts","sourceRoot":"","sources":["../../src/commands/saveElement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAChF,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAA;AAI5E;;GAEG;AACH,wBAA8B,WAAW,CACrC,EACI,eAAe,EACf,OAAO,EACP,OAAO,EACP,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,GAAG,GACN,EAAE,gCAAgC,GACpC,OAAO,CAAC,gBAAgB,CAAC,CAI3B"}
1
+ {"version":3,"file":"saveElement.d.ts","sourceRoot":"","sources":["../../src/commands/saveElement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAChF,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAA;AAI5E;;GAEG;AACH,wBAA8B,WAAW,CACrC,EACI,eAAe,EACf,OAAO,EACP,OAAO,EACP,YAAY,EACZ,eAAe,EACf,MAAM,EACN,kBAAkB,EAClB,GAAG,GACN,EAAE,gCAAgC,GACpC,OAAO,CAAC,gBAAgB,CAAC,CAI3B"}
@@ -3,8 +3,8 @@ import saveWebElement from './saveWebElement.js';
3
3
  /**
4
4
  * Saves an image of an element
5
5
  */
6
- export default async function saveElement({ browserInstance, element, folders, instanceData, isNativeContext, saveElementOptions, tag, }) {
6
+ export default async function saveElement({ browserInstance, element, folders, instanceData, isNativeContext, ignore, saveElementOptions, tag, }) {
7
7
  return isNativeContext
8
8
  ? saveAppElement({ browserInstance, element, folders, instanceData, saveElementOptions, isNativeContext, tag })
9
- : saveWebElement({ browserInstance, element, folders, instanceData, saveElementOptions, tag });
9
+ : saveWebElement({ browserInstance, element, folders, instanceData, saveElementOptions, tag, ignore });
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"saveFullPageScreen.d.ts","sourceRoot":"","sources":["../../src/commands/saveFullPageScreen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAGhF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,sBAAsB,CAAA;AAI7E;;GAEG;AACH,wBAA8B,kBAAkB,CAC5C,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,GAAG,EACH,mBAAmB,EACnB,eAAe,GAClB,EAAE,iCAAiC,GACrC,OAAO,CAAC,gBAAgB,CAAC,CAsE3B"}
1
+ {"version":3,"file":"saveFullPageScreen.d.ts","sourceRoot":"","sources":["../../src/commands/saveFullPageScreen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAGhF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,sBAAsB,CAAA;AAK7E;;GAEG;AACH,wBAA8B,kBAAkB,CAC5C,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,GAAG,EACH,mBAAmB,EACnB,eAAe,GAClB,EAAE,iCAAiC,GACrC,OAAO,CAAC,gBAAgB,CAAC,CA+F3B"}
@@ -4,6 +4,7 @@ import { takeFullPageScreenshots } from '../methods/takeFullPageScreenshots.js';
4
4
  import { makeFullPageBase64Image } from '../methods/images.js';
5
5
  import { getMethodOrWicOption, canUseBidiScreenshot } from '../helpers/utils.js';
6
6
  import { createBeforeScreenshotOptions, buildAfterScreenshotOptions } from '../helpers/options.js';
7
+ import { determineWebFullPageIgnoreRegions } from '../methods/rectangles.js';
7
8
  /**
8
9
  * Saves an image of the full page
9
10
  */
@@ -20,7 +21,7 @@ export default async function saveFullPageScreen({ browserInstance, instanceData
20
21
  // 3. Prepare the screenshot
21
22
  const beforeOptions = createBeforeScreenshotOptions(instanceData, saveFullPageOptions.method, saveFullPageOptions.wic);
22
23
  const enrichedInstanceData = await beforeScreenshot(browserInstance, beforeOptions, true);
23
- const { dimensions: { window: { devicePixelRatio, innerHeight, isEmulated: _isEmulated, isLandscape, screenHeight, screenWidth, }, }, isAndroid, isAndroidChromeDriverScreenshot, isAndroidNativeWebScreenshot, isIOS, } = enrichedInstanceData;
24
+ const { dimensions: { window: { devicePixelRatio, innerHeight, isEmulated: _isEmulated, isLandscape, screenHeight, screenWidth, }, }, isAndroid, isAndroidChromeDriverScreenshot, isAndroidNativeWebScreenshot, isIOS, isMobile, } = enrichedInstanceData;
24
25
  // 4. Take the screenshot
25
26
  const fullPageScreenshotOptions = {
26
27
  addressBarShadowPadding: beforeOptions.addressBarShadowPadding,
@@ -44,7 +45,22 @@ export default async function saveFullPageScreen({ browserInstance, instanceData
44
45
  const fullPageBase64Image = (screenshotsData.fullPageHeight === -1 && screenshotsData.fullPageWidth === -1)
45
46
  ? screenshotsData.data[0].screenshot // BiDi screenshot - use directly
46
47
  : await makeFullPageBase64Image(screenshotsData, { devicePixelRatio: devicePixelRatio || NaN, isLandscape });
47
- // 6. Return the data
48
+ // 6. Resolve ignore regions while the DOM is still in screenshot state.
49
+ // Full-page image (BiDi or stitched) is in document coordinates; regions are document-relative device pixels.
50
+ // On mobile scroll-and-stitch we crop addressBarShadowPadding from the top of each tile, so we pass
51
+ // fullPageCropTopPaddingCSS so ignore regions align with the stitched canvas.
52
+ const ignore = saveFullPageOptions.method?.ignore;
53
+ const ignoreRegionPadding = getMethodOrWicOption(saveFullPageOptions.method, saveFullPageOptions.wic, 'ignoreRegionPadding') ?? 1;
54
+ const usedStitchedMobile = isMobile && !(screenshotsData.fullPageHeight === -1 && screenshotsData.fullPageWidth === -1);
55
+ const ignoreRegions = ignore && ignore.length > 0
56
+ ? await determineWebFullPageIgnoreRegions({
57
+ browserInstance,
58
+ devicePixelRatio: devicePixelRatio || 1,
59
+ fullPageCropTopPaddingCSS: usedStitchedMobile ? beforeOptions.addressBarShadowPadding : 0,
60
+ ignoreRegionPadding,
61
+ }, ignore)
62
+ : undefined;
63
+ // 7. Return the data
48
64
  const afterOptions = buildAfterScreenshotOptions({
49
65
  base64Image: fullPageBase64Image,
50
66
  folders,
@@ -55,5 +71,9 @@ export default async function saveFullPageScreen({ browserInstance, instanceData
55
71
  beforeOptions,
56
72
  wicOptions: saveFullPageOptions.wic
57
73
  });
58
- return afterScreenshot(browserInstance, afterOptions);
74
+ const result = await afterScreenshot(browserInstance, afterOptions);
75
+ return {
76
+ ...result,
77
+ ...(ignoreRegions ? { ignoreRegions } : {}),
78
+ };
59
79
  }
@@ -3,5 +3,5 @@ import type { InternalSaveElementMethodOptions } from './save.interfaces.js';
3
3
  /**
4
4
  * Saves an image of an element
5
5
  */
6
- export default function saveWebElement({ browserInstance, instanceData, folders, element, tag, saveElementOptions, }: InternalSaveElementMethodOptions): Promise<ScreenshotOutput>;
6
+ export default function saveWebElement({ browserInstance, instanceData, folders, element, tag, ignore, saveElementOptions, }: InternalSaveElementMethodOptions): Promise<ScreenshotOutput>;
7
7
  //# sourceMappingURL=saveWebElement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"saveWebElement.d.ts","sourceRoot":"","sources":["../../src/commands/saveWebElement.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAOhF,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAA;AAE5E;;GAEG;AACH,wBAA8B,cAAc,CACxC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,OAAO,EACP,GAAG,EACH,kBAAkB,GACrB,EAAE,gCAAgC,GACpC,OAAO,CAAC,gBAAgB,CAAC,CA+D3B"}
1
+ {"version":3,"file":"saveWebElement.d.ts","sourceRoot":"","sources":["../../src/commands/saveWebElement.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAOhF,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAA;AAG5E;;GAEG;AACH,wBAA8B,cAAc,CACxC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,OAAO,EACP,GAAG,EACH,MAAM,EACN,kBAAkB,GACrB,EAAE,gCAAgC,GACpC,OAAO,CAAC,gBAAgB,CAAC,CA0F3B"}
@@ -4,10 +4,11 @@ import afterScreenshot from '../helpers/afterScreenshot.js';
4
4
  import { DEFAULT_RESIZE_DIMENSIONS } from '../helpers/constants.js';
5
5
  import { canUseBidiScreenshot, getMethodOrWicOption } from '../helpers/utils.js';
6
6
  import { createBeforeScreenshotOptions, buildAfterScreenshotOptions } from '../helpers/options.js';
7
+ import { determineWebElementIgnoreRegions } from '../methods/rectangles.js';
7
8
  /**
8
9
  * Saves an image of an element
9
10
  */
10
- export default async function saveWebElement({ browserInstance, instanceData, folders, element, tag, saveElementOptions, }) {
11
+ export default async function saveWebElement({ browserInstance, instanceData, folders, element, tag, ignore, saveElementOptions, }) {
11
12
  // 1. Set some variables
12
13
  const { addressBarShadowPadding, autoElementScroll } = saveElementOptions.wic;
13
14
  const enableLegacyScreenshotMethod = getMethodOrWicOption(saveElementOptions.method, saveElementOptions.wic, 'enableLegacyScreenshotMethod');
@@ -38,6 +39,23 @@ export default async function saveWebElement({ browserInstance, instanceData, fo
38
39
  };
39
40
  const shouldUseBidi = canUseBidiScreenshot(browserInstance) && !isMobile && !enableLegacyScreenshotMethod;
40
41
  const screenshotData = await takeElementScreenshot(browserInstance, elementScreenshotOptions, shouldUseBidi);
42
+ // 3b. Resolve ignore regions (element-local) while the DOM is still in screenshot state.
43
+ // determineWebElementIgnoreRegions returns device-pixel regions, or CSS-pixel regions when
44
+ // the element image is from the native driver on Android native web (see that function).
45
+ const ignoreRegionPadding = getMethodOrWicOption(saveElementOptions.method, saveElementOptions.wic, 'ignoreRegionPadding') ?? 1;
46
+ const ignoreRegions = ignore && ignore.length > 0
47
+ ? await (async () => {
48
+ const rootElement = await element;
49
+ return determineWebElementIgnoreRegions({
50
+ browserInstance,
51
+ devicePixelRatio: devicePixelRatio || 1,
52
+ rootElement: rootElement,
53
+ ignoreRegionPadding,
54
+ isAndroidNativeWebScreenshot,
55
+ isWebDriverElementScreenshot: screenshotData.isWebDriverElementScreenshot,
56
+ }, ignore);
57
+ })()
58
+ : undefined;
41
59
  // 4. Return the data
42
60
  const afterOptions = buildAfterScreenshotOptions({
43
61
  base64Image: screenshotData.base64Image,
@@ -49,5 +67,9 @@ export default async function saveWebElement({ browserInstance, instanceData, fo
49
67
  beforeOptions,
50
68
  wicOptions: saveElementOptions.wic
51
69
  });
52
- return afterScreenshot(browserInstance, afterOptions);
70
+ const result = await afterScreenshot(browserInstance, afterOptions);
71
+ return {
72
+ ...result,
73
+ ...(ignoreRegions ? { ignoreRegions } : {}),
74
+ };
53
75
  }
@@ -3,5 +3,5 @@ import type { InternalSaveScreenMethodOptions } from './save.interfaces.js';
3
3
  /**
4
4
  * Saves an image of the viewport of the screen
5
5
  */
6
- export default function saveWebScreen({ browserInstance, instanceData, folders, tag, saveScreenOptions, isNativeContext, }: InternalSaveScreenMethodOptions): Promise<ScreenshotOutput>;
6
+ export default function saveWebScreen({ browserInstance, instanceData, folders, tag, ignore, saveScreenOptions, isNativeContext, }: InternalSaveScreenMethodOptions): Promise<ScreenshotOutput>;
7
7
  //# sourceMappingURL=saveWebScreen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"saveWebScreen.d.ts","sourceRoot":"","sources":["../../src/commands/saveWebScreen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAChF,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAK3E;;GAEG;AACH,wBAA8B,aAAa,CACvC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,GAAG,EACH,iBAAiB,EACjB,eAAuB,GAC1B,EAAE,+BAA+B,GACnC,OAAO,CAAC,gBAAgB,CAAC,CA4D3B"}
1
+ {"version":3,"file":"saveWebScreen.d.ts","sourceRoot":"","sources":["../../src/commands/saveWebScreen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAChF,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAM3E;;GAEG;AACH,wBAA8B,aAAa,CACvC,EACI,eAAe,EACf,YAAY,EACZ,OAAO,EACP,GAAG,EACH,MAAM,EACN,iBAAiB,EACjB,eAAuB,GAC1B,EAAE,+BAA+B,GACnC,OAAO,CAAC,gBAAgB,CAAC,CAoF3B"}
@@ -3,10 +3,11 @@ import beforeScreenshot from '../helpers/beforeScreenshot.js';
3
3
  import afterScreenshot from '../helpers/afterScreenshot.js';
4
4
  import { canUseBidiScreenshot, getMethodOrWicOption } from '../helpers/utils.js';
5
5
  import { createBeforeScreenshotOptions, buildAfterScreenshotOptions } from '../helpers/options.js';
6
+ import { determineWebScreenIgnoreRegions } from '../methods/rectangles.js';
6
7
  /**
7
8
  * Saves an image of the viewport of the screen
8
9
  */
9
- export default async function saveWebScreen({ browserInstance, instanceData, folders, tag, saveScreenOptions, isNativeContext = false, }) {
10
+ export default async function saveWebScreen({ browserInstance, instanceData, folders, tag, ignore, saveScreenOptions, isNativeContext = false, }) {
10
11
  // 1. Set some variables
11
12
  const { addIOSBezelCorners } = saveScreenOptions.wic;
12
13
  const enableLegacyScreenshotMethod = getMethodOrWicOption(saveScreenOptions.method, saveScreenOptions.wic, 'enableLegacyScreenshotMethod');
@@ -33,7 +34,22 @@ export default async function saveWebScreen({ browserInstance, instanceData, fol
33
34
  isMobile,
34
35
  };
35
36
  const { base64Image } = await takeWebScreenshot(browserInstance, webScreenshotOptions, shouldUseBidi);
36
- // 4. Return the data
37
+ // 4. Resolve ignore regions while the DOM is still in screenshot state
38
+ // (scrollbar hidden, elements hidden/removed, CSS applied).
39
+ // This must happen BEFORE afterScreenshot restores the DOM.
40
+ const ignoreRegionPadding = getMethodOrWicOption(saveScreenOptions.method, saveScreenOptions.wic, 'ignoreRegionPadding') ?? 1;
41
+ const ignoreRegions = ignore && ignore.length > 0
42
+ ? await determineWebScreenIgnoreRegions({
43
+ browserInstance,
44
+ devicePixelRatio: devicePixelRatio || 1,
45
+ deviceRectangles: instanceData.deviceRectangles,
46
+ isAndroid,
47
+ isAndroidNativeWebScreenshot,
48
+ isIOS,
49
+ ignoreRegionPadding,
50
+ }, ignore)
51
+ : undefined;
52
+ // 5. Restore the DOM and return the data
37
53
  const afterOptions = buildAfterScreenshotOptions({
38
54
  base64Image,
39
55
  folders,
@@ -44,5 +60,9 @@ export default async function saveWebScreen({ browserInstance, instanceData, fol
44
60
  beforeOptions,
45
61
  wicOptions: saveScreenOptions.wic
46
62
  });
47
- return afterScreenshot(browserInstance, afterOptions);
63
+ const result = await afterScreenshot(browserInstance, afterOptions);
64
+ return {
65
+ ...result,
66
+ ...(ignoreRegions ? { ignoreRegions } : {}),
67
+ };
48
68
  }
@@ -1,6 +1,8 @@
1
+ import type { RectanglesOutput } from '../methods/rectangles.interfaces.js';
1
2
  export interface ScreenshotOutput {
2
3
  devicePixelRatio: number;
3
4
  fileName: string;
5
+ ignoreRegions?: RectanglesOutput[];
4
6
  isLandscape: boolean;
5
7
  path: string;
6
8
  base64Image?: string;