@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
|
@@ -12,25 +12,32 @@ export async function takeElementScreenshot(browserInstance, options, shouldUseB
|
|
|
12
12
|
return await takeWebDriverElementScreenshot(browserInstance, options);
|
|
13
13
|
}
|
|
14
14
|
async function takeBiDiElementScreenshot(browserInstance, options) {
|
|
15
|
-
let base64Image;
|
|
16
15
|
const isWebDriverElementScreenshot = false;
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
// Fix #1129: scrollElementIntoView receives a promise
|
|
17
|
+
// The element might be a promise, so we need to resolve it before using it as a browser.execute() argument
|
|
18
|
+
// if we need to use it in browser.execute()
|
|
19
|
+
const element = await options.element;
|
|
20
|
+
// Scroll the element into the viewport so any lazy‑load / intersection
|
|
21
|
+
// observers are triggered. We always capture from the *document* origin,
|
|
22
|
+
// so the clip coordinates are document‑relative and independent of scroll.
|
|
23
|
+
let currentPosition;
|
|
24
|
+
if (options.autoElementScroll) {
|
|
25
|
+
currentPosition = await browserInstance.execute(scrollElementIntoView, element, options.addressBarShadowPadding);
|
|
26
|
+
await waitFor(100);
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
// Get the element rect and clip the screenshot. WebDriver getElementRect
|
|
29
|
+
// returns coordinates relative to the document origin, which matches the
|
|
30
|
+
// BiDi `origin: 'document'` coordinate system.
|
|
31
|
+
const rect = await browserInstance.getElementRect(element.elementId);
|
|
32
|
+
const clip = { x: Math.floor(rect.x), y: Math.floor(rect.y), width: Math.floor(rect.width), height: Math.floor(rect.height) };
|
|
33
|
+
const base64Image = await takeBase64BiDiScreenshot({
|
|
34
|
+
browserInstance,
|
|
35
|
+
origin: 'document',
|
|
36
|
+
clip,
|
|
37
|
+
});
|
|
38
|
+
// Restore scroll position
|
|
39
|
+
if (options.autoElementScroll && currentPosition) {
|
|
40
|
+
await browserInstance.execute(scrollToPosition, currentPosition);
|
|
34
41
|
}
|
|
35
42
|
return {
|
|
36
43
|
base64Image,
|
|
@@ -40,10 +47,14 @@ async function takeBiDiElementScreenshot(browserInstance, options) {
|
|
|
40
47
|
async function takeWebDriverElementScreenshot(browserInstance, options) {
|
|
41
48
|
let base64Image;
|
|
42
49
|
let isWebDriverElementScreenshot = false;
|
|
50
|
+
// Fix #1129: scrollElementIntoView receives a promise
|
|
51
|
+
// The element might be a promise, so we need to resolve it before using it as a browser.execute() argument
|
|
52
|
+
// if we need to use it in browser.execute()
|
|
53
|
+
const element = await options.element;
|
|
43
54
|
// Scroll the element into top of the viewport and return the current scroll position
|
|
44
55
|
let currentPosition;
|
|
45
56
|
if (options.autoElementScroll) {
|
|
46
|
-
currentPosition = await browserInstance.execute(scrollElementIntoView,
|
|
57
|
+
currentPosition = await browserInstance.execute(scrollElementIntoView, element, options.addressBarShadowPadding);
|
|
47
58
|
// We need to wait for the scroll to finish before taking the screenshot
|
|
48
59
|
await waitFor(100);
|
|
49
60
|
}
|
|
@@ -53,7 +64,7 @@ async function takeWebDriverElementScreenshot(browserInstance, options) {
|
|
|
53
64
|
browserInstance,
|
|
54
65
|
devicePixelRatio: options.devicePixelRatio,
|
|
55
66
|
deviceRectangles: options.deviceRectangles,
|
|
56
|
-
element
|
|
67
|
+
element,
|
|
57
68
|
initialDevicePixelRatio: options.initialDevicePixelRatio,
|
|
58
69
|
isEmulated: options.isEmulated,
|
|
59
70
|
innerHeight: options.innerHeight,
|
|
@@ -74,7 +74,7 @@ describe('takeElementScreenshot', () => {
|
|
|
74
74
|
vi.clearAllMocks();
|
|
75
75
|
});
|
|
76
76
|
describe('BiDi screenshots', () => {
|
|
77
|
-
it('should take BiDi screenshot from
|
|
77
|
+
it('should take BiDi screenshot from document when shouldUseBidi is true', async () => {
|
|
78
78
|
const result = await takeElementScreenshot(browserInstance, baseOptions, true);
|
|
79
79
|
expect(result).toEqual({
|
|
80
80
|
base64Image: 'bidi-screenshot-data',
|
|
@@ -83,37 +83,50 @@ describe('takeElementScreenshot', () => {
|
|
|
83
83
|
expect(getElementRectMock).toHaveBeenCalledWith('test-element');
|
|
84
84
|
expect(takeBase64BiDiScreenshotSpy).toHaveBeenCalledWith({
|
|
85
85
|
browserInstance,
|
|
86
|
-
origin: '
|
|
86
|
+
origin: 'document',
|
|
87
87
|
clip: { x: 10, y: 20, width: 100, height: 200 }
|
|
88
88
|
});
|
|
89
89
|
expect(takeWebElementScreenshotSpy).not.toHaveBeenCalled();
|
|
90
90
|
expect(makeCroppedBase64ImageSpy).not.toHaveBeenCalled();
|
|
91
91
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
//
|
|
93
|
+
// We intentionally rely on BiDi with origin: 'document' only. If that
|
|
94
|
+
// ever fails, we surface the underlying error instead of silently
|
|
95
|
+
// falling back to a different origin with mismatched coordinates.
|
|
96
|
+
it('should scroll element into view when autoElementScroll is enabled', async () => {
|
|
97
|
+
const optionsWithScroll = { ...baseOptions, autoElementScroll: true };
|
|
98
|
+
executeMock.mockResolvedValueOnce(100); // previous scroll position
|
|
99
|
+
const result = await takeElementScreenshot(browserInstance, optionsWithScroll, true);
|
|
95
100
|
expect(result).toEqual({
|
|
96
101
|
base64Image: 'bidi-screenshot-data',
|
|
97
102
|
isWebDriverElementScreenshot: false
|
|
98
103
|
});
|
|
99
|
-
|
|
100
|
-
expect(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
});
|
|
105
|
-
expect(takeBase64BiDiScreenshotSpy.mock.calls[1][0]).toEqual({
|
|
106
|
-
browserInstance,
|
|
107
|
-
origin: 'document',
|
|
108
|
-
clip: { x: 10, y: 20, width: 100, height: 200 }
|
|
109
|
-
});
|
|
104
|
+
// First call: scrollElementIntoView, second call: scrollToPosition (restore)
|
|
105
|
+
expect(executeMock).toHaveBeenCalledTimes(2);
|
|
106
|
+
expect(executeMock.mock.calls[0]).toMatchSnapshot();
|
|
107
|
+
expect(executeMock.mock.calls[1]).toMatchSnapshot();
|
|
108
|
+
expect(waitForSpy).toHaveBeenCalledWith(100);
|
|
110
109
|
});
|
|
111
|
-
it('should
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
await
|
|
115
|
-
|
|
116
|
-
expect(
|
|
110
|
+
it('should not restore scroll when autoElementScroll is enabled but no previous position', async () => {
|
|
111
|
+
const optionsWithScroll = { ...baseOptions, autoElementScroll: true };
|
|
112
|
+
executeMock.mockResolvedValueOnce(undefined); // no previous position
|
|
113
|
+
await takeElementScreenshot(browserInstance, optionsWithScroll, true);
|
|
114
|
+
// Only the scrollElementIntoView call, no restore
|
|
115
|
+
expect(executeMock).toHaveBeenCalledTimes(1);
|
|
116
|
+
expect(waitForSpy).toHaveBeenCalledWith(100);
|
|
117
|
+
});
|
|
118
|
+
it('should resolve a Promise-wrapped element (ChainablePromiseElement) before passing to browser.execute()', async () => {
|
|
119
|
+
const resolvedElement = { elementId: 'promise-element' };
|
|
120
|
+
const optionsWithPromiseElement = {
|
|
121
|
+
...baseOptions,
|
|
122
|
+
autoElementScroll: true,
|
|
123
|
+
element: Promise.resolve(resolvedElement),
|
|
124
|
+
};
|
|
125
|
+
executeMock.mockResolvedValueOnce(100);
|
|
126
|
+
await takeElementScreenshot(browserInstance, optionsWithPromiseElement, true);
|
|
127
|
+
expect(getElementRectMock).toHaveBeenCalledWith('promise-element');
|
|
128
|
+
// The resolved element (not the Promise) must be passed to browser.execute()
|
|
129
|
+
expect(executeMock.mock.calls[0][1]).toEqual(resolvedElement);
|
|
117
130
|
});
|
|
118
131
|
});
|
|
119
132
|
describe('Legacy screenshots', () => {
|
|
@@ -184,6 +197,20 @@ describe('takeElementScreenshot', () => {
|
|
|
184
197
|
expect(executeMock).toHaveBeenCalledTimes(1); // Only the scroll into view call
|
|
185
198
|
expect(waitForSpy).toHaveBeenCalledWith(100);
|
|
186
199
|
});
|
|
200
|
+
it('should resolve a Promise-wrapped element (ChainablePromiseElement) before passing to browser.execute()', async () => {
|
|
201
|
+
const resolvedElement = { elementId: 'promise-element' };
|
|
202
|
+
const optionsWithPromiseElement = {
|
|
203
|
+
...baseOptions,
|
|
204
|
+
autoElementScroll: true,
|
|
205
|
+
element: Promise.resolve(resolvedElement),
|
|
206
|
+
};
|
|
207
|
+
executeMock.mockResolvedValueOnce(100);
|
|
208
|
+
await takeElementScreenshot(browserInstance, optionsWithPromiseElement, false);
|
|
209
|
+
// The resolved element (not the Promise) must be passed to browser.execute()
|
|
210
|
+
expect(executeMock.mock.calls[0][1]).toEqual(resolvedElement);
|
|
211
|
+
// And also passed to takeWebElementScreenshot
|
|
212
|
+
expect(takeWebElementScreenshotSpy).toHaveBeenCalledWith(expect.objectContaining({ element: resolvedElement }));
|
|
213
|
+
});
|
|
187
214
|
it('should enable fallback when resizeDimensions is provided', async () => {
|
|
188
215
|
const optionsWithResize = {
|
|
189
216
|
...baseOptions,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wdio/image-comparison-core",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.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.25.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"webdriverio": "^9.
|
|
34
|
+
"webdriverio": "^9.25.0"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|