vitest-plugin-vis 2.3.2 → 2.4.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 (54) hide show
  1. package/esm/client/image_snapshot_matcher.d.ts +2 -2
  2. package/esm/client/image_snapshot_matcher.d.ts.map +1 -1
  3. package/esm/client/image_snapshot_matcher.js +3 -3
  4. package/esm/client/snapshot_options.js +1 -1
  5. package/esm/commands.d.ts +1 -2
  6. package/esm/commands.d.ts.map +1 -1
  7. package/esm/commands.js +1 -2
  8. package/esm/config/types.d.ts +3 -3
  9. package/esm/config/types.d.ts.map +1 -1
  10. package/esm/config/vis.d.ts +1 -2
  11. package/esm/config/vis.d.ts.map +1 -1
  12. package/esm/config/vis.js +4 -3
  13. package/esm/server/commands/browser_command_context.d.ts +14 -0
  14. package/esm/server/commands/browser_command_context.d.ts.map +1 -0
  15. package/esm/server/commands/browser_command_context.js +6 -0
  16. package/esm/server/commands/extend.d.ts +1 -3
  17. package/esm/server/commands/extend.d.ts.map +1 -1
  18. package/esm/server/commands/extend.js +0 -2
  19. package/esm/server/commands/has_image_snapshot.js +1 -1
  20. package/esm/server/commands/image_snapshot_next_index.js +1 -1
  21. package/esm/server/commands/match_image_snapshot.js +1 -1
  22. package/esm/server/commands/prepare_image_snapshot_comparison.d.ts +18 -0
  23. package/esm/server/commands/prepare_image_snapshot_comparison.d.ts.map +1 -1
  24. package/esm/server/commands/prepare_image_snapshot_comparison.js +8 -6
  25. package/esm/server/snapshot_path.js +2 -2
  26. package/esm/server/vis_context.d.ts +13 -12
  27. package/esm/server/vis_context.d.ts.map +1 -1
  28. package/esm/server/vis_context.logic.d.ts +16 -15
  29. package/esm/server/vis_context.logic.d.ts.map +1 -1
  30. package/esm/server/vis_context.logic.js +51 -42
  31. package/esm/server/vis_context.types.d.ts +16 -6
  32. package/esm/server/vis_context.types.d.ts.map +1 -1
  33. package/esm/testing/stubBrowserCommandContext.d.ts.map +1 -1
  34. package/esm/testing/stubBrowserCommandContext.js +7 -0
  35. package/package.json +2 -1
  36. package/src/client/image_snapshot_matcher.ts +6 -6
  37. package/src/client/snapshot_options.ts +1 -1
  38. package/src/commands.ts +1 -2
  39. package/src/config/types.ts +3 -3
  40. package/src/config/vis.ts +5 -3
  41. package/src/server/commands/browser_command_context.ts +9 -0
  42. package/src/server/commands/extend.ts +0 -3
  43. package/src/server/commands/has_image_snapshot.ts +1 -1
  44. package/src/server/commands/image_snapshot_next_index.ts +1 -1
  45. package/src/server/commands/match_image_snapshot.ts +1 -1
  46. package/src/server/commands/prepare_image_snapshot_comparison.ts +26 -7
  47. package/src/server/snapshot_path.ts +2 -2
  48. package/src/server/vis_context.logic.ts +94 -45
  49. package/src/server/vis_context.types.ts +18 -7
  50. package/src/testing/stubBrowserCommandContext.ts +7 -0
  51. package/esm/server/commands/write_image_snapshot.d.ts +0 -12
  52. package/esm/server/commands/write_image_snapshot.d.ts.map +0 -1
  53. package/esm/server/commands/write_image_snapshot.js +0 -9
  54. package/src/server/commands/write_image_snapshot.ts +0 -26
@@ -1,5 +1,8 @@
1
1
  export type VisState = {
2
- projectPath: string;
2
+ [projectPath: string]: Promise<VisProjectState>;
3
+ };
4
+ export type VisProjectState = {
5
+ projectRoot: string;
3
6
  testTimeout: number;
4
7
  hookTimeout: number;
5
8
  snapshotRootDir: string;
@@ -27,14 +30,21 @@ export type PartialBrowserCommandContext = {
27
30
  testTimeout: number;
28
31
  hookTimeout: number;
29
32
  };
33
+ vite: {
34
+ config: {
35
+ test?: {
36
+ name?: string | undefined;
37
+ };
38
+ };
39
+ };
30
40
  };
