vitest-plugin-vis 2.4.3 → 3.0.0

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.
Files changed (264) hide show
  1. package/esm/client/actions/has_image_snapshot_action.d.ts +4 -0
  2. package/esm/client/actions/has_image_snapshot_action.d.ts.map +1 -0
  3. package/esm/client/actions/has_image_snapshot_action.js +6 -0
  4. package/esm/client/actions/load_image_snapshot_results_action.d.ts +3 -0
  5. package/esm/client/actions/load_image_snapshot_results_action.d.ts.map +1 -0
  6. package/esm/client/actions/load_image_snapshot_results_action.js +3 -0
  7. package/esm/client/actions/match_image_snapshot_action.d.ts +6 -0
  8. package/esm/client/actions/match_image_snapshot_action.d.ts.map +1 -0
  9. package/esm/client/actions/match_image_snapshot_action.js +20 -0
  10. package/esm/client/actions/match_page_image_snapshot_action.d.ts +6 -0
  11. package/esm/client/actions/match_page_image_snapshot_action.d.ts.map +1 -0
  12. package/esm/client/actions/match_page_image_snapshot_action.js +9 -0
  13. package/esm/client/auto_snapshot_options.d.ts +29 -0
  14. package/esm/client/auto_snapshot_options.d.ts.map +1 -0
  15. package/esm/client/auto_snapshot_options.js +49 -0
  16. package/esm/client/compare_image_snapshot.d.ts +6 -0
  17. package/esm/client/compare_image_snapshot.d.ts.map +1 -0
  18. package/esm/client/compare_image_snapshot.js +52 -0
  19. package/esm/client/{image_snapshot_matcher.logic.d.ts → compare_image_snapshot.logic.d.ts} +1 -1
  20. package/esm/client/compare_image_snapshot.logic.d.ts.map +1 -0
  21. package/esm/client/expect/to_match_image_snapshot.d.ts.map +1 -1
  22. package/esm/client/expect/to_match_image_snapshot.js +4 -3
  23. package/esm/client/image_resizer.d.ts.map +1 -1
  24. package/esm/client/image_snapshot_options.d.ts +2 -0
  25. package/esm/client/image_snapshot_options.d.ts.map +1 -0
  26. package/esm/client/image_snapshot_options.js +6 -0
  27. package/esm/client/page/augment.d.ts +2 -1
  28. package/esm/client/page/augment.d.ts.map +1 -1
  29. package/esm/client/page/extend.js +2 -1
  30. package/esm/client/page/has_image_snapshot.d.ts +6 -6
  31. package/esm/client/page/has_image_snapshot.d.ts.map +1 -1
  32. package/esm/client/page/has_image_snapshot.js +2 -11
  33. package/esm/client/page/to_match_image_snapshot.d.ts +8 -0
  34. package/esm/client/page/to_match_image_snapshot.d.ts.map +1 -0
  35. package/esm/client/page/to_match_image_snapshot.js +15 -0
  36. package/esm/client/setup/create_vis.d.ts +96 -0
  37. package/esm/client/setup/create_vis.d.ts.map +1 -0
  38. package/esm/{setup → client/setup}/create_vis.js +43 -31
  39. package/esm/client/setup/vis.ctx.d.ts +12 -0
  40. package/esm/client/setup/vis.ctx.d.ts.map +1 -0
  41. package/esm/client/setup/vis.ctx.js +32 -0
  42. package/esm/client/setup/vis.d.ts +5 -0
  43. package/esm/client/setup/vis.d.ts.map +1 -0
  44. package/esm/client/should_take_snapshot.d.ts +2 -9
  45. package/esm/client/should_take_snapshot.d.ts.map +1 -1
  46. package/esm/client/should_take_snapshot.js +1 -11
  47. package/esm/client/snapshot_meta.d.ts +6 -0
  48. package/esm/client/snapshot_meta.d.ts.map +1 -0
  49. package/esm/client/task_id.d.ts +0 -3
  50. package/esm/client/task_id.d.ts.map +1 -1
  51. package/esm/client/task_id.js +0 -3
  52. package/esm/client/vitest_suite_proxy.d.ts +2 -9
  53. package/esm/client/vitest_suite_proxy.d.ts.map +1 -1
  54. package/esm/client-api.d.ts +11 -0
  55. package/esm/client-api.d.ts.map +1 -0
  56. package/esm/client-api.js +8 -0
  57. package/esm/commands.d.ts +0 -1
  58. package/esm/commands.d.ts.map +1 -1
  59. package/esm/commands.js +0 -1
  60. package/esm/config/types.d.ts +22 -22
  61. package/esm/config/types.d.ts.map +1 -1
  62. package/esm/config/vis.d.ts +4 -3
  63. package/esm/config/vis.d.ts.map +1 -1
  64. package/esm/config/vis.js +3 -4
  65. package/esm/index.d.ts +1 -1
  66. package/esm/index.d.ts.map +1 -1
  67. package/esm/index.js +1 -1
  68. package/esm/presets/auto.d.ts +1 -2
  69. package/esm/presets/auto.d.ts.map +1 -1
  70. package/esm/presets/auto.js +8 -4
  71. package/esm/presets/enable.d.ts +1 -2
  72. package/esm/presets/enable.d.ts.map +1 -1
  73. package/esm/presets/enable.js +4 -4
  74. package/esm/presets/manual.d.ts +1 -2
  75. package/esm/presets/manual.d.ts.map +1 -1
  76. package/esm/presets/manual.js +3 -4
  77. package/esm/server/browser_provider/playwright.d.ts.map +1 -1
  78. package/esm/server/browser_provider/playwright.js +9 -3
  79. package/esm/server/browser_provider/types.d.ts +5 -1
  80. package/esm/server/browser_provider/types.d.ts.map +1 -1
  81. package/esm/server/browser_provider/webdriverio.d.ts.map +1 -1
  82. package/esm/server/browser_provider/webdriverio.js +7 -4
  83. package/esm/server/commands/augment.d.ts +11 -0
  84. package/esm/server/commands/augment.d.ts.map +1 -0
  85. package/esm/server/commands/augment.js +1 -0
  86. package/esm/server/commands/commands.d.ts +9 -0
  87. package/esm/server/commands/commands.d.ts.map +1 -0
  88. package/esm/server/commands/commands.js +14 -0
  89. package/esm/server/commands/has_image_snapshot.d.ts +2 -6
  90. package/esm/server/commands/has_image_snapshot.d.ts.map +1 -1
  91. package/esm/server/commands/has_image_snapshot.js +3 -3
  92. package/esm/server/commands/image_snapshot_next_index.d.ts +1 -1
  93. package/esm/server/commands/image_snapshot_next_index.d.ts.map +1 -1
  94. package/esm/server/commands/image_snapshot_next_index.js +2 -2
  95. package/esm/server/commands/load_image_snapshot_results.d.ts +21 -0
  96. package/esm/server/commands/load_image_snapshot_results.d.ts.map +1 -0
  97. package/esm/server/commands/load_image_snapshot_results.js +6 -0
  98. package/esm/server/commands/prepare_image_snapshot_comparison.d.ts +8 -10
  99. package/esm/server/commands/prepare_image_snapshot_comparison.d.ts.map +1 -1
  100. package/esm/server/commands/prepare_image_snapshot_comparison.js +11 -9
  101. package/esm/server/commands/prepare_page_image_snapshot_comparison.d.ts +35 -0
  102. package/esm/server/commands/prepare_page_image_snapshot_comparison.d.ts.map +1 -0
  103. package/esm/server/commands/prepare_page_image_snapshot_comparison.js +27 -0
  104. package/esm/server/commands/setup_vis_suite.d.ts +3 -3
  105. package/esm/server/commands/setup_vis_suite.d.ts.map +1 -1
  106. package/esm/server/commands/setup_vis_suite.js +2 -3
  107. package/esm/server/commands/types.d.ts +3 -0
  108. package/esm/server/commands/types.d.ts.map +1 -0
  109. package/esm/server/commands/types.js +1 -0
  110. package/esm/server/externals/file.d.ts +10 -0
  111. package/esm/server/externals/file.d.ts.map +1 -0
  112. package/esm/server/{file.js → externals/file.js} +12 -4
  113. package/esm/server/{commands/browser_command_context.d.ts → project.d.ts} +8 -3
  114. package/esm/server/project.d.ts.map +1 -0
  115. package/esm/server/{commands/browser_command_context.js → project.js} +2 -2
  116. package/esm/server/snapshot.d.ts +4 -5
  117. package/esm/server/snapshot.d.ts.map +1 -1
  118. package/esm/server/snapshot.js +15 -13
  119. package/esm/server/snapshot_path.d.ts +3 -3
  120. package/esm/server/snapshot_path.d.ts.map +1 -1
  121. package/esm/server/snapshot_path.js +12 -11
  122. package/esm/server/snapshot_writer.d.ts +13 -0
  123. package/esm/server/snapshot_writer.d.ts.map +1 -0
  124. package/esm/server/snapshot_writer.js +15 -0
  125. package/esm/server/suite.d.ts +53 -0
  126. package/esm/server/suite.d.ts.map +1 -0
  127. package/esm/server/suite.js +73 -0
  128. package/esm/server/vis_options.d.ts +18 -0
  129. package/esm/server/vis_options.d.ts.map +1 -0
  130. package/esm/server/vis_options.js +14 -0
  131. package/esm/server/vis_server_context.d.ts +50 -0
  132. package/esm/server/vis_server_context.d.ts.map +1 -0
  133. package/esm/server/{vis_context.ctx.d.ts → vis_server_context.deps.d.ts} +2 -2
  134. package/esm/server/vis_server_context.deps.d.ts.map +1 -0
  135. package/esm/server/{vis_context.ctx.js → vis_server_context.deps.js} +1 -1
  136. package/esm/server/vis_server_context.js +2 -0
  137. package/esm/server/{vis_context.logic.d.ts → vis_server_context.logic.d.ts} +12 -32
  138. package/esm/server/vis_server_context.logic.d.ts.map +1 -0
  139. package/esm/server/vis_server_context.logic.js +79 -0
  140. package/esm/server/{vis_context.types.d.ts → vis_server_context.types.d.ts} +6 -6
  141. package/esm/server/vis_server_context.types.d.ts.map +1 -0
  142. package/esm/server/vis_server_context.types.js +1 -0
  143. package/esm/server-utils.d.ts +3 -0
  144. package/esm/server-utils.d.ts.map +1 -0
  145. package/esm/server-utils.js +2 -0
  146. package/esm/setup.d.ts +2 -2
  147. package/esm/setup.d.ts.map +1 -1
  148. package/esm/setup.js +2 -2
  149. package/esm/shared/asserts.d.ts +2 -0
  150. package/esm/shared/asserts.d.ts.map +1 -0
  151. package/esm/shared/asserts.js +5 -0
  152. package/esm/shared/types.d.ts +22 -21
  153. package/esm/shared/types.d.ts.map +1 -1
  154. package/esm/testing/stubBrowserCommandContext.d.ts +1 -1
  155. package/esm/testing/stubBrowserCommandContext.d.ts.map +1 -1
  156. package/esm/testing/stubBrowserCommandContext.js +3 -13
  157. package/esm/testing/stubSuite.d.ts +10 -0
  158. package/esm/testing/stubSuite.d.ts.map +1 -0
  159. package/esm/testing/stubSuite.js +27 -0
  160. package/esm/testing/stubUserConfig.d.ts +7 -0
  161. package/esm/testing/stubUserConfig.d.ts.map +1 -0
  162. package/esm/testing/stubUserConfig.js +4 -0
  163. package/package.json +29 -28
  164. package/readme.md +409 -110
  165. package/src/client/actions/has_image_snapshot_action.ts +14 -0
  166. package/src/client/actions/load_image_snapshot_results_action.ts +5 -0
  167. package/src/client/actions/match_image_snapshot_action.ts +32 -0
  168. package/src/client/actions/match_page_image_snapshot_action.ts +20 -0
  169. package/src/client/auto_snapshot_options.ts +71 -0
  170. package/src/client/compare_image_snapshot.ts +84 -0
  171. package/src/client/expect/to_match_image_snapshot.ts +4 -3
  172. package/src/client/image_snapshot_options.ts +6 -0
  173. package/src/client/page/augment.ts +2 -1
  174. package/src/client/page/extend.ts +2 -1
  175. package/src/client/page/has_image_snapshot.ts +8 -21
  176. package/src/client/page/to_match_image_snapshot.ts +27 -0
  177. package/src/client/setup/create_vis.ts +227 -0
  178. package/src/client/setup/vis.ctx.ts +33 -0
  179. package/src/client/should_take_snapshot.ts +3 -13
  180. package/src/client/snapshot_meta.ts +7 -0
  181. package/src/client/task_id.ts +0 -3
  182. package/src/client/vitest_suite_proxy.ts +2 -5
  183. package/src/client-api.ts +11 -0
  184. package/src/commands.ts +0 -1
  185. package/src/config/types.ts +32 -27
  186. package/src/config/vis.ts +3 -5
  187. package/src/index.ts +1 -1
  188. package/src/presets/auto.ts +8 -4
  189. package/src/presets/enable.ts +4 -4
  190. package/src/presets/manual.ts +3 -4
  191. package/src/server/browser_provider/playwright.ts +9 -3
  192. package/src/server/browser_provider/types.ts +12 -1
  193. package/src/server/browser_provider/webdriverio.ts +7 -4
  194. package/src/server/commands/augment.ts +16 -0
  195. package/src/server/commands/commands.ts +15 -0
  196. package/src/server/commands/has_image_snapshot.ts +8 -6
  197. package/src/server/commands/image_snapshot_next_index.ts +5 -3
  198. package/src/server/commands/load_image_snapshot_results.ts +32 -0
  199. package/src/server/commands/prepare_image_snapshot_comparison.ts +20 -14
  200. package/src/server/commands/prepare_page_image_snapshot_comparison.ts +75 -0
  201. package/src/server/commands/setup_vis_suite.ts +17 -7
  202. package/src/server/commands/types.ts +9 -0
  203. package/src/server/externals/file.ts +21 -0
  204. package/src/server/{commands/browser_command_context.ts → project.ts} +2 -4
  205. package/src/server/snapshot.ts +23 -14
  206. package/src/server/snapshot_path.ts +15 -13
  207. package/src/server/snapshot_writer.ts +22 -0
  208. package/src/server/suite.ts +96 -0
  209. package/src/server/vis_options.ts +27 -0
  210. package/src/server/{vis_context.ctx.ts → vis_server_context.deps.ts} +1 -1
  211. package/src/server/vis_server_context.logic.ts +112 -0
  212. package/src/server/vis_server_context.ts +3 -0
  213. package/src/server/{vis_context.types.ts → vis_server_context.types.ts} +5 -5
  214. package/src/server-utils.ts +2 -0
  215. package/src/setup.ts +2 -2
  216. package/src/shared/asserts.ts +5 -0
  217. package/src/shared/types.ts +25 -23
  218. package/src/testing/stubBrowserCommandContext.ts +4 -14
  219. package/src/testing/stubSuite.ts +38 -0
  220. package/src/testing/stubUserConfig.ts +6 -0
  221. package/esm/client/image_snapshot_matcher.d.ts +0 -11
  222. package/esm/client/image_snapshot_matcher.d.ts.map +0 -1
  223. package/esm/client/image_snapshot_matcher.js +0 -80
  224. package/esm/client/image_snapshot_matcher.logic.d.ts.map +0 -1
  225. package/esm/client/snapshot_options.d.ts +0 -33
  226. package/esm/client/snapshot_options.d.ts.map +0 -1
  227. package/esm/client/snapshot_options.js +0 -37
  228. package/esm/client.d.ts +0 -8
  229. package/esm/client.d.ts.map +0 -1
  230. package/esm/client.js +0 -5
  231. package/esm/server/commands/browser_command_context.d.ts.map +0 -1
  232. package/esm/server/commands/extend.d.ts +0 -17
  233. package/esm/server/commands/extend.d.ts.map +0 -1
  234. package/esm/server/commands/extend.js +0 -12
  235. package/esm/server/commands/match_image_snapshot.d.ts +0 -18
  236. package/esm/server/commands/match_image_snapshot.d.ts.map +0 -1
  237. package/esm/server/commands/match_image_snapshot.js +0 -81
  238. package/esm/server/file.d.ts +0 -7
  239. package/esm/server/file.d.ts.map +0 -1
  240. package/esm/server/vis_context.ctx.d.ts.map +0 -1
  241. package/esm/server/vis_context.d.ts +0 -56
  242. package/esm/server/vis_context.d.ts.map +0 -1
  243. package/esm/server/vis_context.js +0 -2
  244. package/esm/server/vis_context.logic.d.ts.map +0 -1
  245. package/esm/server/vis_context.logic.js +0 -135
  246. package/esm/server/vis_context.types.d.ts.map +0 -1
  247. package/esm/setup/create_vis.d.ts +0 -53
  248. package/esm/setup/create_vis.d.ts.map +0 -1
  249. package/esm/setup/vis.d.ts +0 -5
  250. package/esm/setup/vis.d.ts.map +0 -1
  251. package/src/client/image_snapshot_matcher.ts +0 -121
  252. package/src/client/snapshot_options.ts +0 -82
  253. package/src/client.ts +0 -7
  254. package/src/server/commands/extend.ts +0 -25
  255. package/src/server/commands/match_image_snapshot.ts +0 -128
  256. package/src/server/file.ts +0 -13
  257. package/src/server/vis_context.logic.ts +0 -198
  258. package/src/server/vis_context.ts +0 -3
  259. package/src/setup/create_vis.ts +0 -154
  260. /package/esm/client/{image_snapshot_matcher.logic.js → compare_image_snapshot.logic.js} +0 -0
  261. /package/esm/{setup → client/setup}/vis.js +0 -0
  262. /package/esm/{server/vis_context.types.js → client/snapshot_meta.js} +0 -0
  263. /package/src/client/{image_snapshot_matcher.logic.ts → compare_image_snapshot.logic.ts} +0 -0
  264. /package/src/{setup → client/setup}/vis.ts +0 -0
