@wdio/image-comparison-core 1.1.4 → 1.2.1
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.
- package/CHANGELOG.md +34 -0
- package/dist/base.interfaces.d.ts +7 -0
- package/dist/base.interfaces.d.ts.map +1 -1
- package/dist/clientSideScripts/injectWebviewOverlay.test.js +29 -0
- package/dist/clientSideScripts/scrollElementIntoView.d.ts.map +1 -1
- package/dist/clientSideScripts/scrollElementIntoView.js +4 -1
- package/dist/clientSideScripts/scrollElementIntoView.test.js +4 -2
- package/dist/commands/check.interfaces.d.ts +1 -1
- package/dist/commands/check.interfaces.d.ts.map +1 -1
- package/dist/commands/checkFullPageScreen.d.ts.map +1 -1
- package/dist/commands/checkFullPageScreen.js +7 -2
- package/dist/commands/checkWebElement.d.ts.map +1 -1
- package/dist/commands/checkWebElement.js +7 -2
- package/dist/commands/checkWebScreen.d.ts.map +1 -1
- package/dist/commands/checkWebScreen.js +10 -3
- package/dist/commands/checkWebScreen.test.js +43 -0
- package/dist/commands/fullPage.interfaces.d.ts +6 -0
- package/dist/commands/fullPage.interfaces.d.ts.map +1 -1
- package/dist/commands/save.interfaces.d.ts +3 -1
- package/dist/commands/save.interfaces.d.ts.map +1 -1
- package/dist/commands/saveElement.d.ts +1 -1
- package/dist/commands/saveElement.d.ts.map +1 -1
- package/dist/commands/saveElement.js +2 -2
- package/dist/commands/saveFullPageScreen.d.ts.map +1 -1
- package/dist/commands/saveFullPageScreen.js +23 -3
- package/dist/commands/saveWebElement.d.ts +1 -1
- package/dist/commands/saveWebElement.d.ts.map +1 -1
- package/dist/commands/saveWebElement.js +24 -2
- package/dist/commands/saveWebScreen.d.ts +1 -1
- package/dist/commands/saveWebScreen.d.ts.map +1 -1
- package/dist/commands/saveWebScreen.js +23 -3
- package/dist/helpers/afterScreenshot.interfaces.d.ts +2 -0
- package/dist/helpers/afterScreenshot.interfaces.d.ts.map +1 -1
- package/dist/helpers/options.d.ts.map +1 -1
- package/dist/helpers/options.interfaces.d.ts +10 -0
- package/dist/helpers/options.interfaces.d.ts.map +1 -1
- package/dist/helpers/options.js +1 -0
- package/dist/helpers/utils.d.ts +6 -0
- package/dist/helpers/utils.d.ts.map +1 -1
- package/dist/helpers/utils.interfaces.d.ts +3 -0
- package/dist/helpers/utils.interfaces.d.ts.map +1 -1
- package/dist/helpers/utils.js +95 -29
- package/dist/helpers/utils.test.js +121 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/methods/images.d.ts.map +1 -1
- package/dist/methods/images.interfaces.d.ts +4 -0
- package/dist/methods/images.interfaces.d.ts.map +1 -1
- package/dist/methods/images.js +4 -2
- package/dist/methods/rectangles.d.ts +33 -2
- package/dist/methods/rectangles.d.ts.map +1 -1
- package/dist/methods/rectangles.interfaces.d.ts +58 -0
- package/dist/methods/rectangles.interfaces.d.ts.map +1 -1
- package/dist/methods/rectangles.js +289 -15
- package/dist/methods/rectangles.test.js +558 -2
- package/dist/methods/screenshots.interfaces.d.ts +2 -1
- package/dist/methods/screenshots.interfaces.d.ts.map +1 -1
- package/dist/methods/takeElementScreenshots.js +30 -19
- package/dist/methods/takeElementScreenshots.test.js +49 -22
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rectangles.d.ts","sourceRoot":"","sources":["../../src/methods/rectangles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rectangles.d.ts","sourceRoot":"","sources":["../../src/methods/rectangles.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,+BAA+B,EAC/B,wCAAwC,EACxC,sCAAsC,EACtC,uCAAuC,EACvC,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,EACvB,YAAY,EACZ,8BAA8B,EAC9B,qCAAqC,EACxC,MAAM,4BAA4B,CAAA;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAA;AAEvE;;GAEG;AACH,wBAAsB,0BAA0B,CAAC,EAC7C,eAAe,EACf,WAAW,EACX,OAAO,EACP,OAAO,GACV,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4C/C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,gBAAgB,CAoCjH;AAED;;GAEG;AACH,wBAAgB,uCAAuC,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAC;IAClF,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,OAAO,EAAE,qCAAqC,CAAC;CAClD,GAAG,8BAA8B,CAgDjC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,WASvC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,WAS9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAC,OAAO,EAAE,OAAO,EAAC,MAAM,UAG9D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAC,OAAO,EAAE,GAAG,YAAY,CA4B1D;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAQ/I;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CACxC,eAAe,EAAE,WAAW,CAAC,OAAO,EACpC,OAAO,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,GAC7C,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAY7B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,+BAA+B,CACjD,OAAO,EAAE,sCAAsC,EAC/C,OAAO,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,GAC7C,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA4E7B;AAED;;;;;;GAMG;AACH,wBAAsB,iCAAiC,CACnD,OAAO,EAAE,wCAAwC,EACjD,OAAO,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,GAC7C,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA4D7B;AAED;;;;;;;;;GASG;AACH,wBAAsB,gCAAgC,CAClD,OAAO,EAAE,uCAAuC,EAChD,OAAO,EAAE,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC,EAAE,GAC7C,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAiF7B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,YAAY,EAAE,EAAE,+BAA+B,+BAwBhI;AAuDD;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAkIxH"}
|
|
@@ -118,6 +118,10 @@ export interface PrepareIgnoreRectanglesOptions {
|
|
|
118
118
|
blockOutStatusBar?: boolean;
|
|
119
119
|
blockOutToolBar?: boolean;
|
|
120
120
|
};
|
|
121
|
+
/** Whether this is a hybrid (native + webview) app; enables status bar fallback when overlay reports zero */
|
|
122
|
+
isHybridApp?: boolean;
|
|
123
|
+
/** Platform version from the device (e.g. "14.0"); used for Android API level lookup in fallback */
|
|
124
|
+
platformVersion?: string;
|
|
121
125
|
actualFilePath?: string;
|
|
122
126
|
}
|
|
123
127
|
export interface PreparedIgnoreRectangles {
|
|
@@ -126,6 +130,60 @@ export interface PreparedIgnoreRectangles {
|
|
|
126
130
|
/** Whether any ignore rectangles were found */
|
|
127
131
|
hasIgnoreRectangles: boolean;
|
|
128
132
|
}
|
|
133
|
+
export interface DetermineWebScreenIgnoreRegionsOptions {
|
|
134
|
+
/** The browser instance */
|
|
135
|
+
browserInstance: WebdriverIO.Browser;
|
|
136
|
+
/** The device pixel ratio */
|
|
137
|
+
devicePixelRatio: number;
|
|
138
|
+
/** The device rectangles (contains viewport offset for mobile) */
|
|
139
|
+
deviceRectangles: DeviceRectangles;
|
|
140
|
+
/** Whether this is an Android device */
|
|
141
|
+
isAndroid: boolean;
|
|
142
|
+
/** Whether this is an Android native web screenshot */
|
|
143
|
+
isAndroidNativeWebScreenshot: boolean;
|
|
144
|
+
/** Whether this is an iOS device */
|
|
145
|
+
isIOS: boolean;
|
|
146
|
+
/** Padding in device pixels added to each side of computed ignore regions (caller defaults to 1). */
|
|
147
|
+
ignoreRegionPadding: number;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Options for full-page web ignore regions (desktop and mobile).
|
|
151
|
+
* Full-page image is in document coordinates; on mobile scroll-and-stitch the canvas
|
|
152
|
+
* crops off the top addressBarShadowPadding (CSS px), so we subtract that from y.
|
|
153
|
+
*/
|
|
154
|
+
export interface DetermineWebFullPageIgnoreRegionsOptions {
|
|
155
|
+
/** The browser instance */
|
|
156
|
+
browserInstance: WebdriverIO.Browser;
|
|
157
|
+
/** The device pixel ratio */
|
|
158
|
+
devicePixelRatio: number;
|
|
159
|
+
/** Padding in device pixels added to each side of computed ignore regions (caller defaults to 1). */
|
|
160
|
+
ignoreRegionPadding: number;
|
|
161
|
+
/**
|
|
162
|
+
* Top crop offset in CSS pixels (e.g. addressBarShadowPadding on mobile full-page).
|
|
163
|
+
* When set, canvas y = (documentY - fullPageCropTopPaddingCSS) × DPR so ignore regions
|
|
164
|
+
* align with the stitched image which crops this much from the top of each tile.
|
|
165
|
+
* @default 0
|
|
166
|
+
*/
|
|
167
|
+
fullPageCropTopPaddingCSS?: number;
|
|
168
|
+
}
|
|
169
|
+
export interface DetermineWebElementIgnoreRegionsOptions {
|
|
170
|
+
/** The browser instance */
|
|
171
|
+
browserInstance: WebdriverIO.Browser;
|
|
172
|
+
/** The device pixel ratio */
|
|
173
|
+
devicePixelRatio: number;
|
|
174
|
+
/** The root element being captured in the element screenshot */
|
|
175
|
+
rootElement: WebdriverIO.Element;
|
|
176
|
+
/** Padding in device pixels added to each side of computed ignore regions (caller defaults to 1). */
|
|
177
|
+
ignoreRegionPadding: number;
|
|
178
|
+
/**
|
|
179
|
+
* When both this and isWebDriverElementScreenshot are true, the element image is at CSS pixel size
|
|
180
|
+
* (native driver returns a downscaled image). We then output ignore regions in CSS pixel coordinates
|
|
181
|
+
* by dividing by DPR; otherwise regions are in device pixels.
|
|
182
|
+
*/
|
|
183
|
+
isAndroidNativeWebScreenshot?: boolean;
|
|
184
|
+
/** When true, the element screenshot came from the native driver (no fallback crop). */
|
|
185
|
+
isWebDriverElementScreenshot?: boolean;
|
|
186
|
+
}
|
|
129
187
|
export interface BoundingBox extends BaseBoundingBox {
|
|
130
188
|
}
|
|
131
189
|
export interface IgnoreBoxes extends BoundingBox {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rectangles.interfaces.d.ts","sourceRoot":"","sources":["../../src/methods/rectangles.interfaces.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rectangles.interfaces.d.ts","sourceRoot":"","sources":["../../src/methods/rectangles.interfaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Jimp } from 'jimp';
|
|
2
|
+
import { ANDROID_OFFSETS, IOS_OFFSETS } from '../helpers/constants.js';
|
|
2
3
|
import { calculateDprData, getBase64ScreenshotSize, isObject } from '../helpers/utils.js';
|
|
3
4
|
import { getElementPositionAndroid, getElementPositionDesktop, getElementWebviewPosition } from './elementPosition.js';
|
|
4
5
|
/**
|
|
@@ -186,6 +187,218 @@ export async function determineIgnoreRegions(browserInstance, ignores) {
|
|
|
186
187
|
height: Math.round(region.height),
|
|
187
188
|
}));
|
|
188
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Translate ignores to regions for web screen (viewport) screenshots.
|
|
192
|
+
* Uses getBoundingClientRect (CSS pixels) and converts to device pixels,
|
|
193
|
+
* accounting for the viewport offset on native web screenshot devices.
|
|
194
|
+
*
|
|
195
|
+
* Coordinate systems per platform:
|
|
196
|
+
* - Desktop / Android ChromeDriver: screenshot is viewport-only, BCR × DPR
|
|
197
|
+
* - iOS: full-device screenshot, viewport offset is in CSS points → (BCR + offset) × DPR
|
|
198
|
+
* - Android native web: full-device screenshot, viewport offset is already in
|
|
199
|
+
* device pixels (injectWebviewOverlay pre-scales by DPR) → BCR × DPR + offset
|
|
200
|
+
*/
|
|
201
|
+
export async function determineWebScreenIgnoreRegions(options, ignores) {
|
|
202
|
+
const awaitedIgnores = await Promise.all(ignores);
|
|
203
|
+
const { elements, regions } = splitIgnores(awaitedIgnores);
|
|
204
|
+
const { browserInstance, devicePixelRatio, deviceRectangles, isAndroid, isAndroidNativeWebScreenshot, isIOS, ignoreRegionPadding: padding } = options;
|
|
205
|
+
// Get raw (unrounded) BCR values so we can multiply by DPR before
|
|
206
|
+
// rounding. The shared getBoundingClientRect script pre-rounds to CSS
|
|
207
|
+
// integers which loses sub-pixel precision that matters at higher DPRs.
|
|
208
|
+
const rawBcr = (el) => {
|
|
209
|
+
const rect = el.getBoundingClientRect();
|
|
210
|
+
return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
|
|
211
|
+
};
|
|
212
|
+
// Browsers can invalidate element references when the DOM is mutated
|
|
213
|
+
// (e.g. by beforeScreenshot CSS/style injection). Re-query via $$ to
|
|
214
|
+
// get fresh refs. Use $$ per unique selector so multiple elements
|
|
215
|
+
// sharing the same selector (e.g. from a $$ call) each resolve to
|
|
216
|
+
// the correct match by index.
|
|
217
|
+
const regionsFromElements = [];
|
|
218
|
+
const selectorCache = new Map();
|
|
219
|
+
const selectorIndex = new Map();
|
|
220
|
+
for (const element of elements) {
|
|
221
|
+
const selector = element.selector;
|
|
222
|
+
if (!selectorCache.has(selector)) {
|
|
223
|
+
const fresh = await browserInstance.$$(selector);
|
|
224
|
+
selectorCache.set(selector, fresh);
|
|
225
|
+
selectorIndex.set(selector, 0);
|
|
226
|
+
}
|
|
227
|
+
const idx = selectorIndex.get(selector);
|
|
228
|
+
const cached = selectorCache.get(selector);
|
|
229
|
+
const el = idx < cached.length ? cached[idx] : element;
|
|
230
|
+
selectorIndex.set(selector, idx + 1);
|
|
231
|
+
const bcr = await browserInstance.execute(rawBcr, el);
|
|
232
|
+
regionsFromElements.push(bcr);
|
|
233
|
+
}
|
|
234
|
+
return [...regions, ...regionsFromElements]
|
|
235
|
+
.map((region) => {
|
|
236
|
+
// Use floor for top-left and ceil for bottom-right so the
|
|
237
|
+
// device-pixel rectangle fully covers the CSS-pixel element.
|
|
238
|
+
// Rounding position and size independently can miss edge pixels.
|
|
239
|
+
let cssX = region.x;
|
|
240
|
+
let cssY = region.y;
|
|
241
|
+
if (isIOS) {
|
|
242
|
+
cssX += deviceRectangles.viewport.x;
|
|
243
|
+
cssY += deviceRectangles.viewport.y;
|
|
244
|
+
}
|
|
245
|
+
const left = Math.floor(cssX * devicePixelRatio);
|
|
246
|
+
const top = Math.floor(cssY * devicePixelRatio);
|
|
247
|
+
const right = Math.ceil((cssX + region.width) * devicePixelRatio);
|
|
248
|
+
const bottom = Math.ceil((cssY + region.height) * devicePixelRatio);
|
|
249
|
+
let x = left;
|
|
250
|
+
let y = top;
|
|
251
|
+
if (isAndroid && isAndroidNativeWebScreenshot) {
|
|
252
|
+
// Android native web viewport offset is already in device pixels
|
|
253
|
+
x += deviceRectangles.viewport.x;
|
|
254
|
+
y += deviceRectangles.viewport.y;
|
|
255
|
+
}
|
|
256
|
+
let width = right - left;
|
|
257
|
+
let height = bottom - top;
|
|
258
|
+
if (padding > 0) {
|
|
259
|
+
x = Math.max(0, x - padding);
|
|
260
|
+
y = Math.max(0, y - padding);
|
|
261
|
+
width += 2 * padding;
|
|
262
|
+
height += 2 * padding;
|
|
263
|
+
}
|
|
264
|
+
return { x, y, width, height };
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Translate ignores to regions for web full-page screenshots (desktop and mobile).
|
|
269
|
+
* Full-page image (BiDi or scroll-and-stitch) is in document coordinates: (0,0) = top-left
|
|
270
|
+
* of document, device pixels. Uses getBoundingClientRect + (scrollX, scrollY) for elements,
|
|
271
|
+
* then converts to device pixels. Same logic for all platforms; no viewport offset needed
|
|
272
|
+
* because the stitched canvas is built in document space.
|
|
273
|
+
*/
|
|
274
|
+
export async function determineWebFullPageIgnoreRegions(options, ignores) {
|
|
275
|
+
const awaitedIgnores = await Promise.all(ignores);
|
|
276
|
+
const { elements, regions } = splitIgnores(awaitedIgnores);
|
|
277
|
+
const { browserInstance, devicePixelRatio, ignoreRegionPadding: padding, fullPageCropTopPaddingCSS: cropTop = 0 } = options;
|
|
278
|
+
const rawDocumentBcr = (el) => {
|
|
279
|
+
const rect = el.getBoundingClientRect();
|
|
280
|
+
return {
|
|
281
|
+
x: rect.x + window.scrollX,
|
|
282
|
+
y: rect.y + window.scrollY,
|
|
283
|
+
width: rect.width,
|
|
284
|
+
height: rect.height,
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
const regionsFromElements = [];
|
|
288
|
+
const selectorCache = new Map();
|
|
289
|
+
const selectorIndex = new Map();
|
|
290
|
+
for (const element of elements) {
|
|
291
|
+
const selector = element.selector;
|
|
292
|
+
if (!selectorCache.has(selector)) {
|
|
293
|
+
const fresh = await browserInstance.$$(selector);
|
|
294
|
+
selectorCache.set(selector, fresh);
|
|
295
|
+
selectorIndex.set(selector, 0);
|
|
296
|
+
}
|
|
297
|
+
const idx = selectorIndex.get(selector);
|
|
298
|
+
const cached = selectorCache.get(selector);
|
|
299
|
+
const el = idx < cached.length ? cached[idx] : element;
|
|
300
|
+
selectorIndex.set(selector, idx + 1);
|
|
301
|
+
const bcr = await browserInstance.execute(rawDocumentBcr, el);
|
|
302
|
+
regionsFromElements.push(bcr);
|
|
303
|
+
}
|
|
304
|
+
return [...regions, ...regionsFromElements]
|
|
305
|
+
.map((region) => {
|
|
306
|
+
const left = Math.floor(region.x * devicePixelRatio);
|
|
307
|
+
const right = Math.ceil((region.x + region.width) * devicePixelRatio);
|
|
308
|
+
// On mobile full-page scroll-and-stitch, the canvas crops cropTop (e.g. 6px) from the top
|
|
309
|
+
// of each tile, so canvas y = (documentY - cropTop) × DPR
|
|
310
|
+
const topDevice = Math.floor((region.y - cropTop) * devicePixelRatio);
|
|
311
|
+
const bottomDevice = Math.ceil((region.y + region.height - cropTop) * devicePixelRatio);
|
|
312
|
+
const top = Math.max(0, topDevice);
|
|
313
|
+
const bottom = Math.max(top, bottomDevice);
|
|
314
|
+
let x = left;
|
|
315
|
+
let y = top;
|
|
316
|
+
let width = right - left;
|
|
317
|
+
let height = bottom - top;
|
|
318
|
+
if (padding > 0) {
|
|
319
|
+
x = Math.max(0, x - padding);
|
|
320
|
+
y = Math.max(0, y - padding);
|
|
321
|
+
width += 2 * padding;
|
|
322
|
+
height += 2 * padding;
|
|
323
|
+
}
|
|
324
|
+
return { x, y, width, height };
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Translate ignores to regions for web element screenshots.
|
|
329
|
+
* By default regions are in *element-local* device pixels so they match the cropped element image
|
|
330
|
+
* (BiDi clip or fallback full-screenshot crop, both at device pixel size).
|
|
331
|
+
* Exception: when the element screenshot is from the native driver on Android native web
|
|
332
|
+
* (isWebDriverElementScreenshot && isAndroidNativeWebScreenshot), the driver returns an image at
|
|
333
|
+
* CSS pixel size (downscaled). We then output regions in CSS pixel coordinates (divide by DPR)
|
|
334
|
+
* so they align with that image. Fallback (full screenshot + crop) is at device size, so we do
|
|
335
|
+
* not downscale when fallback was used.
|
|
336
|
+
*/
|
|
337
|
+
export async function determineWebElementIgnoreRegions(options, ignores) {
|
|
338
|
+
const awaitedIgnores = await Promise.all(ignores);
|
|
339
|
+
const { elements, regions } = splitIgnores(awaitedIgnores);
|
|
340
|
+
const { browserInstance, devicePixelRatio, rootElement, ignoreRegionPadding: padding, isAndroidNativeWebScreenshot, isWebDriverElementScreenshot, } = options;
|
|
341
|
+
// Compute bounding boxes relative to the root element: (childBCR - rootBCR)
|
|
342
|
+
const rawRelativeBcr = (el, root) => {
|
|
343
|
+
const elRect = el.getBoundingClientRect();
|
|
344
|
+
const rootRect = root.getBoundingClientRect();
|
|
345
|
+
return {
|
|
346
|
+
x: elRect.x - rootRect.x,
|
|
347
|
+
y: elRect.y - rootRect.y,
|
|
348
|
+
width: elRect.width,
|
|
349
|
+
height: elRect.height,
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
const regionsFromElements = [];
|
|
353
|
+
const selectorCache = new Map();
|
|
354
|
+
const selectorIndex = new Map();
|
|
355
|
+
for (const element of elements) {
|
|
356
|
+
const selector = element.selector;
|
|
357
|
+
if (!selectorCache.has(selector)) {
|
|
358
|
+
const fresh = await browserInstance.$$(selector);
|
|
359
|
+
selectorCache.set(selector, fresh);
|
|
360
|
+
selectorIndex.set(selector, 0);
|
|
361
|
+
}
|
|
362
|
+
const idx = selectorIndex.get(selector);
|
|
363
|
+
const cached = selectorCache.get(selector);
|
|
364
|
+
const el = idx < cached.length ? cached[idx] : element;
|
|
365
|
+
selectorIndex.set(selector, idx + 1);
|
|
366
|
+
const bcr = await browserInstance.execute(rawRelativeBcr, el, rootElement);
|
|
367
|
+
regionsFromElements.push(bcr);
|
|
368
|
+
}
|
|
369
|
+
// Both literal regions and element-derived regions are currently expected
|
|
370
|
+
// to be in CSS pixels relative to the element. Scale everything by DPR and
|
|
371
|
+
// express as device-pixel rectangles using the same floor-based rounding
|
|
372
|
+
// strategy as the BiDi element clip (x/y/width/height all floored).
|
|
373
|
+
// Then expand each region by ignoreRegionPadding on each side (configurable, default 1)
|
|
374
|
+
// to reduce 1px boundary differences on high-DPR / BiDi.
|
|
375
|
+
let result = [...regions, ...regionsFromElements]
|
|
376
|
+
.map((region) => {
|
|
377
|
+
let x = Math.floor(region.x * devicePixelRatio);
|
|
378
|
+
let y = Math.floor(region.y * devicePixelRatio);
|
|
379
|
+
let width = Math.floor(region.width * devicePixelRatio);
|
|
380
|
+
let height = Math.floor(region.height * devicePixelRatio);
|
|
381
|
+
if (padding > 0) {
|
|
382
|
+
x = Math.max(0, x - padding);
|
|
383
|
+
y = Math.max(0, y - padding);
|
|
384
|
+
width += 2 * padding;
|
|
385
|
+
height += 2 * padding;
|
|
386
|
+
}
|
|
387
|
+
return { x, y, width, height };
|
|
388
|
+
});
|
|
389
|
+
// Only downscale when the element image is at CSS pixel size: native driver element screenshot
|
|
390
|
+
// on Android native web (fallback false). Fallback uses a device-pixel crop, so no downscale.
|
|
391
|
+
if (isAndroidNativeWebScreenshot === true && isWebDriverElementScreenshot === true && devicePixelRatio > 0) {
|
|
392
|
+
const dpr = devicePixelRatio;
|
|
393
|
+
result = result.map((r) => ({
|
|
394
|
+
x: Math.round(r.x / dpr),
|
|
395
|
+
y: Math.round(r.y / dpr),
|
|
396
|
+
width: Math.round(r.width / dpr),
|
|
397
|
+
height: Math.round(r.height / dpr),
|
|
398
|
+
}));
|
|
399
|
+
}
|
|
400
|
+
return result;
|
|
401
|
+
}
|
|
189
402
|
/**
|
|
190
403
|
* Determine the device block outs
|
|
191
404
|
*/
|
|
@@ -211,11 +424,55 @@ export async function determineDeviceBlockOuts({ isAndroid, screenCompareOptions
|
|
|
211
424
|
// }
|
|
212
425
|
return rectangles;
|
|
213
426
|
}
|
|
427
|
+
/**
|
|
428
|
+
* Return a status bar rectangle for hybrid-app fallback when the overlay reports zero height.
|
|
429
|
+
* Uses IOS_OFFSETS / ANDROID_OFFSETS so the system status bar is blocked out in webview context.
|
|
430
|
+
* Android: uses device platformVersion (e.g. "14.0") as API level when present and in list; otherwise latest.
|
|
431
|
+
* iOS: keyed by screen size only (no OS version in data). When device not in list, uses latest entry.
|
|
432
|
+
*/
|
|
433
|
+
function getHybridAppStatusBarFallback(deviceRectangles, isAndroid, platformVersion) {
|
|
434
|
+
const { width: screenWidth, height: screenHeight } = deviceRectangles.screenSize;
|
|
435
|
+
if (screenWidth === 0 || screenHeight === 0) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
if (isAndroid) {
|
|
439
|
+
const apiLevels = Object.keys(ANDROID_OFFSETS).map(Number);
|
|
440
|
+
const latestApiLevel = apiLevels.length > 0 ? Math.max(...apiLevels) : 14;
|
|
441
|
+
const deviceApiLevel = platformVersion !== undefined ? parseInt(platformVersion, 10) : NaN;
|
|
442
|
+
const useApiLevel = Number.isInteger(deviceApiLevel) && apiLevels.includes(deviceApiLevel)
|
|
443
|
+
? deviceApiLevel
|
|
444
|
+
: latestApiLevel;
|
|
445
|
+
const statusBarHeight = ANDROID_OFFSETS[useApiLevel]?.STATUS_BAR ?? 24;
|
|
446
|
+
return {
|
|
447
|
+
x: 0,
|
|
448
|
+
y: 0,
|
|
449
|
+
width: screenWidth,
|
|
450
|
+
height: statusBarHeight,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const isIphone = screenWidth < 1024 && screenHeight < 1024;
|
|
454
|
+
const deviceType = isIphone ? 'IPHONE' : 'IPAD';
|
|
455
|
+
const portraitHeight = screenWidth > screenHeight ? screenWidth : screenHeight;
|
|
456
|
+
const keys = Object.keys(IOS_OFFSETS[deviceType]).map(Number);
|
|
457
|
+
const exactMatch = keys.includes(portraitHeight);
|
|
458
|
+
const offsetPortraitHeight = exactMatch
|
|
459
|
+
? portraitHeight
|
|
460
|
+
: (keys.length > 0 ? Math.max(...keys) : (isIphone ? 667 : 1024));
|
|
461
|
+
const orientation = screenWidth > screenHeight ? 'LANDSCAPE' : 'PORTRAIT';
|
|
462
|
+
const currentOffsets = IOS_OFFSETS[deviceType][offsetPortraitHeight]?.[orientation];
|
|
463
|
+
const statusBarHeight = currentOffsets?.STATUS_BAR ?? (isIphone ? 44 : 20);
|
|
464
|
+
return {
|
|
465
|
+
x: 0,
|
|
466
|
+
y: 0,
|
|
467
|
+
width: screenWidth,
|
|
468
|
+
height: statusBarHeight,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
214
471
|
/**
|
|
215
472
|
* Prepare all ignore rectangles for image comparison
|
|
216
473
|
*/
|
|
217
474
|
export async function prepareIgnoreRectangles(options) {
|
|
218
|
-
const { blockOut, ignoreRegions, deviceRectangles, devicePixelRatio, isMobile, isNativeContext, isAndroid, isAndroidNativeWebScreenshot, isViewPortScreenshot, imageCompareOptions, actualFilePath } = options;
|
|
475
|
+
const { blockOut, ignoreRegions, deviceRectangles, devicePixelRatio, isMobile, isNativeContext, isAndroid, isAndroidNativeWebScreenshot, isViewPortScreenshot, imageCompareOptions, isHybridApp, platformVersion, actualFilePath } = options;
|
|
219
476
|
// Get blockOut rectangles
|
|
220
477
|
let webStatusAddressToolBarOptions = [];
|
|
221
478
|
// Handle mobile web status/address/toolbar rectangles
|
|
@@ -230,6 +487,16 @@ export async function prepareIgnoreRectangles(options) {
|
|
|
230
487
|
isViewPortScreenshot,
|
|
231
488
|
};
|
|
232
489
|
webStatusAddressToolBarOptions.push(...(determineStatusAddressToolBarRectangles({ deviceRectangles, options: statusAddressToolBarOptions })) || []);
|
|
490
|
+
// Hybrid-app fallback: in webview the overlay often reports statusBarAndAddressBar height 0.
|
|
491
|
+
// Use native offsets (IOS_OFFSETS / ANDROID_OFFSETS) so the system status bar is still blocked out.
|
|
492
|
+
const needStatusBarFallback = imageCompareOptions.blockOutStatusBar !== false &&
|
|
493
|
+
(isHybridApp === true || deviceRectangles.statusBarAndAddressBar.height === 0);
|
|
494
|
+
if (needStatusBarFallback) {
|
|
495
|
+
const fallback = getHybridAppStatusBarFallback(deviceRectangles, isAndroid, platformVersion);
|
|
496
|
+
if (fallback && fallback.height > 0) {
|
|
497
|
+
webStatusAddressToolBarOptions.push(fallback);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
233
500
|
if (webStatusAddressToolBarOptions.length > 0) {
|
|
234
501
|
// There's an issue with the resemble lib when all the rectangles are 0,0,0,0, it will see this as a full
|
|
235
502
|
// blockout of the image and the comparison will succeed with 0 % difference.
|
|
@@ -268,29 +535,36 @@ export async function prepareIgnoreRectangles(options) {
|
|
|
268
535
|
}
|
|
269
536
|
}
|
|
270
537
|
}
|
|
271
|
-
//
|
|
272
|
-
const
|
|
273
|
-
// These come from the method
|
|
538
|
+
// blockOut and device bar rectangles are in CSS pixels, scale by DPR
|
|
539
|
+
const dprScaledBoxes = [
|
|
274
540
|
...blockOut,
|
|
275
|
-
// @TODO: I'm defaulting ignore regions for devices
|
|
276
|
-
// Need to check if this is the right thing to do for web and mobile browser tests
|
|
277
|
-
...ignoreRegions,
|
|
278
|
-
// Only get info about the status bars when we are in the web context
|
|
279
541
|
...webStatusAddressToolBarOptions
|
|
280
542
|
]
|
|
281
|
-
.map(
|
|
282
|
-
// Make sure all the rectangles are equal to the dpr for the screenshot
|
|
283
|
-
(rectangles) => {
|
|
543
|
+
.map((rectangles) => {
|
|
284
544
|
return calculateDprData({
|
|
285
|
-
// Adjust for the ResembleJS API
|
|
286
545
|
bottom: rectangles.y + rectangles.height,
|
|
287
546
|
right: rectangles.x + rectangles.width,
|
|
288
547
|
left: rectangles.x,
|
|
289
548
|
top: rectangles.y,
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
|
|
549
|
+
}, isAndroid ? 1 : devicePixelRatio);
|
|
550
|
+
});
|
|
551
|
+
// ignoreRegions: for web they are already in device pixels (pre-scaled by the caller).
|
|
552
|
+
// For native iOS app they are in logical pixels (getElementRect / statusBar/homeBar),
|
|
553
|
+
// so we scale by DPR here to match the device-pixel screenshot.
|
|
554
|
+
const isNativeIos = isNativeContext && isMobile && !isAndroid;
|
|
555
|
+
const preScaledIgnoreBoxes = ignoreRegions.map((rectangles) => {
|
|
556
|
+
const box = {
|
|
557
|
+
left: rectangles.x,
|
|
558
|
+
top: rectangles.y,
|
|
559
|
+
right: rectangles.x + rectangles.width,
|
|
560
|
+
bottom: rectangles.y + rectangles.height,
|
|
561
|
+
};
|
|
562
|
+
if (isNativeIos) {
|
|
563
|
+
return calculateDprData({ ...box }, devicePixelRatio);
|
|
564
|
+
}
|
|
565
|
+
return box;
|
|
293
566
|
});
|
|
567
|
+
const ignoredBoxes = [...dprScaledBoxes, ...preScaledIgnoreBoxes];
|
|
294
568
|
return {
|
|
295
569
|
ignoredBoxes,
|
|
296
570
|
hasIgnoreRectangles: ignoredBoxes.length > 0
|