vitest-plugin-vis 4.2.2 → 5.1.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 (131) hide show
  1. package/dist/auto_snapshots/_extract_auto_snapshot_options.mjs +1 -1
  2. package/dist/auto_snapshots/_extract_auto_snapshot_options.mjs.map +1 -1
  3. package/dist/client/external/vitest/vitest_browser_context_proxy.mjs.map +1 -1
  4. package/dist/client/external/vitest/vitest_suite_proxy.d.mts +1 -3
  5. package/dist/client/external/vitest/vitest_suite_proxy.mjs +5 -5
  6. package/dist/client/external/vitest/vitest_suite_proxy.mjs.map +1 -1
  7. package/dist/client/page/_ctx.d.mts +1 -1
  8. package/dist/client/page/_ctx.mjs.map +1 -1
  9. package/dist/client/snapshot/compare_image_snapshot.logic.mjs +2 -1
  10. package/dist/client/snapshot/compare_image_snapshot.logic.mjs.map +1 -1
  11. package/dist/client/snapshot/compare_image_snapshot.mjs +1 -1
  12. package/dist/client/snapshot/compare_image_snapshot.mjs.map +1 -1
  13. package/dist/client/suite/auto_snapshot_matcher.d.mts +2 -2
  14. package/dist/client/suite/auto_snapshot_matcher.d.mts.map +1 -1
  15. package/dist/client/suite/auto_snapshot_matcher.mjs +4 -2
  16. package/dist/client/suite/auto_snapshot_matcher.mjs.map +1 -1
  17. package/dist/config/types.d.mts +15 -3
  18. package/dist/config/vis.mjs +1 -1
  19. package/dist/config/vis.mjs.map +1 -1
  20. package/dist/{client-api.d.mts → exports/client-api.d.mts} +12 -12
  21. package/dist/exports/client-api.mjs +11 -0
  22. package/dist/exports/config.d.mts +5 -0
  23. package/dist/exports/config.mjs +4 -0
  24. package/dist/exports/presets/auto.mjs +9 -0
  25. package/dist/exports/presets/auto.mjs.map +1 -0
  26. package/dist/exports/presets/manual.mjs +9 -0
  27. package/dist/exports/presets/manual.mjs.map +1 -0
  28. package/dist/exports/server-utils.d.mts +5 -0
  29. package/dist/exports/server-utils.mjs +6 -0
  30. package/dist/exports/setup-api.d.mts +4 -0
  31. package/dist/exports/setup-api.mjs +5 -0
  32. package/dist/exports/setup.d.mts +3 -0
  33. package/dist/exports/setup.mjs +4 -0
  34. package/dist/exports/testing/node.d.mts +4 -0
  35. package/dist/exports/testing/node.mjs +5 -0
  36. package/dist/exports/testing.d.mts +2 -0
  37. package/dist/exports/testing.mjs +3 -0
  38. package/dist/server/commands/prepare_image_snapshot_comparison.mjs.map +1 -1
  39. package/dist/server/commands/prepare_page_image_snapshot_comparison.mjs.map +1 -1
  40. package/dist/server/snapshot_path.d.mts +0 -1
  41. package/dist/server/snapshot_path.d.mts.map +1 -1
  42. package/dist/server/snapshot_path_limits.d.mts +28 -0
  43. package/dist/server/snapshot_path_limits.d.mts.map +1 -0
  44. package/dist/server/snapshot_path_limits.mjs +92 -0
  45. package/dist/server/snapshot_path_limits.mjs.map +1 -0
  46. package/dist/server/suite.mjs +8 -2
  47. package/dist/server/suite.mjs.map +1 -1
  48. package/dist/server/testing/stubBrowserCommandContext.mjs +9 -0
  49. package/dist/server/testing/stubBrowserCommandContext.mjs.map +1 -0
  50. package/dist/server/testing/stubSuite.d.mts +17 -0
  51. package/dist/server/testing/stubSuite.d.mts.map +1 -0
  52. package/dist/server/testing/stubSuite.mjs +23 -0
  53. package/dist/server/testing/stubSuite.mjs.map +1 -0
  54. package/dist/server/testing/stubUserConfig.mjs +8 -0
  55. package/dist/server/testing/stubUserConfig.mjs.map +1 -0
  56. package/dist/server/vis_options.d.mts +120 -0
  57. package/dist/server/vis_options.d.mts.map +1 -0
  58. package/dist/server/vis_options.mjs +7 -1
  59. package/dist/server/vis_options.mjs.map +1 -1
  60. package/dist/server/vis_server_context.logic.mjs +37 -10
  61. package/dist/server/vis_server_context.logic.mjs.map +1 -1
  62. package/dist/server/vis_server_context.types.d.mts +32 -2
  63. package/dist/server/vis_server_context.types.d.mts.map +1 -0
  64. package/dist/setup/create_vis.d.mts +1 -66
  65. package/dist/setup/create_vis.d.mts.map +1 -1
  66. package/dist/setup/create_vis.mjs +9 -45
  67. package/dist/setup/create_vis.mjs.map +1 -1
  68. package/dist/shared/types.d.mts +21 -1
  69. package/dist/shared/types.d.mts.map +1 -1
  70. package/package.json +22 -49
  71. package/readme.md +10 -4
  72. package/src/auto_snapshots/_extract_auto_snapshot_options.ts +1 -1
  73. package/src/client/expect/to_match_image_snapshot.mdx +24 -1
  74. package/src/client/external/vitest/vitest_browser_context_proxy.ts +2 -2
  75. package/src/client/external/vitest/vitest_suite_proxy.ts +6 -6
  76. package/src/client/page/_ctx.ts +2 -2
  77. package/src/client/page/to_match_image_snapshot.mdx +23 -1
  78. package/src/client/snapshot/compare_image_snapshot.logic.ts +1 -0
  79. package/src/client/snapshot/compare_image_snapshot.ts +2 -2
  80. package/src/client/suite/auto_snapshot_matcher.ts +9 -1
  81. package/src/config/types.ts +15 -3
  82. package/src/config/vis.ts +1 -1
  83. package/src/exports/client-api.ts +13 -0
  84. package/src/exports/config.ts +3 -0
  85. package/src/exports/presets/auto.ts +3 -0
  86. package/src/exports/presets/manual.ts +3 -0
  87. package/src/exports/server-utils.ts +7 -0
  88. package/src/exports/setup-api.ts +5 -0
  89. package/src/exports/setup.ts +3 -0
  90. package/src/exports/testing/node.ts +4 -0
  91. package/src/exports/testing.ts +1 -0
  92. package/src/server/commands/prepare_image_snapshot_comparison.ts +2 -2
  93. package/src/server/commands/prepare_page_image_snapshot_comparison.ts +2 -1
  94. package/src/server/snapshot_path_limits.ts +135 -0
  95. package/src/server/suite.ts +19 -4
  96. package/src/server/vis_options.ts +10 -1
  97. package/src/server/vis_server_context.logic.ts +47 -17
  98. package/src/setup/create_vis.mdx +2 -6
  99. package/src/setup/create_vis.ts +13 -123
  100. package/src/shared/types.ts +21 -1
  101. package/dist/client-api.mjs +0 -11
  102. package/dist/config.d.mts +0 -5
  103. package/dist/config.mjs +0 -4
  104. package/dist/presets/auto.mjs +0 -16
  105. package/dist/presets/auto.mjs.map +0 -1
  106. package/dist/presets/enable.d.mts +0 -1
  107. package/dist/presets/enable.mjs +0 -11
  108. package/dist/presets/enable.mjs.map +0 -1
  109. package/dist/presets/manual.mjs +0 -11
  110. package/dist/presets/manual.mjs.map +0 -1
  111. package/dist/server-utils.d.mts +0 -4
  112. package/dist/server-utils.mjs +0 -5
  113. package/dist/setup-api.d.mts +0 -4
  114. package/dist/setup-api.mjs +0 -5
  115. package/dist/setup.d.mts +0 -13
  116. package/dist/setup.d.mts.map +0 -1
  117. package/dist/setup.mjs +0 -13
  118. package/dist/setup.mjs.map +0 -1
  119. package/dist/testing.d.mts +0 -2
  120. package/dist/testing.mjs +0 -3
  121. package/src/client-api.ts +0 -13
  122. package/src/config.ts +0 -3
  123. package/src/presets/auto.ts +0 -9
  124. package/src/presets/enable.ts +0 -5
  125. package/src/presets/manual.ts +0 -5
  126. package/src/server-utils.ts +0 -3
  127. package/src/setup-api.ts +0 -5
  128. package/src/setup.ts +0 -10
  129. package/src/testing.ts +0 -1
  130. /package/dist/{presets → exports/presets}/auto.d.mts +0 -0
  131. /package/dist/{presets → exports/presets}/manual.d.mts +0 -0
@@ -1,5 +1,5 @@
1
1
  import { NAME } from "../shared/constants.mjs";
2
- import "../client-api.mjs";
2
+ import "../exports/client-api.mjs";
3
3
 
4
4
  //#region src/auto_snapshots/_extract_auto_snapshot_options.ts
