Skip to content

Commit b134be2

Browse files
author
Dan Ristea
committed
Refactor compare image to async function with better error handling
1 parent 2d0dbe0 commit b134be2

File tree

3 files changed

+136
-62
lines changed

3 files changed

+136
-62
lines changed

src/chromyRunner.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@ import actions from './actions';
55
import { configTypes } from './defaultConfig';
66

77
const saveImage = (filename, image, testType, screenshotsPath, testReportPath) => {
8-
if (testType === configTypes.test) {
9-
logger.log(`screenshot saved in -> ${testReportPath}/${filename}.png`);
10-
return fs.writeFileSync(`${testReportPath}/${filename}.png`, image);
11-
}
12-
logger.log(`screenshot saved in -> ${screenshotsPath}/${filename}.png`);
13-
return fs.writeFileSync(`${screenshotsPath}/${filename}.png`, image);
8+
const filePath = testType === configTypes.test ? testReportPath : screenshotsPath;
9+
logger.log(`screenshot saved in -> ${filePath}/${filename}.png`);
10+
return fs.writeFileSync(`${filePath}/${filename}.png`, image);
1411
};
1512

1613
const run = async (chromy, options, test) => {

src/compareImage.js

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,40 @@
1-
21
import Jimp from 'jimp';
32
import logger from './logger';
43

5-
const compareImage = (options, testName) =>
6-
new Promise((resolve, reject) => {
7-
const referenceFile = `${options.screenshots}/${testName}.png`;
8-
const testFile = `${options.testReportPath}/${testName}.png`;
9-
Jimp.read(referenceFile).then((referenceImage) => {
10-
Jimp.read(testFile).then((testImage) => {
11-
const distance = Jimp.distance(referenceImage, testImage);
12-
const diff = Jimp.diff(referenceImage, testImage, options.mismatchThreshold);
13-
if (distance < options.mismatchThreshold || diff.percent < options.mismatchThreshold) {
14-
return resolve('No mismatch found!');
15-
}
16-
if (options.saveDifferencifiedImage) {
17-
logger.log('Saving the diff image to disk');
18-
diff.image.write(`${options.testReportPath}/${testName}_differencified.png`);
19-
}
20-
logger.error(`Result -> distance:${distance} diff:${diff.percent}
21-
misMatchThreshold:${options.mismatchThreshold}`);
22-
return reject('Mismatch found!');
23-
}).catch((err) => {
24-
logger.error(err);
25-
return reject('Failed to read test image!');
26-
});
27-
}).catch((err) => {
28-
logger.error(err);
29-
return reject('Failed to read reference image!');
30-
});
31-
});
4+
const compareImage = async (options, testName) => {
5+
const referenceFile = `${options.screenshots}/${testName}.png`;
6+
const testFile = `${options.testReportPath}/${testName}.png`;
7+
8+
let referenceImage;
9+
try {
10+
referenceImage = await Jimp.read(referenceFile);
11+
} catch (err) {
12+
throw new Error(`${testName}: failed to read reference image ${err}`);
13+
}
14+
15+
let testImage;
16+
try {
17+
testImage = await Jimp.read(testFile);
18+
} catch (err) {
19+
throw new Error(`${testName}: failed to read test image ${err}`);
20+
}
21+
22+
const distance = Jimp.distance(referenceImage, testImage);
23+
const diff = Jimp.diff(referenceImage, testImage, options.mismatchThreshold);
24+
if (distance < options.mismatchThreshold || diff.percent < options.mismatchThreshold) {
25+
return `${testName}: no mismatch found ✅`;
26+
}
27+
if (options.saveDifferencifiedImage) {
28+
const diffPath = `${options.testReportPath}/${testName}_differencified.png`;
29+
logger.log(`${testName}: Saving the diff image to disk at ${diffPath}`);
30+
diff.image.write(diffPath);
31+
}
32+
throw new Error(`${testName}: mismatch found❗
33+
Result:
34+
distance: ${distance}
35+
diff: ${diff.percent}
36+
misMatchThreshold: ${options.mismatchThreshold}
37+
`);
38+
};
3239

3340
export default compareImage;

src/compareImage.test.js

Lines changed: 98 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,108 @@
11
import Jimp from 'jimp';
22
import compareImage from './compareImage';
3-
import logger from './logger';
4-
import { globalConfig } from './defaultConfig';
53

6-
Jimp.read = path =>
7-
new Promise((resolve, reject) => {
8-
if (path === './screenshots/test1.png' || path === './differencify_report/test1.png') {
9-
return resolve('image');
4+
const mockConfig = {
5+
screenshots: './screenshots',
6+
testReportPath: './differencify_report',
7+
saveDifferencifiedImage: false,
8+
mismatchThreshold: 0.01,
9+
};
10+
11+
jest.mock('jimp', () => ({
12+
read: jest.fn(),
13+
distance: jest.fn(),
14+
diff: jest.fn(),
15+
}));
16+
17+
18+
jest.mock('./logger', () => ({
19+
log: jest.fn(),
20+
}));
21+
22+
describe('Compare Image', () => {
23+
beforeEach(() => {
24+
Jimp.distance.mockReturnValue(0);
25+
Jimp.diff.mockReturnValue({ percent: 0 });
26+
});
27+
28+
it('calls Jimp with correct image names', async () => {
29+
expect.assertions(2);
30+
await compareImage(mockConfig, 'test');
31+
expect(Jimp.read).toHaveBeenCalledWith('./differencify_report/test.png');
32+
expect(Jimp.read).toHaveBeenCalledWith('./screenshots/test.png');
33+
});
34+
35+
it('throws correct error if it cannot read image', async () => {
36+
expect.assertions(2);
37+
Jimp.read
38+
.mockReturnValueOnce(Promise.reject('error1'))
39+
.mockReturnValueOnce(Promise.resolve())
40+
.mockReturnValueOnce(Promise.reject('error2'));
41+
42+
try {
43+
await compareImage(mockConfig, 'test1');
44+
} catch (err) {
45+
expect(err.message).toEqual('test1: failed to read reference image error1');
46+
}
47+
48+
try {
49+
expect(await compareImage(mockConfig, 'test2')).toThrow();
50+
} catch (err) {
51+
expect(err.message).toEqual('test2: failed to read test image error2');
1052
}
11-
return reject('error');
1253
});
1354

14-
Jimp.distance = (referenceImage, testImage) => {
15-
if (referenceImage === 'image' && testImage === 'image') {
16-
return 0;
17-
}
18-
return 1;
19-
};
55+
it('returns correct value if difference below threshold', async () => {
56+
const result = await compareImage(mockConfig, 'test');
57+
expect(result).toEqual('test: no mismatch found ✅');
58+
});
2059

21-
Jimp.diff = () => jest.fn();
60+
it('returns correct value if only difference above threshold', async () => {
61+
Jimp.diff.mockReturnValue({ percent: 0.02 });
2262

23-
let loggerCalls = [];
24-
logger.log = (...args) => {
25-
loggerCalls.push(...args);
26-
};
63+
const result = await compareImage(mockConfig, 'test');
64+
expect(result).toEqual('test: no mismatch found ✅');
65+
});
2766

28-
describe('Compare Image', () => {
29-
afterEach(() => {
30-
loggerCalls = [];
31-
});
32-
it('returns correct values', async () =>
33-
compareImage(globalConfig, 'test1')
34-
.catch((result) => {
35-
expect(result).toEqual('Failed to read test image!');
36-
expect(loggerCalls[0]).toEqual('Saving the diff image to disk');
37-
}));
67+
it('returns correct value if only distance above threshold', async () => {
68+
Jimp.distance.mockReturnValue(0.02);
69+
70+
const result = await compareImage(mockConfig, 'test');
71+
expect(result).toEqual('test: no mismatch found ✅');
72+
});
73+
74+
it('throws error if distance and difference are above threshold', async () => {
75+
expect.assertions(1);
76+
Jimp.distance.mockReturnValue(0.02);
77+
Jimp.diff.mockReturnValue({ percent: 0.02 });
78+
79+
try {
80+
await compareImage(mockConfig, 'test');
81+
} catch (err) {
82+
expect(err.message).toEqual(`test: mismatch found❗
83+
Result:
84+
distance: 0.02
85+
diff: 0.02
86+
misMatchThreshold: 0.01
87+
`);
88+
}
89+
});
90+
91+
it('writes to disk diff image if saveDifferencifiedImage is true', async () => {
92+
expect.assertions(1);
93+
Jimp.distance.mockReturnValue(0.02);
94+
const mockWrite = jest.fn();
95+
Jimp.diff.mockReturnValue({
96+
percent: 0.02,
97+
image: {
98+
write: mockWrite,
99+
},
100+
});
101+
try {
102+
// eslint-disable-next-line prefer-object-spread/prefer-object-spread
103+
await compareImage(Object.assign({}, mockConfig, { saveDifferencifiedImage: true }), 'test');
104+
} catch (err) {
105+
expect(mockWrite).toHaveBeenCalledWith('./differencify_report/test_differencified.png');
106+
}
107+
});
38108
});

0 commit comments

Comments
 (0)