vitest-plugin-vis 1.7.0 → 2.0.1

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 (40) hide show
  1. package/esm/client/image_snapshot_matcher.js +1 -1
  2. package/esm/client/page/has_image_snapshot.js +1 -1
  3. package/esm/config/types.d.ts +14 -5
  4. package/esm/config/types.d.ts.map +1 -1
  5. package/esm/config/vis.d.ts +1 -1
  6. package/esm/config/vis.js +1 -1
  7. package/esm/server/commands/setup_vis_suite.js +1 -0
  8. package/esm/server/snapshot_path.d.ts +2 -1
  9. package/esm/server/snapshot_path.d.ts.map +1 -1
  10. package/esm/server/snapshot_path.js +18 -2
  11. package/esm/server/vis_context.d.ts +1 -1
  12. package/esm/server/vis_context.d.ts.map +1 -1
  13. package/esm/server/vis_context.logic.d.ts +1 -14
  14. package/esm/server/vis_context.logic.d.ts.map +1 -1
  15. package/esm/server/vis_context.logic.js +8 -7
  16. package/esm/server/vis_context.types.d.ts +22 -1
  17. package/esm/server/vis_context.types.d.ts.map +1 -1
  18. package/esm/setup/create_vis.js +2 -2
  19. package/esm/shared/constants.d.ts +1 -0
  20. package/esm/shared/constants.d.ts.map +1 -1
  21. package/esm/shared/constants.js +1 -0
  22. package/esm/shared/types.d.ts +4 -1
  23. package/esm/shared/types.d.ts.map +1 -1
  24. package/esm/testing/stubBrowserCommandContext.d.ts +5 -0
  25. package/esm/testing/stubBrowserCommandContext.d.ts.map +1 -1
  26. package/esm/testing/stubBrowserCommandContext.js +13 -0
  27. package/package.json +9 -9
  28. package/readme.md +27 -12
  29. package/src/client/image_snapshot_matcher.ts +1 -1
  30. package/src/client/page/has_image_snapshot.ts +1 -1
  31. package/src/config/types.ts +17 -5
  32. package/src/config/vis.ts +1 -1
  33. package/src/server/commands/setup_vis_suite.ts +2 -2
  34. package/src/server/snapshot_path.ts +17 -2
  35. package/src/server/vis_context.logic.ts +9 -22
  36. package/src/server/vis_context.types.ts +23 -1
  37. package/src/setup/create_vis.ts +2 -2
  38. package/src/shared/constants.ts +1 -0
  39. package/src/shared/types.ts +6 -1
  40. package/src/testing/stubBrowserCommandContext.ts +15 -0
