@wdio/image-comparison-core 1.1.0 → 1.1.2
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
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @wdio/image-comparison-core
|
|
2
2
|
|
|
3
|
+
## 1.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0a2b6d0: ## #1111 Respect saveAboveTolerance when deciding to save actual images when alwaysSaveActualImage is false.
|
|
8
|
+
|
|
9
|
+
When `alwaysSaveActualImage` is `false`, the actual image is no longer written to disk if the mismatch is below the configured tolerance, avoiding extra actuals when the comparison still passes.
|
|
10
|
+
|
|
11
|
+
# Committers: 1
|
|
12
|
+
|
|
13
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
14
|
+
|
|
15
|
+
## 1.1.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 340fbe6: # 🐛 Bugfixes
|
|
20
|
+
|
|
21
|
+
## #1098 Improve error message when baseline is missing and both flags are false
|
|
22
|
+
|
|
23
|
+
When `autoSaveBaseline = false` and `alwaysSaveActualImage = false` and a baseline image doesn't exist, the error message now provides clear guidance suggesting users set `alwaysSaveActualImage` to `true` if they need the actual image to create a baseline manually.
|
|
24
|
+
|
|
25
|
+
# Committers: 1
|
|
26
|
+
|
|
27
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
28
|
+
|
|
29
|
+
- e4e5b5c: # 🐛 Bugfixes
|
|
30
|
+
|
|
31
|
+
## #1085 autoSaveBaseline collides with the new alwaysSaveActualImage flag
|
|
32
|
+
|
|
33
|
+
When `autoSaveBaseline` is `true` and `alwaysSaveActualImage` is `false`, actual images were still saved. This patch should fix that
|
|
34
|
+
|
|
35
|
+
# Committers: 1
|
|
36
|
+
|
|
37
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
38
|
+
|
|
3
39
|
## 1.1.0
|
|
4
40
|
|
|
5
41
|
### Minor Changes
|
|
@@ -94,7 +94,7 @@ vi.mock('./images.js', async () => {
|
|
|
94
94
|
addBlockOuts: vi.fn(),
|
|
95
95
|
};
|
|
96
96
|
});
|
|
97
|
-
import { executeImageCompare } from './images.js';
|
|
97
|
+
import { executeImageCompare, checkBaselineImageExists } from './images.js';
|
|
98
98
|
import * as images from './images.js';
|
|
99
99
|
describe('executeImageCompare', () => {
|
|
100
100
|
const mockDeviceRectangles = {
|
|
@@ -597,6 +597,12 @@ describe('executeImageCompare', () => {
|
|
|
597
597
|
autoSaveBaseline: true,
|
|
598
598
|
}
|
|
599
599
|
};
|
|
600
|
+
vi.mocked(fsPromises.access).mockImplementation(async (path) => {
|
|
601
|
+
if (path === '/mock/baseline/test.png') {
|
|
602
|
+
throw new Error('File not found');
|
|
603
|
+
}
|
|
604
|
+
return undefined;
|
|
605
|
+
});
|
|
600
606
|
vi.mocked(compareImages.default).mockResolvedValue({
|
|
601
607
|
rawMisMatchPercentage: 0,
|
|
602
608
|
misMatchPercentage: 0,
|
|
@@ -640,6 +646,72 @@ describe('executeImageCompare', () => {
|
|
|
640
646
|
});
|
|
641
647
|
expect(fsPromises.writeFile).toHaveBeenCalledWith('/mock/actual/test.png', Buffer.from(base64Image, 'base64'));
|
|
642
648
|
});
|
|
649
|
+
it('should not save base64 actual when diff is below saveAboveTolerance', async () => {
|
|
650
|
+
const base64Image = Buffer.from('base64-image').toString('base64');
|
|
651
|
+
const optionsWithTolerance = {
|
|
652
|
+
...mockOptions,
|
|
653
|
+
folderOptions: {
|
|
654
|
+
...mockOptions.folderOptions,
|
|
655
|
+
alwaysSaveActualImage: false,
|
|
656
|
+
},
|
|
657
|
+
compareOptions: {
|
|
658
|
+
...mockOptions.compareOptions,
|
|
659
|
+
wic: {
|
|
660
|
+
...mockOptions.compareOptions.wic,
|
|
661
|
+
saveAboveTolerance: 0.1,
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
vi.mocked(compareImages.default).mockResolvedValue({
|
|
666
|
+
rawMisMatchPercentage: 0.05,
|
|
667
|
+
misMatchPercentage: 0.05,
|
|
668
|
+
getBuffer: vi.fn().mockResolvedValue(Buffer.from('diff-image-data')),
|
|
669
|
+
diffBounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
670
|
+
analysisTime: 10,
|
|
671
|
+
diffPixels: []
|
|
672
|
+
});
|
|
673
|
+
await executeImageCompare({
|
|
674
|
+
isViewPortScreenshot: true,
|
|
675
|
+
isNativeContext: false,
|
|
676
|
+
options: optionsWithTolerance,
|
|
677
|
+
testContext: mockTestContext,
|
|
678
|
+
actualBase64Image: base64Image,
|
|
679
|
+
});
|
|
680
|
+
expect(fsPromises.writeFile).not.toHaveBeenCalled();
|
|
681
|
+
});
|
|
682
|
+
it('should save base64 actual when diff exceeds saveAboveTolerance', async () => {
|
|
683
|
+
const base64Image = Buffer.from('base64-image').toString('base64');
|
|
684
|
+
const optionsWithTolerance = {
|
|
685
|
+
...mockOptions,
|
|
686
|
+
folderOptions: {
|
|
687
|
+
...mockOptions.folderOptions,
|
|
688
|
+
alwaysSaveActualImage: false,
|
|
689
|
+
},
|
|
690
|
+
compareOptions: {
|
|
691
|
+
...mockOptions.compareOptions,
|
|
692
|
+
wic: {
|
|
693
|
+
...mockOptions.compareOptions.wic,
|
|
694
|
+
saveAboveTolerance: 0.1,
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
};
|
|
698
|
+
vi.mocked(compareImages.default).mockResolvedValue({
|
|
699
|
+
rawMisMatchPercentage: 0.2,
|
|
700
|
+
misMatchPercentage: 0.2,
|
|
701
|
+
getBuffer: vi.fn().mockResolvedValue(Buffer.from('diff-image-data')),
|
|
702
|
+
diffBounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
703
|
+
analysisTime: 10,
|
|
704
|
+
diffPixels: []
|
|
705
|
+
});
|
|
706
|
+
await executeImageCompare({
|
|
707
|
+
isViewPortScreenshot: true,
|
|
708
|
+
isNativeContext: false,
|
|
709
|
+
options: optionsWithTolerance,
|
|
710
|
+
testContext: mockTestContext,
|
|
711
|
+
actualBase64Image: base64Image,
|
|
712
|
+
});
|
|
713
|
+
expect(fsPromises.writeFile).toHaveBeenCalledWith('/mock/actual/test.png', Buffer.from(base64Image, 'base64'));
|
|
714
|
+
});
|
|
643
715
|
it('should update baseline using base64 when visual baseline is updated', async () => {
|
|
644
716
|
const base64Image = Buffer.from('base64-image').toString('base64');
|
|
645
717
|
vi.mocked(utils.updateVisualBaseline).mockReturnValueOnce(true);
|
|
@@ -908,4 +980,74 @@ describe('executeImageCompare', () => {
|
|
|
908
980
|
expect(images.saveBase64Image).not.toHaveBeenCalled();
|
|
909
981
|
expect(log.warn).not.toHaveBeenCalled();
|
|
910
982
|
});
|
|
983
|
+
it('should not save actual image when autoSaveBaseline is true, alwaysSaveActualImage is false, baseline exists, and comparison passes', async () => {
|
|
984
|
+
// This test covers issue #1085: autoSaveBaseline collides with alwaysSaveActualImage
|
|
985
|
+
// When baseline exists and comparison passes, actual image should NOT be saved
|
|
986
|
+
const base64Image = Buffer.from('base64-image').toString('base64');
|
|
987
|
+
const optionsWithAutoSave = {
|
|
988
|
+
...mockOptions,
|
|
989
|
+
folderOptions: {
|
|
990
|
+
...mockOptions.folderOptions,
|
|
991
|
+
alwaysSaveActualImage: false,
|
|
992
|
+
autoSaveBaseline: true,
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
vi.mocked(fsPromises.access).mockResolvedValue(undefined);
|
|
996
|
+
vi.mocked(images.checkBaselineImageExists).mockImplementation(async () => {
|
|
997
|
+
return Promise.resolve();
|
|
998
|
+
});
|
|
999
|
+
vi.mocked(compareImages.default).mockResolvedValue({
|
|
1000
|
+
rawMisMatchPercentage: 0,
|
|
1001
|
+
misMatchPercentage: 0,
|
|
1002
|
+
getBuffer: vi.fn().mockResolvedValue(Buffer.from('diff-image-data')),
|
|
1003
|
+
diffBounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
1004
|
+
analysisTime: 10,
|
|
1005
|
+
diffPixels: []
|
|
1006
|
+
});
|
|
1007
|
+
await executeImageCompare({
|
|
1008
|
+
isViewPortScreenshot: true,
|
|
1009
|
+
isNativeContext: false,
|
|
1010
|
+
options: optionsWithAutoSave,
|
|
1011
|
+
testContext: mockTestContext,
|
|
1012
|
+
actualBase64Image: base64Image,
|
|
1013
|
+
});
|
|
1014
|
+
expect(images.saveBase64Image).not.toHaveBeenCalled();
|
|
1015
|
+
expect(fsPromises.writeFile).not.toHaveBeenCalledWith('/mock/actual/test.png', expect.anything());
|
|
1016
|
+
});
|
|
1017
|
+
it('should not save actual image when baseline does not exist, alwaysSaveActualImage is false, and autoSaveBaseline is false', async () => {
|
|
1018
|
+
// This test covers issue #1098: When both flags are false, we respect the user's choice
|
|
1019
|
+
// and provide a helpful error message suggesting to adjust the arguments if needed
|
|
1020
|
+
const base64Image = Buffer.from('base64-image').toString('base64');
|
|
1021
|
+
const optionsWithoutAutoSave = {
|
|
1022
|
+
...mockOptions,
|
|
1023
|
+
folderOptions: {
|
|
1024
|
+
...mockOptions.folderOptions,
|
|
1025
|
+
alwaysSaveActualImage: false,
|
|
1026
|
+
autoSaveBaseline: false,
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
vi.mocked(fsPromises.access).mockImplementation(async (path) => {
|
|
1030
|
+
if (path === '/mock/baseline/test.png' || path === '/mock/actual/test.png') {
|
|
1031
|
+
throw new Error('File not found');
|
|
1032
|
+
}
|
|
1033
|
+
return undefined;
|
|
1034
|
+
});
|
|
1035
|
+
vi.mocked(images.checkBaselineImageExists).mockImplementation(checkBaselineImageExists);
|
|
1036
|
+
vi.mocked(compareImages.default).mockResolvedValue({
|
|
1037
|
+
rawMisMatchPercentage: 0,
|
|
1038
|
+
misMatchPercentage: 0,
|
|
1039
|
+
getBuffer: vi.fn().mockResolvedValue(Buffer.from('diff-image-data')),
|
|
1040
|
+
diffBounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
1041
|
+
analysisTime: 10,
|
|
1042
|
+
diffPixels: []
|
|
1043
|
+
});
|
|
1044
|
+
await expect(executeImageCompare({
|
|
1045
|
+
isViewPortScreenshot: true,
|
|
1046
|
+
isNativeContext: false,
|
|
1047
|
+
options: optionsWithoutAutoSave,
|
|
1048
|
+
testContext: mockTestContext,
|
|
1049
|
+
actualBase64Image: base64Image,
|
|
1050
|
+
})).rejects.toThrow(/If you need the actual image to create a baseline, please set alwaysSaveActualImage to true/);
|
|
1051
|
+
expect(images.saveBase64Image).not.toHaveBeenCalled();
|
|
1052
|
+
});
|
|
911
1053
|
});
|
package/dist/methods/images.js
CHANGED
|
@@ -77,11 +77,11 @@ export async function checkBaselineImageExists({ actualFilePath, baselineFilePat
|
|
|
77
77
|
const actualFileExists = await checkIfImageExists(actualFilePath);
|
|
78
78
|
const filePathMessage = actualFileExists
|
|
79
79
|
? `The image can be found here:\n${actualFilePath}`
|
|
80
|
-
: 'The actual image was not saved to disk (alwaysSaveActualImage is false).';
|
|
80
|
+
: 'The actual image was not saved to disk (alwaysSaveActualImage is false).\nIf you need the actual image to create a baseline, please set alwaysSaveActualImage to true.';
|
|
81
81
|
throw new Error(`
|
|
82
82
|
#####################################################################################
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
Baseline image not found, save the actual image manually to the baseline.
|
|
84
|
+
${filePathMessage}
|
|
85
85
|
#####################################################################################`);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -262,8 +262,8 @@ export async function executeImageCompare({ isViewPortScreenshot, isNativeContex
|
|
|
262
262
|
if (useBase64Image) {
|
|
263
263
|
// Convert base64 to buffer for comparison
|
|
264
264
|
actualImageBuffer = Buffer.from(actualBase64Image, 'base64');
|
|
265
|
-
// Only save if
|
|
266
|
-
if (autoSaveBaseline) {
|
|
265
|
+
// Only save actual image if baseline doesn't exist and autoSaveBaseline is true
|
|
266
|
+
if (autoSaveBaseline && !(await checkIfImageExists(baselineFilePath))) {
|
|
267
267
|
await saveBase64Image(actualBase64Image, actualFilePath);
|
|
268
268
|
}
|
|
269
269
|
}
|
|
@@ -316,7 +316,7 @@ export async function executeImageCompare({ isViewPortScreenshot, isNativeContex
|
|
|
316
316
|
const { diffBoundingBoxes, storeDiffs } = await generateAndSaveDiff(data, imageCompareOptions, ignoredBoxes, diffFilePath, rawMisMatchPercentage);
|
|
317
317
|
// 6a. Save actual image on failure if alwaysSaveActualImage is false
|
|
318
318
|
const saveAboveTolerance = imageCompareOptions.saveAboveTolerance ?? 0;
|
|
319
|
-
const hasFailure = rawMisMatchPercentage >
|
|
319
|
+
const hasFailure = rawMisMatchPercentage > saveAboveTolerance;
|
|
320
320
|
if (useBase64Image && hasFailure && actualBase64Image) {
|
|
321
321
|
// Save the actual image only when comparison fails
|
|
322
322
|
await saveBase64Image(actualBase64Image, actualFilePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wdio/image-comparison-core",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"author": "Wim Selles - wswebcreation",
|
|
5
5
|
"description": "Image comparison core module for @wdio/visual-service - WebdriverIO visual testing framework",
|
|
6
6
|
"keywords": [
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@wdio/types": "^9.20.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"webdriverio": "^9.
|
|
34
|
+
"webdriverio": "^9.23.0"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|