Skip to content

Commit 9f94086

Browse files
committed
feat: externalize important APIs
add proper README info
1 parent 541652c commit 9f94086

File tree

3 files changed

+71
-19
lines changed

3 files changed

+71
-19
lines changed

README.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,34 @@ cy.matchImage();
109109

110110
This plugin can be configured either:
111111

112-
- via global env configuration,
112+
- directly, on a matcher level - by passing in plugin options as an argument to `matchImage` command, e.g.:
113113

114-
- directly, on a matcher level - by passing in plugin options as an argument to `matchImage` command.
114+
```ts
115+
cy.matchImage({
116+
// screenshot configuration, passed directly to the the Cypress screenshot method: https://docs.cypress.io/api/cypress-api/screenshot-api#Arguments
117+
// default: { }
118+
screenshotConfig: {
119+
blackout: ['.element-to-be-blackouted']
120+
},
121+
// pixelmatch options, see: https://www.npmjs.com/package/pixelmatch#pixelmatchimg1-img2-output-width-height-options
122+
// default: { includeAA: true }
123+
diffConfig: {
124+
threshold: '0.01',
125+
},
126+
// whether to update images automatically, without making a diff - useful for CI
127+
// default: false
128+
updateImages: true,
129+
// maximum threshold above which the test should fail
130+
// default: 0.01
131+
maxDiffThreshold: 0.1
132+
})
133+
```
134+
135+
- via [global env configuration](https://docs.cypress.io/guides/guides/environment-variables#Setting). All of the environment variable names are the same as keys of the configuration options passed to `matchImage` method, but with added `pluginVisualRegression` prefix, e.g.:
136+
137+
```bash
138+
npx cypress run --env "pluginVisualRegressionUpdateImages=true" --env 'pluginVisualRegressionDiffConfig={"threshold":"0.01"}'
139+
```
115140

116141
## Questions
117142

src/commands.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ declare global {
55
// eslint-disable-next-line @typescript-eslint/no-namespace
66
namespace Cypress {
77
type MatchImageOptions = {
8-
suffix?: string;
98
screenshotConfig?: Partial<Cypress.ScreenshotDefaultsOptions>;
109
diffConfig?: Parameters<typeof pixelmatch>[5];
10+
updateImages?: boolean;
11+
maxDiffThreshold?: number;
1112
};
1213

1314
interface Chainable {
@@ -35,6 +36,31 @@ Cypress.Commands.add(
3536
nameCacheCounter[title] = -1;
3637
title += ` #${++nameCacheCounter[title]}`;
3738

39+
const updateImages =
40+
options.updateImages ||
41+
(Cypress.env("pluginVisualRegressionUpdateImages") as
42+
| boolean
43+
| undefined) ||
44+
false;
45+
const maxDiffThreshold =
46+
options.maxDiffThreshold ||
47+
(Cypress.env("pluginVisualRegressionMaxDiffThreshold") as
48+
| number
49+
| undefined) ||
50+
0.01;
51+
const diffConfig =
52+
options.diffConfig ||
53+
(Cypress.env("pluginVisualRegressionDiffConfig") as
54+
| Parameters<typeof pixelmatch>[5]
55+
| undefined) ||
56+
{};
57+
const screenshotConfig =
58+
options.screenshotConfig ||
59+
(Cypress.env("pluginVisualRegressionScreenshotConfig") as
60+
| Partial<Cypress.ScreenshotDefaultsOptions>
61+
| undefined) ||
62+
{};
63+
3864
return cy
3965
.then(() =>
4066
cy.task(
@@ -50,10 +76,10 @@ Cypress.Commands.add(
5076
let imgPath: string;
5177
return (subject ? cy.wrap(subject) : cy)
5278
.screenshot(screenshotPath as string, {
53-
...options.screenshotConfig,
79+
...screenshotConfig,
5480
onAfterScreenshot(el, props) {
5581
imgPath = props.path;
56-
options.screenshotConfig?.onAfterScreenshot?.(el, props);
82+
screenshotConfig.onAfterScreenshot?.(el, props);
5783
},
5884
log: false,
5985
})
@@ -66,7 +92,9 @@ Cypress.Commands.add(
6692
{
6793
imgNew: imgPath,
6894
imgOld: imgPath.replace(FILE_SUFFIX.actual, ""),
69-
...(options.diffConfig || {}),
95+
updateImages,
96+
maxDiffThreshold,
97+
diffConfig,
7098
},
7199
{ log: false }
72100
)

src/plugins.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,15 @@ export const initPlugin = (
8787
title: string;
8888
imgNew: string;
8989
imgOld: string;
90+
updateImages: boolean;
91+
maxDiffThreshold: number;
92+
diffConfig: Parameters<typeof pixelmatch>[5];
9093
} & Parameters<typeof pixelmatch>[5]
9194
) {
92-
const maxDiffThreshold = 0.01;
9395
let imgDiff: number | undefined;
9496
let errorMsg: string | undefined;
9597

96-
if (fs.existsSync(cfg.imgOld)) {
98+
if (fs.existsSync(cfg.imgOld) && !cfg.updateImages) {
9799
const rawImgNew = PNG.sync.read(fs.readFileSync(cfg.imgNew));
98100
const rawImgOld = PNG.sync.read(fs.readFileSync(cfg.imgOld));
99101
const isImgSizeDifferent =
@@ -106,26 +108,23 @@ export const initPlugin = (
106108

107109
const { width, height } = imgNew;
108110
const diff = new PNG({ width, height });
109-
const diffOptions = Object.assign(
110-
{ threshold: 0.01, includeAA: true },
111-
cfg
112-
);
111+
const diffConfig = Object.assign({ includeAA: true }, cfg.diffConfig);
113112

114113
const diffPixels = pixelmatch(
115114
imgNew.data,
116115
imgOld.data,
117116
diff.data,
118117
width,
119118
height,
120-
diffOptions
119+
diffConfig
121120
);
122121
imgDiff = (diffPixels / width) * height;
123122

124123
if (isImgSizeDifferent) {
125124
errorMsg = `Images size mismatch - new screenshot is ${rawImgNew.width}px by ${rawImgNew.height}px while old one is ${rawImgOld.width}px by ${rawImgOld.height} (width x height).`;
126-
} else if (imgDiff > maxDiffThreshold) {
125+
} else if (imgDiff > cfg.maxDiffThreshold) {
127126
const roundedImgDiff = Math.ceil(imgDiff * 1000) / 1000;
128-
errorMsg = `Image diff factor (${roundedImgDiff}) is bigger than maximum threshold option ${maxDiffThreshold}`;
127+
errorMsg = `Image diff factor (${roundedImgDiff}) is bigger than maximum threshold option ${cfg.maxDiffThreshold}`;
129128
}
130129

131130
if (errorMsg) {
@@ -137,13 +136,13 @@ export const initPlugin = (
137136
error: true,
138137
message: errorMsg,
139138
imgDiff,
140-
maxDiffThreshold,
139+
maxDiffThreshold: cfg.maxDiffThreshold,
141140
};
142141
}
143142

144143
fs.unlinkSync(cfg.imgOld);
145144
} else {
146-
// there is no "old screenshot"
145+
// there is no "old screenshot" or screenshots should be immediately updated
147146
imgDiff = 0;
148147
}
149148

@@ -152,9 +151,9 @@ export const initPlugin = (
152151
if (typeof imgDiff !== "undefined") {
153152
const roundedImgDiff = Math.ceil(imgDiff * 1000) / 1000;
154153
return {
155-
message: `Image diff (${roundedImgDiff}%) is within boundaries of maximum threshold option ${maxDiffThreshold}`,
154+
message: `Image diff (${roundedImgDiff}%) is within boundaries of maximum threshold option ${cfg.maxDiffThreshold}`,
156155
imgDiff,
157-
maxDiffThreshold,
156+
maxDiffThreshold: cfg.maxDiffThreshold,
158157
};
159158
}
160159

0 commit comments

Comments
 (0)