@@ -72,6 +72,6 @@ async function writeSnapshot(commands, path, image) {
72
72
  async function parseImageSnapshotOptions(commands, taskId, options) {
73
73
  const index = await commands.imageSnapshotNextIndex(taskId);
74
74
  const { customizeSnapshotId, ...rest } = options;
75
- const snapshotFileId = customizeSnapshotId(taskId, index);
75
+ const snapshotFileId = customizeSnapshotId({ id: taskId, index });
76
76
  return { ...rest, snapshotFileId };
77
77
  }
@@ -17,7 +17,7 @@ export function hasImageSnapshot(options) {
17
17
  if (options?.customizeSnapshotId) {
18
18
  return commands
19
19
  .imageSnapshotNextIndex(taskId)
20
- .then((index) => commands.hasImageSnapshot(taskId, options.customizeSnapshotId(taskId, index)));
20
+ .then((index) => commands.hasImageSnapshot(taskId, options.customizeSnapshotId({ id: taskId, index })));
21
21
  }
22
22
  return commands.hasImageSnapshot(taskId);
23
23
  }
@@ -11,22 +11,31 @@ export type VisOptions<M extends ComparisonMethod = 'pixel'> = ImageSnapshotTime
11
11
  * <snapshotRootDir>/<platform>/<snapshotSubpath>/<snapshotId>.png
12
12
  *
13
13
  * Default: undefined
14
+ *
15
+ * @deprecated Use `snapshotRootDir` instead.
14
16
  */
15
17
  platform?: string | undefined;
16
18
  /**
17
19
  * The snapshot folder relative to the root of the project.
18
20
  *
19
- * Default: `__vis__`
21
+ * Default: `{projectRoot}/__vis__/{platform}`
20
22
  */
21
- snapshotRootDir?: string | undefined;
23
+ snapshotRootDir?: string | ((context: {
24
+ ci: boolean;
25
+ browserName: string;
26
+ providerName: string;
27
+ platform: string;
28
+ screenshotFailures: boolean | undefined;
29
+ screenshotDirectory: string | undefined;
30
+ }) => string) | undefined;
22
31
  /**
23
32
  * Customize the snapshot subpath.
24
33
  *
25
34
  * The snapshot subpath is used along with `snapshotRootDir` to determine the folder of the snapshots:
26
35
  *
27
- * - baseline: `<snapshotRootDir>/<platform>/<snapshotSubpath>/<snapshotId>.png`
28
- * - result: `<snapshotRootDir>/__results__/<snapshotSubpath>/<snapshotId>.png`
29
- * - diff: `<snapshotRootDir>/__diffs__/<snapshotSubpath>/<snapshotId>.png`
36
+ * - baseline: `<snapshotRootDir>/baselines/<snapshotSubpath>/<snapshotId>.png`
37
+ * - result: `<snapshotRootDir>/results/<snapshotSubpath>/<snapshotId>.png`
38
+ * - diff: `<snapshotRootDir>/diffs/<snapshotSubpath>/<snapshotId>.png`
30
39
  *
31
40
  * Typically, you place your test files either in a dedicated `tests` folder or in the `src` folder along with your source code.
32
41
  * By default, the snapshot subpath is the test file path with that folder removed to reduces nesting of the snapshot folders.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,mBAAmB,EACnB,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,oBAAoB,CAAA;AAE3B,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAEhC,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,gBAAgB,GAAG,OAAO,IAAI,2BAA2B,GACzF,sBAAsB,GACtB,2BAA2B,CAAC,CAAC,CAAC,GAC9B,mBAAmB,GAAG;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;CACtD,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,mBAAmB,EACnB,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,oBAAoB,CAAA;AAE3B,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAEhC,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,gBAAgB,GAAG,OAAO,IAAI,2BAA2B,GACzF,sBAAsB,GACtB,2BAA2B,CAAC,CAAC,CAAC,GAC9B,mBAAmB,GAAG;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/C;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B;;;;OAIG;IACH,eAAe,CAAC,EACb,MAAM,GACN,CAAC,CAAC,OAAO,EAAE;QACX,EAAE,EAAE,OAAO,CAAA;QACX,WAAW,EAAE,MAAM,CAAA;QACnB,YAAY,EAAE,MAAM,CAAA;QACpB,QAAQ,EAAE,MAAM,CAAA;QAChB,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAA;QACvC,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAA;KACtC,KAAK,MAAM,CAAC,GACb,SAAS,CAAA;IACZ;;;;;;;;;;;;;;;;;;;OAmBG;IACH,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;CACtD,CAAA"}
@@ -21,7 +21,7 @@ export declare function vis<M extends ComparisonMethod = 'pixel'>(options?: VisO
21
21
  writeImageSnapshot: import("vitest/node").BrowserCommand<[relativeFilePath: string, imageBase64: string]>;
22
22
  };
23
23
  };
24
- setupFiles: string[] | undefined;
24
+ setupFiles: string[];
25
25
  };
26
26
  };
27
27
  };
package/esm/config/vis.js CHANGED
@@ -19,7 +19,7 @@ export function vis(options = { preset: 'auto' }) {
19
19
  name: undefined,
20
20
  commands,
21
21
  },
22
- setupFiles: preset && preset !== 'none' ? [`vitest-plugin-vis/presets/${preset}`] : undefined,
22
+ setupFiles: preset && preset !== 'none' ? [`vitest-plugin-vis/presets/${preset}`] : [],
23
23
  },
24
24
  };
25
25
  },
@@ -2,5 +2,6 @@ import { visContext } from "../vis_context.js";
2
2
  import { assertTestPathDefined } from "./_assertions.js";
3
3
  export const setupVisSuite = async (context) => {
4
4
  assertTestPathDefined(context, 'setupVisSuite');
5
+ // using props not currently listed in the types
5
6
  return visContext.setupSuite(context);
6
7
  };
@@ -1,4 +1,5 @@
1
1
  import type { VisOptions } from '../config/types.ts';
2
- export declare function resolveSnapshotRootDir(options: Pick<VisOptions, 'snapshotRootDir'> | undefined): string;
2
+ import type { PartialBrowserCommandContext } from './vis_context.types.ts';
3
+ export declare function resolveSnapshotRootDir(suite: PartialBrowserCommandContext, options: VisOptions): string;
3
4
  export declare function getSnapshotSubpath(suiteName: string, options: Pick<VisOptions, 'customizeSnapshotSubpath'>): string;
4
5
  //# sourceMappingURL=snapshot_path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot_path.d.ts","sourceRoot":"","sources":["../../src/server/snapshot_path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAIpD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,GAAG,SAAS,UAE9F;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,0BAA0B,CAAC,UAG1G"}
1
+ {"version":3,"file":"snapshot_path.d.ts","sourceRoot":"","sources":["../../src/server/snapshot_path.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAGpD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAA;AAE1E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,4BAA4B,EAAE,OAAO,EAAE,UAAU,UAY9F;AAKD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,0BAA0B,CAAC,UAG1G"}
@@ -1,7 +1,23 @@
1
+ import ci from 'is-ci';
1
2
  import { SNAPSHOT_ROOT_DIR } from "../shared/constants.js";
2
3
  import { trimCommonFolder } from "../shared/trim_common_folder.js";
3
- export function resolveSnapshotRootDir(options) {
4
- return options?.snapshotRootDir ?? SNAPSHOT_ROOT_DIR;
4
+ export function resolveSnapshotRootDir(suite, options) {
5
+ if (!options.snapshotRootDir)
6
+ return getSnapshotRootDir(SNAPSHOT_ROOT_DIR, options.platform);
7
+ const snapshotRootDir = options.snapshotRootDir;
8
+ if (typeof snapshotRootDir === 'string')
9
+ return getSnapshotRootDir(snapshotRootDir, options.platform);
10
+ return snapshotRootDir({
11
+ ci,
12
+ browserName: suite.provider.browserName,
13
+ providerName: suite.provider.name,
14
+ platform: process.platform,
15
+ screenshotFailures: suite.provider.options.screenshotFailures,
16
+ screenshotDirectory: suite.provider.options.screenshotDirectory,
17
+ });
18
+ }
19
+ function getSnapshotRootDir(snapshotRootDir, platform = process.platform) {
20
+ return `${snapshotRootDir}/${ci ? platform : 'local'}`;
5
21
  }
6
22
  export function getSnapshotSubpath(suiteName, options) {
7
23
  const customizeSnapshotSubpath = options.customizeSnapshotSubpath ?? trimCommonFolder;
@@ -3,7 +3,7 @@ export declare const visContext: {
3
3
  __test__getOptions(): import("../config.ts").VisOptions<any>;
4
4
  __test__reset(): void;
5
5
  __test__getState(): import("./vis_context.types.ts").VisState;
6
- setupSuite(context: import("./vis_context.logic.ts").PartialBrowserCommandContext): Promise<import("type-plus").Pick._<import("./vis_context.types.ts").VisState, "subjectDataTestId">>;
6
+ setupSuite(context: import("./vis_context.types.ts").PartialBrowserCommandContext): Promise<import("type-plus").Pick._<import("./vis_context.types.ts").VisState, "subjectDataTestId">>;
7
7
  getSnapshotInfo(testPath: string, name: string, options?: {
8
8
  snapshotFileId?: string | undefined;
9
9
  }): {
@@ -1 +1 @@
1
- {"version":3,"file":"vis_context.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU;;;;;;;sBACspD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CADloD,CAAA"}
1
+ {"version":3,"file":"vis_context.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU;;;;;;;sBAC69C,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CADz8C,CAAA"}
@@ -1,18 +1,5 @@
1
1
  import type { VisOptions } from '../config/types.ts';
2
- import type { VisState } from './vis_context.types.ts';
3
- export type PartialBrowserCommandContext = {
4
- project: {
5
- config: {
6
- root: string;
7
- snapshotOptions: {
8
- updateSnapshot: 'all' | 'new' | 'none';
9
- };
10
- testTimeout: number;
11
- hookTimeout: number;
12
- };
13
- };
14
- testPath: string;
15
- };
2
+ import type { PartialBrowserCommandContext, VisState } from './vis_context.types.ts';
16
3
  export declare function createVisContext(): {
17
4
  setOptions<M extends "pixel" | "ssim">(options?: VisOptions<M>): void;
18
5
  __test__getOptions(): VisOptions<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"vis_context.logic.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.logic.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAKpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAEtD,MAAM,MAAM,4BAA4B,GAAG;IAC1C,OAAO,EAAE;QACR,MAAM,EAAE;YACP,IAAI,EAAE,MAAM,CAAA;YACZ,eAAe,EAAE;gBAChB,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;aACtC,CAAA;YACD,WAAW,EAAE,MAAM,CAAA;YACnB,WAAW,EAAE,MAAM,CAAA;SACnB,CAAA;KACD,CAAA;IACD,QAAQ,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,wBAAgB,gBAAgB;eAMnB,CAAC,SAAS,OAAO,GAAG,MAAM,YAAW,UAAU,CAAC,CAAC,CAAC;;;;IAY7D;;;;OAIG;wBACuB,4BAA4B;8BAa5B,MAAM,QAAQ,MAAM,YAAY;QAAE,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE;;;;;;;;;;;;;;;;;;;2BAkB1E,MAAM,UAAU,MAAM;+BAGlB,MAAM,UAAU,MAAM,kBAAkB,MAAM,GAAG,SAAS;8BAI3D;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,kBAAkB,MAAM,GAAG,SAAS;2BAMlF,MAAM,UAAU,MAAM;;;;;;;;;;EAe9C;AA2BD,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,0BAA0B,CAAC;;;;;;;;EAWnH;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,0BAA0B,CAAC,UAElH"}
1
+ {"version":3,"file":"vis_context.logic.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.logic.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAKpD,OAAO,KAAK,EAAE,4BAA4B,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAEpF,wBAAgB,gBAAgB;eAMnB,CAAC,SAAS,OAAO,GAAG,MAAM,YAAW,UAAU,CAAC,CAAC,CAAC;;;;IAY7D;;;;OAIG;wBACuB,4BAA4B;8BAa5B,MAAM,QAAQ,MAAM,YAAY;QAAE,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE;;;;;;;;;;;;;;;;;;;2BAkB1E,MAAM,UAAU,MAAM;+BAGlB,MAAM,UAAU,MAAM,kBAAkB,MAAM,GAAG,SAAS;8BAI3D;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,kBAAkB,MAAM,GAAG,SAAS;2BASlF,MAAM,UAAU,MAAM;;;;;;;;;;EAe9C;AAyBD,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,0BAA0B,CAAC;;;;;;;;EAWnH;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,0BAA0B,CAAC,UAElH"}
@@ -1,6 +1,6 @@
1
1
  import { join, relative } from 'pathe';
2
2
  import { pick } from 'type-plus';
3
- import { DIFF_DIR, RESULT_DIR } from "../shared/constants.js";
3
+ import { BASELINE_DIR, DIFF_DIR, RESULT_DIR } from "../shared/constants.js";
4
4
  import { file } from "./file.js";
5
5
  import { getSnapshotSubpath, resolveSnapshotRootDir } from "./snapshot_path.js";
6
6
  import { ctx } from "./vis_context.ctx.js";
@@ -64,8 +64,11 @@ export function createVisContext() {
64
64
  getSnapshotFilename(info, snapshotFileId) {
65
65
  if (snapshotFileId)
66
66
  return `${snapshotFileId}.png`;
67
- const customizeSnapshotId = visOptions.customizeSnapshotId ?? ((id, index) => `${id}-${index}`);
68
- return `${customizeSnapshotId(info.taskId, info.task.count)}.png`;
67
+ const customizeSnapshotId = visOptions.customizeSnapshotId ?? (({ id, index }) => `${id}-${index}`);
68
+ return `${customizeSnapshotId({
69
+ id: info.taskId,
70
+ index: info.task.count,
71
+ })}.png`;
69
72
  },
70
73
  getSuiteInfo(testPath, taskId) {
71
74
  const suiteId = getSuiteId(state, testPath, visOptions);
@@ -84,16 +87,14 @@ export function createVisContext() {
84
87
  return context;
85
88
  }
86
89
  async function setupState(suite, visOptions) {
87
- const snapshotRootDir = resolveSnapshotRootDir(visOptions);
90
+ const snapshotRootDir = resolveSnapshotRootDir(suite, visOptions);
88
91
  const projectPath = suite.project.config.root;
89
- const platform = visOptions.platform ?? ctx.getSnapshotPlatform();
90
92
  const state = {
91
93
  projectPath,
92
- platform,
93
94
  testTimeout: suite.project.config.testTimeout,
94
95
  hookTimeout: suite.project.config.hookTimeout,
95
96
  snapshotRootDir,
96
- snapshotBaselineDir: join(snapshotRootDir, platform),
97
+ snapshotBaselineDir: join(snapshotRootDir, BASELINE_DIR),
97
98
  snapshotResultDir: join(snapshotRootDir, RESULT_DIR),
98
99
  snapshotDiffDir: join(snapshotRootDir, DIFF_DIR),
99
100
  snapshotRootPath: join(projectPath, snapshotRootDir),
@@ -1,6 +1,5 @@
1
1
  export type VisState = {
2
2
  projectPath: string;
3
- platform: string;
4
3
  testTimeout: number;
5
4
  hookTimeout: number;
6
5
  snapshotRootDir: string;
@@ -18,4 +17,26 @@ export type VisState = {
18
17
  }>;
19
18
  }>;
20
19
  };
20
+ export type PartialBrowserCommandContext = {
21
+ project: {
22
+ config: {
23
+ root: string;
24
+ snapshotOptions: {
25
+ updateSnapshot: 'all' | 'new' | 'none';
26
+ };
27
+ testTimeout: number;
28
+ hookTimeout: number;
29
+ };
30
+ };
31
+ provider: {
32
+ name: string;
33
+ browserName: string;
34
+ options: {
35
+ headless: boolean | undefined;
36
+ screenshotFailures: boolean | undefined;
37
+ screenshotDirectory: string | undefined;
38
+ };
39
+ };
40
+ testPath: string;
41
+ };
21
42
  //# sourceMappingURL=vis_context.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vis_context.types.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,MAAM,EAAE,MAAM,CACb,MAAM,EACN;QACC,WAAW,EAAE,MAAM,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,MAAM,CACZ,MAAM,EACN;YACC,KAAK,EAAE,MAAM,CAAA;SACb,CACD,CAAA;KACD,CACD,CAAA;CACD,CAAA"}
1
+ {"version":3,"file":"vis_context.types.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACtB,WAAW,EAAE,MAAM,CAAA;IAEnB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,MAAM,EAAE,MAAM,CACb,MAAM,EACN;QACC,WAAW,EAAE,MAAM,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,MAAM,CACZ,MAAM,EACN;YACC,KAAK,EAAE,MAAM,CAAA;SACb,CACD,CAAA;KACD,CACD,CAAA;CACD,CAAA;AACD,MAAM,MAAM,4BAA4B,GAAG;IAC1C,OAAO,EAAE;QACR,MAAM,EAAE;YACP,IAAI,EAAE,MAAM,CAAA;YACZ,eAAe,EAAE;gBAChB,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;aACtC,CAAA;YACD,WAAW,EAAE,MAAM,CAAA;YACnB,WAAW,EAAE,MAAM,CAAA;SACnB,CAAA;KACD,CAAA;IACD,QAAQ,EAAE;QACT,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;QACnB,OAAO,EAAE;YACR,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;YAC7B,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAA;YACvC,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAA;SACvC,CAAA;KACD,CAAA;IACD,QAAQ,EAAE,MAAM,CAAA;CAChB,CAAA"}
@@ -81,8 +81,8 @@ export function createVis(commands) {
81
81
  .toMatchImageSnapshot({
82
82
  ...meta,
83
83
  customizeSnapshotId: meta?.customizeSnapshotId
84
- ? (id, index) => `${meta.customizeSnapshotId(id, index)}-${themeId}`
85
- : (id) => `${id}-${themeId}`,
84
+ ? ({ id, index }) => `${meta.customizeSnapshotId({ id, index })}-${themeId}`
85
+ : ({ id }) => `${id}-${themeId}`,
86
86
  });
87
87
  }
88
88
  catch (error) {
@@ -1,5 +1,6 @@
1
1
  export declare const NAME = "vis";
2
2
  export declare const SNAPSHOT_ROOT_DIR = "__vis__";
3
+ export declare const BASELINE_DIR = "__baselines__";
3
4
  export declare const RESULT_DIR = "__results__";
4
5
  export declare const DIFF_DIR = "__diffs__";
5
6
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAAQ,CAAA;AACzB,eAAO,MAAM,iBAAiB,YAAY,CAAA;AAC1C,eAAO,MAAM,UAAU,gBAAgB,CAAA;AACvC,eAAO,MAAM,QAAQ,cAAc,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAAQ,CAAA;AACzB,eAAO,MAAM,iBAAiB,YAAY,CAAA;AAC1C,eAAO,MAAM,YAAY,kBAAkB,CAAA;AAC3C,eAAO,MAAM,UAAU,gBAAgB,CAAA;AACvC,eAAO,MAAM,QAAQ,cAAc,CAAA"}
@@ -1,4 +1,5 @@
1
1
  export const NAME = 'vis';
2
2
  export const SNAPSHOT_ROOT_DIR = '__vis__';
3
+ export const BASELINE_DIR = '__baselines__';
3
4
  export const RESULT_DIR = '__results__';
4
5
  export const DIFF_DIR = '__diffs__';
@@ -15,7 +15,10 @@ export interface ImageSnapshotIdOptions {
15
15
  * @param id The id of the snapshot.
16
16
  * @param index The index of the snapshot.
17
17
  */
18
- customizeSnapshotId?: (id: string, index: number) => string;
18
+ customizeSnapshotId?: (context: {
19
+ id: string;
20
+ index: number;
21
+ }) => string;
19
22
  }
