vitest-plugin-vis 1.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 (204) hide show
  1. package/esm/client/ctx.d.ts +6 -0
  2. package/esm/client/ctx.d.ts.map +1 -0
  3. package/esm/client/ctx.js +7 -0
  4. package/esm/client/expect/expectation_result.d.ts +3 -0
  5. package/esm/client/expect/expectation_result.d.ts.map +1 -0
  6. package/esm/client/expect/expectation_result.js +5 -0
  7. package/esm/client/expect/extend.d.ts +8 -0
  8. package/esm/client/expect/extend.d.ts.map +1 -0
  9. package/esm/client/expect/extend.js +3 -0
  10. package/esm/client/expect/to_match_image_snapshot.d.ts +9 -0
  11. package/esm/client/expect/to_match_image_snapshot.d.ts.map +1 -0
  12. package/esm/client/expect/to_match_image_snapshot.js +32 -0
  13. package/esm/client/expect/to_match_image_snapshot.logic.d.ts +2 -0
  14. package/esm/client/expect/to_match_image_snapshot.logic.d.ts.map +1 -0
  15. package/esm/client/expect/to_match_image_snapshot.logic.js +11 -0
  16. package/esm/client/expect/to_match_image_snapshot.types.d.ts +7 -0
  17. package/esm/client/expect/to_match_image_snapshot.types.d.ts.map +1 -0
  18. package/esm/client/expect/to_match_image_snapshot.types.js +1 -0
  19. package/esm/client/page/extend.d.ts +6 -0
  20. package/esm/client/page/extend.d.ts.map +1 -0
  21. package/esm/client/page/extend.js +3 -0
  22. package/esm/client/page/has_image_snapshot.d.ts +10 -0
  23. package/esm/client/page/has_image_snapshot.d.ts.map +1 -0
  24. package/esm/client/page/has_image_snapshot.js +23 -0
  25. package/esm/client/selector.d.ts +9 -0
  26. package/esm/client/selector.d.ts.map +1 -0
  27. package/esm/client/selector.js +104 -0
  28. package/esm/client/should_take_snapshot.d.ts +10 -0
  29. package/esm/client/should_take_snapshot.d.ts.map +1 -0
  30. package/esm/client/should_take_snapshot.js +13 -0
  31. package/esm/client/snapshot_options.d.ts +34 -0
  32. package/esm/client/snapshot_options.d.ts.map +1 -0
  33. package/esm/client/snapshot_options.internal.d.ts +3 -0
  34. package/esm/client/snapshot_options.internal.d.ts.map +1 -0
  35. package/esm/client/snapshot_options.internal.js +20 -0
  36. package/esm/client/snapshot_options.js +16 -0
  37. package/esm/client/task_id.d.ts +7 -0
  38. package/esm/client/task_id.d.ts.map +1 -0
  39. package/esm/client/task_id.js +10 -0
  40. package/esm/client.d.ts +8 -0
  41. package/esm/client.d.ts.map +1 -0
  42. package/esm/client.js +5 -0
  43. package/esm/commands.d.ts +5 -0
  44. package/esm/commands.d.ts.map +1 -0
  45. package/esm/commands.js +4 -0
  46. package/esm/config/types.d.ts +35 -0
  47. package/esm/config/types.d.ts.map +1 -0
  48. package/esm/config/types.js +1 -0
  49. package/esm/config/vis.d.ts +25 -0
  50. package/esm/config/vis.d.ts.map +1 -0
  51. package/esm/config/vis.js +27 -0
  52. package/esm/config.d.ts +4 -0
  53. package/esm/config.d.ts.map +1 -0
  54. package/esm/config.js +2 -0
  55. package/esm/index.d.ts +2 -0
  56. package/esm/index.d.ts.map +1 -0
  57. package/esm/index.js +2 -0
  58. package/esm/presets/auto.d.ts +2 -0
  59. package/esm/presets/auto.d.ts.map +1 -0
  60. package/esm/presets/auto.js +3 -0
  61. package/esm/presets/manual.d.ts +2 -0
  62. package/esm/presets/manual.d.ts.map +1 -0
  63. package/esm/presets/manual.js +3 -0
  64. package/esm/server/browser_provider/browser_api.d.ts +3 -0
  65. package/esm/server/browser_provider/browser_api.d.ts.map +1 -0
  66. package/esm/server/browser_provider/browser_api.js +11 -0
  67. package/esm/server/browser_provider/playwright.d.ts +4 -0
  68. package/esm/server/browser_provider/playwright.d.ts.map +1 -0
  69. package/esm/server/browser_provider/playwright.js +13 -0
  70. package/esm/server/browser_provider/types.d.ts +6 -0
  71. package/esm/server/browser_provider/types.d.ts.map +1 -0
  72. package/esm/server/browser_provider/types.js +1 -0
  73. package/esm/server/browser_provider/webdriverio.d.ts +4 -0
  74. package/esm/server/browser_provider/webdriverio.d.ts.map +1 -0
  75. package/esm/server/browser_provider/webdriverio.js +10 -0
  76. package/esm/server/commands/extend.d.ts +15 -0
  77. package/esm/server/commands/extend.d.ts.map +1 -0
  78. package/esm/server/commands/extend.js +10 -0
  79. package/esm/server/commands/has_image_snapshot.d.ts +6 -0
  80. package/esm/server/commands/has_image_snapshot.d.ts.map +1 -0
  81. package/esm/server/commands/has_image_snapshot.js +7 -0
  82. package/esm/server/commands/image_snapshot_next_index.d.ts +9 -0
  83. package/esm/server/commands/image_snapshot_next_index.d.ts.map +1 -0
  84. package/esm/server/commands/image_snapshot_next_index.js +7 -0
  85. package/esm/server/commands/is_ci.d.ts +2 -0
  86. package/esm/server/commands/is_ci.d.ts.map +1 -0
  87. package/esm/server/commands/is_ci.js +6 -0
  88. package/esm/server/commands/match_image_snapshot.d.ts +17 -0
  89. package/esm/server/commands/match_image_snapshot.d.ts.map +1 -0
  90. package/esm/server/commands/match_image_snapshot.js +88 -0
  91. package/esm/server/commands/setup_vis_suite.d.ts +13 -0
  92. package/esm/server/commands/setup_vis_suite.d.ts.map +1 -0
  93. package/esm/server/commands/setup_vis_suite.js +4 -0
  94. package/esm/server/compare_image.d.ts +8 -0
  95. package/esm/server/compare_image.d.ts.map +1 -0
  96. package/esm/server/compare_image.js +16 -0
  97. package/esm/server/file.d.ts +6 -0
  98. package/esm/server/file.d.ts.map +1 -0
  99. package/esm/server/file.js +14 -0
  100. package/esm/server/snapshot_path.d.ts +4 -0
  101. package/esm/server/snapshot_path.d.ts.map +1 -0
  102. package/esm/server/snapshot_path.js +9 -0
  103. package/esm/server/vis_context.ctx.d.ts +29 -0
  104. package/esm/server/vis_context.ctx.d.ts.map +1 -0
  105. package/esm/server/vis_context.ctx.js +11 -0
  106. package/esm/server/vis_context.d.ts +33 -0
  107. package/esm/server/vis_context.d.ts.map +1 -0
  108. package/esm/server/vis_context.js +2 -0
  109. package/esm/server/vis_context.logic.d.ts +63 -0
  110. package/esm/server/vis_context.logic.d.ts.map +1 -0
  111. package/esm/server/vis_context.logic.js +116 -0
  112. package/esm/server/vis_context.types.d.ts +20 -0
  113. package/esm/server/vis_context.types.d.ts.map +1 -0
  114. package/esm/server/vis_context.types.js +1 -0
  115. package/esm/setup/create_vis.d.ts +39 -0
  116. package/esm/setup/create_vis.d.ts.map +1 -0
  117. package/esm/setup/create_vis.js +96 -0
  118. package/esm/setup/vis.d.ts +18 -0
  119. package/esm/setup/vis.d.ts.map +1 -0
  120. package/esm/setup/vis.js +6 -0
  121. package/esm/setup.d.ts +5 -0
  122. package/esm/setup.d.ts.map +1 -0
  123. package/esm/setup.js +7 -0
  124. package/esm/shared/base64.d.ts +2 -0
  125. package/esm/shared/base64.d.ts.map +1 -0
  126. package/esm/shared/base64.js +3 -0
  127. package/esm/shared/constants.d.ts +5 -0
  128. package/esm/shared/constants.d.ts.map +1 -0
  129. package/esm/shared/constants.js +4 -0
  130. package/esm/shared/convert_threshold_unit.d.ts +6 -0
  131. package/esm/shared/convert_threshold_unit.d.ts.map +1 -0
  132. package/esm/shared/convert_threshold_unit.js +10 -0
  133. package/esm/shared/get_max_size.d.ts +11 -0
  134. package/esm/shared/get_max_size.d.ts.map +1 -0
  135. package/esm/shared/get_max_size.js +5 -0
  136. package/esm/shared/is_same_size.d.ts +8 -0
  137. package/esm/shared/is_same_size.d.ts.map +1 -0
  138. package/esm/shared/is_same_size.js +3 -0
  139. package/esm/shared/trim_common_folder.d.ts +6 -0
  140. package/esm/shared/trim_common_folder.d.ts.map +1 -0
  141. package/esm/shared/trim_common_folder.js +10 -0
  142. package/esm/shared/types.d.ts +37 -0
  143. package/esm/shared/types.d.ts.map +1 -0
  144. package/esm/shared/types.js +1 -0
  145. package/esm/testing/constants.d.ts +9 -0
  146. package/esm/testing/constants.d.ts.map +1 -0
  147. package/esm/testing/constants.js +1933 -0
  148. package/esm/testing.d.ts +2 -0
  149. package/esm/testing.d.ts.map +1 -0
  150. package/esm/testing.js +1 -0
  151. package/package.json +115 -0
  152. package/readme.md +264 -0
  153. package/src/client/ctx.ts +8 -0
  154. package/src/client/expect/expectation_result.ts +7 -0
  155. package/src/client/expect/extend.ts +12 -0
  156. package/src/client/expect/to_match_image_snapshot.logic.ts +11 -0
  157. package/src/client/expect/to_match_image_snapshot.ts +43 -0
  158. package/src/client/expect/to_match_image_snapshot.types.ts +14 -0
  159. package/src/client/page/extend.ts +8 -0
  160. package/src/client/page/has_image_snapshot.ts +33 -0
  161. package/src/client/selector.ts +118 -0
  162. package/src/client/should_take_snapshot.ts +15 -0
  163. package/src/client/snapshot_options.internal.ts +22 -0
  164. package/src/client/snapshot_options.ts +53 -0
  165. package/src/client/task_id.ts +16 -0
  166. package/src/client.ts +7 -0
  167. package/src/commands.ts +4 -0
  168. package/src/config/readme.md +4 -0
  169. package/src/config/types.ts +35 -0
  170. package/src/config/vis.ts +30 -0
  171. package/src/config.ts +3 -0
  172. package/src/index.ts +2 -0
  173. package/src/presets/auto.ts +4 -0
  174. package/src/presets/manual.ts +4 -0
  175. package/src/server/browser_provider/browser_api.ts +13 -0
  176. package/src/server/browser_provider/playwright.ts +16 -0
  177. package/src/server/browser_provider/types.ts +11 -0
  178. package/src/server/browser_provider/webdriverio.ts +13 -0
  179. package/src/server/commands/extend.ts +19 -0
  180. package/src/server/commands/has_image_snapshot.ts +18 -0
  181. package/src/server/commands/image_snapshot_next_index.ts +17 -0
  182. package/src/server/commands/is_ci.ts +7 -0
  183. package/src/server/commands/match_image_snapshot.ts +139 -0
  184. package/src/server/commands/setup_vis_suite.ts +17 -0
  185. package/src/server/compare_image.ts +34 -0
  186. package/src/server/file.ts +15 -0
  187. package/src/server/readme.md +5 -0
  188. package/src/server/snapshot_path.ts +12 -0
  189. package/src/server/vis_context.ctx.ts +12 -0
  190. package/src/server/vis_context.logic.ts +141 -0
  191. package/src/server/vis_context.ts +3 -0
  192. package/src/server/vis_context.types.ts +25 -0
  193. package/src/setup/create_vis.ts +98 -0
  194. package/src/setup/vis.ts +7 -0
  195. package/src/setup.ts +9 -0
  196. package/src/shared/base64.ts +3 -0
  197. package/src/shared/constants.ts +4 -0
  198. package/src/shared/convert_threshold_unit.ts +13 -0
  199. package/src/shared/get_max_size.ts +5 -0
  200. package/src/shared/is_same_size.ts +3 -0
  201. package/src/shared/trim_common_folder.ts +10 -0
  202. package/src/shared/types.ts +39 -0
  203. package/src/testing/constants.ts +1936 -0
  204. package/src/testing.ts +1 -0
