@vizzly-testing/cli 0.20.0 → 0.20.1-beta.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.
- package/dist/api/client.js +134 -0
- package/dist/api/core.js +341 -0
- package/dist/api/endpoints.js +314 -0
- package/dist/api/index.js +19 -0
- package/dist/auth/client.js +91 -0
- package/dist/auth/core.js +176 -0
- package/dist/auth/index.js +30 -0
- package/dist/auth/operations.js +148 -0
- package/dist/cli.js +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/finalize.js +41 -15
- package/dist/commands/login.js +7 -6
- package/dist/commands/logout.js +4 -4
- package/dist/commands/project.js +5 -4
- package/dist/commands/run.js +158 -90
- package/dist/commands/status.js +22 -18
- package/dist/commands/tdd.js +105 -78
- package/dist/commands/upload.js +61 -26
- package/dist/commands/whoami.js +4 -4
- package/dist/config/core.js +438 -0
- package/dist/config/index.js +13 -0
- package/dist/config/operations.js +327 -0
- package/dist/index.js +1 -1
- package/dist/project/core.js +295 -0
- package/dist/project/index.js +13 -0
- package/dist/project/operations.js +393 -0
- package/dist/report-generator/core.js +315 -0
- package/dist/report-generator/index.js +8 -0
- package/dist/report-generator/operations.js +196 -0
- package/dist/reporter/reporter-bundle.iife.js +16 -16
- package/dist/screenshot-server/core.js +157 -0
- package/dist/screenshot-server/index.js +11 -0
- package/dist/screenshot-server/operations.js +183 -0
- package/dist/sdk/index.js +3 -2
- package/dist/server/handlers/api-handler.js +14 -5
- package/dist/server/handlers/tdd-handler.js +80 -48
- package/dist/server-manager/core.js +183 -0
- package/dist/server-manager/index.js +81 -0
- package/dist/server-manager/operations.js +208 -0
- package/dist/services/build-manager.js +2 -69
- package/dist/services/index.js +21 -48
- package/dist/services/screenshot-server.js +40 -74
- package/dist/services/server-manager.js +45 -80
- package/dist/services/static-report-generator.js +21 -163
- package/dist/services/test-runner.js +90 -250
- package/dist/services/uploader.js +56 -358
- package/dist/tdd/core/hotspot-coverage.js +112 -0
- package/dist/tdd/core/signature.js +101 -0
- package/dist/tdd/index.js +19 -0
- package/dist/tdd/metadata/baseline-metadata.js +103 -0
- package/dist/tdd/metadata/hotspot-metadata.js +93 -0
- package/dist/tdd/services/baseline-downloader.js +151 -0
- package/dist/tdd/services/baseline-manager.js +166 -0
- package/dist/tdd/services/comparison-service.js +230 -0
- package/dist/tdd/services/hotspot-service.js +71 -0
- package/dist/tdd/services/result-service.js +123 -0
- package/dist/tdd/tdd-service.js +1081 -0
- package/dist/test-runner/core.js +255 -0
- package/dist/test-runner/index.js +13 -0
- package/dist/test-runner/operations.js +483 -0
- package/dist/uploader/core.js +396 -0
- package/dist/uploader/index.js +11 -0
- package/dist/uploader/operations.js +412 -0
- package/package.json +7 -12
- package/dist/services/api-service.js +0 -412
- package/dist/services/auth-service.js +0 -226
- package/dist/services/config-service.js +0 -369
- package/dist/services/html-report-generator.js +0 -455
- package/dist/services/project-service.js +0 -326
- package/dist/services/report-generator/report.css +0 -411
- package/dist/services/report-generator/viewer.js +0 -102
- package/dist/services/tdd-service.js +0 -1437
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline Metadata I/O
|
|
3
|
+
*
|
|
4
|
+
* Functions for reading and writing baseline metadata.json files.
|
|
5
|
+
* These handle the local storage of baseline information.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Load baseline metadata from disk
|
|
13
|
+
*
|
|
14
|
+
* @param {string} baselinePath - Path to baselines directory
|
|
15
|
+
* @returns {Object|null} Baseline metadata or null if not found
|
|
16
|
+
*/
|
|
17
|
+
export function loadBaselineMetadata(baselinePath) {
|
|
18
|
+
let metadataPath = join(baselinePath, 'metadata.json');
|
|
19
|
+
if (!existsSync(metadataPath)) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
let content = readFileSync(metadataPath, 'utf8');
|
|
24
|
+
return JSON.parse(content);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// Log for debugging but return null - caller can handle missing metadata
|
|
27
|
+
console.debug?.(`Failed to parse baseline metadata: ${error.message}`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Save baseline metadata to disk
|
|
34
|
+
*
|
|
35
|
+
* @param {string} baselinePath - Path to baselines directory
|
|
36
|
+
* @param {Object} metadata - Metadata object to save
|
|
37
|
+
*/
|
|
38
|
+
export function saveBaselineMetadata(baselinePath, metadata) {
|
|
39
|
+
// Ensure directory exists
|
|
40
|
+
if (!existsSync(baselinePath)) {
|
|
41
|
+
mkdirSync(baselinePath, {
|
|
42
|
+
recursive: true
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
let metadataPath = join(baselinePath, 'metadata.json');
|
|
46
|
+
writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Create empty baseline metadata structure
|
|
51
|
+
*
|
|
52
|
+
* @param {Object} options - Options for the baseline
|
|
53
|
+
* @param {number} options.threshold - Comparison threshold
|
|
54
|
+
* @param {string[]} options.signatureProperties - Custom signature properties
|
|
55
|
+
* @returns {Object} Empty baseline metadata
|
|
56
|
+
*/
|
|
57
|
+
export function createEmptyBaselineMetadata(options = {}) {
|
|
58
|
+
return {
|
|
59
|
+
buildId: 'local-baseline',
|
|
60
|
+
buildName: 'Local TDD Baseline',
|
|
61
|
+
environment: 'test',
|
|
62
|
+
branch: 'local',
|
|
63
|
+
threshold: options.threshold ?? 2.0,
|
|
64
|
+
signatureProperties: options.signatureProperties ?? [],
|
|
65
|
+
createdAt: new Date().toISOString(),
|
|
66
|
+
screenshots: []
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Update or add a screenshot entry in the metadata
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} metadata - Baseline metadata object (mutated)
|
|
74
|
+
* @param {Object} screenshotEntry - Screenshot entry to upsert
|
|
75
|
+
* @param {string} signature - Signature to match for updates
|
|
76
|
+
* @returns {Object} The updated metadata (same reference)
|
|
77
|
+
*/
|
|
78
|
+
export function upsertScreenshotInMetadata(metadata, screenshotEntry, signature) {
|
|
79
|
+
if (!metadata.screenshots) {
|
|
80
|
+
metadata.screenshots = [];
|
|
81
|
+
}
|
|
82
|
+
let existingIndex = metadata.screenshots.findIndex(s => s.signature === signature);
|
|
83
|
+
if (existingIndex >= 0) {
|
|
84
|
+
metadata.screenshots[existingIndex] = screenshotEntry;
|
|
85
|
+
} else {
|
|
86
|
+
metadata.screenshots.push(screenshotEntry);
|
|
87
|
+
}
|
|
88
|
+
return metadata;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find a screenshot in metadata by signature
|
|
93
|
+
*
|
|
94
|
+
* @param {Object} metadata - Baseline metadata object
|
|
95
|
+
* @param {string} signature - Signature to find
|
|
96
|
+
* @returns {Object|null} Screenshot entry or null if not found
|
|
97
|
+
*/
|
|
98
|
+
export function findScreenshotBySignature(metadata, signature) {
|
|
99
|
+
if (!metadata?.screenshots) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return metadata.screenshots.find(s => s.signature === signature) || null;
|
|
103
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hotspot Metadata I/O
|
|
3
|
+
*
|
|
4
|
+
* Functions for reading and writing hotspot data files.
|
|
5
|
+
* Hotspots identify regions of screenshots that frequently change
|
|
6
|
+
* due to dynamic content (timestamps, animations, etc.).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Load hotspot data from disk
|
|
14
|
+
*
|
|
15
|
+
* @param {string} workingDir - Working directory containing .vizzly folder
|
|
16
|
+
* @returns {Object|null} Hotspot data keyed by screenshot name, or null if not found
|
|
17
|
+
*/
|
|
18
|
+
export function loadHotspotMetadata(workingDir) {
|
|
19
|
+
let hotspotsPath = join(workingDir, '.vizzly', 'hotspots.json');
|
|
20
|
+
if (!existsSync(hotspotsPath)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
let content = readFileSync(hotspotsPath, 'utf8');
|
|
25
|
+
let data = JSON.parse(content);
|
|
26
|
+
return data.hotspots || null;
|
|
27
|
+
} catch {
|
|
28
|
+
// Return null for parse/read errors
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Save hotspot data to disk
|
|
35
|
+
*
|
|
36
|
+
* @param {string} workingDir - Working directory containing .vizzly folder
|
|
37
|
+
* @param {Object} hotspotData - Hotspot data keyed by screenshot name
|
|
38
|
+
* @param {Object} summary - Summary information about the hotspots
|
|
39
|
+
*/
|
|
40
|
+
export function saveHotspotMetadata(workingDir, hotspotData, summary = {}) {
|
|
41
|
+
let vizzlyDir = join(workingDir, '.vizzly');
|
|
42
|
+
|
|
43
|
+
// Ensure directory exists
|
|
44
|
+
if (!existsSync(vizzlyDir)) {
|
|
45
|
+
mkdirSync(vizzlyDir, {
|
|
46
|
+
recursive: true
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
let hotspotsPath = join(vizzlyDir, 'hotspots.json');
|
|
50
|
+
let content = {
|
|
51
|
+
downloadedAt: new Date().toISOString(),
|
|
52
|
+
summary,
|
|
53
|
+
hotspots: hotspotData
|
|
54
|
+
};
|
|
55
|
+
writeFileSync(hotspotsPath, JSON.stringify(content, null, 2));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get hotspot for a specific screenshot with caching support
|
|
60
|
+
*
|
|
61
|
+
* This is a pure function that takes a cache object as parameter
|
|
62
|
+
* for stateless operation. The cache is mutated if data needs to be loaded.
|
|
63
|
+
*
|
|
64
|
+
* @param {Object} cache - Cache object { data: Object|null, loaded: boolean }
|
|
65
|
+
* @param {string} workingDir - Working directory
|
|
66
|
+
* @param {string} screenshotName - Name of the screenshot
|
|
67
|
+
* @returns {Object|null} Hotspot analysis or null if not available
|
|
68
|
+
*/
|
|
69
|
+
export function getHotspotForScreenshot(cache, workingDir, screenshotName) {
|
|
70
|
+
// Check cache first
|
|
71
|
+
if (cache.data?.[screenshotName]) {
|
|
72
|
+
return cache.data[screenshotName];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Load from disk if not yet loaded
|
|
76
|
+
if (!cache.loaded) {
|
|
77
|
+
cache.data = loadHotspotMetadata(workingDir);
|
|
78
|
+
cache.loaded = true;
|
|
79
|
+
}
|
|
80
|
+
return cache.data?.[screenshotName] || null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create an empty hotspot cache object
|
|
85
|
+
*
|
|
86
|
+
* @returns {{ data: null, loaded: boolean }}
|
|
87
|
+
*/
|
|
88
|
+
export function createHotspotCache() {
|
|
89
|
+
return {
|
|
90
|
+
data: null,
|
|
91
|
+
loaded: false
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline Downloader
|
|
3
|
+
*
|
|
4
|
+
* Functions for downloading baseline images from the cloud API.
|
|
5
|
+
* These are lower-level utilities - orchestration happens in TddService.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { fetchWithTimeout } from '../../utils/fetch-utils.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Download a single baseline image
|
|
13
|
+
*
|
|
14
|
+
* @param {string} url - URL to download from
|
|
15
|
+
* @param {string} destPath - Destination file path
|
|
16
|
+
* @param {Object} options - Options
|
|
17
|
+
* @param {number} options.timeout - Request timeout in ms (default: 30000)
|
|
18
|
+
* @returns {Promise<{ success: boolean, error?: string }>}
|
|
19
|
+
*/
|
|
20
|
+
export async function downloadBaselineImage(url, destPath, options = {}) {
|
|
21
|
+
let {
|
|
22
|
+
timeout = 30000
|
|
23
|
+
} = options;
|
|
24
|
+
try {
|
|
25
|
+
let response = await fetchWithTimeout(url, {
|
|
26
|
+
timeout
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: `HTTP ${response.status}: ${response.statusText}`
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
let buffer = Buffer.from(await response.arrayBuffer());
|
|
35
|
+
writeFileSync(destPath, buffer);
|
|
36
|
+
return {
|
|
37
|
+
success: true
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
error: error.message
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if a baseline already exists with matching SHA
|
|
49
|
+
*
|
|
50
|
+
* @param {string} filePath - Path to the baseline file
|
|
51
|
+
* @param {string} expectedSha - Expected SHA256 hash
|
|
52
|
+
* @param {Map<string, string>} shaMap - Map of filename -> sha256
|
|
53
|
+
* @returns {boolean}
|
|
54
|
+
*/
|
|
55
|
+
export function baselineMatchesSha(filePath, expectedSha, shaMap) {
|
|
56
|
+
if (!existsSync(filePath) || !expectedSha) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
let filename = filePath.split('/').pop();
|
|
60
|
+
let storedSha = shaMap.get(filename);
|
|
61
|
+
return storedSha === expectedSha;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Download multiple baselines in batches
|
|
66
|
+
*
|
|
67
|
+
* @param {Array} screenshots - Screenshots to download
|
|
68
|
+
* @param {Object} options - Options
|
|
69
|
+
* @param {string} options.baselinePath - Path to baselines directory
|
|
70
|
+
* @param {Map<string, string>} options.existingShaMap - Existing SHA map for skip logic
|
|
71
|
+
* @param {number} options.batchSize - Concurrent downloads (default: 5)
|
|
72
|
+
* @param {Function} options.onProgress - Progress callback (downloaded, skipped, errors, total)
|
|
73
|
+
* @param {Function} options.getFilePath - Function to get file path for a screenshot
|
|
74
|
+
* @returns {Promise<{ downloaded: number, skipped: number, errors: number }>}
|
|
75
|
+
*/
|
|
76
|
+
export async function downloadBaselinesInBatches(screenshots, options = {}) {
|
|
77
|
+
let {
|
|
78
|
+
existingShaMap = new Map(),
|
|
79
|
+
batchSize = 5,
|
|
80
|
+
onProgress,
|
|
81
|
+
getFilePath
|
|
82
|
+
} = options;
|
|
83
|
+
let downloaded = 0;
|
|
84
|
+
let skipped = 0;
|
|
85
|
+
let errors = 0;
|
|
86
|
+
let total = screenshots.length;
|
|
87
|
+
|
|
88
|
+
// Process in batches
|
|
89
|
+
for (let i = 0; i < screenshots.length; i += batchSize) {
|
|
90
|
+
let batch = screenshots.slice(i, i + batchSize);
|
|
91
|
+
let batchPromises = batch.map(async screenshot => {
|
|
92
|
+
let filePath = getFilePath(screenshot);
|
|
93
|
+
let url = screenshot.original_url;
|
|
94
|
+
if (!url) {
|
|
95
|
+
errors++;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Skip if SHA matches
|
|
100
|
+
if (baselineMatchesSha(filePath, screenshot.sha256, existingShaMap)) {
|
|
101
|
+
skipped++;
|
|
102
|
+
downloaded++;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
let result = await downloadBaselineImage(url, filePath);
|
|
106
|
+
if (result.success) {
|
|
107
|
+
downloaded++;
|
|
108
|
+
} else {
|
|
109
|
+
errors++;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
await Promise.all(batchPromises);
|
|
113
|
+
if (onProgress) {
|
|
114
|
+
onProgress(downloaded, skipped, errors, total);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
downloaded,
|
|
119
|
+
skipped,
|
|
120
|
+
errors
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Build baseline metadata entry for a downloaded screenshot
|
|
126
|
+
*
|
|
127
|
+
* @param {Object} screenshot - Screenshot data from API
|
|
128
|
+
* @param {string} filename - Local filename
|
|
129
|
+
* @param {string} filePath - Full file path
|
|
130
|
+
* @param {Object} buildInfo - Build information
|
|
131
|
+
* @returns {Object} Metadata entry
|
|
132
|
+
*/
|
|
133
|
+
export function buildBaselineMetadataEntry(screenshot, filename, filePath, buildInfo = {}) {
|
|
134
|
+
return {
|
|
135
|
+
name: screenshot.name,
|
|
136
|
+
originalName: screenshot.name,
|
|
137
|
+
sha256: screenshot.sha256,
|
|
138
|
+
id: screenshot.id,
|
|
139
|
+
filename,
|
|
140
|
+
path: filePath,
|
|
141
|
+
browser: screenshot.browser || screenshot.metadata?.browser,
|
|
142
|
+
viewport_width: screenshot.viewport_width || screenshot.metadata?.viewport?.width || screenshot.properties?.viewport?.width,
|
|
143
|
+
originalUrl: screenshot.original_url,
|
|
144
|
+
fileSize: screenshot.file_size,
|
|
145
|
+
dimensions: screenshot.dimensions,
|
|
146
|
+
// Build info for tracking
|
|
147
|
+
buildId: buildInfo.buildId,
|
|
148
|
+
commitSha: buildInfo.commitSha,
|
|
149
|
+
approvalStatus: screenshot.approval_status
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline Manager
|
|
3
|
+
*
|
|
4
|
+
* Local baseline CRUD operations - manages the file system aspects
|
|
5
|
+
* of baseline storage without any network operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Initialize TDD directory structure
|
|
13
|
+
*
|
|
14
|
+
* @param {string} workingDir - Working directory
|
|
15
|
+
* @returns {{ baselinePath: string, currentPath: string, diffPath: string }}
|
|
16
|
+
*/
|
|
17
|
+
export function initializeDirectories(workingDir) {
|
|
18
|
+
let vizzlyDir = join(workingDir, '.vizzly');
|
|
19
|
+
let baselinePath = join(vizzlyDir, 'baselines');
|
|
20
|
+
let currentPath = join(vizzlyDir, 'current');
|
|
21
|
+
let diffPath = join(vizzlyDir, 'diffs');
|
|
22
|
+
for (let dir of [baselinePath, currentPath, diffPath]) {
|
|
23
|
+
if (!existsSync(dir)) {
|
|
24
|
+
mkdirSync(dir, {
|
|
25
|
+
recursive: true
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
baselinePath,
|
|
31
|
+
currentPath,
|
|
32
|
+
diffPath
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Clear all baseline data for fresh download
|
|
38
|
+
*
|
|
39
|
+
* @param {{ baselinePath: string, currentPath: string, diffPath: string }} paths
|
|
40
|
+
*/
|
|
41
|
+
export function clearBaselineData(paths) {
|
|
42
|
+
let {
|
|
43
|
+
baselinePath,
|
|
44
|
+
currentPath,
|
|
45
|
+
diffPath
|
|
46
|
+
} = paths;
|
|
47
|
+
for (let dir of [baselinePath, currentPath, diffPath]) {
|
|
48
|
+
if (existsSync(dir)) {
|
|
49
|
+
rmSync(dir, {
|
|
50
|
+
recursive: true,
|
|
51
|
+
force: true
|
|
52
|
+
});
|
|
53
|
+
mkdirSync(dir, {
|
|
54
|
+
recursive: true
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Save an image as baseline
|
|
62
|
+
*
|
|
63
|
+
* @param {string} baselinePath - Path to baselines directory
|
|
64
|
+
* @param {string} filename - Filename for the baseline
|
|
65
|
+
* @param {Buffer} imageBuffer - Image data
|
|
66
|
+
*/
|
|
67
|
+
export function saveBaseline(baselinePath, filename, imageBuffer) {
|
|
68
|
+
let filePath = join(baselinePath, filename);
|
|
69
|
+
writeFileSync(filePath, imageBuffer);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Save current screenshot
|
|
74
|
+
*
|
|
75
|
+
* @param {string} currentPath - Path to current screenshots directory
|
|
76
|
+
* @param {string} filename - Filename for the screenshot
|
|
77
|
+
* @param {Buffer} imageBuffer - Image data
|
|
78
|
+
* @returns {string} Full path to saved file
|
|
79
|
+
*/
|
|
80
|
+
export function saveCurrent(currentPath, filename, imageBuffer) {
|
|
81
|
+
let filePath = join(currentPath, filename);
|
|
82
|
+
writeFileSync(filePath, imageBuffer);
|
|
83
|
+
return filePath;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if baseline exists for a filename
|
|
88
|
+
*
|
|
89
|
+
* @param {string} baselinePath - Path to baselines directory
|
|
90
|
+
* @param {string} filename - Filename to check
|
|
91
|
+
* @returns {boolean}
|
|
92
|
+
*/
|
|
93
|
+
export function baselineExists(baselinePath, filename) {
|
|
94
|
+
return existsSync(join(baselinePath, filename));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get full path to a baseline file
|
|
99
|
+
*
|
|
100
|
+
* @param {string} baselinePath - Path to baselines directory
|
|
101
|
+
* @param {string} filename - Filename
|
|
102
|
+
* @returns {string}
|
|
103
|
+
*/
|
|
104
|
+
export function getBaselinePath(baselinePath, filename) {
|
|
105
|
+
return join(baselinePath, filename);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get full path to a current file
|
|
110
|
+
*
|
|
111
|
+
* @param {string} currentPath - Path to current screenshots directory
|
|
112
|
+
* @param {string} filename - Filename
|
|
113
|
+
* @returns {string}
|
|
114
|
+
*/
|
|
115
|
+
export function getCurrentPath(currentPath, filename) {
|
|
116
|
+
return join(currentPath, filename);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get full path to a diff file
|
|
121
|
+
*
|
|
122
|
+
* @param {string} diffPath - Path to diffs directory
|
|
123
|
+
* @param {string} filename - Filename
|
|
124
|
+
* @returns {string}
|
|
125
|
+
*/
|
|
126
|
+
export function getDiffPath(diffPath, filename) {
|
|
127
|
+
return join(diffPath, filename);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Promote current screenshot to baseline (accept as new baseline)
|
|
132
|
+
*
|
|
133
|
+
* @param {string} currentPath - Path to current screenshots directory
|
|
134
|
+
* @param {string} baselinePath - Path to baselines directory
|
|
135
|
+
* @param {string} filename - Filename
|
|
136
|
+
*/
|
|
137
|
+
export function promoteCurrentToBaseline(currentPath, baselinePath, filename) {
|
|
138
|
+
let currentFile = join(currentPath, filename);
|
|
139
|
+
let baselineFile = join(baselinePath, filename);
|
|
140
|
+
if (!existsSync(currentFile)) {
|
|
141
|
+
throw new Error(`Current screenshot not found: ${currentFile}`);
|
|
142
|
+
}
|
|
143
|
+
copyFileSync(currentFile, baselineFile);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Read baseline image
|
|
148
|
+
*
|
|
149
|
+
* @param {string} baselinePath - Path to baselines directory
|
|
150
|
+
* @param {string} filename - Filename
|
|
151
|
+
* @returns {Buffer}
|
|
152
|
+
*/
|
|
153
|
+
export function readBaseline(baselinePath, filename) {
|
|
154
|
+
return readFileSync(join(baselinePath, filename));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Read current screenshot
|
|
159
|
+
*
|
|
160
|
+
* @param {string} currentPath - Path to current screenshots directory
|
|
161
|
+
* @param {string} filename - Filename
|
|
162
|
+
* @returns {Buffer}
|
|
163
|
+
*/
|
|
164
|
+
export function readCurrent(currentPath, filename) {
|
|
165
|
+
return readFileSync(join(currentPath, filename));
|
|
166
|
+
}
|