@@ -1,121 +0,0 @@
1
- import type { BrowserCommands } from '@vitest/browser/context'
2
- import dedent from 'dedent'
3
- import { resolve } from 'pathe'
4
- import type { ImageSnapshotNextIndexCommand } from '../commands.ts'
5
- import type { PrepareImageSnapshotComparisonCommand } from '../server/commands/prepare_image_snapshot_comparison.ts'
6
- import { isBase64String } from '../shared/base64.ts'
7
- import { compareImage } from '../shared/compare_image.ts'
8
- import type { ToMatchImageSnapshotOptions } from '../shared/types.ts'
9
- import { alignImagesToSameSize } from './align_images.ts'
10
- import { toDataURL, toImageData } from './image_data.ts'
11
- import { prettifyOptions } from './image_snapshot_matcher.logic.ts'
12
- import { convertElementToCssSelector } from './selector.ts'
13
- import { toTaskId } from './task_id.ts'
14
- import { server } from './vitest_browser_context_proxy.ts'
15
- import type { CurrentTest } from './vitest_suite_proxy.ts'
16
-
17
- export function imageSnapshotMatcher(
18
- commands: BrowserCommands & PrepareImageSnapshotComparisonCommand & ImageSnapshotNextIndexCommand,
19
- ) {
20
- return async function matchImageSnapshot(
21
- test: CurrentTest & {},
22
- subject: any,
23
- options?: ToMatchImageSnapshotOptions<any>,
24
- ) {
25
- const isAutoSnapshot = !!test.meta.vis?.isAutoSnapshot
26
- const taskId = toTaskId(test)
27
- const info = await commands.prepareImageSnapshotComparison(
28
- taskId,
29
- parseImageSnapshotSubject(subject),
30
- isAutoSnapshot,
31
- options?.customizeSnapshotId
32
- ? await parseImageSnapshotOptions(commands, taskId, isAutoSnapshot, options)
33
- : options,
34
- )
35
-
36
- if (!info) return
37
-
38
- options = { ...info, ...options } as any
39
-
40
- const baselineImage = await toImageData(info.baseline)
41
- const resultImage = await toImageData(info.result)
42
- const [baselineAlignedImage, resultAlignedImage] = alignImagesToSameSize(baselineImage, resultImage)
43
- const { width, height } = baselineAlignedImage
44
- const diffImage = new ImageData(width, height)
45
- const { pass, diffAmount } = compareImage(
46
- baselineAlignedImage.data,
47
- resultAlignedImage.data,
48
- diffImage.data,
49
- width,
50
- height,
51
- options,
52
- )
53
- if (pass) {
54
- if (options?.expectToFail) {
55
- throw new Error(
56
- dedent`Snapshot \`${taskId}\` matched but expected to fail.
57
-
58
- Options: ${prettifyOptions(options)}
59
- Diff: ${options.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}
60
-
61
- Expected: ${resolve(info.projectRoot, info.baselinePath)}
62
- Actual: ${resolve(info.projectRoot, info.resultPath)}`,
63
- )
64
- }
65
- return
66
- }
67
- if (server.config.snapshotOptions.updateSnapshot === 'all' && !options?.expectToFail) {
68
- await writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage)
69
- return
70
- }
71
-
72
- await writeSnapshot(commands, resolve(info.projectRoot, info.diffPath), diffImage)
73
-
74
- throw new Error(
75
- dedent`Snapshot \`${taskId}\` mismatched
76
-
77
- ${
78
- options?.failureThreshold
79
- ? options?.failureThresholdType === 'percent'
80
- ? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`
81
- : `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`
82
- : `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`
83
- }
84
-
85
- Options: ${prettifyOptions(options)}
86
-
87
- Expected: ${resolve(info.projectRoot, info.baselinePath)}
88
- Actual: ${resolve(info.projectRoot, info.resultPath)}
89
- Difference: ${resolve(info.projectRoot, info.diffPath)}`,
90
- )
91
- }
92
- }
93
-
94
- /**
95
- * @deprecated internalized. Use `matchImageSnapshot` directly instead.
96
- */
97
- export function parseImageSnapshotSubject(subject: any) {
98
- if (subject instanceof Element) return convertElementToCssSelector(subject)
99
- if (subject?.['selector']) return subject['selector']
100
- if (isBase64String(subject)) return subject
101
- throw new Error(
102
- `'toMatchImageSnapshot()' expects the subject to be an element, locator, or image encoded in base64 string, but got: ${subject}`,
103
- )
104
- }
105
-
106
- async function writeSnapshot(commands: BrowserCommands, path: string, image: ImageData) {
107
- const content = (await toDataURL(image)).split(',')[1]!
108
- return commands.writeFile(path, content, { encoding: 'base64' })
109
- }
110
-
111
- async function parseImageSnapshotOptions(
112
- commands: ImageSnapshotNextIndexCommand,
113
- taskId: string,
114
- isAutoSnapshot: boolean,
115
- options: ToMatchImageSnapshotOptions<any>,
116
- ) {
117
- const index = await commands.imageSnapshotNextIndex(taskId)
118
- const { customizeSnapshotId, ...rest } = options
119
- const snapshotFileId = customizeSnapshotId!({ id: taskId, index, isAutoSnapshot })
120
- return { ...rest, snapshotFileId }
121
- }
@@ -1,82 +0,0 @@
1
- import { NAME } from '../shared/constants.ts'
2
- import type { ComparisonMethod, SnapshotMeta } from '../shared/types.ts'
3
- import { ctx } from './ctx.ts'
4
-
5
- type Suite = { meta: Record<string, any>; suite?: Suite | undefined }
6
-
7
- export type MetaTask =
8
- | {
9
- file?: { meta: Record<string, any> } | undefined
10
- suite?: Suite | undefined
11
- meta: Record<string, any>
12
- }
13
- | undefined
14
-
15
- export function enableAuto() {
16
- ctx.autoEnabled = true
17
- }
18
-
19
- /**
20
- * Set the snapshot options for auto snapshot.
21
- *
22
- * ```ts
23
- * beforeAll((suite) => setAutoSnapshotOptions(suite, ...))
24
- * beforeEach(({ task }) => setAutoSnapshotOptions(task, ...))
25
- *
26
- * it('...', ({ task }) => {
27
- * setAutoSnapshotOptions(task, ...)
28
- * })
29
- * ```
30
- *
31
- * @param task Optional. Suite or task to set the options.
32
- * If not provided, it will set the options for the current test.
33
- */
34
- export function setAutoSnapshotOptions<M extends ComparisonMethod>(
35
- task: MetaTask,
36
- meta: SnapshotMeta<M> | boolean,
37
- ): void
38
- export function setAutoSnapshotOptions<M extends ComparisonMethod>(meta: SnapshotMeta<M> | boolean): void
39
- export function setAutoSnapshotOptions<M extends ComparisonMethod>(
40
- ...args: [task: MetaTask, meta: SnapshotMeta<M> | boolean] | [meta: SnapshotMeta<M> | boolean]
41
- ): void {
42
- const [task, meta] = parseArgs(args)
43
- if (task)
44
- task.meta[NAME] = {
45
- ...task.meta[NAME],
46
- ...meta,
47
- }
48
- }
49
-
50
- function parseArgs<M extends ComparisonMethod>(
51
- args: [task: MetaTask, meta: SnapshotMeta<M> | boolean] | [meta: boolean | SnapshotMeta<M>],
52
- ): [MetaTask | undefined, SnapshotMeta<M>] {
53
- return args.length === 1
54
- ? [ctx.getCurrentTest() ?? (ctx.getCurrentSuite()?.tasks?.[0] as any)?.file, parseMeta(args[0])]
55
- : [args[0], parseMeta(args[1])]
56
- }
57
-
58
- function parseMeta<M extends ComparisonMethod>(meta: boolean | SnapshotMeta<M>): SnapshotMeta<M> {
59
- return typeof meta === 'boolean' ? ({ enable: meta } as any) : { enable: true, ...meta }
60
- }
61
-
62
- export function extractAutoSnapshotOptions<M extends SnapshotMeta<any> = SnapshotMeta<any>>(
63
- task: MetaTask,
64
- ): M | undefined {
65
- if (!task) return
66
-
67
- const list: any[] = []
68
- let current = task
69
- while (current?.suite) {
70
- list.unshift(current.suite.meta)
71
- current = current.suite
72
- }
73
- list.unshift(task.file?.meta)
74
- list.push(task.meta)
75
- return list.reduce(
76
- (acc, cur) => {
77
- const meta = cur?.[NAME]
78
- return meta ? Object.assign({}, acc, meta) : acc
79
- },
80
- { enable: ctx.autoEnabled },
81
- )
82
- }
package/src/client.ts DELETED
@@ -1,7 +0,0 @@
1
- export * from './client/expect/expectation_result.ts'
2
- export type * from './client/expect/to_match_image_snapshot.types.ts'
3
- export * from './client/image_snapshot_matcher.ts'
4
- export * from './client/should_take_snapshot.ts'
5
- export { setAutoSnapshotOptions, type MetaTask } from './client/snapshot_options.ts'
6
- export * from './client/task_id.ts'
7
- export type * from './shared/types.ts'
@@ -1,25 +0,0 @@
1
- import { type HasImageSnapshotCommand, hasImageSnapshot } from './has_image_snapshot.ts'
2
- import { type ImageSnapshotNextIndexCommand, imageSnapshotNextIndex } from './image_snapshot_next_index.ts'
3
- import { type MatchImageSnapshotCommand, matchImageSnapshot } from './match_image_snapshot.ts'
4
- import {
5
- type PrepareImageSnapshotComparisonCommand,
6
- prepareImageSnapshotComparison,
7
- } from './prepare_image_snapshot_comparison.ts'
8
- import { type SetupVisSuiteCommand, setupVisSuite } from './setup_vis_suite.ts'
9
-
10
- declare module '@vitest/browser/context' {
11
- interface BrowserCommands
12
- extends SetupVisSuiteCommand,
13
- ImageSnapshotNextIndexCommand,
14
- HasImageSnapshotCommand,
15
- PrepareImageSnapshotComparisonCommand,
16
- MatchImageSnapshotCommand {}
17
- }
18
-
19
- export const commands = {
20
- setupVisSuite,
21
- imageSnapshotNextIndex,
22
- hasImageSnapshot,
23
- matchImageSnapshot,
24
- prepareImageSnapshotComparison,
25
- }
@@ -1,128 +0,0 @@
1
- import dedent from 'dedent'
2
- import { resolve } from 'pathe'
3
- import { PNG } from 'pngjs'
4
- import type { BrowserCommand } from 'vitest/node'
5
- import { isBase64String } from '../../shared/base64.ts'
6
- import { compareImage } from '../../shared/compare_image.ts'
7
- import { getMaxSize } from '../../shared/get_max_size.ts'
8
- import { isSameSize } from '../../shared/is_same_size.ts'
9
- import type {
10
- ImageSnapshotCompareOptions,
11
- ImageSnapshotIdOptions,
12
- ImageSnapshotTimeoutOptions,
13
- } from '../../shared/types.ts'
14
- import { file } from '../file.ts'
15
- import { takeSnapshot, takeSnapshotByBrowser, writeSnapshot, writeSnapshotBuffer } from '../snapshot.ts'
16
- import { visContext } from '../vis_context.ts'
17
- import { assertTestPathDefined } from './_assertions.ts'
18
-
19
- export interface MatchImageSnapshotCommand {
20
- matchImageSnapshot: (
21
- taskId: string | undefined,
22
- subject: string,
23
- isAutoSnapshot: boolean,
24
- options?: MatchImageSnapshotOptions | undefined,
25
- ) => Promise<void>
26
- }
27
-
28
- export type MatchImageSnapshotOptions = ImageSnapshotTimeoutOptions &
29
- ImageSnapshotIdOptions &
30
- ImageSnapshotCompareOptions<any> & {
31
- /**
32
- * The snapshot file id calculated on the client side.
33
- */
34
- snapshotFileId?: string | undefined
35
- }
36
-
37
- export const matchImageSnapshot: BrowserCommand<
38
- [taskId: string, subject: string, isAutoSnapshot: boolean, options?: MatchImageSnapshotOptions | undefined]
39
- > = async (context, taskId, subject, isAutoSnapshot, options) => {
40
- assertTestPathDefined(context, 'matchImageSnapshot')
41
-
42
- // vitest:browser passes in `null` when not defined
43
- if (!options) options = {}
44
- options.timeout = options.timeout ?? 30000
45
-
46
- const info = await visContext.getSnapshotInfo(context as any, taskId, isAutoSnapshot, options)
47
- const baselineBuffer = await file.tryReadFile(info.baselinePath)
48
- if (!baselineBuffer) {
49
- if (isBase64String(subject)) {
50
- await writeSnapshot(info.baselinePath, subject)
51
- } else {
52
- await takeSnapshotByBrowser(context, info.baselinePath, subject, options)
53
- }
54
- return
55
- }
56
-
57
- const resultBuffer = await takeSnapshot(context, info.resultPath, subject, options)
58
- const baselineImage = PNG.sync.read(baselineBuffer, { skipRescale: true, checkCRC: false })
59
- const resultImage = PNG.sync.read(resultBuffer, { skipRescale: true, checkCRC: false })
60
- const [baselineAlignedImage, resultAlignedImage] = alignImageSizes(baselineImage, resultImage)
61
- const { width, height } = baselineAlignedImage
62
- const diffImage = new PNG({ width, height })
63
- const { pass, diffAmount } = compareImage(
64
- baselineAlignedImage.data,
65
- resultAlignedImage.data,
66
- diffImage.data,
67
- width,
68
- height,
69
- options,
70
- )
71
- if (pass) {
72
- if (sizeNotChanged(baselineImage, baselineAlignedImage) && sizeNotChanged(resultImage, resultAlignedImage)) {
73
- return
74
- }
75
- throw new Error(
76
- dedent`Snapshot \`${taskId}\` mismatched
77
-
78
- The image size changed form ${baselineImage.width}x${baselineImage.height} to ${resultImage.width}x${resultImage.height}
79
-
80
- Expected: ${resolve(context.project.config.root, info.baselinePath)}
81
- Actual: ${resolve(context.project.config.root, info.resultPath)}`,
82
- )
83
- }
84
-
85
- if (context.project.config.snapshotOptions.updateSnapshot === 'all') {
86
- await writeSnapshotBuffer(info.baselinePath, resultImage.data)
87
- return
88
- }
89
-
90
- await writeSnapshotBuffer(info.diffPath, diffImage.data)
91
-
92
- throw new Error(
93
- dedent`Snapshot \`${taskId}\` mismatched
94
-
95
- ${
96
- options?.failureThreshold
97
- ? options?.failureThresholdType === 'percent'
98
- ? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`
99
- : `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`
100
- : `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`
101
- }
102
-
103
- Options: ${JSON.stringify(options)}
104
-
105
- Expected: ${resolve(context.project.config.root, info.baselinePath)}
106
- Actual: ${resolve(context.project.config.root, info.resultPath)}
107
- Difference: ${resolve(context.project.config.root, info.diffPath)}`,
108
- )
109
- }
110
-
111
- function alignImageSizes(baseline: PNG, result: PNG) {
112
- if (isSameSize(baseline, result)) return [baseline, result] as const
113
-
114
- const size = getMaxSize(baseline, result)
115
- return [resizeImage(baseline, size), resizeImage(result, size)] as const
116
- }
117
-
118
- function resizeImage(image: PNG, size: { width: number; height: number }) {
119
- if (isSameSize(image, size)) return image
120
-
121
- const resized = new PNG(size)
122
- PNG.bitblt(image, resized, 0, 0, image.width, image.height)
123
- return resized
124
- }
125
-
126
- function sizeNotChanged(baselineImage: PNG, baselineAlignedImage: PNG) {
127
- return baselineImage === baselineAlignedImage
128
- }
@@ -1,13 +0,0 @@
1
- import { readFile, stat, writeFile } from 'node:fs/promises'
2
-
3
- export const file = {
4
- async tryReadFile(filePath: string): Promise<Buffer | undefined> {
5
- return readFile(filePath).catch(() => undefined)
6
- },
7
- writeFile,
8
- existFile(filePath: string) {
9
- return stat(filePath)
10
- .then((s) => s.isFile())
11
- .catch(() => false)
12
- },
13
- }
@@ -1,198 +0,0 @@
1
- import { join, relative, resolve } from 'pathe'
2
- import { pick } from 'type-plus'
3
- import type { VisOptions } from '../config/types.ts'
4
- import { BASELINE_DIR, DIFF_DIR, RESULT_DIR } from '../shared/constants.ts'
5
- import { getProjectName } from './commands/browser_command_context.ts'
6
- import { file } from './file.ts'
7
- import { getSnapshotSubpath, resolveSnapshotRootDir } from './snapshot_path.ts'
8
- import { ctx } from './vis_context.ctx.ts'
9
- import type { PartialBrowserCommandContext, VisProjectState, VisState } from './vis_context.types.ts'
10
-
11
- export function createVisContext() {
12
- let visOptionsRecord: Record<string, VisOptions<any>> = {}
13
- let state: VisState = {}
14
-
15
- const context = {
16
- setOptions<M extends 'pixel' | 'ssim'>(projectName: string | undefined, options: VisOptions<M> = {} as any) {
17
- visOptionsRecord[projectName ?? '__default'] = options
18
- },
19
- __test__getOptions(projectName: string) {
20
- return visOptionsRecord[projectName]
21
- },
22
- __test__reset() {
23
- visOptionsRecord = {}
24
- state = {}
25
- },
26
- __test__getState(context: PartialBrowserCommandContext) {
27
- return state[getProjectId(context)]!
28
- },
29
- /**
30
- * Setup suite is called on each test file's beforeAll hook.
31
- * Test files include vitest test files and storybook story files.
32
- * It needs to make sure there is no race condition between the test files.
33
- */
34
- async setupSuite(browserContext: PartialBrowserCommandContext) {
35
- const projectId = getProjectId(browserContext)
36
-
37
- const visOptions = getVisOptions(visOptionsRecord, browserContext)
38
- if (!state[projectId]) {
39
- state[projectId] = setupState(browserContext, visOptions)
40
- }
41
-
42
- const projectState = await state[projectId]
43
-
44
- const { suiteId, suite } = createSuite(projectState, browserContext.testPath, visOptions)
45
- projectState.suites[suiteId] = suite
46
-
47
- await Promise.allSettled([ctx.rimraf(suite.diffDir), ctx.rimraf(suite.resultDir)])
48
- return pick(projectState, 'subjectDataTestId')
49
- },
50
- async getSnapshotInfo(
51
- browserContext: PartialBrowserCommandContext,
52
- name: string,
53
- isAutoSnapshot: boolean,
54
- options?: { snapshotFileId?: string | undefined },
55
- ) {
56
- const suiteInfo = await context.getSuiteInfo(browserContext, name)
57
- const snapshotFilename = context.getSnapshotFilename(
58
- browserContext,
59
- suiteInfo,
60
- options?.snapshotFileId,
61
- isAutoSnapshot,
62
- )
63
-
64
- const { baselineDir, resultDir, diffDir, task } = suiteInfo
65
-
66
- task.count = task.count + 1
67
- const baselinePath = join(baselineDir, snapshotFilename)
68
- const resultPath = join(resultDir, snapshotFilename)
69
- const diffPath = join(diffDir, snapshotFilename)
70
-
71
- return {
72
- ...pick(
73
- getVisOptions(visOptionsRecord, browserContext),
74
- 'comparisonMethod',
75
- 'diffOptions',
76
- 'failureThreshold',
77
- 'failureThresholdType',
78
- 'timeout',
79
- ),
80
- baselinePath,
81
- resultPath,
82
- diffPath,
83
- }
84
- },
85
- async getTaskCount(browserContext: PartialBrowserCommandContext, taskId: string) {
86
- return (await context.getSuiteInfo(browserContext, taskId)).task.count
87
- },
88
- async hasImageSnapshot(
89
- browserContext: PartialBrowserCommandContext,
90
- taskId: string,
91
- snapshotFileId: string | undefined,
92
- isAutoSnapshot: boolean,
93
- ) {
94
- const info = await context.getSuiteInfo(browserContext, taskId)
95
-
96
- return file.existFile(
97
- resolve(
98
- info.projectRoot,
99
- info.baselineDir,
100
- context.getSnapshotFilename(browserContext, info, snapshotFileId, isAutoSnapshot),
101
- ),
102
- )
103
- },
104
- getSnapshotFilename(
105
- browserContext: PartialBrowserCommandContext,
106
- info: { taskId: string; task: { count: number } },
107
- snapshotFileId: string | undefined,
108
- isAutoSnapshot: boolean,
109
- ) {
110
- if (snapshotFileId) return `${snapshotFileId}.png`
111
- const customizeSnapshotId =
112
- getVisOptions(visOptionsRecord, browserContext).customizeSnapshotId ?? (({ id, index }) => `${id}-${index}`)
113
- return `${customizeSnapshotId({
114
- id: info.taskId,
115
- index: info.task.count,
116
- isAutoSnapshot,
117
- })}.png`
118
- },
119
- async getSuiteInfo(browserContext: PartialBrowserCommandContext, taskId: string) {
120
- const projectId = getProjectId(browserContext)
121
- const projectState = await state[projectId]!
122
- const visOptions = getVisOptions(visOptionsRecord, browserContext)
123
- const suiteId = getSuiteId(projectState, browserContext.testPath, visOptions)
124
- const suite = projectState.suites[suiteId]!
125
- const task = (suite.tasks[taskId] = suite.tasks[taskId] ?? { count: 1 })
126
- return {
127
- projectRoot: projectState.projectRoot,
128
- suiteId,
129
- taskId,
130
- baselineDir: suite.baselineDir,
131
- resultDir: suite.resultDir,
132
- diffDir: suite.diffDir,
133
- task,
134
- }
135
- },
136
- }
137
- return context
138
- }
139
-
140
- async function setupState(
141
- browserContext: PartialBrowserCommandContext,
142
- visOptions: Pick<VisOptions, 'snapshotRootDir' | 'platform' | 'subjectDataTestId'>,
143
- ) {
144
- const snapshotRootDir = resolveSnapshotRootDir(browserContext, visOptions)
145
- const projectRoot = getProjectRoot(browserContext)
146
-
147
- const state = {
148
- projectRoot,
149
- testTimeout: browserContext.project.config.testTimeout,
150
- hookTimeout: browserContext.project.config.hookTimeout,
151
- snapshotRootDir,
152
- snapshotBaselineDir: join(snapshotRootDir, BASELINE_DIR),
153
- snapshotResultDir: join(snapshotRootDir, RESULT_DIR),
154
- snapshotDiffDir: join(snapshotRootDir, DIFF_DIR),
155
- snapshotRootPath: join(projectRoot, snapshotRootDir),
156
- subjectDataTestId: visOptions.subjectDataTestId,
157
- suites: {},
158
- }
159
- await Promise.allSettled([ctx.rimraf(join(state.snapshotDiffDir)), ctx.rimraf(join(state.snapshotResultDir))])
160
- return state
161
- }
162
-
163
- export function createSuite(
164
- state: VisProjectState,
165
- testPath: string,
166
- options: Pick<VisOptions, 'customizeSnapshotSubpath'>,
167
- ) {
168
- const suiteId = getSuiteId(state, testPath, options)
169
- return {
170
- suiteId,
171
- suite: {
172
- baselineDir: join(state.snapshotBaselineDir, suiteId),
173
- resultDir: join(state.snapshotResultDir, suiteId),
174
- diffDir: join(state.snapshotDiffDir, suiteId),
175
- tasks: {},
176
- },
177
- }
178
- }
179
-
180
- export function getSuiteId(
181
- state: VisProjectState,
182
- testPath: string,
183
- options: Pick<VisOptions, 'customizeSnapshotSubpath'>,
184
- ) {
185
- return getSnapshotSubpath(relative(state.projectRoot, testPath), options)
186
- }
187
-
188
- function getVisOptions(visOptionsRecord: Record<string, VisOptions<any>>, context: PartialBrowserCommandContext) {
189
- return visOptionsRecord[getProjectName(context) ?? '__default'] ?? {}
190
- }
191
-
192
- function getProjectRoot(context: PartialBrowserCommandContext) {
193
- return context.project.config.root
194
- }
195
-
196
- function getProjectId(context: PartialBrowserCommandContext) {
197
- return `${context.project.config.root}/${context.project.config.name}`
198
- }
@@ -1,3 +0,0 @@
1
- import { createVisContext } from './vis_context.logic.ts'
2
-
3
- export const visContext = createVisContext()