20
23
  export type ComparisonMethod = 'pixel' | 'ssim';
21
24
  export type FailureThresholdOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,SAAS,CAAA;AAErD,MAAM,WAAW,2BAA2B;IAC3C;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;CAC3D;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAA;AAE/C,MAAM,MAAM,uBAAuB,GAAG;IACrC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;IACtD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,GAAG,MAAM,IAAI;IAC/C,gBAAgB,EAAE,CAAC,CAAA;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,SAAS,CAAA;CAC9C,CAAA;AACD,MAAM,MAAM,sBAAsB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,gBAAgB,CAAC,EAAE,CAAC,GAAG,SAAS,CAAA;IAChC;;OAEG;IACH,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAA;CAC3C,CAAA;AAED,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,gBAAgB,GAAG,OAAO,IAAI,CAAC,CAAC,SAAS,MAAM,GAC9F,qBAAqB,CAAC,CAAC,CAAC,GACxB,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAC5B,uBAAuB,CAAA;AAExB,MAAM,MAAM,mBAAmB,GAAG;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,SAAS,CAAA;AAErD,MAAM,WAAW,2BAA2B;IAC3C;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC/B,EAAE,EAAE,MAAM,CAAA;QAGV,KAAK,EAAE,MAAM,CAAA;KACb,KAAK,MAAM,CAAA;CACZ;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAA;AAE/C,MAAM,MAAM,uBAAuB,GAAG;IACrC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;IACtD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,GAAG,MAAM,IAAI;IAC/C,gBAAgB,EAAE,CAAC,CAAA;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,SAAS,CAAA;CAC9C,CAAA;AACD,MAAM,MAAM,sBAAsB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,gBAAgB,CAAC,EAAE,CAAC,GAAG,SAAS,CAAA;IAChC;;OAEG;IACH,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAA;CAC3C,CAAA;AAED,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,gBAAgB,GAAG,OAAO,IAAI,CAAC,CAAC,SAAS,MAAM,GAC9F,qBAAqB,CAAC,CAAC,CAAC,GACxB,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAC5B,uBAAuB,CAAA;AAExB,MAAM,MAAM,mBAAmB,GAAG;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,CAAA"}