5
5
  function extractAutoSnapshotOptions(task) {
@@ -1 +1 @@
1
- {"version":3,"file":"_extract_auto_snapshot_options.mjs","names":[],"sources":["../../src/auto_snapshots/_extract_auto_snapshot_options.ts"],"sourcesContent":["import { NAME } from '../client-api.ts'\nimport type { MetaTask } from './auto_snapshot_options.ts'\nimport type { SnapshotMeta } from './snapshot_meta.ts'\n\nexport function extractAutoSnapshotOptions<M extends SnapshotMeta<any> = SnapshotMeta<any>>(\n\ttask: MetaTask,\n): M | undefined {\n\tif (!task) return\n\n\tconst list: any[] = []\n\tlet current = task\n\twhile (current?.suite) {\n\t\tlist.unshift(current.suite.meta)\n\t\tcurrent = current.suite\n\t}\n\tlist.unshift(task.file?.meta)\n\tlist.push(task.meta)\n\treturn list.reduce(\n\t\t(acc, cur) => {\n\t\t\tconst meta = cur?.[NAME]\n\t\t\t// biome-ignore lint/performance/noAccumulatingSpread: I think this is needed\n\t\t\treturn meta ? Object.assign({}, acc, meta) : acc\n\t\t},\n\t\t{ enable: false },\n\t)\n}\n"],"mappings":";;;;AAIA,SAAgB,2BACf,MACgB;AAChB,KAAI,CAAC,KAAM;CAEX,MAAM,OAAc,EAAE;CACtB,IAAI,UAAU;AACd,QAAO,SAAS,OAAO;AACtB,OAAK,QAAQ,QAAQ,MAAM,KAAK;AAChC,YAAU,QAAQ;;AAEnB,MAAK,QAAQ,KAAK,MAAM,KAAK;AAC7B,MAAK,KAAK,KAAK,KAAK;AACpB,QAAO,KAAK,QACV,KAAK,QAAQ;EACb,MAAM,OAAO,MAAM;AAEnB,SAAO,OAAO,OAAO,OAAO,EAAE,EAAE,KAAK,KAAK,GAAG;IAE9C,EAAE,QAAQ,OAAO,CACjB"}
1
+ {"version":3,"file":"_extract_auto_snapshot_options.mjs","names":[],"sources":["../../src/auto_snapshots/_extract_auto_snapshot_options.ts"],"sourcesContent":["import { NAME } from '../exports/client-api.ts'\nimport type { MetaTask } from './auto_snapshot_options.ts'\nimport type { SnapshotMeta } from './snapshot_meta.ts'\n\nexport function extractAutoSnapshotOptions<M extends SnapshotMeta<any> = SnapshotMeta<any>>(\n\ttask: MetaTask,\n): M | undefined {\n\tif (!task) return\n\n\tconst list: any[] = []\n\tlet current = task\n\twhile (current?.suite) {\n\t\tlist.unshift(current.suite.meta)\n\t\tcurrent = current.suite\n\t}\n\tlist.unshift(task.file?.meta)\n\tlist.push(task.meta)\n\treturn list.reduce(\n\t\t(acc, cur) => {\n\t\t\tconst meta = cur?.[NAME]\n\t\t\t// biome-ignore lint/performance/noAccumulatingSpread: I think this is needed\n\t\t\treturn meta ? Object.assign({}, acc, meta) : acc\n\t\t},\n\t\t{ enable: false },\n\t)\n}\n"],"mappings":";;;;AAIA,SAAgB,2BACf,MACgB;AAChB,KAAI,CAAC,KAAM;CAEX,MAAM,OAAc,EAAE;CACtB,IAAI,UAAU;AACd,QAAO,SAAS,OAAO;AACtB,OAAK,QAAQ,QAAQ,MAAM,KAAK;AAChC,YAAU,QAAQ;;AAEnB,MAAK,QAAQ,KAAK,MAAM,KAAK;AAC7B,MAAK,KAAK,KAAK,KAAK;AACpB,QAAO,KAAK,QACV,KAAK,QAAQ;EACb,MAAM,OAAO,MAAM;AAEnB,SAAO,OAAO,OAAO,OAAO,EAAE,EAAE,KAAK,KAAK,GAAG;IAE9C,EAAE,QAAQ,OAAO,CACjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"vitest_browser_context_proxy.mjs","names":[],"sources":["../../../../src/client/external/vitest/vitest_browser_context_proxy.ts"],"sourcesContent":["import type { SerializedConfig } from 'vitest'\nimport type { BrowserCommands, Platform } from 'vitest/browser'\n\nlet ctx: Awaited<typeof import('vitest/browser')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('vitest/browser').then((m) => {\n\t\tctx = m\n\t})\n}\n\nexport const server = new Proxy<{\n\t/**\n\t * Platform the Vitest server is running on.\n\t * The same as calling `process.platform` on the server.\n\t */\n\tplatform: Platform\n\t/**\n\t * Runtime version of the Vitest server.\n\t * The same as calling `process.version` on the server.\n\t */\n\tversion: string\n\t/**\n\t * Name of the browser provider.\n\t */\n\tprovider: string\n\t/**\n\t * Name of the current browser.\n\t */\n\tbrowser: string\n\t/**\n\t * Available commands for the browser.\n\t * @see {@link https://vitest.dev/guide/browser/commands}\n\t */\n\tcommands: BrowserCommands\n\t/**\n\t * Serialized test config.\n\t */\n\tconfig: SerializedConfig\n}>({} as any, {\n\tget(target, prop) {\n\t\treturn (target as any)[prop] ?? (ctx?.server as any)[prop]\n\t},\n})\n"],"mappings":";AAGA,IAAI;AAEJ,IAAK,WAAmB,mBACvB,QAAO,kBAAkB,MAAM,MAAM;AACpC,OAAM;EACL;AAGH,MAAa,SAAS,IAAI,MA4BvB,EAAE,EAAS,EACb,IAAI,QAAQ,MAAM;AACjB,QAAQ,OAAe,UAAU,KAAK,QAAe;GAEtD,CAAC"}
1
+ {"version":3,"file":"vitest_browser_context_proxy.mjs","names":[],"sources":["../../../../src/client/external/vitest/vitest_browser_context_proxy.ts"],"sourcesContent":["import type { SerializedConfig } from 'vitest'\nimport type { BrowserCommands } from 'vitest/browser'\n\nlet ctx: Awaited<typeof import('vitest/browser')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('vitest/browser').then((m) => {\n\t\tctx = m\n\t})\n}\n\nexport const server = new Proxy<{\n\t/**\n\t * Platform the Vitest server is running on.\n\t * The same as calling `process.platform` on the server.\n\t */\n\tplatform: string\n\t/**\n\t * Runtime version of the Vitest server.\n\t * The same as calling `process.version` on the server.\n\t */\n\tversion: string\n\t/**\n\t * Name of the browser provider.\n\t */\n\tprovider: string\n\t/**\n\t * Name of the current browser.\n\t */\n\tbrowser: string\n\t/**\n\t * Available commands for the browser.\n\t * @see {@link https://vitest.dev/guide/browser/commands}\n\t */\n\tcommands: BrowserCommands\n\t/**\n\t * Serialized test config.\n\t */\n\tconfig: SerializedConfig\n}>({} as any, {\n\tget(target, prop) {\n\t\treturn (target as any)[prop] ?? (ctx?.server as any)[prop]\n\t},\n})\n"],"mappings":";AAGA,IAAI;AAEJ,IAAK,WAAmB,mBACvB,QAAO,kBAAkB,MAAM,MAAM;AACpC,OAAM;EACL;AAGH,MAAa,SAAS,IAAI,MA4BvB,EAAE,EAAS,EACb,IAAI,QAAQ,MAAM;AACjB,QAAQ,OAAe,UAAU,KAAK,QAAe;GAEtD,CAAC"}
@@ -1,3 +1 @@
1
- import "../../../shared/types.mjs";
2
- import "vitest";
3
- import "vitest/suite";
1
+ import "vitest";
@@ -1,10 +1,10 @@
1
1
  //#region src/client/external/vitest/vitest_suite_proxy.ts
2
- let vitestSuite;
3
- if (globalThis.__vitest_browser__) import("vitest/suite").then((m) => {
4
- vitestSuite = m;
2
+ let vitest;
3
+ if (globalThis.__vitest_browser__) import("vitest").then((m) => {
4
+ vitest = m;
5
5
  });
6
- const getCurrentTest = () => vitestSuite?.getCurrentTest();
7
- const getCurrentSuite = () => vitestSuite?.getCurrentSuite();
6
+ const getCurrentTest = () => vitest?.TestRunner.getCurrentTest();
7
+ const getCurrentSuite = () => vitest?.TestRunner.getCurrentSuite();
8
8
 
9
9
  //#endregion
10
10
  export { getCurrentSuite, getCurrentTest };
@@ -1 +1 @@
1
- {"version":3,"file":"vitest_suite_proxy.mjs","names":[],"sources":["../../../../src/client/external/vitest/vitest_suite_proxy.ts"],"sourcesContent":["import type { SnapshotTestMeta } from '../../../shared/types.ts'\n\nlet vitestSuite: Awaited<typeof import('vitest/suite')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('vitest/suite').then((m) => {\n\t\tvitestSuite = m\n\t})\n}\n\nexport type CurrentTest = ReturnType<typeof vitestSuite.getCurrentTest> & SnapshotTestMeta\n\nexport const getCurrentTest = () => vitestSuite?.getCurrentTest() as CurrentTest\nexport const getCurrentSuite = () => vitestSuite?.getCurrentSuite()\n"],"mappings":";AAEA,IAAI;AAEJ,IAAK,WAAmB,mBACvB,QAAO,gBAAgB,MAAM,MAAM;AAClC,eAAc;EACb;AAKH,MAAa,uBAAuB,aAAa,gBAAgB;AACjE,MAAa,wBAAwB,aAAa,iBAAiB"}
1
+ {"version":3,"file":"vitest_suite_proxy.mjs","names":[],"sources":["../../../../src/client/external/vitest/vitest_suite_proxy.ts"],"sourcesContent":["import type { SnapshotTestMeta } from '../../../shared/types.ts'\n\nlet vitest: Awaited<typeof import('vitest')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('vitest').then((m) => {\n\t\tvitest = m\n\t})\n}\n\nexport type CurrentTest = ReturnType<typeof vitest.TestRunner.getCurrentTest> & SnapshotTestMeta\n\nexport const getCurrentTest = () => vitest?.TestRunner.getCurrentTest() as CurrentTest\nexport const getCurrentSuite = () => vitest?.TestRunner.getCurrentSuite()\n"],"mappings":";AAEA,IAAI;AAEJ,IAAK,WAAmB,mBACvB,QAAO,UAAU,MAAM,MAAM;AAC5B,UAAS;EACR;AAKH,MAAa,uBAAuB,QAAQ,WAAW,gBAAgB;AACvE,MAAa,wBAAwB,QAAQ,WAAW,iBAAiB"}
@@ -1,3 +1,3 @@
1
1
  import "../external/vitest/vitest_suite_proxy.mjs";
2
- import { BrowserPage } from "vitest/browser";
2
+ import { BrowserCommands, BrowserPage } from "vitest/browser";
3
3
  export { type BrowserPage };
@@ -1 +1 @@
1
- {"version":3,"file":"_ctx.mjs","names":[],"sources":["../../../src/client/page/_ctx.ts"],"sourcesContent":["import { type BrowserPage, commands } from 'vitest/browser'\nimport { getCurrentTest } from '../external/vitest/vitest_suite_proxy.ts'\n\nexport type { BrowserPage }\n\nexport const ctx = {\n\tcommands,\n\tgetCurrentTest,\n\t__test__reset() {\n\t\tctx.getCurrentTest = getCurrentTest\n\t},\n}\n"],"mappings":";;;;AAKA,MAAa,MAAM;CAClB;CACA;CACA,gBAAgB;AACf,MAAI,iBAAiB;;CAEtB"}
1
+ {"version":3,"file":"_ctx.mjs","names":[],"sources":["../../../src/client/page/_ctx.ts"],"sourcesContent":["import { commands, type BrowserCommands, type BrowserPage } from 'vitest/browser'\nimport { getCurrentTest } from '../external/vitest/vitest_suite_proxy.ts'\n\nexport type { BrowserPage }\n\nexport const ctx = {\n\tcommands: commands as BrowserCommands,\n\tgetCurrentTest,\n\t__test__reset() {\n\t\tctx.getCurrentTest = getCurrentTest\n\t},\n}\n"],"mappings":";;;;AAKA,MAAa,MAAM;CACR;CACV;CACA,gBAAgB;AACf,MAAI,iBAAiB;;CAEtB"}
@@ -5,7 +5,8 @@ function prettifyOptions(options) {
5
5
  `failureThreshold: ${options.failureThreshold ?? 0} ${options.failureThresholdType ?? "pixels"}`,
6
6
  options.timeout ? `timeout: ${options.timeout} ms` : "",
7
7
  `comparisonMethod: ${options.comparisonMethod ?? "pixel"}`,
8
- options.diffOptions ? `diffOptions: ${JSON.stringify(options.diffOptions)}` : ""
8
+ options.diffOptions ? `diffOptions: ${JSON.stringify(options.diffOptions)}` : "",
9
+ options.createMissingBaseline ? "createMissingBaseline: true" : ""
9
10
  ].filter(Boolean).join("\n ");
10
11
  }
11
12
 
@@ -1 +1 @@
1
- {"version":3,"file":"compare_image_snapshot.logic.mjs","names":[],"sources":["../../../src/client/snapshot/compare_image_snapshot.logic.ts"],"sourcesContent":["import type { ToMatchImageSnapshotOptions } from '../../shared/types.ts'\n\nexport function prettifyOptions(options: ToMatchImageSnapshotOptions<any> | undefined) {\n\tif (!options) return 'none'\n\n\treturn [\n\t\t`failureThreshold: ${options.failureThreshold ?? 0} ${options.failureThresholdType ?? 'pixels'}`,\n\t\toptions.timeout ? `timeout: ${options.timeout} ms` : '',\n\t\t`comparisonMethod: ${options.comparisonMethod ?? 'pixel'}`,\n\t\toptions.diffOptions ? `diffOptions: ${JSON.stringify(options.diffOptions)}` : '',\n\t]\n\t\t.filter(Boolean)\n\t\t.join('\\n ')\n}\n"],"mappings":";AAEA,SAAgB,gBAAgB,SAAuD;AACtF,KAAI,CAAC,QAAS,QAAO;AAErB,QAAO;EACN,qBAAqB,QAAQ,oBAAoB,EAAE,GAAG,QAAQ,wBAAwB;EACtF,QAAQ,UAAU,YAAY,QAAQ,QAAQ,OAAO;EACrD,qBAAqB,QAAQ,oBAAoB;EACjD,QAAQ,cAAc,gBAAgB,KAAK,UAAU,QAAQ,YAAY,KAAK;EAC9E,CACC,OAAO,QAAQ,CACf,KAAK,qBAAqB"}
1
+ {"version":3,"file":"compare_image_snapshot.logic.mjs","names":[],"sources":["../../../src/client/snapshot/compare_image_snapshot.logic.ts"],"sourcesContent":["import type { ToMatchImageSnapshotOptions } from '../../shared/types.ts'\n\nexport function prettifyOptions(options: ToMatchImageSnapshotOptions<any> | undefined) {\n\tif (!options) return 'none'\n\n\treturn [\n\t\t`failureThreshold: ${options.failureThreshold ?? 0} ${options.failureThresholdType ?? 'pixels'}`,\n\t\toptions.timeout ? `timeout: ${options.timeout} ms` : '',\n\t\t`comparisonMethod: ${options.comparisonMethod ?? 'pixel'}`,\n\t\toptions.diffOptions ? `diffOptions: ${JSON.stringify(options.diffOptions)}` : '',\n\t\toptions.createMissingBaseline ? 'createMissingBaseline: true' : '',\n\t]\n\t\t.filter(Boolean)\n\t\t.join('\\n ')\n}\n"],"mappings":";AAEA,SAAgB,gBAAgB,SAAuD;AACtF,KAAI,CAAC,QAAS,QAAO;AAErB,QAAO;EACN,qBAAqB,QAAQ,oBAAoB,EAAE,GAAG,QAAQ,wBAAwB;EACtF,QAAQ,UAAU,YAAY,QAAQ,QAAQ,OAAO;EACrD,qBAAqB,QAAQ,oBAAoB;EACjD,QAAQ,cAAc,gBAAgB,KAAK,UAAU,QAAQ,YAAY,KAAK;EAC9E,QAAQ,wBAAwB,gCAAgC;EAChE,CACC,OAAO,QAAQ,CACf,KAAK,qBAAqB"}
@@ -14,7 +14,7 @@ async function compareImageSnapshot(commands, taskId, info, options) {
14
14
  };
15
15
  const resultImage = await toImageData(info.result);
16
16
  if (!info.baseline) {
17
- if (server.config.snapshotOptions.updateSnapshot === "all") {
17
+ if (server.config.snapshotOptions.updateSnapshot === "all" || options?.createMissingBaseline === true) {
18
18
  await writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage);
19
19
  return;
20
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compare_image_snapshot.mjs","names":[],"sources":["../../../src/client/snapshot/compare_image_snapshot.ts"],"sourcesContent":["import dedent from 'dedent'\nimport { resolve } from 'pathe'\nimport type { BrowserCommands } from 'vitest/browser'\nimport type {\n\tImageSnapshotNextIndexCommand,\n\tPrepareImageSnapshotComparisonCommand,\n} from '../../shared/commands.types.ts'\nimport { compareImage } from '../../shared/compare_image.ts'\nimport type { ImageSnapshotComparisonInfo, ToMatchImageSnapshotOptions } from '../../shared/types.ts'\nimport { toDataURL, toImageData } from '../external/browser/image_data.ts'\nimport { server } from '../external/vitest/vitest_browser_context_proxy.ts'\nimport { alignImagesToSameSize } from '../image/align_images.ts'\nimport { prettifyOptions } from './compare_image_snapshot.logic.ts'\n\nexport async function compareImageSnapshot(\n\tcommands: BrowserCommands & PrepareImageSnapshotComparisonCommand & ImageSnapshotNextIndexCommand,\n\ttaskId: string,\n\tinfo: ImageSnapshotComparisonInfo,\n\toptions?: ToMatchImageSnapshotOptions<any>,\n) {\n\toptions = { ...info, ...options } as any\n\n\tconst resultImage = await toImageData(info.result)\n\n\tif (!info.baseline) {\n\t\tif (server.config.snapshotOptions.updateSnapshot === 'all') {\n\t\t\tawait writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage)\n\t\t\treturn\n\t\t}\n\t\tthrow new Error(\n\t\t\tdedent`Snapshot \\`${taskId}\\` has no baseline image. Please review the new snapshot and update the baseline image.\n\n\t\t\t\tOptions: ${prettifyOptions(options)}\n\t\t\t\tActual: ${resolve(info.projectRoot, info.resultPath)}`,\n\t\t)\n\t}\n\n\tconst baselineImage = await toImageData(info.baseline)\n\tconst [baselineAlignedImage, resultAlignedImage] = alignImagesToSameSize(baselineImage, resultImage)\n\tconst { width, height } = baselineAlignedImage\n\tconst diffImage = new ImageData(width, height)\n\tconst { pass, diffAmount } = compareImage(\n\t\tbaselineAlignedImage.data,\n\t\tresultAlignedImage.data,\n\t\tdiffImage.data,\n\t\twidth,\n\t\theight,\n\t\toptions,\n\t)\n\tif (pass) {\n\t\tif (options?.expectToFail) {\n\t\t\tthrow new Error(\n\t\t\t\tdedent`Snapshot \\`${taskId}\\` matched but expected to fail.\n\n\t\t\t\t\t\t\tOptions: ${prettifyOptions(options)}\n\t\t\t\t\t\t\tDiff: ${options.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}\n\n\t\t\t\t\t\t\tExpected: ${resolve(info.projectRoot, info.baselinePath)}\n\t\t\t\t\t\t\tActual: ${resolve(info.projectRoot, info.resultPath)}`,\n\t\t\t)\n\t\t}\n\t\treturn\n\t}\n\tif (server.config.snapshotOptions.updateSnapshot === 'all' && !options?.expectToFail) {\n\t\tawait writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage)\n\t\treturn\n\t}\n\n\tawait writeSnapshot(commands, resolve(info.projectRoot, info.diffPath), diffImage)\n\n\tthrow new Error(\n\t\tdedent`Snapshot \\`${taskId}\\` mismatched\n\n\t\t\t\t\t${\n\t\t\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\t\t\t\t\t\t\t? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`\n\t\t\t\t\t\t\t\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\t\t\t\t}${\n\t\t\t\t\t\tbaselineImage.width !== resultImage.width || baselineImage.height !== resultImage.height\n\t\t\t\t\t\t\t? `\\nThe image size changed from ${baselineImage.width}x${baselineImage.height} to ${resultImage.width}x${resultImage.height}.`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\t}\n\n\t\t\t\t\tOptions: ${prettifyOptions(options)}\n\n\t\t\t\t\tExpected: ${resolve(info.projectRoot, info.baselinePath)}\n\t\t\t\t\tActual: ${resolve(info.projectRoot, info.resultPath)}\n\t\t\t\t\tDifference: ${resolve(info.projectRoot, info.diffPath)}`,\n\t)\n}\n\nasync function writeSnapshot(commands: BrowserCommands, path: string, image: ImageData) {\n\tconst content = (await toDataURL(image)).split(',')[1]!\n\treturn commands.writeFile(path, content, { encoding: 'base64' })\n}\n"],"mappings":";;;;;;;;;AAcA,eAAsB,qBACrB,UACA,QACA,MACA,SACC;AACD,WAAU;EAAE,GAAG;EAAM,GAAG;EAAS;CAEjC,MAAM,cAAc,MAAM,YAAY,KAAK,OAAO;AAElD,KAAI,CAAC,KAAK,UAAU;AACnB,MAAI,OAAO,OAAO,gBAAgB,mBAAmB,OAAO;AAC3D,SAAM,cAAc,UAAU,QAAQ,KAAK,aAAa,KAAK,aAAa,EAAE,YAAY;AACxF;;AAED,QAAM,IAAI,MACT,MAAM,cAAc,OAAO;;kBAEZ,gBAAgB,QAAQ,CAAC;kBACzB,QAAQ,KAAK,aAAa,KAAK,WAAW,GACzD;;CAGF,MAAM,gBAAgB,MAAM,YAAY,KAAK,SAAS;CACtD,MAAM,CAAC,sBAAsB,sBAAsB,sBAAsB,eAAe,YAAY;CACpG,MAAM,EAAE,OAAO,WAAW;CAC1B,MAAM,YAAY,IAAI,UAAU,OAAO,OAAO;CAC9C,MAAM,EAAE,MAAM,eAAe,aAC5B,qBAAqB,MACrB,mBAAmB,MACnB,UAAU,MACV,OACA,QACA,QACA;AACD,KAAI,MAAM;AACT,MAAI,SAAS,aACZ,OAAM,IAAI,MACT,MAAM,cAAc,OAAO;;qBAEV,gBAAgB,QAAQ,CAAC;qBACzB,QAAQ,yBAAyB,YAAY,GAAG,WAAW,KAAK,GAAG,WAAW,SAAS;;qBAEvF,QAAQ,KAAK,aAAa,KAAK,aAAa,CAAC;qBAC7C,QAAQ,KAAK,aAAa,KAAK,WAAW,GAC3D;AAEF;;AAED,KAAI,OAAO,OAAO,gBAAgB,mBAAmB,SAAS,CAAC,SAAS,cAAc;AACrF,QAAM,cAAc,UAAU,QAAQ,KAAK,aAAa,KAAK,aAAa,EAAE,YAAY;AACxF;;AAGD,OAAM,cAAc,UAAU,QAAQ,KAAK,aAAa,KAAK,SAAS,EAAE,UAAU;AAElF,OAAM,IAAI,MACT,MAAM,cAAc,OAAO;;OAGvB,SAAS,mBACN,SAAS,yBAAyB,YACjC,kCAAkC,QAAQ,iBAAiB,sBAAsB,WAAW,MAC5F,kCAAkC,QAAQ,iBAAiB,4BAA4B,WAAW,YACnG,6CAA6C,SAAS,yBAAyB,YAAY,GAAG,WAAW,KAAK,GAAG,WAAW,SAAS,KAExI,cAAc,UAAU,YAAY,SAAS,cAAc,WAAW,YAAY,SAC/E,iCAAiC,cAAc,MAAM,GAAG,cAAc,OAAO,MAAM,YAAY,MAAM,GAAG,YAAY,OAAO,KAC3H,GACH;;mBAEa,gBAAgB,QAAQ,CAAC;;mBAEzB,QAAQ,KAAK,aAAa,KAAK,aAAa,CAAC;mBAC7C,QAAQ,KAAK,aAAa,KAAK,WAAW,CAAC;mBAC3C,QAAQ,KAAK,aAAa,KAAK,SAAS,GACzD;;AAGF,eAAe,cAAc,UAA2B,MAAc,OAAkB;CACvF,MAAM,WAAW,MAAM,UAAU,MAAM,EAAE,MAAM,IAAI,CAAC;AACpD,QAAO,SAAS,UAAU,MAAM,SAAS,EAAE,UAAU,UAAU,CAAC"}
1
+ {"version":3,"file":"compare_image_snapshot.mjs","names":[],"sources":["../../../src/client/snapshot/compare_image_snapshot.ts"],"sourcesContent":["import dedent from 'dedent'\nimport { resolve } from 'pathe'\nimport type { BrowserCommands } from 'vitest/browser'\nimport type {\n\tImageSnapshotNextIndexCommand,\n\tPrepareImageSnapshotComparisonCommand,\n} from '../../shared/commands.types.ts'\nimport { compareImage } from '../../shared/compare_image.ts'\nimport type { ImageSnapshotComparisonInfo, ToMatchImageSnapshotOptions } from '../../shared/types.ts'\nimport { toDataURL, toImageData } from '../external/browser/image_data.ts'\nimport { server } from '../external/vitest/vitest_browser_context_proxy.ts'\nimport { alignImagesToSameSize } from '../image/align_images.ts'\nimport { prettifyOptions } from './compare_image_snapshot.logic.ts'\n\nexport async function compareImageSnapshot(\n\tcommands: BrowserCommands & PrepareImageSnapshotComparisonCommand & ImageSnapshotNextIndexCommand,\n\ttaskId: string,\n\tinfo: ImageSnapshotComparisonInfo,\n\toptions?: ToMatchImageSnapshotOptions<any>,\n) {\n\toptions = { ...info, ...options } as any\n\n\tconst resultImage = await toImageData(info.result)\n\n\tif (!info.baseline) {\n\t\tif (server.config.snapshotOptions.updateSnapshot === 'all' || options?.createMissingBaseline === true) {\n\t\t\tawait writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage)\n\t\t\treturn\n\t\t}\n\t\tthrow new Error(\n\t\t\tdedent`Snapshot \\`${taskId}\\` has no baseline image. Please review the new snapshot and update the baseline image.\n\n\t\t\t\tOptions: ${prettifyOptions(options)}\n\t\t\t\tActual: ${resolve(info.projectRoot, info.resultPath)}`,\n\t\t)\n\t}\n\n\tconst baselineImage = await toImageData(info.baseline)\n\tconst [baselineAlignedImage, resultAlignedImage] = alignImagesToSameSize(baselineImage, resultImage)\n\tconst { width, height } = baselineAlignedImage\n\tconst diffImage = new ImageData(width, height)\n\tconst { pass, diffAmount } = compareImage(\n\t\tbaselineAlignedImage.data,\n\t\tresultAlignedImage.data,\n\t\tdiffImage.data,\n\t\twidth,\n\t\theight,\n\t\toptions as ToMatchImageSnapshotOptions<any>,\n\t)\n\tif (pass) {\n\t\tif (options?.expectToFail) {\n\t\t\tthrow new Error(\n\t\t\t\tdedent`Snapshot \\`${taskId}\\` matched but expected to fail.\n\n\t\t\t\t\t\t\tOptions: ${prettifyOptions(options)}\n\t\t\t\t\t\t\tDiff: ${options.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}\n\n\t\t\t\t\t\t\tExpected: ${resolve(info.projectRoot, info.baselinePath)}\n\t\t\t\t\t\t\tActual: ${resolve(info.projectRoot, info.resultPath)}`,\n\t\t\t)\n\t\t}\n\t\treturn\n\t}\n\tif (server.config.snapshotOptions.updateSnapshot === 'all' && !options?.expectToFail) {\n\t\tawait writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage)\n\t\treturn\n\t}\n\n\tawait writeSnapshot(commands, resolve(info.projectRoot, info.diffPath), diffImage)\n\n\tthrow new Error(\n\t\tdedent`Snapshot \\`${taskId}\\` mismatched\n\n\t\t\t\t\t${\n\t\t\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\t\t\t\t\t\t\t? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`\n\t\t\t\t\t\t\t\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\t\t\t\t}${\n\t\t\t\t\t\tbaselineImage.width !== resultImage.width || baselineImage.height !== resultImage.height\n\t\t\t\t\t\t\t? `\\nThe image size changed from ${baselineImage.width}x${baselineImage.height} to ${resultImage.width}x${resultImage.height}.`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\t}\n\n\t\t\t\t\tOptions: ${prettifyOptions(options)}\n\n\t\t\t\t\tExpected: ${resolve(info.projectRoot, info.baselinePath)}\n\t\t\t\t\tActual: ${resolve(info.projectRoot, info.resultPath)}\n\t\t\t\t\tDifference: ${resolve(info.projectRoot, info.diffPath)}`,\n\t)\n}\n\nasync function writeSnapshot(commands: BrowserCommands, path: string, image: ImageData) {\n\tconst content = (await toDataURL(image)).split(',')[1]!\n\treturn commands.writeFile(path, content, { encoding: 'base64' })\n}\n"],"mappings":";;;;;;;;;AAcA,eAAsB,qBACrB,UACA,QACA,MACA,SACC;AACD,WAAU;EAAE,GAAG;EAAM,GAAG;EAAS;CAEjC,MAAM,cAAc,MAAM,YAAY,KAAK,OAAO;AAElD,KAAI,CAAC,KAAK,UAAU;AACnB,MAAI,OAAO,OAAO,gBAAgB,mBAAmB,SAAS,SAAS,0BAA0B,MAAM;AACtG,SAAM,cAAc,UAAU,QAAQ,KAAK,aAAa,KAAK,aAAa,EAAE,YAAY;AACxF;;AAED,QAAM,IAAI,MACT,MAAM,cAAc,OAAO;;kBAEZ,gBAAgB,QAAQ,CAAC;kBACzB,QAAQ,KAAK,aAAa,KAAK,WAAW,GACzD;;CAGF,MAAM,gBAAgB,MAAM,YAAY,KAAK,SAAS;CACtD,MAAM,CAAC,sBAAsB,sBAAsB,sBAAsB,eAAe,YAAY;CACpG,MAAM,EAAE,OAAO,WAAW;CAC1B,MAAM,YAAY,IAAI,UAAU,OAAO,OAAO;CAC9C,MAAM,EAAE,MAAM,eAAe,aAC5B,qBAAqB,MACrB,mBAAmB,MACnB,UAAU,MACV,OACA,QACA,QACA;AACD,KAAI,MAAM;AACT,MAAI,SAAS,aACZ,OAAM,IAAI,MACT,MAAM,cAAc,OAAO;;qBAEV,gBAAgB,QAAQ,CAAC;qBACzB,QAAQ,yBAAyB,YAAY,GAAG,WAAW,KAAK,GAAG,WAAW,SAAS;;qBAEvF,QAAQ,KAAK,aAAa,KAAK,aAAa,CAAC;qBAC7C,QAAQ,KAAK,aAAa,KAAK,WAAW,GAC3D;AAEF;;AAED,KAAI,OAAO,OAAO,gBAAgB,mBAAmB,SAAS,CAAC,SAAS,cAAc;AACrF,QAAM,cAAc,UAAU,QAAQ,KAAK,aAAa,KAAK,aAAa,EAAE,YAAY;AACxF;;AAGD,OAAM,cAAc,UAAU,QAAQ,KAAK,aAAa,KAAK,SAAS,EAAE,UAAU;AAElF,OAAM,IAAI,MACT,MAAM,cAAc,OAAO;;OAGvB,SAAS,mBACN,SAAS,yBAAyB,YACjC,kCAAkC,QAAQ,iBAAiB,sBAAsB,WAAW,MAC5F,kCAAkC,QAAQ,iBAAiB,4BAA4B,WAAW,YACnG,6CAA6C,SAAS,yBAAyB,YAAY,GAAG,WAAW,KAAK,GAAG,WAAW,SAAS,KAExI,cAAc,UAAU,YAAY,SAAS,cAAc,WAAW,YAAY,SAC/E,iCAAiC,cAAc,MAAM,GAAG,cAAc,OAAO,MAAM,YAAY,MAAM,GAAG,YAAY,OAAO,KAC3H,GACH;;mBAEa,gBAAgB,QAAQ,CAAC;;mBAEzB,QAAQ,KAAK,aAAa,KAAK,aAAa,CAAC;mBAC7C,QAAQ,KAAK,aAAa,KAAK,WAAW,CAAC;mBAC3C,QAAQ,KAAK,aAAa,KAAK,SAAS,GACzD;;AAGF,eAAe,cAAc,UAA2B,MAAc,OAAkB;CACvF,MAAM,WAAW,MAAM,UAAU,MAAM,EAAE,MAAM,IAAI,CAAC;AACpD,QAAO,SAAS,UAAU,MAAM,SAAS,EAAE,UAAU,UAAU,CAAC"}
@@ -1,11 +1,11 @@
1
1
  import { SnapshotMeta } from "../../auto_snapshots/snapshot_meta.mjs";
2
- import { ComparisonMethod } from "../../shared/types.mjs";
2
+ import { ComparisonMethod, SetupVisOptions } from "../../shared/types.mjs";
3
3
  import { SetupVisSuiteCommand } from "../../shared/commands.types.mjs";
4
4
 
5
5
  //#region src/client/suite/auto_snapshot_matcher.d.ts
6
6
  declare function autoSnapshotMatcher<GM extends Record<string, any> | unknown = unknown>(commands: SetupVisSuiteCommand, expect: any): {
7
7
  setup(): Promise<void>;
8
- createMatcher<C extends ComparisonMethod, M extends Record<string, any> | unknown = unknown>(themes: Record<string, boolean | ((options: SnapshotMeta<C> & M & GM) => Promise<boolean> | Promise<void> | boolean | void)>): () => Promise<void>;
8
+ createMatcher<C extends ComparisonMethod, M extends Record<string, any> | unknown = unknown>(themes: Record<string, boolean | ((options: SnapshotMeta<C> & M & GM) => Promise<boolean> | Promise<void> | boolean | void)>, suiteDefaults?: Pick<SetupVisOptions<GM>, "createMissingBaseline"> | undefined): () => Promise<void>;
9
9
  };
10
10
  //#endregion
11
11
  export { autoSnapshotMatcher };
@@ -1 +1 @@
1
- {"version":3,"file":"auto_snapshot_matcher.d.mts","names":[],"sources":["../../../src/client/suite/auto_snapshot_matcher.ts"],"sourcesContent":[],"mappings":";;;;;iBASgB,+BAA+B,mDACpC;;EADK,aAAA,CAAA,UAUU,gBAVS,EAAA,UAUmB,MAVnB,CAAA,MAAA,EAAA,GAAA,CAAA,GAAA,OAAA,GAAA,OAAA,CAAA,CAAA,MAAA,EAWxB,MAXwB,CAAA,MAAA,EAAA,OAAA,GAAA,CAAA,CAAA,OAAA,EAaV,YAbU,CAaG,CAbH,CAAA,GAaQ,CAbR,GAaY,EAbZ,EAAA,GAamB,OAbnB,CAAA,OAAA,CAAA,GAasC,OAbtC,CAAA,IAAA,CAAA,GAAA,OAAA,GAAA,IAAA,CAAA,CAAA,CAAA,EAAA,GAAA,GAc/B,OAd+B,CAAA,IAAA,CAAA;CAAY"}
1
+ {"version":3,"file":"auto_snapshot_matcher.d.mts","names":[],"sources":["../../../src/client/suite/auto_snapshot_matcher.ts"],"sourcesContent":[],"mappings":";;;;;iBASgB,+BAA+B,mDACpC;;EADK,aAAA,CAAA,UAUU,gBAVS,EAAA,UAUmB,MAVnB,CAAA,MAAA,EAAA,GAAA,CAAA,GAAA,OAAA,GAAA,OAAA,CAAA,CAAA,MAAA,EAWxB,MAXwB,CAAA,MAAA,EAAA,OAAA,GAAA,CAAA,CAAA,OAAA,EAaV,YAbU,CAaG,CAbH,CAAA,GAaQ,CAbR,GAaY,EAbZ,EAAA,GAamB,OAbnB,CAAA,OAAA,CAAA,GAasC,OAbtC,CAAA,IAAA,CAAA,GAAA,OAAA,GAAA,IAAA,CAAA,CAAA,EAAA,aAAA,CAAA,EAehB,IAfgB,CAeX,eAfW,CAeK,EAfL,CAAA,EAAA,uBAAA,CAAA,GAAA,SAAA,CAAA,EAAA,GAAA,GAe8C,OAf9C,CAAA,IAAA,CAAA;CAAY"}
@@ -11,7 +11,7 @@ function autoSnapshotMatcher(commands, expect) {
11
11
  async setup() {
12
12
  subject = (await commands.setupVisSuite()).subject;
13
13
  },
14
- createMatcher(themes) {
14
+ createMatcher(themes, suiteDefaults) {
15
15
  return async function matchImageSnapshot() {
16
16
  const test = ctx.getCurrentTest();
17
17
  const meta = extractAutoSnapshotOptions(test);
@@ -21,9 +21,11 @@ function autoSnapshotMatcher(commands, expect) {
21
21
  await new Promise((a) => setTimeout(a, 10));
22
22
  const theme = themes[themeId];
23
23
  if ((typeof theme === "function" ? await theme(meta) : theme) === false) continue;
24
+ const effectiveCreateMissingBaseline = meta != null && Object.hasOwn(meta, "createMissingBaseline") ? meta.createMissingBaseline : suiteDefaults?.createMissingBaseline;
24
25
  await expect(getSubject(meta?.subject ?? subject)).toMatchImageSnapshot({
25
26
  ...meta,
26
- snapshotKey: meta?.snapshotKey ?? themeId
27
+ snapshotKey: meta?.snapshotKey ?? themeId,
28
+ ...effectiveCreateMissingBaseline !== void 0 ? { createMissingBaseline: effectiveCreateMissingBaseline } : {}
27
29
  });
28
30
  } catch (error) {
29
31
  errors.push([themeId, error]);
@@ -1 +1 @@
1
- {"version":3,"file":"auto_snapshot_matcher.mjs","names":[],"sources":["../../../src/client/suite/auto_snapshot_matcher.ts"],"sourcesContent":["import dedent from 'dedent'\nimport { extractAutoSnapshotOptions } from '../../auto_snapshots/_extract_auto_snapshot_options.ts'\nimport type { SnapshotMeta } from '../../auto_snapshots/snapshot_meta.ts'\nimport type { SetupVisSuiteCommand } from '../../shared/commands.types.ts'\nimport type { ComparisonMethod } from '../../shared/types.ts'\nimport { shouldTakeSnapshot } from '../snapshot/should_take_snapshot.ts'\nimport { toTaskId } from '../task/task_id.ts'\nimport { ctx } from './_ctx.ts'\n\nexport function autoSnapshotMatcher<GM extends Record<string, any> | unknown = unknown>(\n\tcommands: SetupVisSuiteCommand,\n\texpect: any,\n) {\n\tlet subject: string | undefined\n\n\treturn {\n\t\tasync setup() {\n\t\t\tsubject = (await commands.setupVisSuite()).subject\n\t\t},\n\t\tcreateMatcher<C extends ComparisonMethod, M extends Record<string, any> | unknown = unknown>(\n\t\t\tthemes: Record<\n\t\t\t\tstring,\n\t\t\t\tboolean | ((options: SnapshotMeta<C> & M & GM) => Promise<boolean> | Promise<void> | boolean | void)\n\t\t\t>,\n\t\t) {\n\t\t\treturn async function matchImageSnapshot() {\n\t\t\t\tconst test = ctx.getCurrentTest()\n\n\t\t\t\tconst meta = extractAutoSnapshotOptions(test)\n\t\t\t\tif (!shouldTakeSnapshot(meta)) return\n\t\t\t\tconst errors: Array<[string, Error]> = []\n\t\t\t\tfor (const themeId in themes) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait new Promise((a) => setTimeout(a, 10))\n\t\t\t\t\t\tconst theme = themes[themeId]\n\t\t\t\t\t\tconst r = typeof theme === 'function' ? await theme(meta! as any) : theme\n\t\t\t\t\t\tif (r === false) continue\n\t\t\t\t\t\tawait expect(getSubject(meta?.subject ?? subject)).toMatchImageSnapshot({\n\t\t\t\t\t\t\t...meta,\n\t\t\t\t\t\t\tsnapshotKey: meta?.snapshotKey ?? themeId,\n\t\t\t\t\t\t})\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\terrors.push([themeId, error as Error])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (errors.length > 0) {\n\t\t\t\t\tif (errors.length === 1) throw errors[0]![1]\n\t\t\t\t\tconst taskId = toTaskId(test!)\n\t\t\t\t\tthrow new AggregateError(\n\t\t\t\t\t\terrors,\n\t\t\t\t\t\tdedent`Snapshot \\`${taskId}\\` mismatched\n\n\t\t\t\t\t${errors\n\t\t\t\t\t\t.map(([themeId, error]) => {\n\t\t\t\t\t\t\treturn `Theme \\`${themeId}\\` failed: ${error.message}`\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join('\\n\\n')}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}\n}\n\nfunction getSubject(selectors: string | undefined) {\n\treturn selectors ? (document.querySelector(selectors) ?? document.body) : document.body\n}\n"],"mappings":";;;;;;;AASA,SAAgB,oBACf,UACA,QACC;CACD,IAAI;AAEJ,QAAO;EACN,MAAM,QAAQ;AACb,cAAW,MAAM,SAAS,eAAe,EAAE;;EAE5C,cACC,QAIC;AACD,UAAO,eAAe,qBAAqB;IAC1C,MAAM,OAAO,IAAI,gBAAgB;IAEjC,MAAM,OAAO,2BAA2B,KAAK;AAC7C,QAAI,CAAC,mBAAmB,KAAK,CAAE;IAC/B,MAAM,SAAiC,EAAE;AACzC,SAAK,MAAM,WAAW,OACrB,KAAI;AACH,WAAM,IAAI,SAAS,MAAM,WAAW,GAAG,GAAG,CAAC;KAC3C,MAAM,QAAQ,OAAO;AAErB,UADU,OAAO,UAAU,aAAa,MAAM,MAAM,KAAa,GAAG,WAC1D,MAAO;AACjB,WAAM,OAAO,WAAW,MAAM,WAAW,QAAQ,CAAC,CAAC,qBAAqB;MACvE,GAAG;MACH,aAAa,MAAM,eAAe;MAClC,CAAC;aACM,OAAO;AACf,YAAO,KAAK,CAAC,SAAS,MAAe,CAAC;;AAGxC,QAAI,OAAO,SAAS,GAAG;AACtB,SAAI,OAAO,WAAW,EAAG,OAAM,OAAO,GAAI;KAC1C,MAAM,SAAS,SAAS,KAAM;AAC9B,WAAM,IAAI,eACT,QACA,MAAM,cAAc,OAAO;;OAE1B,OACA,KAAK,CAAC,SAAS,WAAW;AAC1B,aAAO,WAAW,QAAQ,aAAa,MAAM;OAC5C,CACD,KAAK,OAAO,GACb;;;;EAIJ;;AAGF,SAAS,WAAW,WAA+B;AAClD,QAAO,YAAa,SAAS,cAAc,UAAU,IAAI,SAAS,OAAQ,SAAS"}
1
+ {"version":3,"file":"auto_snapshot_matcher.mjs","names":[],"sources":["../../../src/client/suite/auto_snapshot_matcher.ts"],"sourcesContent":["import dedent from 'dedent'\nimport { extractAutoSnapshotOptions } from '../../auto_snapshots/_extract_auto_snapshot_options.ts'\nimport type { SnapshotMeta } from '../../auto_snapshots/snapshot_meta.ts'\nimport type { SetupVisSuiteCommand } from '../../shared/commands.types.ts'\nimport type { ComparisonMethod, SetupVisOptions } from '../../shared/types.ts'\nimport { shouldTakeSnapshot } from '../snapshot/should_take_snapshot.ts'\nimport { toTaskId } from '../task/task_id.ts'\nimport { ctx } from './_ctx.ts'\n\nexport function autoSnapshotMatcher<GM extends Record<string, any> | unknown = unknown>(\n\tcommands: SetupVisSuiteCommand,\n\texpect: any,\n) {\n\tlet subject: string | undefined\n\n\treturn {\n\t\tasync setup() {\n\t\t\tsubject = (await commands.setupVisSuite()).subject\n\t\t},\n\t\tcreateMatcher<C extends ComparisonMethod, M extends Record<string, any> | unknown = unknown>(\n\t\t\tthemes: Record<\n\t\t\t\tstring,\n\t\t\t\tboolean | ((options: SnapshotMeta<C> & M & GM) => Promise<boolean> | Promise<void> | boolean | void)\n\t\t\t>,\n\t\t\tsuiteDefaults?: Pick<SetupVisOptions<GM>, 'createMissingBaseline'> | undefined,\n\t\t) {\n\t\t\treturn async function matchImageSnapshot() {\n\t\t\t\tconst test = ctx.getCurrentTest()\n\n\t\t\t\tconst meta = extractAutoSnapshotOptions(test)\n\t\t\t\tif (!shouldTakeSnapshot(meta)) return\n\t\t\t\tconst errors: Array<[string, Error]> = []\n\t\t\t\tfor (const themeId in themes) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait new Promise((a) => setTimeout(a, 10))\n\t\t\t\t\t\tconst theme = themes[themeId]\n\t\t\t\t\t\tconst r = typeof theme === 'function' ? await theme(meta! as any) : theme\n\t\t\t\t\t\tif (r === false) continue\n\t\t\t\t\t\tconst effectiveCreateMissingBaseline =\n\t\t\t\t\t\t\tmeta != null && Object.hasOwn(meta as object, 'createMissingBaseline')\n\t\t\t\t\t\t\t\t? (meta as { createMissingBaseline?: boolean }).createMissingBaseline\n\t\t\t\t\t\t\t\t: suiteDefaults?.createMissingBaseline\n\t\t\t\t\t\tawait expect(getSubject(meta?.subject ?? subject)).toMatchImageSnapshot({\n\t\t\t\t\t\t\t...meta,\n\t\t\t\t\t\t\tsnapshotKey: meta?.snapshotKey ?? themeId,\n\t\t\t\t\t\t\t...(effectiveCreateMissingBaseline !== undefined\n\t\t\t\t\t\t\t\t? { createMissingBaseline: effectiveCreateMissingBaseline }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t})\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\terrors.push([themeId, error as Error])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (errors.length > 0) {\n\t\t\t\t\tif (errors.length === 1) throw errors[0]![1]\n\t\t\t\t\tconst taskId = toTaskId(test!)\n\t\t\t\t\tthrow new AggregateError(\n\t\t\t\t\t\terrors,\n\t\t\t\t\t\tdedent`Snapshot \\`${taskId}\\` mismatched\n\n\t\t\t\t\t${errors\n\t\t\t\t\t\t.map(([themeId, error]) => {\n\t\t\t\t\t\t\treturn `Theme \\`${themeId}\\` failed: ${error.message}`\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join('\\n\\n')}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}\n}\n\nfunction getSubject(selectors: string | undefined) {\n\treturn selectors ? (document.querySelector(selectors) ?? document.body) : document.body\n}\n"],"mappings":";;;;;;;AASA,SAAgB,oBACf,UACA,QACC;CACD,IAAI;AAEJ,QAAO;EACN,MAAM,QAAQ;AACb,cAAW,MAAM,SAAS,eAAe,EAAE;;EAE5C,cACC,QAIA,eACC;AACD,UAAO,eAAe,qBAAqB;IAC1C,MAAM,OAAO,IAAI,gBAAgB;IAEjC,MAAM,OAAO,2BAA2B,KAAK;AAC7C,QAAI,CAAC,mBAAmB,KAAK,CAAE;IAC/B,MAAM,SAAiC,EAAE;AACzC,SAAK,MAAM,WAAW,OACrB,KAAI;AACH,WAAM,IAAI,SAAS,MAAM,WAAW,GAAG,GAAG,CAAC;KAC3C,MAAM,QAAQ,OAAO;AAErB,UADU,OAAO,UAAU,aAAa,MAAM,MAAM,KAAa,GAAG,WAC1D,MAAO;KACjB,MAAM,iCACL,QAAQ,QAAQ,OAAO,OAAO,MAAgB,wBAAwB,GAClE,KAA6C,wBAC9C,eAAe;AACnB,WAAM,OAAO,WAAW,MAAM,WAAW,QAAQ,CAAC,CAAC,qBAAqB;MACvE,GAAG;MACH,aAAa,MAAM,eAAe;MAClC,GAAI,mCAAmC,SACpC,EAAE,uBAAuB,gCAAgC,GACzD,EAAE;MACL,CAAC;aACM,OAAO;AACf,YAAO,KAAK,CAAC,SAAS,MAAe,CAAC;;AAGxC,QAAI,OAAO,SAAS,GAAG;AACtB,SAAI,OAAO,WAAW,EAAG,OAAM,OAAO,GAAI;KAC1C,MAAM,SAAS,SAAS,KAAM;AAC9B,WAAM,IAAI,eACT,QACA,MAAM,cAAc,OAAO;;OAE1B,OACA,KAAK,CAAC,SAAS,WAAW;AAC1B,aAAO,WAAW,QAAQ,aAAa,MAAM;OAC5C,CACD,KAAK,OAAO,GACb;;;;EAIJ;;AAGF,SAAS,WAAW,WAA+B;AAClD,QAAO,YAAa,SAAS,cAAc,UAAU,IAAI,SAAS,OAAQ,SAAS"}
@@ -18,10 +18,8 @@ type VisOptions<M extends ComparisonMethod = 'pixel'> = (M extends 'ssim' ? {
18
18
  * Loads the `test.setupFiles` of the specified preset.
19
19
  *
20
20
  * @default 'auto'
21
- * @deprecated 'enable' is deprecated. Use `manual` for the same effect.
22
- * @deprecated 'none' is deprecated. Use `custom` for the same effect.
23
21
  */
24
- preset?: 'enable' | 'manual' | 'auto' | 'custom' | 'none' | undefined;
22
+ preset?: 'manual' | 'auto' | 'custom' | undefined;
25
23
  /**
26
24
  * The snapshot folder relative to the root of the project.
27
25
  *
@@ -56,6 +54,20 @@ type VisOptions<M extends ComparisonMethod = 'pixel'> = (M extends 'ssim' ? {
56
54
  snapshotSubpath?: ((options: {
57
55
  subpath: string;
58
56
  }) => string) | undefined;
57
+ /**
58
+ * When `true`, shortenspaths that would exceed Windows-safe limits (full path length at
59
+ * least 250, below classic `MAX_PATH` 260, or a final path component longer than 255):
60
+ * - After `snapshotRootDir` and `snapshotSubpath`, if the path
61
+ * would exceed that budget, the **final** subpath segment is shortened to
62
+ * `{firstToken}-{hash12}{ext}` (tersify-style).
63
+ * - When writing a baseline, if the **actual** absolute path for the legacy `taskId-key.png` file would
64
+ * exceed the budget, only the final segment of that relative path is shortened the same way (nested
65
+ * `describe` directories from `taskId` stay as-is so `taskId-*.png` globs still work).
66
+ * `snapshotRootDir` itself is not rewritten.
67
+ *
68
+ * @default false
69
+ */
70
+ shortenLongSnapshotPaths?: boolean | undefined;
59
71
  };
60
72
  //#endregion
61
73
  export { VisOptions };
@@ -20,7 +20,7 @@ function vis(options = { preset: "auto" }) {
20
20
  name: void 0,
21
21
  commands
22
22
  },
23
- setupFiles: preset && preset !== "none" && preset !== "custom" ? [`vitest-plugin-vis/presets/${preset}`] : []
23
+ setupFiles: preset && preset !== "custom" ? [`vitest-plugin-vis/presets/${preset}`] : []
24
24
  } };
25
25
  }
26
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"vis.mjs","names":[],"sources":["../../src/config/vis.ts"],"sourcesContent":["import type { Plugin } from 'vitest/config'\nimport { commands } from '../server/commands/commands.ts'\nimport { setVisOption } from '../server/vis_options.ts'\nimport { NAME } from '../shared/constants.ts'\nimport type { ComparisonMethod } from '../shared/types.ts'\nimport type { VisOptions } from './types.ts'\n\n/**\n * Create a Vite plugin for visual testing.\n *\n * If options are not provided, the plugin will use the default options,\n * which enables the `auto` preset.\n */\nexport function vis<M extends ComparisonMethod = 'pixel'>(options: VisOptions<M> = { preset: 'auto' } as any) {\n\treturn {\n\t\tname: NAME,\n\t\tconfig(this: unknown, userConfig) {\n\t\t\tsetVisOption(userConfig, options)\n\t\t\tconst preset = options?.preset\n\t\t\treturn {\n\t\t\t\ttest: {\n\t\t\t\t\tbrowser: {\n\t\t\t\t\t\tname: undefined,\n\t\t\t\t\t\tcommands: commands as any,\n\t\t\t\t\t},\n\t\t\t\t\tsetupFiles: preset && preset !== 'none' && preset !== 'custom' ? [`vitest-plugin-vis/presets/${preset}`] : [],\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t} satisfies Plugin\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,IAA0C,UAAyB,EAAE,QAAQ,QAAQ,EAAS;AAC7G,QAAO;EACN,MAAM;EACN,OAAsB,YAAY;AACjC,gBAAa,YAAY,QAAQ;GACjC,MAAM,SAAS,SAAS;AACxB,UAAO,EACN,MAAM;IACL,SAAS;KACR,MAAM;KACI;KACV;IACD,YAAY,UAAU,WAAW,UAAU,WAAW,WAAW,CAAC,6BAA6B,SAAS,GAAG,EAAE;IAC7G,EACD;;EAEF"}
1
+ {"version":3,"file":"vis.mjs","names":[],"sources":["../../src/config/vis.ts"],"sourcesContent":["import type { Plugin } from 'vitest/config'\nimport { commands } from '../server/commands/commands.ts'\nimport { setVisOption } from '../server/vis_options.ts'\nimport { NAME } from '../shared/constants.ts'\nimport type { ComparisonMethod } from '../shared/types.ts'\nimport type { VisOptions } from './types.ts'\n\n/**\n * Create a Vite plugin for visual testing.\n *\n * If options are not provided, the plugin will use the default options,\n * which enables the `auto` preset.\n */\nexport function vis<M extends ComparisonMethod = 'pixel'>(options: VisOptions<M> = { preset: 'auto' } as any) {\n\treturn {\n\t\tname: NAME,\n\t\tconfig(this: unknown, userConfig) {\n\t\t\tsetVisOption(userConfig, options)\n\t\t\tconst preset = options?.preset\n\t\t\treturn {\n\t\t\t\ttest: {\n\t\t\t\t\tbrowser: {\n\t\t\t\t\t\tname: undefined,\n\t\t\t\t\t\tcommands: commands as any,\n\t\t\t\t\t},\n\t\t\t\t\tsetupFiles: preset && preset !== 'custom' ? [`vitest-plugin-vis/presets/${preset}`] : [],\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t} satisfies Plugin\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,IAA0C,UAAyB,EAAE,QAAQ,QAAQ,EAAS;AAC7G,QAAO;EACN,MAAM;EACN,OAAsB,YAAY;AACjC,gBAAa,YAAY,QAAQ;GACjC,MAAM,SAAS,SAAS;AACxB,UAAO,EACN,MAAM;IACL,SAAS;KACR,MAAM;KACI;KACV;IACD,YAAY,UAAU,WAAW,WAAW,CAAC,6BAA6B,SAAS,GAAG,EAAE;IACxF,EACD;;EAEF"}
@@ -1,13 +1,13 @@
1
- import { BASELINE_DIR, DIFF_DIR, NAME, RESULT_DIR, SNAPSHOT_ROOT_DIR } from "./shared/constants.mjs";
2
- import { Awaitable, ComparisonMethod, FailureThresholdOptions, ImageSnapshotCompareOptions, ImageSnapshotComparisonInfo, ImageSnapshotKeyOptions, ImageSnapshotSubjectOptions, ImageSnapshotTimeoutOptions, MatchImageSnapshotOptions, PageImageSnapshotOptions, PixelComparisonOptions, PixelDiffOptions, SetupVisOptions, SnapshotTestMeta, SsimComparisonOptions, SsimDiffOptions, ToMatchImageSnapshotOptions, ToMatchPageImageSnapshotOptions } from "./shared/types.mjs";
3
- import "./server/commands/augment.mjs";
4
- import { MetaTask, setAutoSnapshotOptions } from "./auto_snapshots/auto_snapshot_options.mjs";
5
- import { hasImageSnapshotAction } from "./client/actions/has_image_snapshot_action.mjs";
6
- import { loadImageSnapshotResultsAction } from "./client/actions/load_image_snapshot_results_action.mjs";
7
- import { matchImageSnapshotAction } from "./client/actions/match_image_snapshot_action.mjs";
8
- import { matchPageImageSnapshotAction } from "./client/actions/match_page_image_snapshot_action.mjs";
9
- import { success } from "./client/expect/expectation_result.mjs";
10
- import { ImageSnapshotMatcher } from "./client/expect/to_match_image_snapshot.types.mjs";
11
- import { autoSnapshotMatcher } from "./client/suite/auto_snapshot_matcher.mjs";
12
- import { toTaskId } from "./client/task/task_id.mjs";
1
+ import { BASELINE_DIR, DIFF_DIR, NAME, RESULT_DIR, SNAPSHOT_ROOT_DIR } from "../shared/constants.mjs";
2
+ import { Awaitable, ComparisonMethod, FailureThresholdOptions, ImageSnapshotCompareOptions, ImageSnapshotComparisonInfo, ImageSnapshotKeyOptions, ImageSnapshotSubjectOptions, ImageSnapshotTimeoutOptions, MatchImageSnapshotOptions, PageImageSnapshotOptions, PixelComparisonOptions, PixelDiffOptions, SetupVisOptions, SnapshotTestMeta, SsimComparisonOptions, SsimDiffOptions, ToMatchImageSnapshotOptions, ToMatchPageImageSnapshotOptions } from "../shared/types.mjs";
3
+ import "../server/commands/augment.mjs";
4
+ import { MetaTask, setAutoSnapshotOptions } from "../auto_snapshots/auto_snapshot_options.mjs";
5
+ import { hasImageSnapshotAction } from "../client/actions/has_image_snapshot_action.mjs";
6
+ import { loadImageSnapshotResultsAction } from "../client/actions/load_image_snapshot_results_action.mjs";
7
+ import { matchImageSnapshotAction } from "../client/actions/match_image_snapshot_action.mjs";
8
+ import { matchPageImageSnapshotAction } from "../client/actions/match_page_image_snapshot_action.mjs";
9
+ import { success } from "../client/expect/expectation_result.mjs";
10
+ import { ImageSnapshotMatcher } from "../client/expect/to_match_image_snapshot.types.mjs";
11
+ import { autoSnapshotMatcher } from "../client/suite/auto_snapshot_matcher.mjs";
12
+ import { toTaskId } from "../client/task/task_id.mjs";
13
13
  export { Awaitable, BASELINE_DIR, ComparisonMethod, DIFF_DIR, FailureThresholdOptions, ImageSnapshotCompareOptions, ImageSnapshotComparisonInfo, ImageSnapshotKeyOptions, ImageSnapshotMatcher, ImageSnapshotSubjectOptions, ImageSnapshotTimeoutOptions, MatchImageSnapshotOptions, MetaTask, NAME, PageImageSnapshotOptions, PixelComparisonOptions, PixelDiffOptions, RESULT_DIR, SNAPSHOT_ROOT_DIR, SetupVisOptions, SnapshotTestMeta, SsimComparisonOptions, SsimDiffOptions, ToMatchImageSnapshotOptions, ToMatchPageImageSnapshotOptions, autoSnapshotMatcher, hasImageSnapshotAction, loadImageSnapshotResultsAction, matchImageSnapshotAction, matchPageImageSnapshotAction, setAutoSnapshotOptions, success, toTaskId };
@@ -0,0 +1,11 @@
1
+ import { BASELINE_DIR, DIFF_DIR, NAME, RESULT_DIR, SNAPSHOT_ROOT_DIR } from "../shared/constants.mjs";
2
+ import { setAutoSnapshotOptions } from "../auto_snapshots/auto_snapshot_options.mjs";
3
+ import { hasImageSnapshotAction } from "../client/actions/has_image_snapshot_action.mjs";
4
+ import { loadImageSnapshotResultsAction } from "../client/actions/load_image_snapshot_results_action.mjs";
5
+ import { matchImageSnapshotAction } from "../client/actions/match_image_snapshot_action.mjs";
6
+ import { matchPageImageSnapshotAction } from "../client/actions/match_page_image_snapshot_action.mjs";
7
+ import { success } from "../client/expect/expectation_result.mjs";
8
+ import { toTaskId } from "../client/task/task_id.mjs";
9
+ import { autoSnapshotMatcher } from "../client/suite/auto_snapshot_matcher.mjs";
10
+
11
+ export { BASELINE_DIR, DIFF_DIR, NAME, RESULT_DIR, SNAPSHOT_ROOT_DIR, autoSnapshotMatcher, hasImageSnapshotAction, loadImageSnapshotResultsAction, matchImageSnapshotAction, matchPageImageSnapshotAction, setAutoSnapshotOptions, success, toTaskId };
@@ -0,0 +1,5 @@
1
+ import { ComparisonMethod, PixelComparisonOptions, PixelDiffOptions, SsimComparisonOptions, SsimDiffOptions } from "../shared/types.mjs";
2
+ import { VisOptions } from "../config/types.mjs";
3
+ import { vis } from "../config/vis.mjs";
4
+ import { trimCommonFolder } from "../shared/trim_common_folder.mjs";
5
+ export { ComparisonMethod, PixelComparisonOptions, PixelDiffOptions, SsimComparisonOptions, SsimDiffOptions, VisOptions, trimCommonFolder, vis };
@@ -0,0 +1,4 @@
1
+ import { trimCommonFolder } from "../shared/trim_common_folder.mjs";
2
+ import { vis } from "../config/vis.mjs";
3
+
4
+ export { trimCommonFolder, vis };
@@ -0,0 +1,9 @@
1
+ import { vis } from "../../setup/vis.mjs";
2
+ import "../setup.mjs";
3
+
4
+ //#region src/exports/presets/auto.ts
5
+ vis.setup({ auto: true });
6
+
7
+ //#endregion
8
+ export { };
9
+ //# sourceMappingURL=auto.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.mjs","names":[],"sources":["../../../src/exports/presets/auto.ts"],"sourcesContent":["import { vis } from '../setup.ts'\n\nvis.setup({ auto: true })\n"],"mappings":";;;;AAEA,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { vis } from "../../setup/vis.mjs";
2
+ import "../setup.mjs";
3
+
4
+ //#region src/exports/presets/manual.ts
5
+ vis.setup({ auto: false });
6
+
7
+ //#endregion
8
+ export { };
9
+ //# sourceMappingURL=manual.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.mjs","names":[],"sources":["../../../src/exports/presets/manual.ts"],"sourcesContent":["import { vis } from '../setup.ts'\n\nvis.setup({ auto: false })\n"],"mappings":";;;;AAEA,IAAI,MAAM,EAAE,MAAM,OAAO,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { BASELINE_DIR, DIFF_DIR, SNAPSHOT_ROOT_DIR } from "../shared/constants.mjs";
2
+ import { trimCommonFolder } from "../shared/trim_common_folder.mjs";
3
+ import { getSnapshotRootDir } from "../server/snapshot_path.mjs";
4
+ import { resolveLegacySnapshotFileRelativePath, resolveSnapshotSubpathWithinLimits } from "../server/snapshot_path_limits.mjs";
5
+ export { BASELINE_DIR, DIFF_DIR, SNAPSHOT_ROOT_DIR, getSnapshotRootDir, resolveLegacySnapshotFileRelativePath, resolveSnapshotSubpathWithinLimits, trimCommonFolder };
@@ -0,0 +1,6 @@
1
+ import { BASELINE_DIR, DIFF_DIR, SNAPSHOT_ROOT_DIR } from "../shared/constants.mjs";
2
+ import { resolveLegacySnapshotFileRelativePath, resolveSnapshotSubpathWithinLimits } from "../server/snapshot_path_limits.mjs";
3
+ import { trimCommonFolder } from "../shared/trim_common_folder.mjs";
4
+ import { getSnapshotRootDir } from "../server/snapshot_path.mjs";
5
+
6
+ export { BASELINE_DIR, DIFF_DIR, SNAPSHOT_ROOT_DIR, getSnapshotRootDir, resolveLegacySnapshotFileRelativePath, resolveSnapshotSubpathWithinLimits, trimCommonFolder };
@@ -0,0 +1,4 @@
1
+ import "../client/expect/extend.mjs";
2
+ import "../client/page/extend.mjs";
3
+ import { VisClientConfigurator, createVis } from "../setup/create_vis.mjs";
4
+ export { VisClientConfigurator, createVis };
@@ -0,0 +1,5 @@
1
+ import "../client/expect/extend.mjs";
2
+ import "../client/page/extend.mjs";
3
+ import { createVis } from "../setup/create_vis.mjs";
4
+
5
+ export { createVis };
@@ -0,0 +1,3 @@
1
+ import "./setup-api.mjs";
2
+ import { vis } from "../setup/vis.mjs";
3
+ export { vis };
@@ -0,0 +1,4 @@
1
+ import "./setup-api.mjs";
2
+ import { vis } from "../setup/vis.mjs";
3
+
4
+ export { vis };
@@ -0,0 +1,4 @@
1
+ import { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL } from "../../testing/constants.mjs";
2
+ import { stubSuite } from "../../server/testing/stubSuite.mjs";
3
+ import { getVisOption } from "../../server/vis_options.mjs";
4
+ export { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL, getVisOption, stubSuite };
@@ -0,0 +1,5 @@
1
+ import { getVisOption } from "../../server/vis_options.mjs";
2
+ import { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL } from "../../testing/constants.mjs";
3
+ import { stubSuite } from "../../server/testing/stubSuite.mjs";
4
+
5
+ export { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL, getVisOption, stubSuite };
@@ -0,0 +1,2 @@
1
+ import { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL } from "../testing/constants.mjs";
2
+ export { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL };
@@ -0,0 +1,3 @@
1
+ import { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL } from "../testing/constants.mjs";
2
+
3
+ export { UNI_IMAGE_DATA, UNI_PNG_BASE64, UNI_PNG_URL };
@@ -1 +1 @@
1
- {"version":3,"file":"prepare_image_snapshot_comparison.mjs","names":[],"sources":["../../../src/server/commands/prepare_image_snapshot_comparison.ts"],"sourcesContent":["import { resolve } from 'pathe'\nimport { isBase64String } from '../../shared/base64.ts'\nimport type { PrepareImageSnapshotComparisonCommand } from '../../shared/commands.types.ts'\nimport type { ImageSnapshotComparisonInfo } from '../../shared/types.ts'\nimport { file } from '../externals/file.ts'\nimport { getProjectRoot } from '../project.ts'\nimport { takeSnapshot } from '../snapshot.ts'\nimport { snapshotWriter } from '../snapshot_writer.ts'\nimport { visServerContext } from '../vis_server_context.ts'\nimport type { ExtendedBrowserCommand } from '../vis_server_context.types.ts'\nimport { assertTestPathDefined } from './_assertions.ts'\n\nexport const prepareImageSnapshotComparison: ExtendedBrowserCommand<\n\tParameters<PrepareImageSnapshotComparisonCommand['prepareImageSnapshotComparison']>\n> = async (context, taskId, subject, options): Promise<ImageSnapshotComparisonInfo | undefined> => {\n\tassertTestPathDefined(context, 'prepareImageSnapshotComparison')\n\t// vitest:browser passes in `null` when not defined\n\tif (!options) options = {}\n\toptions.timeout = options.timeout ?? 30000\n\n\tconst projectRoot = getProjectRoot(context)\n\tconst info = await visServerContext.getSnapshotInfo(context, taskId, options)\n\n\tconst baselineBuffer = await file.tryReadFile(resolve(projectRoot, info.baselinePath))\n\tif (!baselineBuffer && isBase64String(subject)) {\n\t\tawait snapshotWriter.writeBase64(resolve(projectRoot, info.resultPath), subject)\n\t\treturn {\n\t\t\t...info,\n\t\t\tprojectRoot,\n\t\t\tresult: subject,\n\t\t}\n\t}\n\n\tconst resultBuffer = await takeSnapshot(context, projectRoot, info.resultPath, subject, options)\n\treturn {\n\t\t...info,\n\t\tprojectRoot,\n\t\tbaseline: baselineBuffer?.toString('base64'),\n\t\tresult: resultBuffer.toString('base64'),\n\t}\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAa,iCAET,OAAO,SAAS,QAAQ,SAAS,YAA8D;AAClG,uBAAsB,SAAS,iCAAiC;AAEhE,KAAI,CAAC,QAAS,WAAU,EAAE;AAC1B,SAAQ,UAAU,QAAQ,WAAW;CAErC,MAAM,cAAc,eAAe,QAAQ;CAC3C,MAAM,OAAO,MAAM,iBAAiB,gBAAgB,SAAS,QAAQ,QAAQ;CAE7E,MAAM,iBAAiB,MAAM,KAAK,YAAY,QAAQ,aAAa,KAAK,aAAa,CAAC;AACtF,KAAI,CAAC,kBAAkB,eAAe,QAAQ,EAAE;AAC/C,QAAM,eAAe,YAAY,QAAQ,aAAa,KAAK,WAAW,EAAE,QAAQ;AAChF,SAAO;GACN,GAAG;GACH;GACA,QAAQ;GACR;;CAGF,MAAM,eAAe,MAAM,aAAa,SAAS,aAAa,KAAK,YAAY,SAAS,QAAQ;AAChG,QAAO;EACN,GAAG;EACH;EACA,UAAU,gBAAgB,SAAS,SAAS;EAC5C,QAAQ,aAAa,SAAS,SAAS;EACvC"}
1
+ {"version":3,"file":"prepare_image_snapshot_comparison.mjs","names":[],"sources":["../../../src/server/commands/prepare_image_snapshot_comparison.ts"],"sourcesContent":["import { resolve } from 'pathe'\nimport { isBase64String } from '../../shared/base64.ts'\nimport type { PrepareImageSnapshotComparisonCommand } from '../../shared/commands.types.ts'\nimport type { ImageSnapshotComparisonInfo } from '../../shared/types.ts'\nimport { file } from '../externals/file.ts'\nimport { getProjectRoot } from '../project.ts'\nimport { takeSnapshot } from '../snapshot.ts'\nimport { snapshotWriter } from '../snapshot_writer.ts'\nimport { visServerContext } from '../vis_server_context.ts'\nimport type { ExtendedBrowserCommand } from '../vis_server_context.types.ts'\nimport { assertTestPathDefined } from './_assertions.ts'\n\nexport const prepareImageSnapshotComparison: ExtendedBrowserCommand<\n\tParameters<PrepareImageSnapshotComparisonCommand['prepareImageSnapshotComparison']>\n> = async (context, taskId, subject, options): Promise<ImageSnapshotComparisonInfo | undefined> => {\n\tassertTestPathDefined(context, 'prepareImageSnapshotComparison')\n\t// vitest:browser passes in `null` when not defined\n\tif (!options) options = {}\n\toptions.timeout = options.timeout ?? 30000\n\n\tconst projectRoot = getProjectRoot(context)\n\tconst info = await visServerContext.getSnapshotInfo(context, taskId, options)\n\n\tconst baselineBuffer = await file.tryReadFile(resolve(projectRoot, info.baselinePath))\n\tif (!baselineBuffer && isBase64String(subject)) {\n\t\tawait snapshotWriter.writeBase64(resolve(projectRoot, info.resultPath), subject)\n\t\treturn {\n\t\t\t...info,\n\t\t\tprojectRoot,\n\t\t\tresult: subject,\n\t\t} as ImageSnapshotComparisonInfo\n\t}\n\n\tconst resultBuffer = await takeSnapshot(context, projectRoot, info.resultPath, subject, options)\n\treturn {\n\t\t...info,\n\t\tprojectRoot,\n\t\tbaseline: baselineBuffer?.toString('base64'),\n\t\tresult: resultBuffer.toString('base64'),\n\t} as ImageSnapshotComparisonInfo\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAa,iCAET,OAAO,SAAS,QAAQ,SAAS,YAA8D;AAClG,uBAAsB,SAAS,iCAAiC;AAEhE,KAAI,CAAC,QAAS,WAAU,EAAE;AAC1B,SAAQ,UAAU,QAAQ,WAAW;CAErC,MAAM,cAAc,eAAe,QAAQ;CAC3C,MAAM,OAAO,MAAM,iBAAiB,gBAAgB,SAAS,QAAQ,QAAQ;CAE7E,MAAM,iBAAiB,MAAM,KAAK,YAAY,QAAQ,aAAa,KAAK,aAAa,CAAC;AACtF,KAAI,CAAC,kBAAkB,eAAe,QAAQ,EAAE;AAC/C,QAAM,eAAe,YAAY,QAAQ,aAAa,KAAK,WAAW,EAAE,QAAQ;AAChF,SAAO;GACN,GAAG;GACH;GACA,QAAQ;GACR;;CAGF,MAAM,eAAe,MAAM,aAAa,SAAS,aAAa,KAAK,YAAY,SAAS,QAAQ;AAChG,QAAO;EACN,GAAG;EACH;EACA,UAAU,gBAAgB,SAAS,SAAS;EAC5C,QAAQ,aAAa,SAAS,SAAS;EACvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"prepare_page_image_snapshot_comparison.mjs","names":[],"sources":["../../../src/server/commands/prepare_page_image_snapshot_comparison.ts"],"sourcesContent":["import { resolve } from 'pathe'\nimport type { PreparePageImageSnapshotComparisonCommand } from '../../shared/commands.types.ts'\nimport { file } from '../externals/file.ts'\nimport { getProjectRoot } from '../project.ts'\nimport { takePageSnapshot } from '../snapshot.ts'\nimport { visServerContext } from '../vis_server_context.ts'\nimport type { ExtendedBrowserCommand } from '../vis_server_context.types.ts'\nimport { assertTestPathDefined } from './_assertions.ts'\n\nexport const preparePageImageSnapshotComparison: ExtendedBrowserCommand<\n\tParameters<PreparePageImageSnapshotComparisonCommand['preparePageImageSnapshotComparison']>\n> = async (context, taskId, options) => {\n\tassertTestPathDefined(context, 'preparePageImageSnapshotComparison')\n\t// vitest:browser passes in `null` when not defined\n\tif (!options) options = {}\n\toptions.timeout = options.timeout ?? 30000\n\n\tconst projectRoot = getProjectRoot(context)\n\tconst info = await visServerContext.getSnapshotInfo(context, taskId, options)\n\tconst baselineBuffer = await file.tryReadFile(resolve(projectRoot, info.baselinePath))\n\tconst resultBuffer = await takePageSnapshot(context, projectRoot, info.resultPath, options)\n\treturn {\n\t\t...info,\n\t\tprojectRoot,\n\t\tbaseline: baselineBuffer?.toString('base64'),\n\t\tresult: resultBuffer.toString('base64'),\n\t}\n}\n"],"mappings":";;;;;;;;AASA,MAAa,qCAET,OAAO,SAAS,QAAQ,YAAY;AACvC,uBAAsB,SAAS,qCAAqC;AAEpE,KAAI,CAAC,QAAS,WAAU,EAAE;AAC1B,SAAQ,UAAU,QAAQ,WAAW;CAErC,MAAM,cAAc,eAAe,QAAQ;CAC3C,MAAM,OAAO,MAAM,iBAAiB,gBAAgB,SAAS,QAAQ,QAAQ;CAC7E,MAAM,iBAAiB,MAAM,KAAK,YAAY,QAAQ,aAAa,KAAK,aAAa,CAAC;CACtF,MAAM,eAAe,MAAM,iBAAiB,SAAS,aAAa,KAAK,YAAY,QAAQ;AAC3F,QAAO;EACN,GAAG;EACH;EACA,UAAU,gBAAgB,SAAS,SAAS;EAC5C,QAAQ,aAAa,SAAS,SAAS;EACvC"}
1
+ {"version":3,"file":"prepare_page_image_snapshot_comparison.mjs","names":[],"sources":["../../../src/server/commands/prepare_page_image_snapshot_comparison.ts"],"sourcesContent":["import { resolve } from 'pathe'\nimport type { PreparePageImageSnapshotComparisonCommand } from '../../shared/commands.types.ts'\nimport type { ImageSnapshotComparisonInfo } from '../../shared/types.ts'\nimport { file } from '../externals/file.ts'\nimport { getProjectRoot } from '../project.ts'\nimport { takePageSnapshot } from '../snapshot.ts'\nimport { visServerContext } from '../vis_server_context.ts'\nimport type { ExtendedBrowserCommand } from '../vis_server_context.types.ts'\nimport { assertTestPathDefined } from './_assertions.ts'\n\nexport const preparePageImageSnapshotComparison: ExtendedBrowserCommand<\n\tParameters<PreparePageImageSnapshotComparisonCommand['preparePageImageSnapshotComparison']>\n> = async (context, taskId, options) => {\n\tassertTestPathDefined(context, 'preparePageImageSnapshotComparison')\n\t// vitest:browser passes in `null` when not defined\n\tif (!options) options = {}\n\toptions.timeout = options.timeout ?? 30000\n\n\tconst projectRoot = getProjectRoot(context)\n\tconst info = await visServerContext.getSnapshotInfo(context, taskId, options)\n\tconst baselineBuffer = await file.tryReadFile(resolve(projectRoot, info.baselinePath))\n\tconst resultBuffer = await takePageSnapshot(context, projectRoot, info.resultPath, options)\n\treturn {\n\t\t...info,\n\t\tprojectRoot,\n\t\tbaseline: baselineBuffer?.toString('base64'),\n\t\tresult: resultBuffer.toString('base64'),\n\t} as ImageSnapshotComparisonInfo\n}\n"],"mappings":";;;;;;;;AAUA,MAAa,qCAET,OAAO,SAAS,QAAQ,YAAY;AACvC,uBAAsB,SAAS,qCAAqC;AAEpE,KAAI,CAAC,QAAS,WAAU,EAAE;AAC1B,SAAQ,UAAU,QAAQ,WAAW;CAErC,MAAM,cAAc,eAAe,QAAQ;CAC3C,MAAM,OAAO,MAAM,iBAAiB,gBAAgB,SAAS,QAAQ,QAAQ;CAC7E,MAAM,iBAAiB,MAAM,KAAK,YAAY,QAAQ,aAAa,KAAK,aAAa,CAAC;CACtF,MAAM,eAAe,MAAM,iBAAiB,SAAS,aAAa,KAAK,YAAY,QAAQ;AAC3F,QAAO;EACN,GAAG;EACH;EACA,UAAU,gBAAgB,SAAS,SAAS;EAC5C,QAAQ,aAAa,SAAS,SAAS;EACvC"}
@@ -1,4 +1,3 @@
1
- import "../config/types.mjs";
2
1
  import "./vis_server_context.types.mjs";
3
2
 
4
3
  //#region src/server/snapshot_path.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot_path.d.mts","names":[],"sources":["../../src/server/snapshot_path.ts"],"sourcesContent":[],"mappings":";;;;;;AAgCA;;;;;;;iBAAgB,kBAAA"}
1
+ {"version":3,"file":"snapshot_path.d.mts","names":[],"sources":["../../src/server/snapshot_path.ts"],"sourcesContent":[],"mappings":";;;;AAgCA;;;;;;;;iBAAgB,kBAAA"}
@@ -0,0 +1,28 @@
1
+ //#region src/server/snapshot_path_limits.d.ts
2
+
3
+ /**
4
+ * Returns {@link rawSnapshotSubpath} or a tersified final segment when `shortenLongSnapshotPaths` is on and
5
+ * `snapshotBaselineRootAbs` + subpath + a minimal `0.png` would exceed {@link legacySnapshotPathExceedsLimit},
6
+ * or a subpath segment exceeds NTFS length. Long snapshot **filenames** (`taskId-key.png`) are shortened
7
+ * separately via {@link resolveLegacySnapshotFileRelativePath}. Baseline, result, and diff trees share the
8
+ * same resolved subpath via {@link getTaskSubpath}.
9
+ */
10
+ declare function resolveSnapshotSubpathWithinLimits(params: {
11
+ snapshotBaselineRootAbs: string;
12
+ rawSnapshotSubpath: string;
13
+ shortenLongSnapshotPaths: boolean;
14
+ }): string;
15
+ /**
16
+ * When `shortenLongSnapshotPaths` is on and the legacy `{@link getLegacySnapshotFilename}` path exceeds
17
+ * {@link legacySnapshotPathExceedsLimit}, rewrites only the final path segment (after the last `/`) like
18
+ * {@link formatCondensedSnapshotSubpath}, so nested `taskId` directories stay intact and `…-*.png` globs keep working.
19
+ */
20
+ declare function resolveLegacySnapshotFileRelativePath(params: {
21
+ projectRoot: string;
22
+ baselineDir: string;
23
+ legacySnapshotFilename: string;
24
+ shortenLongSnapshotPaths: boolean;
25
+ }): string;
26
+ //#endregion
27
+ export { resolveLegacySnapshotFileRelativePath, resolveSnapshotSubpathWithinLimits };
28
+ //# sourceMappingURL=snapshot_path_limits.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot_path_limits.d.mts","names":[],"sources":["../../src/server/snapshot_path_limits.ts"],"sourcesContent":[],"mappings":";;;;;;;;;iBAwFgB,kCAAA;;;;;;;;;;iBAoBA,qCAAA"}
@@ -0,0 +1,92 @@
1
+ import { basename, dirname, extname, join, resolve } from "pathe";
2
+ import { createHash } from "node:crypto";
3
+
4
+ //#region src/server/snapshot_path_limits.ts
5
+ /**
6
+ * Budget under {@link WIN_MAX_PATH} to leave margin for tooling and long `projectRoot` prefixes.
7
+ */
8
+ const WIN_SNAPSHOT_PATH_BUDGET = 250;
9
+ /** NTFS maximum length of a single path component (directory or file name). */
10
+ const NTFS_MAX_FILENAME = 255;
11
+ /** Max length of the readable prefix taken from the original basename (tersify-style). */
12
+ const SNAPSHOT_SUBPATH_PREFIX_MAX_LEN = 24;
13
+ /**
14
+ * Minimal probe file under the snapshot folder — detects when the directory prefix alone is too long.
15
+ */
16
+ const SNAPSHOT_SUBPATH_PROBE_MIN_BASENAME = "0.png";
17
+ function absoluteSnapshotFilePath(projectRoot, baselineDir, snapshotFilename) {
18
+ return resolve(projectRoot, join(baselineDir, snapshotFilename));
19
+ }
20
+ /**
21
+ * @returns true when the legacy absolute path should be shortened for Windows-safe tooling.
22
+ */
23
+ function legacySnapshotPathExceedsLimit(absolutePath) {
24
+ if (absolutePath.length >= WIN_SNAPSHOT_PATH_BUDGET) return true;
25
+ if (basename(absolutePath).length > NTFS_MAX_FILENAME) return true;
26
+ return false;
27
+ }
28
+ /**
29
+ * First readable token of a snapshot basename stem (before the first `.`), similar in spirit to
30
+ * [tersify](https://github.com/unional/tersify) terse labels — keeps a short human hint, not the whole name.
31
+ */
32
+ function snapshotBasenameTersifyPrefix(stem) {
33
+ if (!stem) return "snap";
34
+ const dot = stem.indexOf(".");
35
+ return ((dot === -1 ? stem : stem.slice(0, dot)).replace(/[^\w-]/g, "") || "snap").slice(0, SNAPSHOT_SUBPATH_PREFIX_MAX_LEN);
36
+ }
37
+ /**
38
+ * Keeps all directory segments of {@link rawSnapshotSubpath}; only the final filename is replaced with
39
+ * `{prefix}-{hash12}{ext}` where `prefix` comes from the first segment of the original stem (e.g. `Button.stories.ts` → `Button`).
40
+ */
41
+ function formatCondensedSnapshotSubpath(rawSnapshotSubpath) {
42
+ const norm = rawSnapshotSubpath.replace(/\\/g, "/");
43
+ const dir = dirname(norm);
44
+ const file = basename(norm);
45
+ const ext = extname(file);
46
+ const shortFile = `${snapshotBasenameTersifyPrefix(ext ? file.slice(0, -ext.length) : file)}-${createHash("sha256").update(norm).digest("hex").slice(0, 12)}${ext}`;
47
+ if (dir === "." || dir === "") return shortFile;
48
+ return join(dir, shortFile);
49
+ }
50
+ /**
51
+ * `snapshotBaselineRootAbs` is the absolute `__baselines__` root; with `rawSnapshotSubpath` this yields the
52
+ * test-module snapshot directory. Only checks whether that layout can host a tiny baseline file; long
53
+ * `taskId-key.png` paths are handled with {@link resolveLegacySnapshotFileRelativePath} using real names.
54
+ */
55
+ function rawSnapshotSubpathExceedsSafePathBudget(snapshotBaselineRootAbs, rawSnapshotSubpath) {
56
+ if (legacySnapshotPathExceedsLimit(resolve(resolve(snapshotBaselineRootAbs, rawSnapshotSubpath), SNAPSHOT_SUBPATH_PROBE_MIN_BASENAME))) return true;
57
+ for (const segment of rawSnapshotSubpath.split(/[/\\]/)) if (segment.length > NTFS_MAX_FILENAME) return true;
58
+ return false;
59
+ }
60
+ /**
61
+ * Returns {@link rawSnapshotSubpath} or a tersified final segment when `shortenLongSnapshotPaths` is on and
62
+ * `snapshotBaselineRootAbs` + subpath + a minimal `0.png` would exceed {@link legacySnapshotPathExceedsLimit},
63
+ * or a subpath segment exceeds NTFS length. Long snapshot **filenames** (`taskId-key.png`) are shortened
64
+ * separately via {@link resolveLegacySnapshotFileRelativePath}. Baseline, result, and diff trees share the
65
+ * same resolved subpath via {@link getTaskSubpath}.
66
+ */
67
+ function resolveSnapshotSubpathWithinLimits(params) {
68
+ const { snapshotBaselineRootAbs, rawSnapshotSubpath, shortenLongSnapshotPaths } = params;
69
+ if (!shortenLongSnapshotPaths) return rawSnapshotSubpath;
70
+ if (!rawSnapshotSubpathExceedsSafePathBudget(snapshotBaselineRootAbs, rawSnapshotSubpath)) return rawSnapshotSubpath;
71
+ return formatCondensedSnapshotSubpath(rawSnapshotSubpath);
72
+ }
73
+ /**
74
+ * When `shortenLongSnapshotPaths` is on and the legacy `{@link getLegacySnapshotFilename}` path exceeds
75
+ * {@link legacySnapshotPathExceedsLimit}, rewrites only the final path segment (after the last `/`) like
76
+ * {@link formatCondensedSnapshotSubpath}, so nested `taskId` directories stay intact and `…-*.png` globs keep working.
77
+ */
78
+ function resolveLegacySnapshotFileRelativePath(params) {
79
+ const { projectRoot, baselineDir, legacySnapshotFilename, shortenLongSnapshotPaths } = params;
80
+ if (!shortenLongSnapshotPaths) return legacySnapshotFilename;
81
+ const norm = legacySnapshotFilename.replace(/\\/g, "/");
82
+ if (!legacySnapshotPathExceedsLimit(absoluteSnapshotFilePath(projectRoot, baselineDir, norm))) return legacySnapshotFilename;
83
+ return formatCondensedSnapshotSubpath(norm);
84
+ }
85
+ function getLegacySnapshotFilename(params) {
86
+ const key = params.explicitSnapshotKey ?? (typeof params.defaultSnapshotKey === "string" ? params.defaultSnapshotKey : String(params.taskCount));
87
+ return `${params.taskId}-${key}.png`;
88
+ }
89
+
90
+ //#endregion
91
+ export { absoluteSnapshotFilePath, getLegacySnapshotFilename, resolveLegacySnapshotFileRelativePath, resolveSnapshotSubpathWithinLimits };
92
+ //# sourceMappingURL=snapshot_path_limits.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot_path_limits.mjs","names":[],"sources":["../../src/server/snapshot_path_limits.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\nimport { basename, dirname, extname, join, resolve } from 'pathe'\n\n/** Classic Win32 `MAX_PATH` includes NUL; tools often treat ~259 as usable. */\nexport const WIN_MAX_PATH = 260\n\n/**\n * Budget under {@link WIN_MAX_PATH} to leave margin for tooling and long `projectRoot` prefixes.\n */\nexport const WIN_SNAPSHOT_PATH_BUDGET = 250\n\n/** NTFS maximum length of a single path component (directory or file name). */\nexport const NTFS_MAX_FILENAME = 255\n\n/** Max length of the readable prefix taken from the original basename (tersify-style). */\nconst SNAPSHOT_SUBPATH_PREFIX_MAX_LEN = 24\n\n/**\n * Minimal probe file under the snapshot folder — detects when the directory prefix alone is too long.\n */\nconst SNAPSHOT_SUBPATH_PROBE_MIN_BASENAME = '0.png'\n\nexport function absoluteSnapshotFilePath(projectRoot: string, baselineDir: string, snapshotFilename: string): string {\n\treturn resolve(projectRoot, join(baselineDir, snapshotFilename))\n}\n\n/**\n * @returns true when the legacy absolute path should be shortened for Windows-safe tooling.\n */\nexport function legacySnapshotPathExceedsLimit(absolutePath: string): boolean {\n\tif (absolutePath.length >= WIN_SNAPSHOT_PATH_BUDGET) return true\n\tif (basename(absolutePath).length > NTFS_MAX_FILENAME) return true\n\treturn false\n}\n\n/**\n * First readable token of a snapshot basename stem (before the first `.`), similar in spirit to\n * [tersify](https://github.com/unional/tersify) terse labels — keeps a short human hint, not the whole name.\n */\nfunction snapshotBasenameTersifyPrefix(stem: string): string {\n\tif (!stem) return 'snap'\n\tconst dot = stem.indexOf('.')\n\tconst first = dot === -1 ? stem : stem.slice(0, dot)\n\tconst cleaned = first.replace(/[^\\w-]/g, '')\n\treturn (cleaned || 'snap').slice(0, SNAPSHOT_SUBPATH_PREFIX_MAX_LEN)\n}\n\n/**\n * Keeps all directory segments of {@link rawSnapshotSubpath}; only the final filename is replaced with\n * `{prefix}-{hash12}{ext}` where `prefix` comes from the first segment of the original stem (e.g. `Button.stories.ts` → `Button`).\n */\nexport function formatCondensedSnapshotSubpath(rawSnapshotSubpath: string): string {\n\tconst norm = rawSnapshotSubpath.replace(/\\\\/g, '/')\n\tconst dir = dirname(norm)\n\tconst file = basename(norm)\n\tconst ext = extname(file)\n\tconst stem = ext ? file.slice(0, -ext.length) : file\n\tconst prefix = snapshotBasenameTersifyPrefix(stem)\n\tconst h = createHash('sha256').update(norm).digest('hex').slice(0, 12)\n\tconst shortFile = `${prefix}-${h}${ext}`\n\tif (dir === '.' || dir === '') return shortFile\n\treturn join(dir, shortFile)\n}\n\n/**\n * `snapshotBaselineRootAbs` is the absolute `__baselines__` root; with `rawSnapshotSubpath` this yields the\n * test-module snapshot directory. Only checks whether that layout can host a tiny baseline file; long\n * `taskId-key.png` paths are handled with {@link resolveLegacySnapshotFileRelativePath} using real names.\n */\nfunction rawSnapshotSubpathExceedsSafePathBudget(snapshotBaselineRootAbs: string, rawSnapshotSubpath: string): boolean {\n\tconst dirAbs = resolve(snapshotBaselineRootAbs, rawSnapshotSubpath)\n\n\tif (legacySnapshotPathExceedsLimit(resolve(dirAbs, SNAPSHOT_SUBPATH_PROBE_MIN_BASENAME))) return true\n\n\tfor (const segment of rawSnapshotSubpath.split(/[/\\\\]/)) {\n\t\tif (segment.length > NTFS_MAX_FILENAME) return true\n\t}\n\n\treturn false\n}\n\n/**\n * Returns {@link rawSnapshotSubpath} or a tersified final segment when `shortenLongSnapshotPaths` is on and\n * `snapshotBaselineRootAbs` + subpath + a minimal `0.png` would exceed {@link legacySnapshotPathExceedsLimit},\n * or a subpath segment exceeds NTFS length. Long snapshot **filenames** (`taskId-key.png`) are shortened\n * separately via {@link resolveLegacySnapshotFileRelativePath}. Baseline, result, and diff trees share the\n * same resolved subpath via {@link getTaskSubpath}.\n */\nexport function resolveSnapshotSubpathWithinLimits(params: {\n\tsnapshotBaselineRootAbs: string\n\trawSnapshotSubpath: string\n\tshortenLongSnapshotPaths: boolean\n}): string {\n\tconst { snapshotBaselineRootAbs, rawSnapshotSubpath, shortenLongSnapshotPaths } = params\n\tif (!shortenLongSnapshotPaths) return rawSnapshotSubpath\n\n\tif (!rawSnapshotSubpathExceedsSafePathBudget(snapshotBaselineRootAbs, rawSnapshotSubpath)) {\n\t\treturn rawSnapshotSubpath\n\t}\n\n\treturn formatCondensedSnapshotSubpath(rawSnapshotSubpath)\n}\n\n/**\n * When `shortenLongSnapshotPaths` is on and the legacy `{@link getLegacySnapshotFilename}` path exceeds\n * {@link legacySnapshotPathExceedsLimit}, rewrites only the final path segment (after the last `/`) like\n * {@link formatCondensedSnapshotSubpath}, so nested `taskId` directories stay intact and `…-*.png` globs keep working.\n */\nexport function resolveLegacySnapshotFileRelativePath(params: {\n\tprojectRoot: string\n\tbaselineDir: string\n\tlegacySnapshotFilename: string\n\tshortenLongSnapshotPaths: boolean\n}): string {\n\tconst { projectRoot, baselineDir, legacySnapshotFilename, shortenLongSnapshotPaths } = params\n\tif (!shortenLongSnapshotPaths) return legacySnapshotFilename\n\n\tconst norm = legacySnapshotFilename.replace(/\\\\/g, '/')\n\tconst abs = absoluteSnapshotFilePath(projectRoot, baselineDir, norm)\n\tif (!legacySnapshotPathExceedsLimit(abs)) return legacySnapshotFilename\n\n\treturn formatCondensedSnapshotSubpath(norm)\n}\n\nexport function getLegacySnapshotFilename(params: {\n\ttaskId: string\n\texplicitSnapshotKey: string | undefined\n\tdefaultSnapshotKey: string | undefined\n\ttaskCount: number\n}): string {\n\tconst key =\n\t\tparams.explicitSnapshotKey ??\n\t\t(typeof params.defaultSnapshotKey === 'string' ? params.defaultSnapshotKey : String(params.taskCount))\n\treturn `${params.taskId}-${key}.png`\n}\n"],"mappings":";;;;;;;AASA,MAAa,2BAA2B;;AAGxC,MAAa,oBAAoB;;AAGjC,MAAM,kCAAkC;;;;AAKxC,MAAM,sCAAsC;AAE5C,SAAgB,yBAAyB,aAAqB,aAAqB,kBAAkC;AACpH,QAAO,QAAQ,aAAa,KAAK,aAAa,iBAAiB,CAAC;;;;;AAMjE,SAAgB,+BAA+B,cAA+B;AAC7E,KAAI,aAAa,UAAU,yBAA0B,QAAO;AAC5D,KAAI,SAAS,aAAa,CAAC,SAAS,kBAAmB,QAAO;AAC9D,QAAO;;;;;;AAOR,SAAS,8BAA8B,MAAsB;AAC5D,KAAI,CAAC,KAAM,QAAO;CAClB,MAAM,MAAM,KAAK,QAAQ,IAAI;AAG7B,UAFc,QAAQ,KAAK,OAAO,KAAK,MAAM,GAAG,IAAI,EAC9B,QAAQ,WAAW,GAAG,IACzB,QAAQ,MAAM,GAAG,gCAAgC;;;;;;AAOrE,SAAgB,+BAA+B,oBAAoC;CAClF,MAAM,OAAO,mBAAmB,QAAQ,OAAO,IAAI;CACnD,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,OAAO,SAAS,KAAK;CAC3B,MAAM,MAAM,QAAQ,KAAK;CAIzB,MAAM,YAAY,GAFH,8BADF,MAAM,KAAK,MAAM,GAAG,CAAC,IAAI,OAAO,GAAG,KACE,CAEtB,GADlB,WAAW,SAAS,CAAC,OAAO,KAAK,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG,GACnC;AACnC,KAAI,QAAQ,OAAO,QAAQ,GAAI,QAAO;AACtC,QAAO,KAAK,KAAK,UAAU;;;;;;;AAQ5B,SAAS,wCAAwC,yBAAiC,oBAAqC;AAGtH,KAAI,+BAA+B,QAFpB,QAAQ,yBAAyB,mBAAmB,EAEhB,oCAAoC,CAAC,CAAE,QAAO;AAEjG,MAAK,MAAM,WAAW,mBAAmB,MAAM,QAAQ,CACtD,KAAI,QAAQ,SAAS,kBAAmB,QAAO;AAGhD,QAAO;;;;;;;;;AAUR,SAAgB,mCAAmC,QAIxC;CACV,MAAM,EAAE,yBAAyB,oBAAoB,6BAA6B;AAClF,KAAI,CAAC,yBAA0B,QAAO;AAEtC,KAAI,CAAC,wCAAwC,yBAAyB,mBAAmB,CACxF,QAAO;AAGR,QAAO,+BAA+B,mBAAmB;;;;;;;AAQ1D,SAAgB,sCAAsC,QAK3C;CACV,MAAM,EAAE,aAAa,aAAa,wBAAwB,6BAA6B;AACvF,KAAI,CAAC,yBAA0B,QAAO;CAEtC,MAAM,OAAO,uBAAuB,QAAQ,OAAO,IAAI;AAEvD,KAAI,CAAC,+BADO,yBAAyB,aAAa,aAAa,KAAK,CAC5B,CAAE,QAAO;AAEjD,QAAO,+BAA+B,KAAK;;AAG5C,SAAgB,0BAA0B,QAK/B;CACV,MAAM,MACL,OAAO,wBACN,OAAO,OAAO,uBAAuB,WAAW,OAAO,qBAAqB,OAAO,OAAO,UAAU;AACtG,QAAO,GAAG,OAAO,OAAO,GAAG,IAAI"}