vitest-plugin-vis 1.0.2 → 1.0.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../../src/server/browser_provider/playwright.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,wBAAgB,UAAU,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAYrE"}
1
+ {"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../../src/server/browser_provider/playwright.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,wBAAgB,UAAU,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAWrE"}
@@ -3,11 +3,10 @@ export function playwright(context) {
3
3
  async takeScreenshot(filePath, selector, options) {
4
4
  // The `Locator` type from `vitest` has less props than the `Locator` in `playwright`
5
5
  const subject = context.iframe.locator(selector ?? 'body');
6
- const buffer = await subject.screenshot({
6
+ return subject.screenshot({
7
7
  timeout: options?.timeout,
8
8
  path: filePath,
9
9
  });
10
- return buffer.toString('base64');
11
10
  },
12
11
  };
13
12
  }
@@ -1,6 +1,6 @@
1
1
  export interface BrowserApi {
2
2
  takeScreenshot(filePath: string, selector: string, options: {
3
3
  timeout?: number | undefined;
4
- } | undefined): Promise<string>;
4
+ } | undefined): Promise<Buffer>;
5
5
  }
6
6
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webdriverio.d.ts","sourceRoot":"","sources":["../../../src/server/browser_provider/webdriverio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,wBAAgB,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAStE"}
1
+ {"version":3,"file":"webdriverio.d.ts","sourceRoot":"","sources":["../../../src/server/browser_provider/webdriverio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,wBAAgB,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAQtE"}
@@ -3,8 +3,7 @@ export function webdriverio(context) {
3
3
  return {
4
4
  async takeScreenshot(filePath, selector) {
5
5
  const element = await page.$(`${selector ?? 'body'}`);
6
- const buffer = await element.saveScreenshot(filePath);
7
- return buffer.toString('base64');
6
+ return element.saveScreenshot(filePath);
8
7
  },
9
8
  };
10
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"match_image_snapshot.d.ts","sourceRoot":"","sources":["../../../src/server/commands/match_image_snapshot.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAyB,MAAM,aAAa,CAAA;AAIxE,OAAO,KAAK,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,uBAAuB,CAAA;AAM9B,MAAM,WAAW,yBAAyB;IACzC,kBAAkB,EAAE,CACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,yBAAyB,GAAG,SAAS,KAC3C,OAAO,CAAC,IAAI,CAAC,CAAA;CAClB;AAED,MAAM,WAAW,yBAChB,SAAQ,2BAA2B,EAClC,sBAAsB,EACtB,2BAA2B;IAC5B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAC9C;IAAC,MAAM,EAAE,MAAM;IAAE,OAAO,EAAE,MAAM;IAAE,OAAO,CAAC,EAAE,yBAAyB,GAAG,SAAS;CAAC,CA2DlF,CAAA"}
1
+ {"version":3,"file":"match_image_snapshot.d.ts","sourceRoot":"","sources":["../../../src/server/commands/match_image_snapshot.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAyB,MAAM,aAAa,CAAA;AAIxE,OAAO,KAAK,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,uBAAuB,CAAA;AAM9B,MAAM,WAAW,yBAAyB;IACzC,kBAAkB,EAAE,CACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,yBAAyB,GAAG,SAAS,KAC3C,OAAO,CAAC,IAAI,CAAC,CAAA;CAClB;AAED,MAAM,WAAW,yBAChB,SAAQ,2BAA2B,EAClC,sBAAsB,EACtB,2BAA2B;IAC5B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAC9C;IAAC,MAAM,EAAE,MAAM;IAAE,OAAO,EAAE,MAAM;IAAE,OAAO,CAAC,EAAE,yBAAyB,GAAG,SAAS;CAAC,CA4DlF,CAAA"}
@@ -19,17 +19,20 @@ export const matchImageSnapshot = async (context, taskId, subject, options) => {
19
19
  options = {};
20
20
  options.timeout = options.timeout ?? (ci ? 30000 : 5000);
21
21
  const info = visContext.getSnapshotInfo(context.testPath, taskId, options);
22
- const baselineBase64 = await file.tryReadFileBase64(info.baselinePath);
23
- if (!baselineBase64) {
24
- await takeSnapshot(context, subject, info.baselinePath, options);
22
+ const baselineBuffer = await file.tryReadFile(info.baselinePath);
23
+ if (!baselineBuffer) {
24
+ if (isBase64String(subject)) {
25
+ await writeSnapshot(info.baselinePath, subject);
26
+ }
27
+ else {
28
+ await takeSnapshotByBrowser(context, info.baselinePath, subject, options);
29
+ }
25
30
  return;
26
31
  }
27
- const resultBase64 = await takeSnapshot(context, subject, info.resultPath, options);
28
- const baselineImage = PNG.sync.read(Buffer.from(baselineBase64, 'base64'));
29
- const resultImage = PNG.sync.read(Buffer.from(resultBase64, 'base64'));
30
- const [baselineAlignedImage, resultAlignedImage] = isSameSize(baselineImage, resultImage)
31
- ? [baselineImage, resultImage]
32
- : alignImageSizes(baselineImage, resultImage);
32
+ const resultBuffer = await takeSnapshot(context, subject, info.resultPath, options);
33
+ const baselineImage = PNG.sync.read(baselineBuffer, { skipRescale: true, checkCRC: false });
34
+ const resultImage = PNG.sync.read(resultBuffer, { skipRescale: true, checkCRC: false });
35
+ const [baselineAlignedImage, resultAlignedImage] = alignImageSizes(baselineImage, resultImage);
33
36
  const { pass, diffAmount, diffImage } = compareImage(baselineAlignedImage, resultAlignedImage, options);
34
37
  if (pass) {
35
38
  if (sizeNotChanged(baselineImage, baselineAlignedImage) && sizeNotChanged(resultImage, resultAlignedImage)) {
@@ -42,8 +45,7 @@ export const matchImageSnapshot = async (context, taskId, subject, options) => {
42
45
  Expected: ${resolve(context.project.runner.root, info.baselinePath)}
43
46
  Actual: ${resolve(context.project.runner.root, info.resultPath)}`);
44
47
  }
45
- const diffBase64 = PNG.sync.write(diffImage).toString('base64');
46
- await writeSnapshot(diffBase64, info.diffPath);
48
+ await writeSnapshotBuffer(info.diffPath, diffImage.data);
47
49
  throw new Error(dedent `Snapshot \`${taskId}\` mismatched
48
50
 
49
51
  ${options?.failureThreshold
@@ -60,30 +62,35 @@ export const matchImageSnapshot = async (context, taskId, subject, options) => {
60
62
  };
61
63
  async function takeSnapshot(context, subject, filePath, options) {
62
64
  if (isBase64String(subject)) {
63
- return writeSnapshot(subject, filePath);
65
+ await writeSnapshot(filePath, subject);
66
+ return Buffer.from(subject, 'base64');
64
67
  }
68
+ return takeSnapshotByBrowser(context, filePath, subject, options);
69
+ }
70
+ async function takeSnapshotByBrowser(context, filePath, subject, options) {
65
71
  await mkdirp(dirname(filePath));
66
72
  const browser = browserApi(context);
67
73
  return browser.takeScreenshot(filePath, subject, {
68
74
  timeout: options?.timeout,
69
75
  });
70
76
  }
71
- async function writeSnapshot(subject, filePath) {
77
+ async function writeSnapshot(filePath, subject) {
72
78
  await mkdirp(dirname(filePath));
73
- await file.writeFileBase64(filePath, subject);
74
- return subject;
79
+ await file.writeFile(filePath, subject, { encoding: 'base64' });
80
+ }
81
+ async function writeSnapshotBuffer(filePath, subject) {
82
+ await mkdirp(dirname(filePath));
83
+ await file.writeFile(filePath, subject);
75
84
  }
76
85
  function alignImageSizes(baseline, result) {
86
+ if (isSameSize(baseline, result))
87
+ return [baseline, result];
77
88
  const size = getMaxSize(baseline, result);
78
- if (baseline.width !== size.width || baseline.height !== size.height) {
79
- baseline = resizeImage(baseline, size);
80
- }
81
- if (result.width !== size.width || result.height !== size.height) {
82
- result = resizeImage(result, size);
83
- }
84
- return [baseline, result];
89
+ return [resizeImage(baseline, size), resizeImage(result, size)];
85
90
  }
86
91
  function resizeImage(image, size) {
92
+ if (isSameSize(image, size))
93
+ return image;
87
94
  const resized = new PNG(size);
88
95
  PNG.bitblt(image, resized, 0, 0, image.width, image.height);
89
96
  return resized;
@@ -1,6 +1,7 @@
1
+ import { writeFile } from 'node:fs/promises';
1
2
  export declare const file: {
2
- tryReadFileBase64(filePath: string): Promise<string | undefined>;
3
- writeFileBase64(filePath: string, data: string): Promise<void>;
3
+ tryReadFile(filePath: string): Promise<Buffer | undefined>;
4
+ writeFile: typeof writeFile;
4
5
  existFile(filePath: string): Promise<boolean>;
5
6
  };
6
7
  //# sourceMappingURL=file.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/server/file.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI;gCACkB,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;8BAG5C,MAAM,QAAQ,MAAM;wBAG1B,MAAM;CAK1B,CAAA"}
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/server/file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAE5D,eAAO,MAAM,IAAI;0BACY,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;;wBAI5C,MAAM;CAK1B,CAAA"}
@@ -1,11 +1,9 @@
1
1
  import { readFile, stat, writeFile } from 'node:fs/promises';
2
2
  export const file = {
3
- async tryReadFileBase64(filePath) {
4
- return readFile(filePath, { encoding: 'base64' }).catch(() => undefined);
5
- },
6
- writeFileBase64(filePath, data) {
7
- return writeFile(filePath, data, { encoding: 'base64' });
3
+ async tryReadFile(filePath) {
4
+ return readFile(filePath).catch(() => undefined);
8
5
  },
6
+ writeFile,
9
7
  existFile(filePath) {
10
8
  return stat(filePath)
11
9
  .then((s) => s.isFile())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitest-plugin-vis",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Vitest visual testing plugin",
5
5
  "keywords": [
6
6
  "image-snapshot",
@@ -6,11 +6,10 @@ export function playwright(context: BrowserCommandContext): BrowserApi {
6
6
  async takeScreenshot(filePath, selector, options) {
7
7
  // The `Locator` type from `vitest` has less props than the `Locator` in `playwright`
8
8
  const subject = context.iframe.locator(selector ?? 'body')
9
- const buffer = await subject.screenshot({
9
+ return subject.screenshot({
10
10
  timeout: options?.timeout,
11
11
  path: filePath,
12
12
  })
13
- return buffer.toString('base64')
14
13
  },
15
14
  }
16
15
  }
@@ -7,5 +7,5 @@ export interface BrowserApi {
7
7
  timeout?: number | undefined
8
8
  }
9
9
  | undefined,
10
- ): Promise<string>
10
+ ): Promise<Buffer>
11
11
  }
@@ -6,8 +6,7 @@ export function webdriverio(context: BrowserCommandContext): BrowserApi {
6
6
  return {
7
7
  async takeScreenshot(filePath, selector) {
8
8
  const element = await page.$(`${selector ?? 'body'}`)
9
- const buffer = await element.saveScreenshot(filePath)
10
- return buffer.toString('base64')
9
+ return element.saveScreenshot(filePath)
11
10
  },
12
11
  }
13
12
  }
@@ -47,18 +47,20 @@ export const matchImageSnapshot: BrowserCommand<
47
47
  options.timeout = options.timeout ?? (ci ? 30000 : 5000)
48
48
 
49
49
  const info = visContext.getSnapshotInfo(context.testPath, taskId, options)
50
- const baselineBase64 = await file.tryReadFileBase64(info.baselinePath)
51
- if (!baselineBase64) {
52
- await takeSnapshot(context, subject, info.baselinePath, options)
50
+ const baselineBuffer = await file.tryReadFile(info.baselinePath)
51
+ if (!baselineBuffer) {
52
+ if (isBase64String(subject)) {
53
+ await writeSnapshot(info.baselinePath, subject)
54
+ } else {
55
+ await takeSnapshotByBrowser(context, info.baselinePath, subject, options)
56
+ }
53
57
  return
54
58
  }
55
59
 
56
- const resultBase64 = await takeSnapshot(context, subject, info.resultPath, options)
57
- const baselineImage = PNG.sync.read(Buffer.from(baselineBase64, 'base64'))
58
- const resultImage = PNG.sync.read(Buffer.from(resultBase64, 'base64'))
59
- const [baselineAlignedImage, resultAlignedImage] = isSameSize(baselineImage, resultImage)
60
- ? [baselineImage, resultImage]
61
- : alignImageSizes(baselineImage, resultImage)
60
+ const resultBuffer = await takeSnapshot(context, subject, info.resultPath, options)
61
+ const baselineImage = PNG.sync.read(baselineBuffer, { skipRescale: true, checkCRC: false })
62
+ const resultImage = PNG.sync.read(resultBuffer, { skipRescale: true, checkCRC: false })
63
+ const [baselineAlignedImage, resultAlignedImage] = alignImageSizes(baselineImage, resultImage)
62
64
 
63
65
  const { pass, diffAmount, diffImage } = compareImage(baselineAlignedImage, resultAlignedImage, options)
64
66
  if (pass) {
@@ -75,8 +77,7 @@ export const matchImageSnapshot: BrowserCommand<
75
77
  )
76
78
  }
77
79
 
78
- const diffBase64 = PNG.sync.write(diffImage).toString('base64')
79
- await writeSnapshot(diffBase64, info.diffPath)
80
+ await writeSnapshotBuffer(info.diffPath, diffImage.data)
80
81
 
81
82
  throw new Error(
82
83
  dedent`Snapshot \`${taskId}\` mismatched
@@ -104,9 +105,18 @@ async function takeSnapshot(
104
105
  options: ImageSnapshotTimeoutOptions | undefined,
105
106
  ) {
106
107
  if (isBase64String(subject)) {
107
- return writeSnapshot(subject, filePath)
108
+ await writeSnapshot(filePath, subject)
109
+ return Buffer.from(subject, 'base64')
108
110
  }
111
+ return takeSnapshotByBrowser(context, filePath, subject, options)
112
+ }
109
113
 
114
+ async function takeSnapshotByBrowser(
115
+ context: BrowserCommandContext,
116
+ filePath: string,
117
+ subject: string,
118
+ options: ImageSnapshotTimeoutOptions | undefined,
119
+ ) {
110
120
  await mkdirp(dirname(filePath))
111
121
  const browser = browserApi(context)
112
122
  return browser.takeScreenshot(filePath, subject, {
@@ -114,27 +124,25 @@ async function takeSnapshot(
114
124
  })
115
125
  }
116
126
 
117
- async function writeSnapshot(subject: string, filePath: string) {
127
+ async function writeSnapshot(filePath: string, subject: string) {
128
+ await mkdirp(dirname(filePath))
129
+ await file.writeFile(filePath, subject, { encoding: 'base64' })
130
+ }
131
+ async function writeSnapshotBuffer(filePath: string, subject: Buffer) {
118
132
  await mkdirp(dirname(filePath))
119
- await file.writeFileBase64(filePath, subject)
120
- return subject
133
+ await file.writeFile(filePath, subject)
121
134
  }
122
135
 
123
136
  function alignImageSizes(baseline: PNG, result: PNG) {
124
- const size = getMaxSize(baseline, result)
125
-
126
- if (baseline.width !== size.width || baseline.height !== size.height) {
127
- baseline = resizeImage(baseline, size)
128
- }
137
+ if (isSameSize(baseline, result)) return [baseline, result] as const
129
138
 
130
- if (result.width !== size.width || result.height !== size.height) {
131
- result = resizeImage(result, size)
132
- }
133
-
134
- return [baseline, result] as const
139
+ const size = getMaxSize(baseline, result)
140
+ return [resizeImage(baseline, size), resizeImage(result, size)] as const
135
141
  }
136
142
 
137
143
  function resizeImage(image: PNG, size: { width: number; height: number }) {
144
+ if (isSameSize(image, size)) return image
145
+
138
146
  const resized = new PNG(size)
139
147
  PNG.bitblt(image, resized, 0, 0, image.width, image.height)
140
148
  return resized
@@ -1,12 +1,10 @@
1
1
  import { readFile, stat, writeFile } from 'node:fs/promises'
2
2
 
3
3
  export const file = {
4
- async tryReadFileBase64(filePath: string): Promise<string | undefined> {
5
- return readFile(filePath, { encoding: 'base64' }).catch(() => undefined)
6
- },
7
- writeFileBase64(filePath: string, data: string) {
8
- return writeFile(filePath, data, { encoding: 'base64' })
4
+ async tryReadFile(filePath: string): Promise<Buffer | undefined> {
5
+ return readFile(filePath).catch(() => undefined)
9
6
  },
7
+ writeFile,
10
8
  existFile(filePath: string) {
11
9
  return stat(filePath)
12
10
  .then((s) => s.isFile())