@@ -1,3 +1,8 @@
1
1
  import type { BrowserCommandContext } from 'vitest/node';
2
+ import type { PartialBrowserCommandContext } from '../server/vis_context.types.ts';
2
3
  export declare const stubBrowserCommandContext: (stub?: import("type-plus").RecursivePartial<BrowserCommandContext> | undefined) => BrowserCommandContext;
4
+ export declare function createStubPartialBrowserCommandContext({ root, testPath }: {
5
+ root: string;
6
+ testPath: string;
7
+ }): (stub?: import("type-plus").RecursivePartial<PartialBrowserCommandContext> | undefined) => PartialBrowserCommandContext;
3
8
  //# sourceMappingURL=stubBrowserCommandContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stubBrowserCommandContext.d.ts","sourceRoot":"","sources":["../../src/testing/stubBrowserCommandContext.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAExD,eAAO,MAAM,yBAAyB,2GAAwC,CAAA"}
1
+ {"version":3,"file":"stubBrowserCommandContext.d.ts","sourceRoot":"","sources":["../../src/testing/stubBrowserCommandContext.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAA;AAElF,eAAO,MAAM,yBAAyB,2GAAwC,CAAA;AAE9E,wBAAgB,sCAAsC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,2HAY5G"}
@@ -1,2 +1,15 @@
1
1
  import { stub } from 'type-plus';
2
2
  export const stubBrowserCommandContext = stub.build({});
3
+ export function createStubPartialBrowserCommandContext({ root, testPath }) {
4
+ return stub.build({
5
+ project: {
6
+ config: {
7
+ root,
8
+ },
9
+ },
10
+ provider: {
11
+ options: {},
12
+ },
13
+ testPath,
14
+ });
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitest-plugin-vis",
3
- "version": "1.7.0",
3
+ "version": "2.0.1",
4
4
  "description": "Vitest visual testing plugin",
5
5
  "keywords": [
6
6
  "image-snapshot",
@@ -70,28 +70,28 @@
70
70
  "pngjs": "^7.0.0",
71
71
  "rimraf": "^6.0.1",
72
72
  "ssim.js": "^3.5.0",
73
- "type-plus": "^8.0.0-beta.6"
73
+ "type-plus": "8.0.0-beta.7"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@repobuddy/typescript": "^2.1.0",
77
77
  "@types/is-ci": "^3.0.4",
78
78
  "@types/pngjs": "^6.0.5",
79
79
  "@types/react": "^19.0.2",
80
- "@vitest/browser": "^3.0.0",
81
- "@vitest/coverage-istanbul": "^3.0.0",
82
- "@vitest/coverage-v8": "^3.0.0",
83
- "@vitest/expect": "^3.0.0",
80
+ "@vitest/browser": "^3.0.5",
81
+ "@vitest/coverage-istanbul": "^3.0.5",
82
+ "@vitest/coverage-v8": "^3.0.5",
83
+ "@vitest/expect": "^3.0.5",
84
84
  "cross-env": "^7.0.3",
85
85
  "never-fail": "^1.1.4",
86
86
  "npm-run-all2": "^7.0.2",
87
- "playwright": "^1.49.0",
87
+ "playwright": "latest",
88
88
  "react": "^19.0.0",
89
89
  "react-dom": "^19.0.0",
90
90
  "typescript": "^5.7.2",
91
91
  "vite": "^6.0.9",
92
- "vitest": "^3.0.0",
92
+ "vitest": "^3.0.5",
93
93
  "vitest-browser-react": "^0.0.4",
94
- "webdriverio": "^9.5.7"
94
+ "webdriverio": "latest"
95
95
  },
96
96
  "peerDependencies": {
97
97
  "@vitest/browser": "^2 || ^3",
package/readme.md CHANGED
@@ -29,11 +29,19 @@ import { vis } from 'vitest-plugin-vis/config'
29
29
  export default defineConfig({
30
30
  plugins: [vis()],
31
31
  test: {
32
+ // vitest v2
32
33
  browser: {
33
- // typical browser config
34
34
  enabled: true,
35
35
  provider: 'playwright',
36
- name: 'chromium'
36
+ name: 'chromium',
37
+ },
38
+ // vitest v3
39
+ browser: {
40
+ enabled: true,
41
+ provider: 'playwright',
42
+ instances: [
43
+ { browser: 'chromium' }
44
+ ]
37
45
  }
38
46
  }
39
47
  })
@@ -47,8 +55,9 @@ This default configuration will:
47
55
  - Timeout for image comparison is set to `30000 ms`.
48
56
  - Local (non-CI) image snapshots are saved in the `<root>/__vis__/local` directory.
49
57
  - CI image snapshots are saved in the `<root>/__vis__/<process.platform>` directory.
50
- - Image snapshots of the current test run are saved in the `<root>/__vis__/__results__` directory.
51
- - Diff images are saved in the `<root>/__vis__/__diffs__` directory.
58
+ - Image snapshots of the current test run are saved in the `<root>/__vis__/*/__results__` directory.
59
+ - Diff images are saved in the `<root>/__vis__/*/__diffs__` directory.
60
+ - Baseline images are saved in the `<root>/__vis__/*/__baselines__` directory.
52
61
 
53
62
  You can customize the configuration:
54
63
 
@@ -61,8 +70,15 @@ export default defineConfig({
61
70
  plugins: [
62
71
  vis({
63
72
  preset: 'auto',
64
- snapshotRootDir: '__vis__',
65
- platform: '...', // {process.platform} or `local`
73
+ snapshotRootDir: ({
74
+ ci, // true if running on CI
75
+ platform, // process.platform
76
+ providerName, // 'playwright' or 'webdriverio'
77
+ browserName,
78
+ screenshotFailures, // from `browser` config
79
+ screenshotDirectory, // from `browser` config
80
+ }) => `__vis__/${ci ? platform : 'local'}`,
81
+ platform: '...', // {process.platform} or `local` (deprecated use `snapshotRootDir` instead)
66
82
  customizeSnapshotSubpath: (subpath) => trimCommonFolder(subpath),
67
83
  customizeSnapshotId: (id, index) => `${id}-${index}`,
68
84
  // set a default subject (e.g. 'subject') to capture image snapshot
@@ -92,8 +108,7 @@ import { vis } from 'vitest-plugin-vis/config'
92
108
 
93
109
  export default defineConfig({
94
110
  plugins: [
95
- // preset is disabled by default when you provide a custom config
96
- vis({}) // or vis({ preset: 'none' })
111
+ vis({ preset: 'none' })
97
112
  ],
98
113
  test:{
99
114
  browser:{/* ... */},
@@ -113,8 +128,8 @@ vis.presets.manual()
113
128
  // or capture image snapshot for all rendering tests
114
129
  // for multiple themes (light and dark in this example)
115
130
  vis.presets.theme({
116
- light() { document.body.classList.remove('dark') },
117
- dark() { document.body.classList.add('dark') },
131
+ async light() { document.body.classList.remove('dark') },
132
+ async dark() { document.body.classList.add('dark') },
118
133
  })
119
134
  ```
120
135
 
@@ -295,8 +310,8 @@ The local snapshots, current run results, and diffs should be ignored by git.
295
310
  Add the following lines to your `.gitignore` file:
296
311
 
297
312
  ```sh
298
- **/__vis__/__diffs__
299
- **/__vis__/__results__
313
+ **/__vis__/**/__diffs__
314
+ **/__vis__/**/__results__
300
315
  **/__vis__/local
301
316
  ```
302
317
 
@@ -107,6 +107,6 @@ async function parseImageSnapshotOptions(
107
107
  ) {
108
108
  const index = await commands.imageSnapshotNextIndex(taskId)
109
109
  const { customizeSnapshotId, ...rest } = options
110
- const snapshotFileId = customizeSnapshotId!(taskId, index)
110
+ const snapshotFileId = customizeSnapshotId!({ id: taskId, index })
111
111
  return { ...rest, snapshotFileId }
112
112
  }
@@ -26,7 +26,7 @@ export function hasImageSnapshot(this: BrowserPage, options?: ImageSnapshotIdOpt
26
26
  if (options?.customizeSnapshotId) {
27
27
  return commands
28
28
  .imageSnapshotNextIndex(taskId)
29
- .then((index) => commands.hasImageSnapshot(taskId, options.customizeSnapshotId!(taskId, index)))
29
+ .then((index) => commands.hasImageSnapshot(taskId, options.customizeSnapshotId!({ id: taskId, index })))
30
30
  }
31
31
 
32
32
  return commands.hasImageSnapshot(taskId)
@@ -22,22 +22,34 @@ export type VisOptions<M extends ComparisonMethod = 'pixel'> = ImageSnapshotTime
22
22
  * <snapshotRootDir>/<platform>/<snapshotSubpath>/<snapshotId>.png
23
23
  *
24
24
  * Default: undefined
25
+ *
26
+ * @deprecated Use `snapshotRootDir` instead.
25
27
  */
26
28
  platform?: string | undefined
27
29
  /**
28
30
  * The snapshot folder relative to the root of the project.
29
31
  *
30
- * Default: `__vis__`
32
+ * Default: `{projectRoot}/__vis__/{platform}`
31
33
  */
32
- snapshotRootDir?: string | undefined
34
+ snapshotRootDir?:
35
+ | string
36
+ | ((context: {
37
+ ci: boolean
38
+ browserName: string
39
+ providerName: string
40
+ platform: string
41
+ screenshotFailures: boolean | undefined
42
+ screenshotDirectory: string | undefined
43
+ }) => string)
44
+ | undefined
33
45
  /**
34
46
  * Customize the snapshot subpath.
35
47
  *
36
48
  * The snapshot subpath is used along with `snapshotRootDir` to determine the folder of the snapshots:
37
49
  *
38
- * - baseline: `<snapshotRootDir>/<platform>/<snapshotSubpath>/<snapshotId>.png`
39
- * - result: `<snapshotRootDir>/__results__/<snapshotSubpath>/<snapshotId>.png`
40
- * - diff: `<snapshotRootDir>/__diffs__/<snapshotSubpath>/<snapshotId>.png`
50
+ * - baseline: `<snapshotRootDir>/baselines/<snapshotSubpath>/<snapshotId>.png`
51
+ * - result: `<snapshotRootDir>/results/<snapshotSubpath>/<snapshotId>.png`
52
+ * - diff: `<snapshotRootDir>/diffs/<snapshotSubpath>/<snapshotId>.png`
41
53
  *
42
54
  * Typically, you place your test files either in a dedicated `tests` folder or in the `src` folder along with your source code.
43
55
  * By default, the snapshot subpath is the test file path with that folder removed to reduces nesting of the snapshot folders.
package/src/config/vis.ts CHANGED
@@ -23,7 +23,7 @@ export function vis<M extends ComparisonMethod = 'pixel'>(options: VisOptions<M>
23
23
  name: undefined as unknown as string,
24
24
  commands,
25
25
  },
26
- setupFiles: preset && preset !== 'none' ? [`vitest-plugin-vis/presets/${preset}`] : undefined,
26
+ setupFiles: preset && preset !== 'none' ? [`vitest-plugin-vis/presets/${preset}`] : [],
27
27
  },
28
28
  }
29
29
  },
@@ -17,6 +17,6 @@ export const setupVisSuite: BrowserCommand<[]> = async (
17
17
  context,
18
18
  ): Promise<{ subjectDataTestId: string | undefined }> => {
19
19
  assertTestPathDefined(context, 'setupVisSuite')
20
-
21
- return visContext.setupSuite(context)
20
+ // using props not currently listed in the types
21
+ return visContext.setupSuite(context as any)
22
22
  }
@@ -1,11 +1,26 @@
1
+ import ci from 'is-ci'
1
2
  import type { VisOptions } from '../config/types.ts'
2
3
  import { SNAPSHOT_ROOT_DIR } from '../shared/constants.ts'
3
4
  import { trimCommonFolder } from '../shared/trim_common_folder.ts'
5
+ import type { PartialBrowserCommandContext } from './vis_context.types.ts'
4
6
 
5
- export function resolveSnapshotRootDir(options: Pick<VisOptions, 'snapshotRootDir'> | undefined) {
6
- return options?.snapshotRootDir ?? SNAPSHOT_ROOT_DIR
7
+ export function resolveSnapshotRootDir(suite: PartialBrowserCommandContext, options: VisOptions) {
8
+ if (!options.snapshotRootDir) return getSnapshotRootDir(SNAPSHOT_ROOT_DIR, options.platform)
9
+ const snapshotRootDir = options.snapshotRootDir
10
+ if (typeof snapshotRootDir === 'string') return getSnapshotRootDir(snapshotRootDir, options.platform!)
11
+ return snapshotRootDir({
12
+ ci,
13
+ browserName: suite.provider.browserName,
14
+ providerName: suite.provider.name,
15
+ platform: process.platform,
16
+ screenshotFailures: suite.provider.options.screenshotFailures,
17
+ screenshotDirectory: suite.provider.options.screenshotDirectory,
18
+ })
7
19
  }
8
20
 
21
+ function getSnapshotRootDir(snapshotRootDir: string, platform: string | undefined = process.platform) {
22
+ return `${snapshotRootDir}/${ci ? platform : 'local'}`
23
+ }
9
24
  export function getSnapshotSubpath(suiteName: string, options: Pick<VisOptions, 'customizeSnapshotSubpath'>) {
10
25
  const customizeSnapshotSubpath = options.customizeSnapshotSubpath ?? trimCommonFolder
11
26
  return customizeSnapshotSubpath(suiteName)
@@ -1,25 +1,11 @@
1
1
  import { join, relative } from 'pathe'
2
2
  import { pick } from 'type-plus'
3
3
  import type { VisOptions } from '../config/types.ts'
4
- import { DIFF_DIR, RESULT_DIR } from '../shared/constants.ts'
4
+ import { BASELINE_DIR, DIFF_DIR, RESULT_DIR } from '../shared/constants.ts'
5
5
  import { file } from './file.ts'
6
6
  import { getSnapshotSubpath, resolveSnapshotRootDir } from './snapshot_path.ts'
7
7
  import { ctx } from './vis_context.ctx.ts'
8
- import type { VisState } from './vis_context.types.ts'
9
-
10
- export type PartialBrowserCommandContext = {
11
- project: {
12
- config: {
13
- root: string
14
- snapshotOptions: {
15
- updateSnapshot: 'all' | 'new' | 'none'
16
- }
17
- testTimeout: number
18
- hookTimeout: number
19
- }
20
- }
21
- testPath: string
22
- }
8
+ import type { PartialBrowserCommandContext, VisState } from './vis_context.types.ts'
23
9
 
24
10
  export function createVisContext() {
25
11
  let visOptions: VisOptions<any> = {}
@@ -85,8 +71,11 @@ export function createVisContext() {
85
71
  getSnapshotFilename(info: { taskId: string; task: { count: number } }, snapshotFileId: string | undefined) {
86
72
  if (snapshotFileId) return `${snapshotFileId}.png`
87
73
 
88
- const customizeSnapshotId = visOptions.customizeSnapshotId ?? ((id, index) => `${id}-${index}`)
89
- return `${customizeSnapshotId(info.taskId, info.task.count)}.png`
74
+ const customizeSnapshotId = visOptions.customizeSnapshotId ?? (({ id, index }) => `${id}-${index}`)
75
+ return `${customizeSnapshotId({
76
+ id: info.taskId,
77
+ index: info.task.count,
78
+ })}.png`
90
79
  },
91
80
  getSuiteInfo(testPath: string, taskId: string) {
92
81
  const suiteId = getSuiteId(state, testPath, visOptions)
@@ -109,17 +98,15 @@ async function setupState(
109
98
  suite: PartialBrowserCommandContext,
110
99
  visOptions: Pick<VisOptions, 'snapshotRootDir' | 'platform' | 'subjectDataTestId'>,
111
100
  ) {
112
- const snapshotRootDir = resolveSnapshotRootDir(visOptions)
101
+ const snapshotRootDir = resolveSnapshotRootDir(suite, visOptions)
113
102
  const projectPath = suite.project.config.root
114
- const platform = visOptions.platform ?? ctx.getSnapshotPlatform()
115
103
 
116
104
  const state = {
117
105
  projectPath,
118
- platform,
119
106
  testTimeout: suite.project.config.testTimeout,
120
107
  hookTimeout: suite.project.config.hookTimeout,
121
108
  snapshotRootDir,
122
- snapshotBaselineDir: join(snapshotRootDir, platform),
109
+ snapshotBaselineDir: join(snapshotRootDir, BASELINE_DIR),
123
110
  snapshotResultDir: join(snapshotRootDir, RESULT_DIR),
124
111
  snapshotDiffDir: join(snapshotRootDir, DIFF_DIR),
125
112
  snapshotRootPath: join(projectPath, snapshotRootDir),
@@ -1,6 +1,6 @@
1
1
  export type VisState = {
2
2
  projectPath: string
3
- platform: string
3
+ // platform: string
4
4
  testTimeout: number
5
5
  hookTimeout: number
6
6
  snapshotRootDir: string
@@ -24,3 +24,25 @@ export type VisState = {
24
24
  }
25
25
  >
26
26
  }
27
+ export type PartialBrowserCommandContext = {
28
+ project: {
29
+ config: {
30
+ root: string
31
+ snapshotOptions: {
32
+ updateSnapshot: 'all' | 'new' | 'none'
33
+ }
34
+ testTimeout: number
35
+ hookTimeout: number
36
+ }
37
+ }
38
+ provider: {
39
+ name: string
40
+ browserName: string
41
+ options: {
42
+ headless: boolean | undefined
43
+ screenshotFailures: boolean | undefined
44
+ screenshotDirectory: string | undefined
45
+ }
46
+ }
47
+ testPath: string
48
+ }
@@ -82,8 +82,8 @@ export function createVis<M extends SnapshotMeta<any>>(commands: SetupVisSuiteCo
82
82
  .toMatchImageSnapshot({
83
83
  ...meta,
84
84
  customizeSnapshotId: meta?.customizeSnapshotId
85
- ? (id, index) => `${meta.customizeSnapshotId!(id, index)}-${themeId}`
86
- : (id) => `${id}-${themeId}`,
85
+ ? ({ id, index }) => `${meta.customizeSnapshotId!({ id, index })}-${themeId}`
86
+ : ({ id }) => `${id}-${themeId}`,
87
87
  })
88
88
  } catch (error) {
89
89
  errors.push([themeId, error])
@@ -1,4 +1,5 @@
1
1
  export const NAME = 'vis'
2
2
  export const SNAPSHOT_ROOT_DIR = '__vis__'
3
+ export const BASELINE_DIR = '__baselines__'
3
4
  export const RESULT_DIR = '__results__'
4
5
  export const DIFF_DIR = '__diffs__'
@@ -17,7 +17,12 @@ export interface ImageSnapshotIdOptions {
17
17
  * @param id The id of the snapshot.
18
18
  * @param index The index of the snapshot.
19
19
  */
20
- customizeSnapshotId?: (id: string, index: number) => string
20
+ customizeSnapshotId?: (context: {
21
+ id: string
22
+ // width: number
23
+ // height: number
24
+ index: number
25
+ }) => string
21
26
  }
22
27
 
23
28
  export type ComparisonMethod = 'pixel' | 'ssim'
@@ -1,4 +1,19 @@
1
1
  import { stub } from 'type-plus'
2
2
  import type { BrowserCommandContext } from 'vitest/node'
3
+ import type { PartialBrowserCommandContext } from '../server/vis_context.types.ts'
3
4
 
4
5
  export const stubBrowserCommandContext = stub.build<BrowserCommandContext>({})
6
+
7
+ export function createStubPartialBrowserCommandContext({ root, testPath }: { root: string; testPath: string }) {
8
+ return stub.build<PartialBrowserCommandContext>({
9
+ project: {
10
+ config: {
11
+ root,
12
+ },
13
+ },
14
+ provider: {
15
+ options: {},
16
+ },
17
+ testPath,
18
+ })
19
+ }