31
41
  provider: {
32
42
  name: string;
33
- browserName: string;
34
- options: {
35
- headless: boolean | undefined;
36
- screenshotFailures: boolean | undefined;
37
- screenshotDirectory: string | undefined;
43
+ browserName?: string | undefined;
44
+ options?: {
45
+ headless?: boolean | undefined;
46
+ screenshotFailures?: boolean | undefined;
47
+ screenshotDirectory?: string | undefined;
38
48
  };
39
49
  };
40
50
  testPath: string;
@@ -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;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"}
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,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAC/C,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,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;AAED,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;QACD,IAAI,EAAE;YACL,MAAM,EAAE;gBACP,IAAI,CAAC,EAAE;oBACN,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;iBACzB,CAAA;aACD,CAAA;SACD,CAAA;KACD,CAAA;IACD,QAAQ,EAAE;QACT,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAChC,OAAO,CAAC,EAAE;YACT,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;YAC9B,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;YACxC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SACxC,CAAA;KACD,CAAA;IACD,QAAQ,EAAE,MAAM,CAAA;CAChB,CAAA"}
@@ -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;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
+ {"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,2HAmB5G"}
@@ -6,6 +6,13 @@ export function createStubPartialBrowserCommandContext({ root, testPath }) {
6
6
  config: {
7
7
  root,
8
8
  },
9
+ vite: {
10
+ config: {
11
+ test: {
12
+ name: 'subject',
13
+ },
14
+ },
15
+ },
9
16
  },
10
17
  provider: {
11
18
  options: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitest-plugin-vis",
3
- "version": "2.3.2",
3
+ "version": "2.4.0",
4
4
  "description": "Vitest visual testing plugin",
5
5
  "keywords": [
6
6
  "image-snapshot",
@@ -107,6 +107,7 @@
107
107
  "build": "tsc",
108
108
  "build:watch": "tsc -w",
109
109
  "clean": "rimraf coverage esm *.tsbuildinfo vitest.*.timestamp*",
110
+ "clean:vis:local": "rimraf __vis__/local",
110
111
  "cov": "cross-env COVERAGE=true vitest run --coverage",
111
112
  "coverage": "cross-env COVERAGE=true vitest run --coverage",
112
113
  "dev": "run-p build:watch w",
@@ -1,8 +1,8 @@
1
+ import type { BrowserCommands } from '@vitest/browser/context'
1
2
  import dedent from 'dedent'
2
3
  import { resolve } from 'pathe'
3
4
  import type { ImageSnapshotNextIndexCommand } from '../commands.ts'
4
5
  import type { PrepareImageSnapshotComparisonCommand } from '../server/commands/prepare_image_snapshot_comparison.ts'
5
- import type { WriteImageSnapshotCommand } from '../server/commands/write_image_snapshot.ts'
6
6
  import { isBase64String } from '../shared/base64.ts'
7
7
  import { compareImage } from '../shared/compare_image.ts'
8
8
  import type { ToMatchImageSnapshotOptions } from '../shared/types.ts'
@@ -15,7 +15,7 @@ import { server } from './vitest_browser_context_proxy.ts'
15
15
  import type { CurrentTest } from './vitest_suite_proxy.ts'
16
16
 
17
17
  export function imageSnapshotMatcher(
18
- commands: PrepareImageSnapshotComparisonCommand & WriteImageSnapshotCommand & ImageSnapshotNextIndexCommand,
18
+ commands: BrowserCommands & PrepareImageSnapshotComparisonCommand & ImageSnapshotNextIndexCommand,
19
19
  ) {
20
20
  return async function matchImageSnapshot(
21
21
  test: CurrentTest & {},
@@ -65,11 +65,11 @@ export function imageSnapshotMatcher(
65
65
  return
66
66
  }
67
67
  if (server.config.snapshotOptions.updateSnapshot === 'all' && !options?.expectToFail) {
68
- await writeSnapshot(commands, info.baselinePath, resultImage)
68
+ await writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage)
69
69
  return
70
70
  }
71
71
 
72
- await writeSnapshot(commands, info.diffPath, diffImage)
72
+ await writeSnapshot(commands, resolve(info.projectRoot, info.diffPath), diffImage)
73
73
 
74
74
  throw new Error(
75
75
  dedent`Snapshot \`${taskId}\` mismatched
@@ -103,9 +103,9 @@ export function parseImageSnapshotSubject(subject: any) {
103
103
  )
104
104
  }
105
105
 
106
- async function writeSnapshot(commands: WriteImageSnapshotCommand, path: string, image: ImageData) {
106
+ async function writeSnapshot(commands: BrowserCommands, path: string, image: ImageData) {
107
107
  const content = (await toDataURL(image)).split(',')[1]!
108
- return commands.writeImageSnapshot(path, content)
108
+ return commands.writeFile(path, content, { encoding: 'base64' })
109
109
  }
110
110
 
111
111
  async function parseImageSnapshotOptions(
@@ -51,7 +51,7 @@ function parseArgs<M extends ComparisonMethod>(
51
51
  args: [task: MetaTask, meta: SnapshotMeta<M> | boolean] | [meta: boolean | SnapshotMeta<M>],
52
52
  ): [MetaTask | undefined, SnapshotMeta<M>] {
53
53
  return args.length === 1
54
- ? [ctx.getCurrentTest() ?? (ctx.getCurrentSuite().tasks?.[0] as any)?.file, parseMeta(args[0])]
54
+ ? [ctx.getCurrentTest() ?? (ctx.getCurrentSuite()?.tasks?.[0] as any)?.file, parseMeta(args[0])]
55
55
  : [args[0], parseMeta(args[1])]
56
56
  }
57
57
 
package/src/commands.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from './server/commands/has_image_snapshot.ts'
2
2
  export * from './server/commands/image_snapshot_next_index.ts'
3
3
  export * from './server/commands/match_image_snapshot.ts'
4
- export * from './server/commands/setup_vis_suite.ts'
5
4
  export * from './server/commands/prepare_image_snapshot_comparison.ts'
6
- export * from './server/commands/write_image_snapshot.ts'
5
+ export * from './server/commands/setup_vis_suite.ts'
@@ -35,11 +35,11 @@ export type VisOptions<M extends ComparisonMethod = 'pixel'> = ImageSnapshotTime
35
35
  | string
36
36
  | ((context: {
37
37
  ci: boolean
38
- browserName: string
38
+ browserName?: string | undefined
39
39
  providerName: string
40
40
  platform: string
41
- screenshotFailures: boolean | undefined
42
- screenshotDirectory: string | undefined
41
+ screenshotFailures?: boolean | undefined
42
+ screenshotDirectory?: string | undefined
43
43
  }) => string)
44
44
  | undefined
45
45
  /**
package/src/config/vis.ts CHANGED
@@ -12,11 +12,13 @@ import type { VisOptions } from './types.ts'
12
12
  * which enables the `auto` preset.
13
13
  */
14
14
  export function vis<M extends ComparisonMethod = 'pixel'>(options: VisOptions<M> = { preset: 'auto' } as any) {
15
- visContext.setOptions(options)
16
- const preset = options?.preset
17
15
  return {
18
16
  name: NAME,
19
- config() {
17
+ config(userConfig) {
18
+ const projectName = userConfig?.test?.name
19
+
20
+ visContext.setOptions(projectName, options)
21
+ const preset = options?.preset
20
22
  return {
21
23
  test: {
22
24
  browser: {
@@ -0,0 +1,9 @@
1
+ import type { BrowserCommandContext } from 'vitest/node'
2
+
3
+ export function getProjectName(context: { project: { vite: { config: { test?: { name?: string | undefined } } } } }) {
4
+ return context.project.vite.config.test?.name
5
+ }
6
+
7
+ export function getBrowserInstanceProjectName(context: BrowserCommandContext) {
8
+ return context.project.config
9
+ }
@@ -6,7 +6,6 @@ import {
6
6
  prepareImageSnapshotComparison,
7
7
  } from './prepare_image_snapshot_comparison.ts'
8
8
  import { type SetupVisSuiteCommand, setupVisSuite } from './setup_vis_suite.ts'
9
- import { type WriteImageSnapshotCommand, writeImageSnapshot } from './write_image_snapshot.ts'
10
9
 
11
10
  declare module '@vitest/browser/context' {
12
11
  interface BrowserCommands
@@ -14,7 +13,6 @@ declare module '@vitest/browser/context' {
14
13
  ImageSnapshotNextIndexCommand,
15
14
  HasImageSnapshotCommand,
16
15
  PrepareImageSnapshotComparisonCommand,
17
- WriteImageSnapshotCommand,
18
16
  MatchImageSnapshotCommand {}
19
17
  }
20
18
 
@@ -24,5 +22,4 @@ export const commands = {
24
22
  hasImageSnapshot,
25
23
  matchImageSnapshot,
26
24
  prepareImageSnapshotComparison,
27
- writeImageSnapshot,
28
25
  }
@@ -11,5 +11,5 @@ export const hasImageSnapshot: BrowserCommand<
11
11
  > = async (context, taskId, snapshotId, isAutoSnapshot) => {
12
12
  assertTestPathDefined(context, 'hasImageSnapshot')
13
13
 
14
- return visContext.hasImageSnapshot(context.testPath, taskId, snapshotId, isAutoSnapshot)
14
+ return visContext.hasImageSnapshot(context as any, taskId, snapshotId, isAutoSnapshot)
15
15
  }
@@ -12,5 +12,5 @@ export interface ImageSnapshotNextIndexCommand {
12
12
  export const imageSnapshotNextIndex: BrowserCommand<[taskId: string]> = async (context, taskId) => {
13
13
  assertTestPathDefined(context, 'imageSnapshotNextIndex')
14
14
 
15
- return visContext.getTaskCount(context.testPath, taskId)
15
+ return visContext.getTaskCount(context, taskId)
16
16
  }
@@ -43,7 +43,7 @@ export const matchImageSnapshot: BrowserCommand<
43
43
  if (!options) options = {}
44
44
  options.timeout = options.timeout ?? 30000
45
45
 
46
- const info = visContext.getSnapshotInfo(context.testPath, taskId, isAutoSnapshot, options)
46
+ const info = await visContext.getSnapshotInfo(context as any, taskId, isAutoSnapshot, options)
47
47
  const baselineBuffer = await file.tryReadFile(info.baselinePath)
48
48
  if (!baselineBuffer) {
49
49
  if (isBase64String(subject)) {
@@ -1,3 +1,4 @@
1
+ import { resolve } from 'pathe'
1
2
  import type { BrowserCommand } from 'vitest/node'
2
3
  import { isBase64String } from '../../shared/base64.ts'
3
4
  import type {
@@ -13,11 +14,29 @@ import { assertTestPathDefined } from './_assertions.ts'
13
14
  import type { MatchImageSnapshotOptions } from './match_image_snapshot.ts'
14
15
 
15
16
  type ImageSnapshotComparisonInfo = {
17
+ /**
18
+ * Path to the project root.
19
+ */
16
20
  projectRoot: string
21
+ /**
22
+ * Path to the baseline image relative to the project root.
23
+ */
17
24
  baselinePath: string
25
+ /**
26
+ * Path to the result image relative to the project root.
27
+ */
18
28
  resultPath: string
29
+ /**
30
+ * Path to the diff image relative to the project root.
31
+ */
19
32
  diffPath: string
33
+ /**
34
+ * Base64 encoded baseline image.
35
+ */
20
36
  baseline: string
37
+ /**
38
+ * Base64 encoded result image.
39
+ */
21
40
  result: string
22
41
  } & ImageSnapshotTimeoutOptions &
23
42
  FailureThresholdOptions &
@@ -36,26 +55,26 @@ export const prepareImageSnapshotComparison: BrowserCommand<
36
55
  [taskId: string, snapshotId: string, isAutoSnapshot: boolean, options?: MatchImageSnapshotOptions | undefined]
37
56
  > = async (context, taskId, subject, isAutoSnapshot, options) => {
38
57
  assertTestPathDefined(context, 'prepareImageSnapshotComparison')
39
-
40
58
  // vitest:browser passes in `null` when not defined
41
59
  if (!options) options = {}
42
60
  options.timeout = options.timeout ?? 30000
43
61
 
44
- const info = visContext.getSnapshotInfo(context.testPath, taskId, isAutoSnapshot, options)
45
- const baselineBuffer = await file.tryReadFile(info.baselinePath)
62
+ const projectRoot = context.project.config.root
63
+ const info = await visContext.getSnapshotInfo(context as any, taskId, isAutoSnapshot, options)
64
+ const baselineBuffer = await file.tryReadFile(resolve(projectRoot, info.baselinePath))
46
65
  if (!baselineBuffer) {
47
66
  if (isBase64String(subject)) {
48
- await writeSnapshot(info.baselinePath, subject)
67
+ await writeSnapshot(resolve(projectRoot, info.baselinePath), subject)
49
68
  } else {
50
- await takeSnapshotByBrowser(context, info.baselinePath, subject, options)
69
+ await takeSnapshotByBrowser(context, resolve(projectRoot, info.baselinePath), subject, options)
51
70
  }
52
71
  return
53
72
  }
54
73
 
55
- const resultBuffer = await takeSnapshot(context, info.resultPath, subject, options)
74
+ const resultBuffer = await takeSnapshot(context, resolve(projectRoot, info.resultPath), subject, options)
56
75
  return {
57
76
  ...info,
58
- projectRoot: context.project.config.root,
77
+ projectRoot,
59
78
  baseline: baselineBuffer.toString('base64'),
60
79
  result: resultBuffer.toString('base64'),
61
80
  }
@@ -13,8 +13,8 @@ export function resolveSnapshotRootDir(suite: PartialBrowserCommandContext, opti
13
13
  browserName: suite.provider.browserName,
14
14
  providerName: suite.provider.name,
15
15
  platform: process.platform,
16
- screenshotFailures: suite.provider.options.screenshotFailures,
17
- screenshotDirectory: suite.provider.options.screenshotDirectory,
16
+ screenshotFailures: suite.provider.options?.screenshotFailures,
17
+ screenshotDirectory: suite.provider.options?.screenshotDirectory,
18
18
  })
19
19
  }
20
20
 
@@ -1,29 +1,31 @@
1
- import { join, relative } from 'pathe'
1
+ import { join, relative, resolve } from 'pathe'
2
2
  import { pick } from 'type-plus'
3
3
  import type { VisOptions } from '../config/types.ts'
4
4
  import { BASELINE_DIR, DIFF_DIR, RESULT_DIR } from '../shared/constants.ts'
5
+ import { getProjectName } from './commands/browser_command_context.ts'
5
6
  import { file } from './file.ts'
6
7
  import { getSnapshotSubpath, resolveSnapshotRootDir } from './snapshot_path.ts'
7
8
  import { ctx } from './vis_context.ctx.ts'
8
- import type { PartialBrowserCommandContext, VisState } from './vis_context.types.ts'
9
+ import type { PartialBrowserCommandContext, VisProjectState, VisState } from './vis_context.types.ts'
9
10
 
10
11
  export function createVisContext() {
11
- let visOptions: VisOptions<any> = {}
12
- let state: VisState
13
- let globalStateReady: Promise<VisState>
12
+ let visOptionsRecord: Record<string, VisOptions<any>> = {}
13
+ let state: VisState = {}
14
14
 
15
15
  const context = {
16
- setOptions<M extends 'pixel' | 'ssim'>(options: VisOptions<M> = {} as any) {
17
- visOptions = options
16
+ setOptions<M extends 'pixel' | 'ssim'>(projectName: string | undefined, options: VisOptions<M> = {} as any) {
17
+ visOptionsRecord[projectName ?? '__default'] = options
18
18
  },
19
- __test__getOptions() {
20
- return visOptions
19
+ __test__getOptions(projectName: string) {
20
+ return visOptionsRecord[projectName]
21
21
  },
22
22
  __test__reset() {
23
- visOptions = undefined as any
23
+ visOptionsRecord = {}
24
+ state = {}
24
25
  },
25
- __test__getState() {
26
- return state
26
+ __test__getState(context: PartialBrowserCommandContext) {
27
+ const projectRoot = getProjectRoot(context)
28
+ return state[projectRoot]!
27
29
  },
28
30
  /**
29
31
  * Setup suite is called on each test file's beforeAll hook.
@@ -31,26 +33,33 @@ export function createVisContext() {
31
33
  * It needs to make sure there is no race condition between the test files.
32
34
  */
33
35
  async setupSuite(context: PartialBrowserCommandContext) {
34
- if (!globalStateReady) {
35
- globalStateReady = setupState(context, visOptions)
36
- state = await globalStateReady
37
- } else {
38
- await globalStateReady
36
+ const projectRoot = getProjectRoot(context)
37
+
38
+ if (!state[projectRoot]) {
39
+ state[projectRoot] = setupState(context, getVisOptions(visOptionsRecord, context) ?? {})
39
40
  }
40
41
 
41
- const { suiteId, suite } = createSuite(state, context.testPath, visOptions)
42
- state.suites[suiteId] = suite
42
+ const projectState = await state[projectRoot]
43
+
44
+ const { suiteId, suite } = createSuite(projectState, context.testPath, visOptionsRecord)
45
+ projectState.suites[suiteId] = suite
46
+
43
47
  await Promise.allSettled([ctx.rimraf(suite.diffDir), ctx.rimraf(suite.resultDir)])
44
- return pick(state, 'subjectDataTestId')
48
+ return pick(projectState, 'subjectDataTestId')
45
49
  },
46
- getSnapshotInfo(
47
- testPath: string,
50
+ async getSnapshotInfo(
51
+ browserContext: PartialBrowserCommandContext,
48
52
  name: string,
49
53
  isAutoSnapshot: boolean,
50
54
  options?: { snapshotFileId?: string | undefined },
51
55
  ) {
52
- const suiteInfo = context.getSuiteInfo(testPath, name)
53
- const snapshotFilename = context.getSnapshotFilename(suiteInfo, options?.snapshotFileId, isAutoSnapshot)
56
+ const suiteInfo = await context.getSuiteInfo(browserContext, name)
57
+ const snapshotFilename = context.getSnapshotFilename(
58
+ browserContext,
59
+ suiteInfo,
60
+ options?.snapshotFileId,
61
+ isAutoSnapshot,
62
+ )
54
63
 
55
64
  const { baselineDir, resultDir, diffDir, task } = suiteInfo
56
65
 
@@ -60,38 +69,62 @@ export function createVisContext() {
60
69
  const diffPath = join(diffDir, snapshotFilename)
61
70
 
62
71
  return {
63
- ...pick(visOptions, 'comparisonMethod', 'diffOptions', 'failureThreshold', 'failureThresholdType', 'timeout'),
72
+ ...pick(
73
+ getVisOptions(visOptionsRecord, browserContext),
74
+ 'comparisonMethod',
75
+ 'diffOptions',
76
+ 'failureThreshold',
77
+ 'failureThresholdType',
78
+ 'timeout',
79
+ ),
64
80
  baselinePath,
65
81
  resultPath,
66
82
  diffPath,
67
83
  }
68
84
  },
69
- getTaskCount(testPath: string, taskId: string) {
70
- return context.getSuiteInfo(testPath, taskId).task.count
85
+ async getTaskCount(browserContext: PartialBrowserCommandContext, taskId: string) {
86
+ return (await context.getSuiteInfo(browserContext, taskId)).task.count
71
87
  },
72
- hasImageSnapshot(testPath: string, taskId: string, snapshotFileId: string | undefined, isAutoSnapshot: boolean) {
73
- const info = context.getSuiteInfo(testPath, taskId)
74
- return file.existFile(join(info.baselineDir, context.getSnapshotFilename(info, snapshotFileId, isAutoSnapshot)))
88
+ async hasImageSnapshot(
89
+ browserContext: PartialBrowserCommandContext,
90
+ taskId: string,
91
+ snapshotFileId: string | undefined,
92
+ isAutoSnapshot: boolean,
93
+ ) {
94
+ const info = await context.getSuiteInfo(browserContext, taskId)
95
+
96
+ return file.existFile(
97
+ resolve(
98
+ info.projectRoot,
99
+ info.baselineDir,
100
+ context.getSnapshotFilename(browserContext, info, snapshotFileId, isAutoSnapshot),
101
+ ),
102
+ )
75
103
  },
76
104
  getSnapshotFilename(
105
+ browserContext: PartialBrowserCommandContext,
77
106
  info: { taskId: string; task: { count: number } },
78
-
79
107
  snapshotFileId: string | undefined,
80
108
  isAutoSnapshot: boolean,
81
109
  ) {
82
110
  if (snapshotFileId) return `${snapshotFileId}.png`
83
- const customizeSnapshotId = visOptions.customizeSnapshotId ?? (({ id, index }) => `${id}-${index}`)
111
+ const customizeSnapshotId =
112
+ getVisOptions(visOptionsRecord, browserContext).customizeSnapshotId ?? (({ id, index }) => `${id}-${index}`)
84
113
  return `${customizeSnapshotId({
85
114
  id: info.taskId,
86
115
  index: info.task.count,
87
116
  isAutoSnapshot,
88
117
  })}.png`
89
118
  },
90
- getSuiteInfo(testPath: string, taskId: string) {
91
- const suiteId = getSuiteId(state, testPath, visOptions)
92
- const suite = state.suites[suiteId]!
119
+ async getSuiteInfo(browserContext: PartialBrowserCommandContext, taskId: string) {
120
+ const projectRoot = getProjectRoot(browserContext)
121
+ const projectState = await state[projectRoot]!
122
+
123
+ const suiteId = getSuiteId(projectState, browserContext.testPath, visOptionsRecord)
124
+ const suite = projectState.suites[suiteId]!
93
125
  const task = (suite.tasks[taskId] = suite.tasks[taskId] ?? { count: 1 })
94
126
  return {
127
+ projectRoot,
95
128
  suiteId,
96
129
  taskId,
97
130
  baselineDir: suite.baselineDir,
@@ -105,21 +138,21 @@ export function createVisContext() {
105
138
  }
106
139
 
107
140
  async function setupState(
108
- suite: PartialBrowserCommandContext,
141
+ browserContext: PartialBrowserCommandContext,
109
142
  visOptions: Pick<VisOptions, 'snapshotRootDir' | 'platform' | 'subjectDataTestId'>,
110
143
  ) {
111
- const snapshotRootDir = resolveSnapshotRootDir(suite, visOptions)
112
- const projectPath = suite.project.config.root
144
+ const snapshotRootDir = resolveSnapshotRootDir(browserContext, visOptions)
145
+ const projectRoot = getProjectRoot(browserContext)
113
146
 
114
147
  const state = {
115
- projectPath,
116
- testTimeout: suite.project.config.testTimeout,
117
- hookTimeout: suite.project.config.hookTimeout,
148
+ projectRoot,
149
+ testTimeout: browserContext.project.config.testTimeout,
150
+ hookTimeout: browserContext.project.config.hookTimeout,
118
151
  snapshotRootDir,
119
152
  snapshotBaselineDir: join(snapshotRootDir, BASELINE_DIR),
120
153
  snapshotResultDir: join(snapshotRootDir, RESULT_DIR),
121
154
  snapshotDiffDir: join(snapshotRootDir, DIFF_DIR),
122
- snapshotRootPath: join(projectPath, snapshotRootDir),
155
+ snapshotRootPath: join(projectRoot, snapshotRootDir),
123
156
  subjectDataTestId: visOptions.subjectDataTestId,
124
157
  suites: {},
125
158
  }
@@ -127,7 +160,11 @@ async function setupState(
127
160
  return state
128
161
  }
129
162
 
130
- export function createSuite(state: VisState, testPath: string, options: Pick<VisOptions, 'customizeSnapshotSubpath'>) {
163
+ export function createSuite(
164
+ state: VisProjectState,
165
+ testPath: string,
166
+ options: Pick<VisOptions, 'customizeSnapshotSubpath'>,
167
+ ) {
131
168
  const suiteId = getSuiteId(state, testPath, options)
132
169
  return {
133
170
  suiteId,
@@ -140,6 +177,18 @@ export function createSuite(state: VisState, testPath: string, options: Pick<Vis
140
177
  }
141
178
  }
142
179
 
143
- export function getSuiteId(state: VisState, testPath: string, options: Pick<VisOptions, 'customizeSnapshotSubpath'>) {
144
- return getSnapshotSubpath(relative(state.projectPath, testPath), options)
180
+ export function getSuiteId(
181
+ state: VisProjectState,
182
+ testPath: string,
183
+ options: Pick<VisOptions, 'customizeSnapshotSubpath'>,
184
+ ) {
185
+ return getSnapshotSubpath(relative(state.projectRoot, testPath), options)
186
+ }
187
+
188
+ function getVisOptions(visOptionsRecord: Record<string, VisOptions<any>>, context: PartialBrowserCommandContext) {
189
+ return visOptionsRecord[getProjectName(context) ?? '__default']!
190
+ }
191
+
192
+ function getProjectRoot(context: PartialBrowserCommandContext) {
193
+ return context.project.config.root
145
194
  }
@@ -1,6 +1,9 @@
1
1
  export type VisState = {
2
- projectPath: string
3
- // platform: string
2
+ [projectPath: string]: Promise<VisProjectState>
3
+ }
4
+
5
+ export type VisProjectState = {
6
+ projectRoot: string
4
7
  testTimeout: number
5
8
  hookTimeout: number
6
9
  snapshotRootDir: string
@@ -24,6 +27,7 @@ export type VisState = {
24
27
  }
25
28
  >
26
29
  }
30
+
27
31
  export type PartialBrowserCommandContext = {
28
32
  project: {
29
33
  config: {
@@ -34,14 +38,21 @@ export type PartialBrowserCommandContext = {
34
38
  testTimeout: number
35
39
  hookTimeout: number
36
40
  }
41
+ vite: {
42
+ config: {
43
+ test?: {
44
+ name?: string | undefined
45
+ }
46
+ }
47
+ }
37
48
  }
38
49
  provider: {
39
50
  name: string
40
- browserName: string
41
- options: {
42
- headless: boolean | undefined
43
- screenshotFailures: boolean | undefined
44
- screenshotDirectory: string | undefined
51
+ browserName?: string | undefined
52
+ options?: {
53
+ headless?: boolean | undefined
54
+ screenshotFailures?: boolean | undefined
55
+ screenshotDirectory?: string | undefined
45
56
  }
46
57
  }
47
58
  testPath: string
@@ -10,6 +10,13 @@ export function createStubPartialBrowserCommandContext({ root, testPath }: { roo
10
10
  config: {
11
11
  root,
12
12
  },
13
+ vite: {
14
+ config: {
15
+ test: {
16
+ name: 'subject',
17
+ },
18
+ },
19
+ },
13
20
  },
14
21
  provider: {
15
22
  options: {},
@@ -1,12 +0,0 @@
1
- import type { BrowserCommand } from 'vitest/node';
2
- export interface WriteImageSnapshotCommand {
3
- /**
4
- * Writes the image snapshot to the file system.
5
- * @param relativeFilePath The file path to write the image snapshot to.
6
- * It is relative to the project root.
7
- * @param imageBase64 The base64 encoded image.
8
- */
9
- writeImageSnapshot(relativeFilePath: string, imageBase64: string): Promise<void>;
10
- }
11
- export declare const writeImageSnapshot: BrowserCommand<[relativeFilePath: string, imageBase64: string]>;
12
- //# sourceMappingURL=write_image_snapshot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"write_image_snapshot.d.ts","sourceRoot":"","sources":["../../../src/server/commands/write_image_snapshot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAIjD,MAAM,WAAW,yBAAyB;IACzC;;;;;OAKG;IACH,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAChF;AAED,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,CAAC,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAS9F,CAAA"}
@@ -1,9 +0,0 @@
1
- import { mkdirp } from 'mkdirp';
2
- import { dirname, isAbsolute } from 'pathe';
3
- import { file } from "../file.js";
4
- import { assertIsRelativePath } from "./_assertions.js";
5
- export const writeImageSnapshot = async (_, relativeFilePath, imageBase64) => {
6
- assertIsRelativePath(relativeFilePath, 'relativeFilePath');
7
- await mkdirp(dirname(relativeFilePath));
8
- await file.writeFile(relativeFilePath, imageBase64, { encoding: 'base64' });
9
- };