nuxt-spec 0.2.4-alpha.2 → 0.2.4-alpha.4

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.
@@ -1,104 +1,104 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { resolve } from 'node:path'
3
- import { decode } from 'fast-png'
4
- import { expect } from 'vitest'
5
- import { appendToReport, ensureReportCreated, resolveWithin, screenshotSetup, toRGBA } from './screenshot/report-utils'
6
- import pixelmatch from 'pixelmatch'
7
- import type { NuxtPage } from '@nuxt/test-utils'
8
-
9
- export interface CompareScreenshotOptions {
10
- /** Name of the PNG file used for baseline storage and comparison (defaults to route and `index.png` for `/`) */
11
- fileName?: string
12
- /** Directory for baseline/current screenshots, relative to project root (defaults to `test/e2e`) */
13
- targetDir?: string
14
- /** CSS selector for a specific element to capture (defaults to full page) */
15
- selector?: string
16
- /** Max ratio of different pixels (0–1). Default: 0 (exact match) */
17
- maxDiffPixelRatio?: number
18
- /** Max absolute number of different pixels. Takes precedence over `maxDiffPixelRatio` when set. Default: 0 (exact match) */
19
- maxDiffPixels?: number
20
- /** Per-pixel color distance threshold (0–1). Lower = stricter. Default: 0.1 */
21
- threshold?: number
22
- }
23
-
24
- // capture a browser screenshot and compare it against a stored baseline PNG
25
- export async function compareScreenshot(page: NuxtPage, options?: CompareScreenshotOptions): Promise<boolean> {
26
- const root = process.cwd()
27
-
28
- // ensure the target directory stays within the project root
29
- const dir = resolveWithin(root, options?.targetDir ?? 'test/e2e')
30
-
31
- // create report file on first call
32
- ensureReportCreated(dir)
33
-
34
- const baselineDir = resolve(dir, '__baseline__')
35
- const currentDir = resolve(dir, '__current__')
36
-
37
- const route = page.url().substring(page.url().lastIndexOf('/') + 1) || 'index'
38
- const fileName = options?.fileName ?? `${route}.png`
39
-
40
- // warning on custom non-png file extensions
41
- if (!fileName.toLowerCase().endsWith('.png')) {
42
- console.warn(`Screenshots from \`compareScreenshot\` are always saved as PNG. Consider different file name than '${fileName}'.`)
43
- }
44
-
45
- // ensure the file name cannot escape its target directory
46
- const baselinePath = resolveWithin(baselineDir, fileName)
47
- const currentPath = resolveWithin(currentDir, fileName)
48
-
49
- // capture element specified by locator or a full-page screenshot as PNG
50
- const screenshot = options?.selector
51
- ? await page.locator(options.selector).screenshot()
52
- : await page.screenshot({ fullPage: true })
53
-
54
- // always save the current screenshot for inspection
55
- mkdirSync(currentDir, { recursive: true })
56
- writeFileSync(currentPath, screenshot)
57
-
58
- // @ts-expect-error - this is reliable way of reading Vitest "update" flag
59
- const updating = expect.getState().snapshotState?._updateSnapshot === 'all'
60
- if (updating || !existsSync(baselinePath)) {
61
- // save new baseline screenshot
62
- mkdirSync(baselineDir, { recursive: true })
63
- writeFileSync(baselinePath, screenshot)
64
- return true
65
- }
66
-
67
- // compare against stored baseline PNG using pixelmatch
68
- const baseline = readFileSync(baselinePath)
69
- const baselineImg = decode(baseline)
70
- const actualImg = decode(screenshot)
71
- const { width, height } = baselineImg
72
-
73
- if (actualImg.width !== width || actualImg.height !== height) {
74
- const message = `Screenshot size mismatch: expected ${width}x${height}, got ${actualImg.width}x${actualImg.height}. Actual saved to: ${currentPath}`
75
- appendToReport(fileName, message, baseline, screenshot)
76
- expect.fail(message)
77
- }
78
-
79
- const diffCount = pixelmatch(toRGBA(baselineImg), toRGBA(actualImg), undefined, width, height, {
80
- threshold: options?.threshold ?? 0.1,
81
- })
82
-
83
- const totalPixels = width * height
84
- const maxAllowed = options?.maxDiffPixels ?? Math.ceil(totalPixels * (options?.maxDiffPixelRatio ?? 0))
85
-
86
- if (diffCount > maxAllowed) {
87
- const ratio = (diffCount / totalPixels * 100).toFixed(2)
88
- const message = `Screenshot mismatch: ${diffCount} pixels differ (${ratio}%), allowed ${maxAllowed}. Actual saved to: ${currentPath}`
89
- appendToReport(fileName, message, baseline, screenshot)
90
- expect.fail(message)
91
- }
92
-
93
- return true
94
- }
95
-
96
- // Vitest globalSetup entry point
97
- // - computes stable timestamp values and exposes them via env variables
98
- // - the report file itself is created lazily on first compareScreenshot call
99
- // - provides a callback to close the HTML report once tests are finished (if it was created)
100
- export default function setup() {
101
- // the function itself is defined in the helper file
102
- // to avoid imports here and there
103
- return screenshotSetup()
104
- }
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+ import { decode } from 'fast-png'
4
+ import { expect } from 'vitest'
5
+ import { appendToReport, ensureReportCreated, resolveWithin, screenshotSetup, toRGBA } from './screenshot/report-utils'
6
+ import pixelmatch from 'pixelmatch'
7
+ import type { NuxtPage } from '@nuxt/test-utils'
8
+
9
+ export interface CompareScreenshotOptions {
10
+ /** Name of the PNG file used for baseline storage and comparison (defaults to route and `index.png` for `/`) */
11
+ fileName?: string
12
+ /** Directory for baseline/current screenshots, relative to project root (defaults to `test/e2e`) */
13
+ targetDir?: string
14
+ /** CSS selector for a specific element to capture (defaults to full page) */
15
+ selector?: string
16
+ /** Max ratio of different pixels (0–1). Default: 0 (exact match) */
17
+ maxDiffPixelRatio?: number
18
+ /** Max absolute number of different pixels. Takes precedence over `maxDiffPixelRatio` when set. Default: 0 (exact match) */
19
+ maxDiffPixels?: number
20
+ /** Per-pixel color distance threshold (0–1). Lower = stricter. Default: 0.1 */
21
+ threshold?: number
22
+ }
23
+
24
+ // capture a browser screenshot and compare it against a stored baseline PNG
25
+ export async function compareScreenshot(page: NuxtPage, options?: CompareScreenshotOptions): Promise<boolean> {
26
+ const root = process.cwd()
27
+
28
+ // ensure the target directory stays within the project root
29
+ const dir = resolveWithin(root, options?.targetDir ?? 'test/e2e')
30
+
31
+ // create report file on first call
32
+ ensureReportCreated(dir)
33
+
34
+ const baselineDir = resolve(dir, '__baseline__')
35
+ const currentDir = resolve(dir, '__current__')
36
+
37
+ const route = page.url().substring(page.url().lastIndexOf('/') + 1) || 'index'
38
+ const fileName = options?.fileName ?? `${route}.png`
39
+
40
+ // warning on custom non-png file extensions
41
+ if (!fileName.toLowerCase().endsWith('.png')) {
42
+ console.warn(`Screenshots from \`compareScreenshot\` are always saved as PNG. Consider different file name than '${fileName}'.`)
43
+ }
44
+
45
+ // ensure the file name cannot escape its target directory
46
+ const baselinePath = resolveWithin(baselineDir, fileName)
47
+ const currentPath = resolveWithin(currentDir, fileName)
48
+
49
+ // capture element specified by locator or a full-page screenshot as PNG
50
+ const screenshot = options?.selector
51
+ ? await page.locator(options.selector).screenshot()
52
+ : await page.screenshot({ fullPage: true })
53
+
54
+ // always save the current screenshot for inspection
55
+ mkdirSync(currentDir, { recursive: true })
56
+ writeFileSync(currentPath, screenshot)
57
+
58
+ // @ts-expect-error - this is reliable way of reading Vitest "update" flag
59
+ const updating = expect.getState().snapshotState?._updateSnapshot === 'all'
60
+ if (updating || !existsSync(baselinePath)) {
61
+ // save new baseline screenshot
62
+ mkdirSync(baselineDir, { recursive: true })
63
+ writeFileSync(baselinePath, screenshot)
64
+ return true
65
+ }
66
+
67
+ // compare against stored baseline PNG using pixelmatch
68
+ const baseline = readFileSync(baselinePath)
69
+ const baselineImg = decode(baseline)
70
+ const actualImg = decode(screenshot)
71
+ const { width, height } = baselineImg
72
+
73
+ if (actualImg.width !== width || actualImg.height !== height) {
74
+ const message = `Screenshot size mismatch: expected ${width}x${height}, got ${actualImg.width}x${actualImg.height}. Actual saved to: ${currentPath}`
75
+ appendToReport(fileName, message, baseline, screenshot)
76
+ expect.fail(message)
77
+ }
78
+
79
+ const diffCount = pixelmatch(toRGBA(baselineImg), toRGBA(actualImg), undefined, width, height, {
80
+ threshold: options?.threshold ?? 0.1,
81
+ })
82
+
83
+ const totalPixels = width * height
84
+ const maxAllowed = options?.maxDiffPixels ?? Math.ceil(totalPixels * (options?.maxDiffPixelRatio ?? 0))
85
+
86
+ if (diffCount > maxAllowed) {
87
+ const ratio = (diffCount / totalPixels * 100).toFixed(2)
88
+ const message = `Screenshot mismatch: ${diffCount} pixels differ (${ratio}%), allowed ${maxAllowed}. Actual saved to: ${currentPath}`
89
+ appendToReport(fileName, message, baseline, screenshot)
90
+ expect.fail(message)
91
+ }
92
+
93
+ return true
94
+ }
95
+
96
+ // Vitest globalSetup entry point
97
+ // - computes stable timestamp values and exposes them via env variables
98
+ // - the report file itself is created lazily on first compareScreenshot call
99
+ // - provides a callback to close the HTML report once tests are finished (if it was created)
100
+ export default function setup() {
101
+ // the function itself is defined in the helper file
102
+ // to avoid imports here and there
103
+ return screenshotSetup()
104
+ }