@wdio/image-comparison-core 1.0.0 → 1.0.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 +37 -2
- package/dist/helpers/options.d.ts +1 -2
- package/dist/helpers/options.d.ts.map +1 -1
- package/dist/helpers/utils.interfaces.d.ts +1 -2
- package/dist/helpers/utils.interfaces.d.ts.map +1 -1
- package/dist/methods/images.d.ts.map +1 -1
- package/dist/methods/images.executeImageCompare.test.js +8 -9
- package/dist/methods/images.interfaces.d.ts +1 -2
- package/dist/methods/images.interfaces.d.ts.map +1 -1
- package/dist/methods/images.js +17 -6
- package/dist/methods/images.test.js +4 -0
- package/dist/methods/processDiffPixels.d.ts +1 -2
- package/dist/methods/processDiffPixels.d.ts.map +1 -1
- package/dist/methods/rectangles.d.ts +1 -1
- package/dist/methods/rectangles.d.ts.map +1 -1
- package/dist/methods/rectangles.interfaces.d.ts +1 -0
- package/dist/methods/rectangles.interfaces.d.ts.map +1 -1
- package/dist/methods/rectangles.js +36 -4
- package/dist/methods/rectangles.test.js +18 -18
- package/dist/methods/screenshots.d.ts.map +1 -1
- package/dist/methods/screenshots.interfaces.d.ts +1 -2
- package/dist/methods/screenshots.interfaces.d.ts.map +1 -1
- package/dist/methods/screenshots.js +164 -20
- package/dist/methods/screenshots.test.js +16 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @wdio/image-comparison-core
|
|
2
2
|
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 79d2b1d: # 🐛 Bugfixes
|
|
8
|
+
|
|
9
|
+
## #1073 Normalize Safari desktop screenshots by trimming macOS window corner radius and top window shadow
|
|
10
|
+
|
|
11
|
+
Safari desktop screenshots included the macOS window mask at the bottom and a shadow at the top. These artifacts caused incorrect detection of the viewable area for full page screenshots, which resulted in misaligned stitching. The viewable region is now calculated correctly by trimming these areas.
|
|
12
|
+
|
|
13
|
+
# Committers: 1
|
|
14
|
+
|
|
15
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
16
|
+
|
|
17
|
+
- 782b98a: # 🐛 Bugfixes
|
|
18
|
+
|
|
19
|
+
## #1000 fix incorrect cropping and stitching of last image for fullpage screenshots on mobile
|
|
20
|
+
|
|
21
|
+
The determination of the position of the last image in mobile fullpage webscreenshots was incorrect. This was mostly seen with iOS, but also had some impact on Android. This is now fixed
|
|
22
|
+
|
|
23
|
+
# Committers: 1
|
|
24
|
+
|
|
25
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
26
|
+
|
|
27
|
+
- 2c109b3: # 🐛 Bugfixes
|
|
28
|
+
|
|
29
|
+
## #1038 fix incorrect determination of ignore area
|
|
30
|
+
|
|
31
|
+
Ignore regions with `left: 0` and `right:0` lead to an incorrect width which lead to an incorrect ignore area. This is now fixed
|
|
32
|
+
|
|
33
|
+
# Committers: 1
|
|
34
|
+
|
|
35
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
36
|
+
|
|
3
37
|
## 1.0.0
|
|
4
38
|
|
|
5
39
|
### Major Changes
|
|
@@ -77,6 +111,7 @@
|
|
|
77
111
|
**Note**: This is an architectural improvement that modernizes the codebase while maintaining full backward compatibility. All existing functionality remains unchanged for users.
|
|
78
112
|
|
|
79
113
|
***
|
|
80
|
-
## Committers: 1
|
|
81
114
|
|
|
82
|
-
|
|
115
|
+
## Committers: 1
|
|
116
|
+
|
|
117
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ClassOptions, DefaultOptions } from './options.interfaces.js';
|
|
2
2
|
import type { MethodImageCompareCompareOptions, ScreenMethodImageCompareCompareOptions } from '../methods/images.interfaces.js';
|
|
3
|
-
import type { BeforeScreenshotOptions } from './beforeScreenshot.interfaces.js';
|
|
3
|
+
import type { BeforeScreenshotOptions, BeforeScreenshotResult } from './beforeScreenshot.interfaces.js';
|
|
4
4
|
import type { AfterScreenshotOptions } from './afterScreenshot.interfaces.js';
|
|
5
|
-
import type { BeforeScreenshotResult } from './beforeScreenshot.interfaces.js';
|
|
6
5
|
import type { InstanceData } from '../methods/instanceData.interfaces.js';
|
|
7
6
|
import type { ComparisonIgnoreOption } from '../resemble/compare.interfaces.js';
|
|
8
7
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/helpers/options.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC3E,OAAO,KAAK,EAAE,gCAAgC,EAAE,sCAAsC,EAAE,MAAM,iCAAiC,CAAA;AAC/H,OAAO,KAAK,EAAE,uBAAuB,EAAE,
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/helpers/options.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC3E,OAAO,KAAK,EAAE,gCAAgC,EAAE,sCAAsC,EAAE,MAAM,iCAAiC,CAAA;AAC/H,OAAO,KAAK,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AACvG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAS/E;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,cAAc,CA2DpE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACtC,OAAO,EAAE,sCAAsC,GAChD,sCAAsC,CAOxC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,gCAAgC,GAAG,gCAAgC,CAoBhH;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CACzC,YAAY,EAAE,GAAG,EACjB,aAAa,EAAE;IACX,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B,cAAc,CAAC,EAAE,WAAW,EAAE,CAAA;IAC9B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC/B,EACD,UAAU,EAAE;IACR,uBAAuB,EAAE,MAAM,CAAA;IAC/B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC/B,GACF,uBAAuB,CAazB;AAED,MAAM,WAAW,gCAAgC;IAE7C,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,eAAe,EAAE,OAAO,CAAA;IACxB,YAAY,EAAE,YAAY,CAAA;IAC1B,UAAU,EAAE;QACR,eAAe,EAAE,MAAM,CAAA;QACvB,eAAe,EAAE,OAAO,CAAA;KAC3B,CAAA;IAGD,oBAAoB,CAAC,EAAE,sBAAsB,CAAA;IAC7C,aAAa,CAAC,EAAE,uBAAuB,CAAA;CAC1C;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,EACxC,WAAW,EACX,OAAO,EACP,GAAG,EACH,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,UAAU,EACb,EAAE,gCAAgC,GAAG,sBAAsB,CAyE3D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,mBAAmB,EAAE,gCAAgC,GAAG,sBAAsB,EAAE,CAQpH"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { BaseCoordinates, BaseDimensions, FilePaths, FolderPaths } from '../base.interfaces.js';
|
|
1
|
+
import type { BaseCoordinates, BaseDimensions, FilePaths, FolderPaths, Folders } from '../base.interfaces.js';
|
|
2
2
|
import type { DeviceRectangles } from '../methods/rectangles.interfaces.js';
|
|
3
|
-
import type { Folders } from '../base.interfaces.js';
|
|
4
3
|
export interface GetAndCreatePathOptions {
|
|
5
4
|
/** The name of the browser */
|
|
6
5
|
browserName: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.interfaces.d.ts","sourceRoot":"","sources":["../../src/helpers/utils.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"utils.interfaces.d.ts","sourceRoot":"","sources":["../../src/helpers/utils.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC7G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAA;AAE3E,MAAM,WAAW,uBAAuB;IACpC,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,0DAA0D;IAC1D,eAAe,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IAClC,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACtD,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iCAAiC;IAC9C,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,+BAA+B;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,mBAAmB,EAAE,OAAO,CAAC;IAC7B,qCAAqC;IACrC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB;IACtB,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,8BAA8B;IAC3C,gCAAgC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,+BAA+B;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB;IACtB,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,cAAe,SAAQ,cAAc;CAAG;AAEzD,MAAM,WAAW,gCAAgC;IAC7C,2BAA2B;IAC3B,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC;IACrC,oCAAoC;IACpC,uBAAuB,EAAE,gBAAgB,CAAC;IAC1C,4BAA4B;IAC5B,eAAe,EAAE,OAAO,CAAC;IACzB,4BAA4B;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,wBAAwB;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,6DAA6D;IAC7D,mBAAmB,EAAE,OAAO,CAAC;IAC7B,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACvC,2BAA2B;IAC3B,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC;IACrC,wBAAwB;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,4BAA4B;IAC5B,eAAe,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IAClC,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IAClC,2BAA2B;IAC3B,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC;IACrC,wBAAwB;IACxB,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,yBAA0B,SAAQ,eAAe;IAC9D,2BAA2B;IAC3B,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC;IACrC,wBAAwB;IACxB,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACjC,mBAAmB;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IAEnB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,GAAG,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,4BAA4B,EAAE,OAAO,CAAC;IAEtC,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,kBAAkB;IAClB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;IAEzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kCAAkC;IAC/C,yBAAyB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,+BAA+B;IAC/B,YAAY,EAAE,GAAG,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,GAAG,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC1B,2CAA2C;IAC3C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,mCAAmC;IACnC,eAAe,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,yBAAyB;IACtC,mFAAmF;IACnF,oBAAoB,EAAE,oBAAoB,CAAC;CAC9C;AAED,MAAM,WAAW,yBAAyB;IACtC,8CAA8C;IAC9C,cAAc,EAAE;QACZ,GAAG,EAAE,GAAG,CAAC;QACT,MAAM,EAAE,GAAG,CAAC;KACf,CAAC;IACF,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,wBAAwB;IACxB,gBAAgB,EAAE,GAAG,CAAC;IACtB,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,8BAA8B;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,4BAA4B,EAAE,OAAO,CAAC;IACtC,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iDAAiD;IACjD,aAAa,CAAC,EAAE,GAAG,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,qCAAqC;IAClD,iEAAiE;IACjE,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,0BAA0B;IAC1B,iBAAiB,EAAE,GAAG,CAAC;IACvB,6BAA6B;IAC7B,oBAAoB,EAAE,GAAG,CAAC;IAC1B,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kDAAkD;IAClD,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,iCAAkC,SAAQ,OAAO;IAC9D,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,mCAAmC;IACnC,eAAe,EAAE,OAAO,CAAC;IACzB,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAoB,SAAQ,SAAS,EAAE,WAAW;CAAG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../src/methods/images.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../src/methods/images.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import logger from '@wdio/logger';
|
|
4
|
-
import { promises as fsPromises } from 'node:fs';
|
|
5
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { promises as fsPromises, readFileSync, writeFileSync } from 'node:fs';
|
|
6
5
|
import * as utils from '../helpers/utils.js';
|
|
7
6
|
import * as rectangles from './rectangles.js';
|
|
8
7
|
import * as processDiffPixels from './processDiffPixels.js';
|
|
@@ -196,7 +195,7 @@ describe('executeImageCompare', () => {
|
|
|
196
195
|
diffFilePath: '/mock/diff/test.png'
|
|
197
196
|
});
|
|
198
197
|
vi.mocked(rectangles.determineStatusAddressToolBarRectangles).mockReturnValue(null);
|
|
199
|
-
vi.mocked(rectangles.prepareIgnoreRectangles).
|
|
198
|
+
vi.mocked(rectangles.prepareIgnoreRectangles).mockResolvedValue({
|
|
200
199
|
ignoredBoxes: [],
|
|
201
200
|
hasIgnoreRectangles: false
|
|
202
201
|
});
|
|
@@ -262,7 +261,7 @@ describe('executeImageCompare', () => {
|
|
|
262
261
|
}
|
|
263
262
|
}
|
|
264
263
|
};
|
|
265
|
-
vi.mocked(rectangles.prepareIgnoreRectangles).
|
|
264
|
+
vi.mocked(rectangles.prepareIgnoreRectangles).mockResolvedValue({
|
|
266
265
|
ignoredBoxes: [{ left: 0, top: 0, right: 100, bottom: 50 }],
|
|
267
266
|
hasIgnoreRectangles: true
|
|
268
267
|
});
|
|
@@ -294,7 +293,7 @@ describe('executeImageCompare', () => {
|
|
|
294
293
|
...mockOptions,
|
|
295
294
|
folderOptions: { ...mockOptions.folderOptions, isMobile: true }
|
|
296
295
|
};
|
|
297
|
-
vi.mocked(rectangles.prepareIgnoreRectangles).
|
|
296
|
+
vi.mocked(rectangles.prepareIgnoreRectangles).mockResolvedValue({
|
|
298
297
|
ignoredBoxes: [{ left: 10, top: 10, right: 60, bottom: 60 }], // Only non-zero rectangle
|
|
299
298
|
hasIgnoreRectangles: true
|
|
300
299
|
});
|
|
@@ -334,7 +333,7 @@ describe('executeImageCompare', () => {
|
|
|
334
333
|
}
|
|
335
334
|
}
|
|
336
335
|
};
|
|
337
|
-
vi.mocked(rectangles.prepareIgnoreRectangles).
|
|
336
|
+
vi.mocked(rectangles.prepareIgnoreRectangles).mockResolvedValue({
|
|
338
337
|
ignoredBoxes: [],
|
|
339
338
|
hasIgnoreRectangles: false
|
|
340
339
|
});
|
|
@@ -372,7 +371,7 @@ describe('executeImageCompare', () => {
|
|
|
372
371
|
}
|
|
373
372
|
}
|
|
374
373
|
};
|
|
375
|
-
vi.mocked(rectangles.prepareIgnoreRectangles).
|
|
374
|
+
vi.mocked(rectangles.prepareIgnoreRectangles).mockResolvedValue({
|
|
376
375
|
ignoredBoxes: [
|
|
377
376
|
{ left: 0, top: 0, right: 100, bottom: 50 },
|
|
378
377
|
{ left: 200, top: 200, right: 300, bottom: 300 }
|
|
@@ -533,7 +532,7 @@ describe('executeImageCompare', () => {
|
|
|
533
532
|
devicePixelRatio: 3,
|
|
534
533
|
ignoreRegions: [{ x: 0, y: 0, width: 100, height: 50 }]
|
|
535
534
|
};
|
|
536
|
-
vi.mocked(rectangles.prepareIgnoreRectangles).
|
|
535
|
+
vi.mocked(rectangles.prepareIgnoreRectangles).mockResolvedValue({
|
|
537
536
|
ignoredBoxes: [{ left: 0, top: 0, right: 100, bottom: 50 }],
|
|
538
537
|
hasIgnoreRectangles: true
|
|
539
538
|
});
|
|
@@ -635,7 +634,7 @@ describe('executeImageCompare', () => {
|
|
|
635
634
|
}
|
|
636
635
|
}
|
|
637
636
|
};
|
|
638
|
-
vi.mocked(rectangles.prepareIgnoreRectangles).
|
|
637
|
+
vi.mocked(rectangles.prepareIgnoreRectangles).mockResolvedValue({
|
|
639
638
|
ignoredBoxes: [{ bottom: 50, right: 100, left: 0, top: 0 }],
|
|
640
639
|
hasIgnoreRectangles: true
|
|
641
640
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { RectanglesOutput } from './rectangles.interfaces.js';
|
|
1
|
+
import type { RectanglesOutput, DeviceRectangles } from './rectangles.interfaces.js';
|
|
2
2
|
import type { BaseCoordinates, BaseDeviceInfo, BaseDimensions, BaseImageCompareOptions, BaseMobileBlockOutOptions, Folders } from '../base.interfaces.js';
|
|
3
3
|
import type { TestContext } from './compareReport.interfaces.js';
|
|
4
|
-
import type { DeviceRectangles } from './rectangles.interfaces.js';
|
|
5
4
|
import type { WicElement } from 'src/index.js';
|
|
6
5
|
export interface ResizeDimensions {
|
|
7
6
|
/** The bottom margin */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"images.interfaces.d.ts","sourceRoot":"","sources":["../../src/methods/images.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"images.interfaces.d.ts","sourceRoot":"","sources":["../../src/methods/images.interfaces.ts"],"names":[],"mappings":"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"}
|
package/dist/methods/images.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { fileURLToPath } from 'node:url';
|
|
2
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { promises as fsPromises, constants } from 'node:fs';
|
|
2
|
+
import { readFileSync, writeFileSync, promises as fsPromises, constants } from 'node:fs';
|
|
4
3
|
import { dirname, join } from 'node:path';
|
|
5
4
|
import { Jimp, JimpMime } from 'jimp';
|
|
6
5
|
import logger from '@wdio/logger';
|
|
@@ -248,7 +247,7 @@ export async function executeImageCompare({ isViewPortScreenshot, isNativeContex
|
|
|
248
247
|
// 4a.Determine the ignore options
|
|
249
248
|
const ignore = prepareIgnoreOptions(imageCompareOptions);
|
|
250
249
|
// 4b. Determine the ignore rectangles for the block outs
|
|
251
|
-
const { ignoredBoxes } = prepareIgnoreRectangles({
|
|
250
|
+
const { ignoredBoxes } = await prepareIgnoreRectangles({
|
|
252
251
|
blockOut: imageCompareOptions.blockOut ?? [],
|
|
253
252
|
ignoreRegions,
|
|
254
253
|
deviceRectangles,
|
|
@@ -262,7 +261,8 @@ export async function executeImageCompare({ isViewPortScreenshot, isNativeContex
|
|
|
262
261
|
blockOutSideBar: imageCompareOptions.blockOutSideBar,
|
|
263
262
|
blockOutStatusBar: imageCompareOptions.blockOutStatusBar,
|
|
264
263
|
blockOutToolBar: imageCompareOptions.blockOutToolBar,
|
|
265
|
-
}
|
|
264
|
+
},
|
|
265
|
+
actualFilePath: isViewPortScreenshot ? undefined : actualFilePath,
|
|
266
266
|
});
|
|
267
267
|
const compareOptions = {
|
|
268
268
|
ignore,
|
|
@@ -327,9 +327,20 @@ export async function makeFullPageBase64Image(screenshotsData, { devicePixelRati
|
|
|
327
327
|
const { height: screenshotHeight, width: screenshotWidth } = getBase64ScreenshotSize(currentScreenshot, devicePixelRatio);
|
|
328
328
|
const isRotated = isLandscape && screenshotHeight > screenshotWidth;
|
|
329
329
|
const newBase64Image = isRotated ? await rotateBase64Image({ base64Image: currentScreenshot, degrees: 90 }) : currentScreenshot;
|
|
330
|
-
const { canvasYPosition, imageHeight,
|
|
330
|
+
const { canvasYPosition, imageHeight, imageXPosition, imageYPosition } = screenshotsData.data[i];
|
|
331
331
|
const image = await Jimp.read(Buffer.from(newBase64Image, 'base64'));
|
|
332
|
-
|
|
332
|
+
// Clamp crop dimensions to fit within the actual image bounds
|
|
333
|
+
// This is especially important for the last image where the calculated height might exceed available pixels
|
|
334
|
+
const actualImageWidth = image.bitmap.width;
|
|
335
|
+
const actualImageHeight = image.bitmap.height;
|
|
336
|
+
const clampedCropX = Math.max(0, Math.min(imageXPosition, actualImageWidth - 1));
|
|
337
|
+
const clampedCropY = Math.max(0, Math.min(imageYPosition, actualImageHeight - 1));
|
|
338
|
+
// Ensure the cropped width matches the canvas width to avoid 1px gaps due to rounding
|
|
339
|
+
// The canvas width is the target, but we must not exceed the available image bounds
|
|
340
|
+
const maxAvailableWidth = actualImageWidth - clampedCropX;
|
|
341
|
+
const clampedCropWidth = Math.min(canvasWidth, maxAvailableWidth);
|
|
342
|
+
const clampedCropHeight = Math.min(imageHeight, actualImageHeight - clampedCropY);
|
|
343
|
+
canvas.composite(image.crop({ x: clampedCropX, y: clampedCropY, w: clampedCropWidth, h: clampedCropHeight }), 0, canvasYPosition);
|
|
333
344
|
}
|
|
334
345
|
const base64FullPageImage = await canvas.getBase64(JimpMime.png);
|
|
335
346
|
return base64FullPageImage.replace(/^data:image\/png;base64,/, '');
|
|
@@ -989,6 +989,10 @@ describe('makeFullPageBase64Image', () => {
|
|
|
989
989
|
getBase64: vi.fn().mockResolvedValue('data:image/png;base64,fullPageImageData'),
|
|
990
990
|
};
|
|
991
991
|
mockImage = {
|
|
992
|
+
bitmap: {
|
|
993
|
+
width: 1000,
|
|
994
|
+
height: 800,
|
|
995
|
+
},
|
|
992
996
|
crop: vi.fn().mockReturnThis(),
|
|
993
997
|
composite: vi.fn().mockReturnThis(),
|
|
994
998
|
getBase64: vi.fn().mockResolvedValue('data:image/png;base64,mockImageData'),
|
|
@@ -44,8 +44,7 @@
|
|
|
44
44
|
* [0-0] Number merged: 24
|
|
45
45
|
*/
|
|
46
46
|
import type { Pixel, WicImageCompareOptions } from 'src/methods/images.interfaces.js';
|
|
47
|
-
import type { BoundingBox } from './rectangles.interfaces.js';
|
|
48
|
-
import type { IgnoreBoxes } from './rectangles.interfaces.js';
|
|
47
|
+
import type { BoundingBox, IgnoreBoxes } from './rectangles.interfaces.js';
|
|
49
48
|
import type { CompareData } from '../resemble/compare.interfaces.js';
|
|
50
49
|
declare function processDiffPixels(diffPixels: Pixel[], proximity: number): BoundingBox[];
|
|
51
50
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processDiffPixels.d.ts","sourceRoot":"","sources":["../../src/methods/processDiffPixels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AACrF,OAAO,KAAK,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"processDiffPixels.d.ts","sourceRoot":"","sources":["../../src/methods/processDiffPixels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AACrF,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAqFpE,iBAAS,iBAAiB,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAkHhF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACrC,IAAI,EAAE,WAAW,EACjB,mBAAmB,EAAE,sBAAsB,EAC3C,YAAY,EAAE,WAAW,EAAE,EAC3B,YAAY,EAAE,MAAM,EACpB,qBAAqB,EAAE,MAAM,GAC9B,OAAO,CAAC;IAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CA2BpE;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -47,5 +47,5 @@ export declare function determineDeviceBlockOuts({ isAndroid, screenCompareOptio
|
|
|
47
47
|
/**
|
|
48
48
|
* Prepare all ignore rectangles for image comparison
|
|
49
49
|
*/
|
|
50
|
-
export declare function prepareIgnoreRectangles(options: PrepareIgnoreRectanglesOptions): PreparedIgnoreRectangles
|
|
50
|
+
export declare function prepareIgnoreRectangles(options: PrepareIgnoreRectanglesOptions): Promise<PreparedIgnoreRectangles>;
|
|
51
51
|
//# sourceMappingURL=rectangles.d.ts.map
|
|
@@ -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":"AAGA,OAAO,KAAK,EACR,+BAA+B,EAC/B,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,aAAa,EAAE,GACzB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAY7B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,YAAY,EAAE,EAAE,+BAA+B,+BAwBhI;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAyGxH"}
|
|
@@ -118,6 +118,7 @@ export interface PrepareIgnoreRectanglesOptions {
|
|
|
118
118
|
blockOutStatusBar?: boolean;
|
|
119
119
|
blockOutToolBar?: boolean;
|
|
120
120
|
};
|
|
121
|
+
actualFilePath?: string;
|
|
121
122
|
}
|
|
122
123
|
export interface PreparedIgnoreRectangles {
|
|
123
124
|
/** The final ignored boxes ready for resemble comparison */
|
|
@@ -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,3 +1,4 @@
|
|
|
1
|
+
import { Jimp } from 'jimp';
|
|
1
2
|
import { calculateDprData, getBase64ScreenshotSize, isObject } from '../helpers/utils.js';
|
|
2
3
|
import { getElementPositionAndroid, getElementPositionDesktop, getElementWebviewPosition } from './elementPosition.js';
|
|
3
4
|
/**
|
|
@@ -213,8 +214,8 @@ export async function determineDeviceBlockOuts({ isAndroid, screenCompareOptions
|
|
|
213
214
|
/**
|
|
214
215
|
* Prepare all ignore rectangles for image comparison
|
|
215
216
|
*/
|
|
216
|
-
export function prepareIgnoreRectangles(options) {
|
|
217
|
-
const { blockOut, ignoreRegions, deviceRectangles, devicePixelRatio, isMobile, isNativeContext, isAndroid, isAndroidNativeWebScreenshot, isViewPortScreenshot, imageCompareOptions } = options;
|
|
217
|
+
export async function prepareIgnoreRectangles(options) {
|
|
218
|
+
const { blockOut, ignoreRegions, deviceRectangles, devicePixelRatio, isMobile, isNativeContext, isAndroid, isAndroidNativeWebScreenshot, isViewPortScreenshot, imageCompareOptions, actualFilePath } = options;
|
|
218
219
|
// Get blockOut rectangles
|
|
219
220
|
let webStatusAddressToolBarOptions = [];
|
|
220
221
|
// Handle mobile web status/address/toolbar rectangles
|
|
@@ -231,9 +232,40 @@ export function prepareIgnoreRectangles(options) {
|
|
|
231
232
|
webStatusAddressToolBarOptions.push(...(determineStatusAddressToolBarRectangles({ deviceRectangles, options: statusAddressToolBarOptions })) || []);
|
|
232
233
|
if (webStatusAddressToolBarOptions.length > 0) {
|
|
233
234
|
// There's an issue with the resemble lib when all the rectangles are 0,0,0,0, it will see this as a full
|
|
234
|
-
// blockout of the image and the comparison will succeed with 0 % difference
|
|
235
|
+
// blockout of the image and the comparison will succeed with 0 % difference.
|
|
236
|
+
// Additionally, rectangles with either width or height equal to 0 will result in an entire axis being ignored
|
|
237
|
+
// due to how resemble handles falsy values. Filter those out up front.
|
|
235
238
|
webStatusAddressToolBarOptions = webStatusAddressToolBarOptions
|
|
236
|
-
.filter((rectangle) => !(rectangle.x === 0 && rectangle.y === 0 && rectangle.width === 0 && rectangle.height === 0))
|
|
239
|
+
.filter((rectangle) => !(rectangle.x === 0 && rectangle.y === 0 && rectangle.width === 0 && rectangle.height === 0))
|
|
240
|
+
.filter((rectangle) => rectangle.width > 0 && rectangle.height > 0);
|
|
241
|
+
}
|
|
242
|
+
// Handle home bar (iOS) blockOut for full page screenshots
|
|
243
|
+
// The toolbar should be blocked out by default (when blockOutToolBar is true or undefined)
|
|
244
|
+
if (!isViewPortScreenshot && imageCompareOptions.blockOutToolBar !== false && actualFilePath) {
|
|
245
|
+
try {
|
|
246
|
+
// For iOS: block out home bar
|
|
247
|
+
if (!isAndroid && deviceRectangles.homeBar.height > 0) {
|
|
248
|
+
const image = await Jimp.read(actualFilePath);
|
|
249
|
+
const imageHeightDevicePixels = image.bitmap.height;
|
|
250
|
+
const imageHeightCssPixels = imageHeightDevicePixels / devicePixelRatio;
|
|
251
|
+
// Adjust home bar X position relative to the viewport (full page image only contains viewport)
|
|
252
|
+
const viewportXCssPixels = deviceRectangles.viewport.x;
|
|
253
|
+
const homeBarXRelativeToViewport = deviceRectangles.homeBar.x - viewportXCssPixels;
|
|
254
|
+
// Position the home bar at the bottom of the full page image
|
|
255
|
+
const homeBarYFullPageCssPixels = imageHeightCssPixels - deviceRectangles.homeBar.height;
|
|
256
|
+
const homeBarRectangle = {
|
|
257
|
+
x: homeBarXRelativeToViewport,
|
|
258
|
+
y: homeBarYFullPageCssPixels,
|
|
259
|
+
width: deviceRectangles.homeBar.width,
|
|
260
|
+
height: deviceRectangles.homeBar.height,
|
|
261
|
+
};
|
|
262
|
+
webStatusAddressToolBarOptions.push(homeBarRectangle);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch (_error) {
|
|
266
|
+
// If we can't read the image, skip adding the toolbar blockOut
|
|
267
|
+
// This shouldn't happen in normal operation, but we don't want to fail the comparison
|
|
268
|
+
}
|
|
237
269
|
}
|
|
238
270
|
}
|
|
239
271
|
// Combine all ignore regions
|
|
@@ -710,37 +710,37 @@ describe('rectangles', () => {
|
|
|
710
710
|
});
|
|
711
711
|
});
|
|
712
712
|
describe('prepareIgnoreRectangles', () => {
|
|
713
|
-
it('should return empty ignored boxes and false hasIgnoreRectangles when no inputs provided', () => {
|
|
713
|
+
it('should return empty ignored boxes and false hasIgnoreRectangles when no inputs provided', async () => {
|
|
714
714
|
const options = createPrepareIgnoreRectanglesOptions();
|
|
715
|
-
const result = prepareIgnoreRectangles(options);
|
|
715
|
+
const result = await prepareIgnoreRectangles(options);
|
|
716
716
|
expect(result).toEqual({
|
|
717
717
|
ignoredBoxes: [],
|
|
718
718
|
hasIgnoreRectangles: false
|
|
719
719
|
});
|
|
720
720
|
});
|
|
721
|
-
it('should handle blockOut and ignoreRegions without mobile web rectangles', () => {
|
|
721
|
+
it('should handle blockOut and ignoreRegions without mobile web rectangles', async () => {
|
|
722
722
|
const options = createPrepareIgnoreRectanglesOptions({
|
|
723
723
|
blockOut: [{ x: 10, y: 20, width: 100, height: 50 }],
|
|
724
724
|
ignoreRegions: [{ x: 200, y: 300, width: 150, height: 75 }],
|
|
725
725
|
devicePixelRatio: 2,
|
|
726
726
|
isAndroid: false
|
|
727
727
|
});
|
|
728
|
-
const result = prepareIgnoreRectangles(options);
|
|
728
|
+
const result = await prepareIgnoreRectangles(options);
|
|
729
729
|
expect(result.hasIgnoreRectangles).toBe(true);
|
|
730
730
|
expect(result.ignoredBoxes).toMatchSnapshot();
|
|
731
731
|
});
|
|
732
|
-
it('should handle Android device with different DPR calculation', () => {
|
|
732
|
+
it('should handle Android device with different DPR calculation', async () => {
|
|
733
733
|
const options = createPrepareIgnoreRectanglesOptions({
|
|
734
734
|
blockOut: [{ x: 10, y: 20, width: 100, height: 50 }],
|
|
735
735
|
ignoreRegions: [{ x: 200, y: 300, width: 150, height: 75 }],
|
|
736
736
|
devicePixelRatio: 3,
|
|
737
737
|
isAndroid: true
|
|
738
738
|
});
|
|
739
|
-
const result = prepareIgnoreRectangles(options);
|
|
739
|
+
const result = await prepareIgnoreRectangles(options);
|
|
740
740
|
expect(result.hasIgnoreRectangles).toBe(true);
|
|
741
741
|
expect(result.ignoredBoxes).toMatchSnapshot();
|
|
742
742
|
});
|
|
743
|
-
it('should skip mobile web rectangles when not mobile', () => {
|
|
743
|
+
it('should skip mobile web rectangles when not mobile', async () => {
|
|
744
744
|
const options = createPrepareIgnoreRectanglesOptions({
|
|
745
745
|
isMobile: false,
|
|
746
746
|
isNativeContext: false,
|
|
@@ -750,13 +750,13 @@ describe('rectangles', () => {
|
|
|
750
750
|
blockOutToolBar: true,
|
|
751
751
|
}
|
|
752
752
|
});
|
|
753
|
-
const result = prepareIgnoreRectangles(options);
|
|
753
|
+
const result = await prepareIgnoreRectangles(options);
|
|
754
754
|
expect(result).toEqual({
|
|
755
755
|
ignoredBoxes: [],
|
|
756
756
|
hasIgnoreRectangles: false
|
|
757
757
|
});
|
|
758
758
|
});
|
|
759
|
-
it('should skip mobile web rectangles when in native context', () => {
|
|
759
|
+
it('should skip mobile web rectangles when in native context', async () => {
|
|
760
760
|
const options = createPrepareIgnoreRectanglesOptions({
|
|
761
761
|
isMobile: true,
|
|
762
762
|
isNativeContext: true,
|
|
@@ -766,13 +766,13 @@ describe('rectangles', () => {
|
|
|
766
766
|
blockOutToolBar: true,
|
|
767
767
|
}
|
|
768
768
|
});
|
|
769
|
-
const result = prepareIgnoreRectangles(options);
|
|
769
|
+
const result = await prepareIgnoreRectangles(options);
|
|
770
770
|
expect(result).toEqual({
|
|
771
771
|
ignoredBoxes: [],
|
|
772
772
|
hasIgnoreRectangles: false
|
|
773
773
|
});
|
|
774
774
|
});
|
|
775
|
-
it('should include mobile web rectangles when mobile and not native context', () => {
|
|
775
|
+
it('should include mobile web rectangles when mobile and not native context', async () => {
|
|
776
776
|
const options = createPrepareIgnoreRectanglesOptions({
|
|
777
777
|
isMobile: true,
|
|
778
778
|
isNativeContext: false,
|
|
@@ -786,11 +786,11 @@ describe('rectangles', () => {
|
|
|
786
786
|
blockOutToolBar: true,
|
|
787
787
|
}
|
|
788
788
|
});
|
|
789
|
-
const result = prepareIgnoreRectangles(options);
|
|
789
|
+
const result = await prepareIgnoreRectangles(options);
|
|
790
790
|
expect(result.hasIgnoreRectangles).toBe(true);
|
|
791
791
|
expect(result.ignoredBoxes).toMatchSnapshot();
|
|
792
792
|
});
|
|
793
|
-
it('should filter out zero-sized rectangles from mobile web context', () => {
|
|
793
|
+
it('should filter out zero-sized rectangles from mobile web context', async () => {
|
|
794
794
|
const deviceRectanglesWithZeros = createDeviceRectanglesWithData({
|
|
795
795
|
statusBarAndAddressBar: { x: 0, y: 0, width: 0, height: 0 }, // Will be filtered
|
|
796
796
|
bottomBar: { x: 0, y: 0, width: 390, height: 47 }, // Will be kept
|
|
@@ -808,11 +808,11 @@ describe('rectangles', () => {
|
|
|
808
808
|
blockOutToolBar: true,
|
|
809
809
|
}
|
|
810
810
|
});
|
|
811
|
-
const result = prepareIgnoreRectangles(options);
|
|
811
|
+
const result = await prepareIgnoreRectangles(options);
|
|
812
812
|
expect(result.hasIgnoreRectangles).toBe(true);
|
|
813
813
|
expect(result.ignoredBoxes).toMatchSnapshot();
|
|
814
814
|
});
|
|
815
|
-
it('should handle empty web rectangles without filtering', () => {
|
|
815
|
+
it('should handle empty web rectangles without filtering', async () => {
|
|
816
816
|
const options = createPrepareIgnoreRectanglesOptions({
|
|
817
817
|
isMobile: true,
|
|
818
818
|
isNativeContext: false,
|
|
@@ -825,13 +825,13 @@ describe('rectangles', () => {
|
|
|
825
825
|
blockOutSideBar: false,
|
|
826
826
|
}
|
|
827
827
|
});
|
|
828
|
-
const result = prepareIgnoreRectangles(options);
|
|
828
|
+
const result = await prepareIgnoreRectangles(options);
|
|
829
829
|
expect(result).toEqual({
|
|
830
830
|
ignoredBoxes: [],
|
|
831
831
|
hasIgnoreRectangles: false
|
|
832
832
|
});
|
|
833
833
|
});
|
|
834
|
-
it('should combine all rectangle sources correctly', () => {
|
|
834
|
+
it('should combine all rectangle sources correctly', async () => {
|
|
835
835
|
const options = createPrepareIgnoreRectanglesOptions({
|
|
836
836
|
blockOut: [{ x: 10, y: 20, width: 100, height: 50 }],
|
|
837
837
|
ignoreRegions: [{ x: 200, y: 300, width: 150, height: 75 }],
|
|
@@ -845,7 +845,7 @@ describe('rectangles', () => {
|
|
|
845
845
|
blockOutStatusBar: true,
|
|
846
846
|
}
|
|
847
847
|
});
|
|
848
|
-
const result = prepareIgnoreRectangles(options);
|
|
848
|
+
const result = await prepareIgnoreRectangles(options);
|
|
849
849
|
expect(result.hasIgnoreRectangles).toBe(true);
|
|
850
850
|
expect(result.ignoredBoxes).toMatchSnapshot();
|
|
851
851
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshots.d.ts","sourceRoot":"","sources":["../../src/methods/screenshots.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,yBAAyB,EACzB,qCAAqC,EACrC,uBAAuB,EACvB,wBAAwB,EACxB,4BAA4B,EAC/B,MAAM,6BAA6B,CAAA;AAGpC,OAAO,KAAK,EAA4B,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAK5F;;GAEG;AACH,wBAAsB,yCAAyC,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,qCAAqC,GAAG,OAAO,CAAC,uBAAuB,CAAC,
|
|
1
|
+
{"version":3,"file":"screenshots.d.ts","sourceRoot":"","sources":["../../src/methods/screenshots.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,yBAAyB,EACzB,qCAAqC,EACrC,uBAAuB,EACvB,wBAAwB,EACxB,4BAA4B,EAC/B,MAAM,6BAA6B,CAAA;AAGpC,OAAO,KAAK,EAA4B,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAK5F;;GAEG;AACH,wBAAsB,yCAAyC,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,qCAAqC,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA8LtL;AAED;;GAEG;AACH,wBAAsB,6CAA6C,CAAC,eAAe,EAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA2F7K;AAED;;GAEG;AACH,wBAAsB,iCAAiC,CAAC,eAAe,EAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAmNjK;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAEhG;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,EAC3C,eAAe,EACf,MAAmB,EACnB,IAAI,GACP,EAAE;IACC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC;IACrC,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACjC,IAAI,CAAC,EAAE,gBAAgB,CAAC;CAC3B,GAAG,OAAO,CAAC,MAAM,CAAC,CASlB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,GAAG,QAa/C;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,EAC3C,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,QAAgB,EAChB,uBAAuB,EACvB,UAAU,EACV,WAAW,EACX,SAAS,EACT,+BAA+B,EAC/B,4BAA4B,EAC5B,KAAK,EACL,WAAW,EACX,oBAAoB,GACvB,EAAE,wBAAwB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAgElE"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { DeviceRectangles } from './rectangles.interfaces.js';
|
|
2
|
-
import type { RectanglesOutput } from './rectangles.interfaces.js';
|
|
1
|
+
import type { DeviceRectangles, RectanglesOutput } from './rectangles.interfaces.js';
|
|
3
2
|
/**
|
|
4
3
|
* Universal screenshot information that applies to ALL screenshot scenarios.
|
|
5
4
|
* This includes desktop browsers on high-DPI displays, mobile browsers, and native apps.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshots.interfaces.d.ts","sourceRoot":"","sources":["../../src/methods/screenshots.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"screenshots.interfaces.d.ts","sourceRoot":"","sources":["../../src/methods/screenshots.interfaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,7 @@ export async function getMobileFullPageNativeWebScreenshotsData(browserInstance,
|
|
|
29
29
|
const amountOfScrollsArray = [];
|
|
30
30
|
let scrollHeight;
|
|
31
31
|
let isRotated = false;
|
|
32
|
+
let actualFullPageWidth;
|
|
32
33
|
for (let i = 0; i <= amountOfScrollsArray.length; i++) {
|
|
33
34
|
// Determine and start scrolling
|
|
34
35
|
const scrollY = effectiveViewportHeight * i;
|
|
@@ -82,11 +83,21 @@ export async function getMobileFullPageNativeWebScreenshotsData(browserInstance,
|
|
|
82
83
|
isRotated = Boolean(isLandscape && effectiveViewportHeight > viewportWidth);
|
|
83
84
|
// Determine scroll height and check if we need to scroll again
|
|
84
85
|
scrollHeight = await browserInstance.execute(getDocumentScrollHeight);
|
|
86
|
+
// Get actual scroll position after scrolling to verify it matches scrollY
|
|
87
|
+
const actualScrollInfo = await browserInstance.execute(() => ({
|
|
88
|
+
scrollTop: window.pageYOffset || document.documentElement.scrollTop,
|
|
89
|
+
}));
|
|
85
90
|
if (scrollHeight && (scrollY + effectiveViewportHeight < scrollHeight)) {
|
|
86
91
|
amountOfScrollsArray.push(amountOfScrollsArray.length);
|
|
87
92
|
}
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
// For the last image, use the actual scroll position instead of the intended scrollY
|
|
94
|
+
// because the browser may not be able to scroll to the exact position we requested
|
|
95
|
+
const isLastImage = amountOfScrollsArray.length === i;
|
|
96
|
+
const scrollPositionForCalculation = isLastImage && actualScrollInfo
|
|
97
|
+
? actualScrollInfo.scrollTop
|
|
98
|
+
: scrollY;
|
|
99
|
+
const remainingContent = scrollHeight ? scrollHeight - scrollPositionForCalculation : 0;
|
|
100
|
+
const imageHeight = isLastImage && scrollHeight && remainingContent > 0
|
|
90
101
|
? remainingContent
|
|
91
102
|
: effectiveViewportHeight;
|
|
92
103
|
if (amountOfScrollsArray.length === i && remainingContent <= 0) {
|
|
@@ -94,19 +105,39 @@ export async function getMobileFullPageNativeWebScreenshotsData(browserInstance,
|
|
|
94
105
|
}
|
|
95
106
|
// The starting position for cropping could be different for the last image
|
|
96
107
|
// The cropping always needs to start at status and address bar height and the address bar shadow padding
|
|
97
|
-
|
|
108
|
+
// For the last image, if imageHeight > effectiveViewportHeight, we crop from the top (y=0)
|
|
109
|
+
// Otherwise, we crop from the bottom to align with previous images
|
|
110
|
+
const imageYPositionBase = isLastImage && imageHeight <= effectiveViewportHeight
|
|
111
|
+
? effectiveViewportHeight - imageHeight
|
|
112
|
+
: 0;
|
|
113
|
+
const imageYPosition = imageYPositionBase + viewportY + addressBarShadowPadding;
|
|
114
|
+
// For the last image, use the actual scroll position for canvasYPosition
|
|
115
|
+
// because the browser may not be able to scroll to the exact position we requested
|
|
116
|
+
const canvasYPositionForStorage = isLastImage && actualScrollInfo
|
|
117
|
+
? actualScrollInfo.scrollTop
|
|
118
|
+
: scrollY;
|
|
98
119
|
// Store all the screenshot data in the screenshot object
|
|
99
|
-
|
|
120
|
+
const screenshotData = {
|
|
100
121
|
...calculateDprData({
|
|
101
122
|
canvasWidth: isRotated ? effectiveViewportHeight : viewportWidth,
|
|
102
|
-
canvasYPosition:
|
|
123
|
+
canvasYPosition: canvasYPositionForStorage,
|
|
103
124
|
imageHeight: imageHeight,
|
|
104
125
|
imageWidth: isRotated ? effectiveViewportHeight : viewportWidth,
|
|
105
126
|
imageXPosition: viewportX,
|
|
106
127
|
imageYPosition: imageYPosition,
|
|
107
128
|
}, devicePixelRatio),
|
|
108
129
|
screenshot,
|
|
109
|
-
}
|
|
130
|
+
};
|
|
131
|
+
viewportScreenshots.push(screenshotData);
|
|
132
|
+
// Calculate the actual cropped width from the first screenshot to handle rounding differences
|
|
133
|
+
if (i === 0 && !actualFullPageWidth) {
|
|
134
|
+
const { height: screenshotHeightDevicePixels, width: screenshotWidthDevicePixels } = getBase64ScreenshotSize(screenshot);
|
|
135
|
+
const screenshotIsRotated = Boolean(isLandscape && screenshotHeightDevicePixels > screenshotWidthDevicePixels);
|
|
136
|
+
const actualScreenshotWidthDevicePixels = screenshotIsRotated ? screenshotHeightDevicePixels : screenshotWidthDevicePixels;
|
|
137
|
+
const maxAvailableWidthDevicePixels = actualScreenshotWidthDevicePixels - screenshotData.imageXPosition;
|
|
138
|
+
const actualCroppedWidthDevicePixels = Math.min(screenshotData.imageWidth, maxAvailableWidthDevicePixels);
|
|
139
|
+
actualFullPageWidth = actualCroppedWidthDevicePixels / devicePixelRatio;
|
|
140
|
+
}
|
|
110
141
|
// Show scrollbars again
|
|
111
142
|
await browserInstance.execute(hideScrollBars, false);
|
|
112
143
|
}
|
|
@@ -122,10 +153,12 @@ export async function getMobileFullPageNativeWebScreenshotsData(browserInstance,
|
|
|
122
153
|
if (!scrollHeight) {
|
|
123
154
|
throw new Error('Couldn\'t determine scroll height or screenshot size');
|
|
124
155
|
}
|
|
156
|
+
const fullPageHeight = scrollHeight - addressBarShadowPadding - toolBarShadowPadding;
|
|
157
|
+
const fullPageWidth = actualFullPageWidth ?? (isRotated ? effectiveViewportHeight : viewportWidth);
|
|
125
158
|
return {
|
|
126
159
|
...calculateDprData({
|
|
127
|
-
fullPageHeight
|
|
128
|
-
fullPageWidth
|
|
160
|
+
fullPageHeight,
|
|
161
|
+
fullPageWidth,
|
|
129
162
|
}, devicePixelRatio),
|
|
130
163
|
data: viewportScreenshots,
|
|
131
164
|
};
|
|
@@ -214,13 +247,32 @@ export async function getDesktopFullPageScreenshotsData(browserInstance, options
|
|
|
214
247
|
const viewportScreenshots = [];
|
|
215
248
|
const { devicePixelRatio, fullPageScrollTimeout, hideAfterFirstScroll, innerHeight } = options;
|
|
216
249
|
let actualInnerHeight = innerHeight;
|
|
250
|
+
const { capabilities } = browserInstance;
|
|
251
|
+
const browserName = (capabilities?.browserName || '').toLowerCase();
|
|
252
|
+
// Safari desktop returns the browser mask with rounded corners and a drop shadow, so we need to fix this
|
|
253
|
+
const isSafariDesktop = browserName.includes('safari') && !browserInstance.isMobile;
|
|
254
|
+
const safariTopDropShadowCssPixels = isSafariDesktop ? Math.round(1 * devicePixelRatio) : 0;
|
|
255
|
+
const safariBottomCropOffsetCssPixels = isSafariDesktop ? Math.round(10 * devicePixelRatio) : 0;
|
|
256
|
+
// For Safari desktop, calculate effective scroll increment
|
|
257
|
+
// First image: scroll by 0, use full height (e.g.716px), crop 10px from bottom
|
|
258
|
+
// Subsequent images: scroll by (actualInnerHeight - dropShadowOffset - bottomCropOffset) = 705px, crop 1px from top and 10px from bottom
|
|
259
|
+
const effectiveScrollIncrement = isSafariDesktop
|
|
260
|
+
? actualInnerHeight - safariTopDropShadowCssPixels - safariBottomCropOffsetCssPixels
|
|
261
|
+
: actualInnerHeight;
|
|
217
262
|
// Start with an empty array, during the scroll it will be filled because a page could also have a lazy loading
|
|
218
263
|
const amountOfScrollsArray = [];
|
|
219
264
|
let scrollHeight;
|
|
220
265
|
let screenshotSize;
|
|
221
266
|
for (let i = 0; i <= amountOfScrollsArray.length; i++) {
|
|
222
267
|
// Determine and start scrolling
|
|
223
|
-
|
|
268
|
+
// For Safari desktop: first image scrolls to 0, subsequent images scroll by effectiveScrollIncrement (715px)
|
|
269
|
+
// Image 0: scrollY = 0
|
|
270
|
+
// Image 1: scrollY = 715 (effectiveScrollIncrement)
|
|
271
|
+
// Image 2: scrollY = 1430 (2 * effectiveScrollIncrement)
|
|
272
|
+
// etc.
|
|
273
|
+
const scrollY = isSafariDesktop
|
|
274
|
+
? (i === 0 ? 0 : i * effectiveScrollIncrement)
|
|
275
|
+
: actualInnerHeight * i;
|
|
224
276
|
await browserInstance.execute(scrollToPosition, scrollY);
|
|
225
277
|
// Simply wait the amount of time specified for lazy-loading
|
|
226
278
|
await waitFor(fullPageScrollTimeout);
|
|
@@ -245,26 +297,118 @@ export async function getDesktopFullPageScreenshotsData(browserInstance, options
|
|
|
245
297
|
// No else, because some drivers take a full page screenshot, e.g. some versions of FireFox,
|
|
246
298
|
// and SafariDriver for Safari 11
|
|
247
299
|
}
|
|
248
|
-
// Determine scroll height and check if we need to scroll again
|
|
249
300
|
scrollHeight = await browserInstance.execute(getDocumentScrollHeight);
|
|
250
|
-
|
|
301
|
+
// For Safari desktop, use effectiveScrollIncrement for the scroll check
|
|
302
|
+
const scrollCheckHeight = isSafariDesktop ? effectiveScrollIncrement : actualInnerHeight;
|
|
303
|
+
if (scrollHeight && (scrollY + scrollCheckHeight < scrollHeight) && screenshotSize.height === actualInnerHeight) {
|
|
251
304
|
amountOfScrollsArray.push(amountOfScrollsArray.length);
|
|
252
305
|
}
|
|
253
|
-
// There is no else, Lazy load and large screenshots,
|
|
254
|
-
// like with older drivers such as FF <= 47 and IE11, will not work
|
|
255
306
|
// The height of the image of the last 1 could be different
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
307
|
+
// For Safari desktop, account for first image being full height and subsequent images being cropped
|
|
308
|
+
const isFirstImage = i === 0;
|
|
309
|
+
const isLastImage = amountOfScrollsArray.length === i;
|
|
310
|
+
let imageHeight;
|
|
311
|
+
if (scrollHeight && isLastImage) {
|
|
312
|
+
if (isSafariDesktop) {
|
|
313
|
+
// Calculate remaining content: scrollHeight - (firstImageHeight + (numberOfPreviousImages - 1) * effectiveScrollIncrement)
|
|
314
|
+
const numberOfPreviousImages = viewportScreenshots.length;
|
|
315
|
+
const totalPreviousHeight = numberOfPreviousImages === 0
|
|
316
|
+
? 0
|
|
317
|
+
: actualInnerHeight + (numberOfPreviousImages - 1) * effectiveScrollIncrement;
|
|
318
|
+
const remainingContent = scrollHeight - totalPreviousHeight;
|
|
319
|
+
// For the last image, we need to be smart:
|
|
320
|
+
// - If remainingContent >= actualInnerHeight: it's a full screenshot, treat it like a regular non-first image
|
|
321
|
+
// (crop 1px from top, visible height = 705px, but last image doesn't crop bottom, so add 10px)
|
|
322
|
+
// - If remainingContent < actualInnerHeight: it's a partial screenshot
|
|
323
|
+
// For partial screenshots, we're cropping from a position that doesn't include the drop shadow at pixel 0
|
|
324
|
+
// Last image doesn't crop bottom, so we need to add 10px to account for that
|
|
325
|
+
imageHeight = remainingContent >= actualInnerHeight
|
|
326
|
+
? effectiveScrollIncrement + safariBottomCropOffsetCssPixels
|
|
327
|
+
: remainingContent + safariBottomCropOffsetCssPixels;
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
imageHeight = scrollHeight - actualInnerHeight * viewportScreenshots.length;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
// Non-last images: use full height for first, effectiveScrollIncrement for subsequent
|
|
335
|
+
// For non-first images, effectiveScrollIncrement already accounts for top and bottom crops
|
|
336
|
+
imageHeight = isSafariDesktop && !isFirstImage
|
|
337
|
+
? effectiveScrollIncrement
|
|
338
|
+
: screenshotSize.height;
|
|
339
|
+
}
|
|
259
340
|
// The starting position for cropping could be different for the last image (0 means no cropping)
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
341
|
+
// For Safari desktop, crop 1px from top for all images except first
|
|
342
|
+
if (isSafariDesktop && isFirstImage && safariBottomCropOffsetCssPixels > 0) {
|
|
343
|
+
imageHeight -= safariBottomCropOffsetCssPixels;
|
|
344
|
+
}
|
|
345
|
+
// The starting position for cropping could be different for the last image (0 means no cropping)
|
|
346
|
+
// For Safari desktop, crop 1px from top for all images except first
|
|
347
|
+
let imageYPosition;
|
|
348
|
+
if (isSafariDesktop) {
|
|
349
|
+
if (isLastImage && !isFirstImage) {
|
|
350
|
+
// Last image: need to handle two cases
|
|
351
|
+
const numberOfPreviousImages = viewportScreenshots.length;
|
|
352
|
+
const totalPreviousHeight = numberOfPreviousImages === 0
|
|
353
|
+
? 0
|
|
354
|
+
: actualInnerHeight + (numberOfPreviousImages - 1) * effectiveScrollIncrement;
|
|
355
|
+
const remainingContent = scrollHeight ? scrollHeight - totalPreviousHeight : 0;
|
|
356
|
+
// Full screenshot: treat like regular non-first image (crop 1px from top)
|
|
357
|
+
// Partial screenshot: we want to show the last remainingContent pixels
|
|
358
|
+
// But we need to include the bottom 10px that we're not cropping, so start 10px higher
|
|
359
|
+
// imageHeight = remainingContent, so we start at: 716 - remainingContent - 10px
|
|
360
|
+
// This way we crop 10px higher to include the bottom corners
|
|
361
|
+
imageYPosition = remainingContent >= actualInnerHeight
|
|
362
|
+
? safariTopDropShadowCssPixels
|
|
363
|
+
: actualInnerHeight - remainingContent - safariBottomCropOffsetCssPixels;
|
|
364
|
+
// If remainingContent is too small, we might get negative imageYPosition or invalid dimensions
|
|
365
|
+
if (imageYPosition < 0) {
|
|
366
|
+
imageYPosition = actualInnerHeight - remainingContent;
|
|
367
|
+
imageHeight = remainingContent;
|
|
368
|
+
}
|
|
369
|
+
else if (imageYPosition + imageHeight > screenshotSize.height) {
|
|
370
|
+
imageHeight = screenshotSize.height - imageYPosition;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
else if (!isFirstImage) {
|
|
374
|
+
// Non-last, non-first images: crop 1px from top
|
|
375
|
+
imageYPosition = safariTopDropShadowCssPixels;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
// First image: no crop
|
|
379
|
+
imageYPosition = 0;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
imageYPosition = isLastImage && !isFirstImage
|
|
384
|
+
? actualInnerHeight - imageHeight
|
|
385
|
+
: 0;
|
|
386
|
+
}
|
|
387
|
+
// Ensure imageYPosition and imageHeight are valid for all cases
|
|
388
|
+
if (imageYPosition < 0) {
|
|
389
|
+
imageHeight += imageYPosition;
|
|
390
|
+
imageYPosition = 0;
|
|
391
|
+
}
|
|
392
|
+
if (imageYPosition + imageHeight > screenshotSize.height) {
|
|
393
|
+
imageHeight = screenshotSize.height - imageYPosition;
|
|
394
|
+
}
|
|
395
|
+
// Calculate based on where the previous image ends
|
|
396
|
+
// Previous image's canvasYPosition + previous image's height
|
|
397
|
+
let canvasYPosition;
|
|
398
|
+
if (isSafariDesktop && !isFirstImage) {
|
|
399
|
+
const previousImage = viewportScreenshots[viewportScreenshots.length - 1];
|
|
400
|
+
canvasYPosition = previousImage
|
|
401
|
+
? previousImage.canvasYPosition + previousImage.imageHeight
|
|
402
|
+
: actualInnerHeight + (i - 1) * effectiveScrollIncrement;
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
canvasYPosition = isSafariDesktop ? 0 : scrollY;
|
|
406
|
+
}
|
|
263
407
|
// Store all the screenshot data in the screenshot object
|
|
264
408
|
viewportScreenshots.push({
|
|
265
409
|
...calculateDprData({
|
|
266
410
|
canvasWidth: screenshotSize.width,
|
|
267
|
-
canvasYPosition:
|
|
411
|
+
canvasYPosition: canvasYPosition,
|
|
268
412
|
imageHeight: imageHeight,
|
|
269
413
|
imageWidth: screenshotSize.width,
|
|
270
414
|
imageXPosition: 0,
|
|
@@ -73,6 +73,14 @@ describe('screenshots', () => {
|
|
|
73
73
|
logWarnSpy = vi.spyOn(log, 'warn');
|
|
74
74
|
vi.mocked(utilsModule.waitFor).mockResolvedValue(undefined);
|
|
75
75
|
vi.mocked(utilsModule.calculateDprData).mockImplementation((data) => data);
|
|
76
|
+
vi.mocked(utilsModule.getBase64ScreenshotSize).mockImplementation((_screenshot, dpr = 1) => {
|
|
77
|
+
const baseWidth = 750;
|
|
78
|
+
const baseHeight = 1334;
|
|
79
|
+
return {
|
|
80
|
+
width: Math.round(baseWidth / dpr),
|
|
81
|
+
height: Math.round(baseHeight / dpr)
|
|
82
|
+
};
|
|
83
|
+
});
|
|
76
84
|
});
|
|
77
85
|
afterEach(() => {
|
|
78
86
|
vi.clearAllMocks();
|
|
@@ -84,6 +92,7 @@ describe('screenshots', () => {
|
|
|
84
92
|
.mockResolvedValueOnce(undefined) // scrollToPosition
|
|
85
93
|
.mockResolvedValueOnce(undefined) // hideScrollBars
|
|
86
94
|
.mockResolvedValueOnce(652) // getDocumentScrollHeight (effective viewport height)
|
|
95
|
+
.mockResolvedValueOnce({ scrollTop: 0 }) // actualScrollInfo
|
|
87
96
|
.mockResolvedValueOnce(undefined); // hideScrollBars
|
|
88
97
|
const options = createMobileOptions(); // iOS device by default
|
|
89
98
|
const result = await getMobileFullPageNativeWebScreenshotsData(mockBrowserInstance, options);
|
|
@@ -97,10 +106,12 @@ describe('screenshots', () => {
|
|
|
97
106
|
.mockResolvedValueOnce(undefined) // scrollToPosition 0 (i=0)
|
|
98
107
|
.mockResolvedValueOnce(undefined) // hideScrollBars true
|
|
99
108
|
.mockResolvedValueOnce(1304) // getDocumentScrollHeight (2x effectiveViewportHeight)
|
|
109
|
+
.mockResolvedValueOnce({ scrollTop: 0 }) // actualScrollInfo
|
|
100
110
|
.mockResolvedValueOnce(undefined) // hideScrollBars false
|
|
101
111
|
.mockResolvedValueOnce(undefined) // scrollToPosition 652 (i=1)
|
|
102
112
|
.mockResolvedValueOnce(undefined) // hideScrollBars true
|
|
103
113
|
.mockResolvedValueOnce(1304) // getDocumentScrollHeight
|
|
114
|
+
.mockResolvedValueOnce({ scrollTop: 652 }) // actualScrollInfo
|
|
104
115
|
.mockResolvedValueOnce(undefined); // hideScrollBars false
|
|
105
116
|
const options = createMobileOptions({ isAndroid: true });
|
|
106
117
|
const result = await getMobileFullPageNativeWebScreenshotsData(mockBrowserInstance, options);
|
|
@@ -114,6 +125,7 @@ describe('screenshots', () => {
|
|
|
114
125
|
.mockResolvedValueOnce(undefined) // scrollToPosition
|
|
115
126
|
.mockResolvedValueOnce(undefined) // hideScrollBars
|
|
116
127
|
.mockResolvedValueOnce(652) // getDocumentScrollHeight
|
|
128
|
+
.mockResolvedValueOnce({ scrollTop: 0 }) // actualScrollInfo
|
|
117
129
|
.mockResolvedValueOnce(undefined); // hideScrollBars
|
|
118
130
|
const options = createMobileOptions({
|
|
119
131
|
isLandscape: true,
|
|
@@ -138,11 +150,13 @@ describe('screenshots', () => {
|
|
|
138
150
|
.mockResolvedValueOnce(undefined) // scrollToPosition 0 (i=0)
|
|
139
151
|
.mockResolvedValueOnce(undefined) // hideScrollBars true
|
|
140
152
|
.mockResolvedValueOnce(2638) // getDocumentScrollHeight (2x effectiveViewportHeight to trigger scroll)
|
|
153
|
+
.mockResolvedValueOnce({ scrollTop: 0 }) // actualScrollInfo
|
|
141
154
|
.mockResolvedValueOnce(undefined) // hideScrollBars false
|
|
142
155
|
.mockResolvedValueOnce(undefined) // scrollToPosition 1319 (i=1)
|
|
143
156
|
.mockResolvedValueOnce(undefined) // hideScrollBars true
|
|
144
157
|
.mockResolvedValueOnce(undefined) // hideRemoveElements (i=1, hide elements)
|
|
145
158
|
.mockResolvedValueOnce(2638) // getDocumentScrollHeight
|
|
159
|
+
.mockResolvedValueOnce({ scrollTop: 1319 }) // actualScrollInfo
|
|
146
160
|
.mockResolvedValueOnce(undefined) // hideScrollBars false
|
|
147
161
|
.mockResolvedValueOnce(undefined); // hideRemoveElements (restore at end)
|
|
148
162
|
const mockElements = [{ tagName: 'div' }];
|
|
@@ -169,11 +183,13 @@ describe('screenshots', () => {
|
|
|
169
183
|
.mockResolvedValueOnce(undefined) // scrollToPosition 0 (i=0)
|
|
170
184
|
.mockResolvedValueOnce(undefined) // hideScrollBars true
|
|
171
185
|
.mockResolvedValueOnce(2638) // getDocumentScrollHeight (2x effectiveViewportHeight)
|
|
186
|
+
.mockResolvedValueOnce({ scrollTop: 0 }) // actualScrollInfo
|
|
172
187
|
.mockResolvedValueOnce(undefined) // hideScrollBars false
|
|
173
188
|
.mockResolvedValueOnce(undefined) // scrollToPosition 1319 (i=1)
|
|
174
189
|
.mockResolvedValueOnce(undefined) // hideScrollBars true
|
|
175
190
|
.mockRejectedValueOnce(executeError) // hideRemoveElements fails
|
|
176
191
|
.mockResolvedValueOnce(2638) // getDocumentScrollHeight
|
|
192
|
+
.mockResolvedValueOnce({ scrollTop: 1319 }) // actualScrollInfo
|
|
177
193
|
.mockResolvedValueOnce(undefined) // hideScrollBars false
|
|
178
194
|
.mockRejectedValueOnce(executeError); // hideRemoveElements restore fails
|
|
179
195
|
const mockElements = [{ tagName: 'div' }];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wdio/image-comparison-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"author": "Wim Selles - wswebcreation",
|
|
5
5
|
"description": "Image comparison core module for @wdio/visual-service - WebdriverIO visual testing framework",
|
|
6
6
|
"keywords": [
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"jimp": "^1.6.0",
|
|
30
30
|
"@wdio/logger": "^9.18.0",
|
|
31
|
-
"@wdio/types": "^9.
|
|
31
|
+
"@wdio/types": "^9.20.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"webdriverio": "^9.
|
|
34
|
+
"webdriverio": "^9.20.1"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|