@@ -0,0 +1,141 @@
1
+ import { join, relative } from 'pathe'
2
+ import type { VisOptions } from '../config/types.ts'
3
+ import { DIFF_DIR, RESULT_DIR } from '../shared/constants.ts'
4
+ import { file } from './file.ts'
5
+ import { getSnapshotSubpath, resolveSnapshotRootDir } from './snapshot_path.ts'
6
+ import { ctx } from './vis_context.ctx.ts'
7
+ import type { VisState } from './vis_context.types.ts'
8
+
9
+ export type PartialBrowserCommandContext = {
10
+ project: {
11
+ config: {
12
+ root: string
13
+ snapshotOptions: {
14
+ updateSnapshot: 'all' | 'new' | 'none'
15
+ }
16
+ testTimeout: number
17
+ hookTimeout: number
18
+ }
19
+ }
20
+ testPath: string | undefined
21
+ }
22
+
23
+ export function createVisContext() {
24
+ let visOptions: VisOptions = {}
25
+ let state: VisState
26
+ let globalStateReady: Promise<VisState>
27
+
28
+ const context = {
29
+ setOptions(options: VisOptions = {}) {
30
+ visOptions = options
31
+ },
32
+ __test__getOptions() {
33
+ return visOptions
34
+ },
35
+ __test__reset() {
36
+ visOptions = undefined as any
37
+ },
38
+ __test__getState() {
39
+ return state
40
+ },
41
+ /**
42
+ * Setup suite is called on each test file's beforeAll hook.
43
+ * Test files include vitest test files and storybook story files.
44
+ * It needs to make sure there is no race condition between the test files.
45
+ */
46
+ async setupSuite(context: PartialBrowserCommandContext) {
47
+ if (!globalStateReady) {
48
+ globalStateReady = setupState(context, visOptions)
49
+ state = await globalStateReady
50
+ } else {
51
+ await globalStateReady
52
+ }
53
+
54
+ const { suiteId, suite } = createSuite(state, context.testPath!, visOptions)
55
+ state.suites[suiteId] = suite
56
+ await Promise.allSettled([ctx.rimraf(suite.diffDir), ctx.rimraf(suite.resultDir)])
57
+ },
58
+ getSnapshotInfo(testPath: string, name: string, options?: { snapshotFileId?: string | undefined }) {
59
+ const info = context.getSuiteInfo(testPath, name)
60
+ const snapshotFilename = context.getSnapshotFilename(info, options?.snapshotFileId)
61
+
62
+ const { baselineDir, resultDir, diffDir, task } = info
63
+
64
+ task.count = task.count + 1
65
+ const baselinePath = join(baselineDir, snapshotFilename)
66
+ const resultPath = join(resultDir, snapshotFilename)
67
+ const diffPath = join(diffDir, snapshotFilename)
68
+
69
+ return {
70
+ baselinePath,
71
+ resultPath,
72
+ diffPath,
73
+ }
74
+ },
75
+ getTaskCount(testPath: string, taskId: string) {
76
+ return context.getSuiteInfo(testPath, taskId).task.count
77
+ },
78
+ hasImageSnapshot(testPath: string, taskId: string, snapshotFileId: string | undefined) {
79
+ const info = context.getSuiteInfo(testPath, taskId)
80
+ return file.existFile(join(info.baselineDir, context.getSnapshotFilename(info, snapshotFileId)))
81
+ },
82
+ getSnapshotFilename(info: { taskId: string; task: { count: number } }, snapshotFileId: string | undefined) {
83
+ if (snapshotFileId) return `${snapshotFileId}.png`
84
+
85
+ const customizeSnapshotId = visOptions.customizeSnapshotId ?? ((id, index) => `${id}-${index}`)
86
+ return `${customizeSnapshotId(info.taskId, info.task.count)}.png`
87
+ },
88
+ getSuiteInfo(testPath: string, taskId: string) {
89
+ const suiteId = getSuiteId(state, testPath, visOptions)
90
+ const suite = state.suites[suiteId]!
91
+ const task = (suite.tasks[taskId] = suite.tasks[taskId] ?? { count: 1 })
92
+ return {
93
+ suiteId,
94
+ taskId,
95
+ baselineDir: suite.baselineDir,
96
+ resultDir: suite.resultDir,
97
+ diffDir: suite.diffDir,
98
+ task,
99
+ }
100
+ },
101
+ }
102
+ return context
103
+ }
104
+
105
+ async function setupState(suite: PartialBrowserCommandContext, visOptions: VisOptions) {
106
+ const snapshotRootDir = resolveSnapshotRootDir(visOptions)
107
+ const projectPath = suite.project.config.root
108
+ const platform = ctx.getSnapshotPlatform()
109
+
110
+ const state = {
111
+ projectPath,
112
+ platform,
113
+ testTimeout: suite.project.config.testTimeout,
114
+ hookTimeout: suite.project.config.hookTimeout,
115
+ snapshotRootDir,
116
+ snapshotBaselineDir: join(snapshotRootDir, platform),
117
+ snapshotResultDir: join(snapshotRootDir, RESULT_DIR),
118
+ snapshotDiffDir: join(snapshotRootDir, DIFF_DIR),
119
+ snapshotRootPath: join(projectPath, snapshotRootDir),
120
+ suites: {},
121
+ }
122
+ await Promise.allSettled([ctx.rimraf(join(state.snapshotDiffDir)), ctx.rimraf(join(state.snapshotResultDir))])
123
+ return state
124
+ }
125
+
126
+ export function getSuiteId(state: VisState, testPath: string, options: VisOptions) {
127
+ return getSnapshotSubpath(relative(state.projectPath, testPath), options)
128
+ }
129
+
130
+ export function createSuite(state: VisState, testPath: string, options: VisOptions) {
131
+ const suiteId = getSuiteId(state, testPath, options)
132
+ return {
133
+ suiteId,
134
+ suite: {
135
+ baselineDir: join(state.snapshotBaselineDir, suiteId),
136
+ resultDir: join(state.snapshotResultDir, suiteId),
137
+ diffDir: join(state.snapshotDiffDir, suiteId),
138
+ tasks: {},
139
+ },
140
+ }
141
+ }
@@ -0,0 +1,3 @@
1
+ import { createVisContext } from './vis_context.logic.ts'
2
+
3
+ export const visContext = createVisContext()
@@ -0,0 +1,25 @@
1
+ export type VisState = {
2
+ projectPath: string
3
+ platform: string
4
+ testTimeout: number
5
+ hookTimeout: number
6
+ snapshotRootDir: string
7
+ snapshotBaselineDir: string
8
+ snapshotResultDir: string
9
+ snapshotDiffDir: string
10
+ snapshotRootPath: string
11
+ suites: Record<
12
+ string,
13
+ {
14
+ baselineDir: string
15
+ resultDir: string
16
+ diffDir: string
17
+ tasks: Record<
18
+ string,
19
+ {
20
+ count: number
21
+ }
22
+ >
23
+ }
24
+ >
25
+ }
@@ -0,0 +1,98 @@
1
+ import dedent from 'dedent'
2
+ import { afterEach, beforeAll, expect } from 'vitest'
3
+ import { toTaskId } from '../client.ts'
4
+ import { ctx } from '../client/ctx.ts'
5
+ import { shouldTakeSnapshot } from '../client/should_take_snapshot.ts'
6
+ import { getAutoSnapshotOptions } from '../client/snapshot_options.internal.js'
7
+ import type { SetupVisSuiteCommand } from '../server/commands/setup_vis_suite.ts'
8
+
9
+ export function createVis(commands: SetupVisSuiteCommand) {
10
+ /**
11
+ * Visual test configuration on the client side.
12
+ */
13
+ const vis = {
14
+ presets: {
15
+ /**
16
+ * Enable manual visual testing.
17
+ */
18
+ manual() {
19
+ beforeAll(vis.beforeAll.setup)
20
+ },
21
+ /**
22
+ * Enable automatic visual testing.
23
+ *
24
+ * This will take a snapshot after each test.
25
+ */
26
+ auto() {
27
+ beforeAll(vis.beforeAll.setup)
28
+ afterEach(vis.afterEach.matchImageSnapshot)
29
+ },
30
+ /**
31
+ * Enable automatic visual testing with multiple themes.
32
+ *
33
+ * This will take a snapshot after each test for each theme.
34
+ *
35
+ * @param themes A record of theme names and their setup functions.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * vis().presets.theme({
40
+ * light() { document.body.classList.add('light') },
41
+ * dark() { document.body.classList.add('dark') },
42
+ * })
43
+ * ```
44
+ */
45
+ theme(themes: Record<string, () => void | Promise<void>>) {
46
+ beforeAll(vis.beforeAll.setup)
47
+ afterEach(vis.afterEach.matchPerTheme(themes))
48
+ },
49
+ },
50
+ beforeAll: {
51
+ async setup() {
52
+ await commands.setupVisSuite()
53
+ },
54
+ },
55
+ afterEach: {
56
+ async matchImageSnapshot() {
57
+ const meta = getAutoSnapshotOptions(ctx.getCurrentTest())
58
+ if (!shouldTakeSnapshot(meta)) return
59
+ await expect(document.body).toMatchImageSnapshot(meta)
60
+ },
61
+ matchPerTheme(themes: Record<string, () => Promise<void> | void>) {
62
+ return async function matchImageSnapshot() {
63
+ const test = ctx.getCurrentTest()
64
+ const meta = getAutoSnapshotOptions(test)
65
+ if (!shouldTakeSnapshot(meta)) return
66
+
67
+ const errors: any[] = []
68
+ for (const themeId in themes) {
69
+ try {
70
+ await themes[themeId]!()
71
+ await expect(document.body).toMatchImageSnapshot({
72
+ ...meta,
73
+ customizeSnapshotId: (id) => `${id}-${themeId}`,
74
+ })
75
+ } catch (error) {
76
+ errors.push([themeId, error])
77
+ }
78
+ }
79
+ if (errors.length > 0) {
80
+ if (errors.length === 1) throw errors[0][1]
81
+ const taskId = toTaskId(test!)
82
+ throw new AggregateError(
83
+ errors,
84
+ dedent`Snapshot \`${taskId}\` mismatched
85
+
86
+ ${errors
87
+ .map(([themeId, error]) => {
88
+ return `Theme \`${themeId}\` failed: ${error.message}`
89
+ })
90
+ .join('\n')}`,
91
+ )
92
+ }
93
+ }
94
+ },
95
+ },
96
+ }
97
+ return vis
98
+ }
@@ -0,0 +1,7 @@
1
+ import { commands } from '@vitest/browser/context'
2
+ import { createVis } from './create_vis.ts'
3
+
4
+ /**
5
+ * Visual test configuration on the client side.
6
+ */
7
+ export const vis = createVis(commands)
package/src/setup.ts ADDED
@@ -0,0 +1,9 @@
1
+ // `vitest-plugin-vis/setup` provides code needed in `vitest.setup.ts`.
2
+ import './client/expect/extend.ts'
3
+ import './client/page/extend.ts'
4
+
5
+ export * from './setup/vis.ts'
6
+
7
+ // This is exported for main/app boundary separation
8
+ // They can co-exist in the same export file thanks to ESM.
9
+ export * from './setup/create_vis.ts'
@@ -0,0 +1,3 @@
1
+ export function isBase64String(value: unknown): value is string {
2
+ return typeof value === 'string' && /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/.test(value)
3
+ }
@@ -0,0 +1,4 @@
1
+ export const NAME = 'vis'
2
+ export const SNAPSHOT_ROOT_DIR = '__vis__'
3
+ export const RESULT_DIR = '__results__'
4
+ export const DIFF_DIR = '__diffs__'
@@ -0,0 +1,13 @@
1
+ export function convertThresholdUnit(
2
+ { failureThresholdType, width, height }: { failureThresholdType: 'pixel' | 'percent'; width: number; height: number },
3
+ pixelDiff: number,
4
+ ): number {
5
+ switch (failureThresholdType) {
6
+ case 'pixel':
7
+ return pixelDiff
8
+ case 'percent':
9
+ return (pixelDiff / (width * height)) * 100
10
+ default:
11
+ throw new Error(`Invalid failureThresholdType: ${failureThresholdType}`)
12
+ }
13
+ }
@@ -0,0 +1,5 @@
1
+ export function getMaxSize(image1: { width: number; height: number }, image2: { width: number; height: number }) {
2
+ const width = Math.max(image1.width, image2.width)
3
+ const height = Math.max(image1.height, image2.height)
4
+ return { width, height }
5
+ }
@@ -0,0 +1,3 @@
1
+ export function isSameSize(image1: { width: number; height: number }, image2: { width: number; height: number }) {
2
+ return image1.width === image2.width && image1.height === image2.height
3
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Trim off common folder such as `src` or `tests` from the test file path.
3
+ * This is used to generate the default snapshot sub-path.
4
+ */
5
+ export function trimCommonFolder(suiteName: string) {
6
+ const suiteDir = suiteName.split('/', 1)[0]!
7
+ if (['tests', 'test', 'src', 'source', 'js', 'ts', 'lib'].includes(suiteDir))
8
+ return suiteName.slice(suiteDir.length + 1)
9
+ return suiteName
10
+ }
@@ -0,0 +1,39 @@
1
+ import type { PixelmatchOptions } from 'pixelmatch'
2
+
3
+ export interface ImageSnapshotTimeoutOptions {
4
+ /**
5
+ * Timeout for taking the snapshot.
6
+ *
7
+ * Default: 5000 ms locally, 30000 ms on CI.
8
+ */
9
+ timeout?: number | undefined
10
+ }
11
+
12
+ export interface ImageSnapshotIdOptions {
13
+ /**
14
+ * Customize the snapshot id. This is used as the filename of the snapshot: `${snapshotId}.png`
15
+ *
16
+ * @param id The id of the snapshot.
17
+ * @param index The index of the snapshot.
18
+ */
19
+ customizeSnapshotId?: (id: string, index: number) => string
20
+ }
21
+
22
+ export interface ImageSnapshotCompareOptions {
23
+ /**
24
+ * Custom options passed to 'pixelmatch'
25
+ */
26
+ diffOptions?: PixelmatchOptions | undefined
27
+ /**
28
+ * Failure threshold should measure in `pixel` or `percent`.
29
+ *
30
+ * Default is `pixel`.
31
+ */
32
+ failureThresholdType?: 'pixel' | 'percent' | undefined
33
+ /**
34
+ * Failure tolerance threshold.
35
+ *
36
+ * Default is `0`.
37
+ */
38
+ failureThreshold?: number | undefined
39
+ }