@vizzly-testing/cli 0.29.6 → 0.31.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/README.md +34 -6
- package/dist/api/client.js +6 -3
- package/dist/api/endpoints.js +59 -0
- package/dist/api/index.js +1 -1
- package/dist/auth/core.js +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/cli.js +206 -51
- package/dist/client/index.js +21 -29
- package/dist/commands/api.js +145 -90
- package/dist/commands/baselines.js +78 -47
- package/dist/commands/builds.js +9 -8
- package/dist/commands/comparisons.js +7 -8
- package/dist/commands/config-cmd.js +15 -7
- package/dist/commands/context.js +870 -0
- package/dist/commands/doctor.js +116 -81
- package/dist/commands/init.js +202 -201
- package/dist/commands/login.js +134 -65
- package/dist/commands/logout.js +18 -7
- package/dist/commands/preview.js +29 -57
- package/dist/commands/project.js +120 -0
- package/dist/commands/projects.js +9 -2
- package/dist/commands/review.js +236 -202
- package/dist/commands/run.js +75 -72
- package/dist/commands/status.js +228 -150
- package/dist/commands/tdd-daemon-process.js +98 -0
- package/dist/commands/tdd-daemon.js +318 -212
- package/dist/commands/tdd.js +23 -8
- package/dist/commands/upload.js +10 -9
- package/dist/commands/whoami.js +64 -26
- package/dist/config/core.js +37 -36
- package/dist/context/local-workspace-provider.js +532 -0
- package/dist/context/provider-resolver.js +36 -0
- package/dist/index.js +5 -4
- package/dist/plugin-loader.js +55 -49
- package/dist/project/core.js +2 -2
- package/dist/project/operations.js +6 -3
- package/dist/reporter/reporter-bundle.css +2 -1
- package/dist/reporter/reporter-bundle.iife.js +119 -119
- package/dist/reporter-ssr/ssr-entry.js +605 -509
- package/dist/sdk/index.js +162 -107
- package/dist/server/handlers/tdd-handler.js +30 -54
- package/dist/server/routers/assets.js +4 -0
- package/dist/server/routers/baseline.js +195 -178
- package/dist/server/routers/events.js +226 -148
- package/dist/server/routers/projects.js +14 -5
- package/dist/server/routers/screenshot.js +1 -31
- package/dist/services/build-manager.js +19 -97
- package/dist/services/config-service.js +26 -34
- package/dist/services/index.js +2 -4
- package/dist/services/static-report-generator.js +11 -12
- package/dist/services/test-runner.js +21 -27
- package/dist/tdd/core/hotspot-coverage.js +1 -1
- package/dist/tdd/index.js +1 -1
- package/dist/tdd/metadata/region-metadata.js +0 -37
- package/dist/tdd/runtime-context.js +78 -0
- package/dist/tdd/server-registry.js +38 -17
- package/dist/tdd/services/baseline-manager.js +23 -0
- package/dist/tdd/services/hotspot-service.js +1 -14
- package/dist/tdd/tdd-service.js +82 -113
- package/dist/types/client.d.ts +36 -1
- package/dist/types/index.d.ts +114 -22
- package/dist/types/sdk.d.ts +47 -7
- package/dist/uploader/core.js +5 -4
- package/dist/uploader/index.js +79 -2
- package/dist/uploader/operations.js +40 -5
- package/dist/utils/api-url.js +14 -0
- package/dist/utils/async-utils.js +26 -0
- package/dist/utils/ci-env.js +19 -12
- package/dist/utils/colors.js +46 -44
- package/dist/utils/config-loader.js +39 -65
- package/dist/utils/config-schema.js +19 -55
- package/dist/utils/fetch-utils.js +12 -5
- package/dist/utils/git.js +35 -72
- package/dist/utils/global-config.js +22 -3
- package/dist/utils/output.js +19 -7
- package/dist/utils/patterns.js +14 -0
- package/dist/utils/project-link-store.js +105 -0
- package/dist/utils/report-data.js +31 -0
- package/dist/utils/screenshot-options.js +28 -0
- package/dist/utils/secret-store.js +65 -0
- package/dist/utils/security.js +3 -2
- package/package.json +14 -11
- package/dist/services/screenshot-server.js +0 -65
- package/dist/services/server-manager.js +0 -81
- package/dist/services/uploader.js +0 -100
- package/dist/tdd/services/region-service.js +0 -75
- package/dist/utils/build-history.js +0 -103
package/dist/sdk/index.js
CHANGED
|
@@ -11,13 +11,15 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { EventEmitter } from 'node:events';
|
|
14
|
+
import { createServer } from 'node:http';
|
|
14
15
|
import { VizzlyError } from '../errors/vizzly-error.js';
|
|
15
|
-
import {
|
|
16
|
-
import { createUploader } from '../services/uploader.js';
|
|
16
|
+
import { handleRequest as handleScreenshotRequest, startServer as startScreenshotServer, stopServer as stopScreenshotServer } from '../screenshot-server/index.js';
|
|
17
17
|
import { createTDDService } from '../tdd/tdd-service.js';
|
|
18
|
+
import { createUploader } from '../uploader/index.js';
|
|
18
19
|
import { loadConfig } from '../utils/config-loader.js';
|
|
19
20
|
import { resolveImageBuffer } from '../utils/file-helpers.js';
|
|
20
21
|
import * as output from '../utils/output.js';
|
|
22
|
+
import { createScreenshotProperties } from '../utils/screenshot-options.js';
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Create a new Vizzly instance with custom configuration
|
|
@@ -52,79 +54,94 @@ import * as output from '../utils/output.js';
|
|
|
52
54
|
* // Cleanup
|
|
53
55
|
* await vizzly.stop();
|
|
54
56
|
*/
|
|
55
|
-
export function createVizzly(config = {}, options = {}) {
|
|
57
|
+
export async function createVizzly(config = {}, options = {}) {
|
|
56
58
|
// Configure output based on options
|
|
57
59
|
output.configure({
|
|
58
60
|
verbose: options.verbose || false
|
|
59
61
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
let loadConfigFn = options.loadConfig || loadConfig;
|
|
63
|
+
let fileConfig = await loadConfigFn();
|
|
64
|
+
let resolvedConfig = {
|
|
65
|
+
...fileConfig,
|
|
63
66
|
...config
|
|
64
67
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
68
|
+
return new VizzlySDK(resolvedConfig, {
|
|
69
|
+
createUploader: (uploaderOptions = {}, activeConfig = resolvedConfig) => {
|
|
70
|
+
let {
|
|
71
|
+
upload: uploadConfig = activeConfig.upload,
|
|
72
|
+
...serviceOptions
|
|
73
|
+
} = uploaderOptions;
|
|
74
|
+
let createUploaderService = options.createUploader || createUploader;
|
|
75
|
+
return createUploaderService({
|
|
76
|
+
apiKey: activeConfig.apiKey,
|
|
77
|
+
apiUrl: activeConfig.apiUrl,
|
|
78
|
+
upload: uploadConfig
|
|
79
|
+
}, {
|
|
80
|
+
...options,
|
|
81
|
+
...serviceOptions
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
createTDDService: (tddOptions = {}, activeConfig = resolvedConfig) => {
|
|
85
|
+
let createTDDServiceInstance = options.createTDDService || createTDDService;
|
|
86
|
+
return createTDDServiceInstance(activeConfig, {
|
|
87
|
+
...options,
|
|
88
|
+
...tddOptions
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
createScreenshotServer: createLocalScreenshotServer,
|
|
92
|
+
fetch: options.fetch,
|
|
93
|
+
loadConfig: loadConfigFn
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function createLocalBuildManager() {
|
|
97
|
+
let screenshots = new Map();
|
|
98
|
+
return {
|
|
99
|
+
async addScreenshot(buildId, screenshot) {
|
|
100
|
+
if (!screenshots.has(buildId)) {
|
|
101
|
+
screenshots.set(buildId, []);
|
|
102
|
+
}
|
|
103
|
+
screenshots.get(buildId).push(screenshot);
|
|
104
|
+
},
|
|
105
|
+
getScreenshots(buildId) {
|
|
106
|
+
return screenshots.get(buildId) || [];
|
|
107
|
+
}
|
|
104
108
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
}
|
|
110
|
+
function createLocalScreenshotServer(config, buildManager, options = {}) {
|
|
111
|
+
let server = null;
|
|
112
|
+
let deps = {
|
|
113
|
+
createHttpServer: options.createHttpServer || createServer,
|
|
114
|
+
output: options.output || output,
|
|
115
|
+
createError: options.createError || ((message, code) => new VizzlyError(message, code))
|
|
112
116
|
};
|
|
113
117
|
return {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
118
|
+
async start() {
|
|
119
|
+
server = await startScreenshotServer({
|
|
120
|
+
config,
|
|
121
|
+
requestHandler: (req, res) => handleScreenshotRequest({
|
|
122
|
+
req,
|
|
123
|
+
res,
|
|
124
|
+
deps: {
|
|
125
|
+
buildManager,
|
|
126
|
+
createError: deps.createError,
|
|
127
|
+
output: deps.output
|
|
128
|
+
}
|
|
129
|
+
}),
|
|
130
|
+
deps
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
async stop() {
|
|
134
|
+
await stopScreenshotServer({
|
|
135
|
+
server,
|
|
136
|
+
deps: {
|
|
137
|
+
output: deps.output
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
server = null;
|
|
141
|
+
},
|
|
142
|
+
isRunning() {
|
|
143
|
+
return Boolean(server?.listening);
|
|
144
|
+
}
|
|
128
145
|
};
|
|
129
146
|
}
|
|
130
147
|
|
|
@@ -153,7 +170,7 @@ export class VizzlySDK extends EventEmitter {
|
|
|
153
170
|
constructor(config, services) {
|
|
154
171
|
super();
|
|
155
172
|
this.config = config;
|
|
156
|
-
this.services = services;
|
|
173
|
+
this.services = services || {};
|
|
157
174
|
this.server = null;
|
|
158
175
|
this.currentBuildId = null;
|
|
159
176
|
}
|
|
@@ -181,6 +198,59 @@ export class VizzlySDK extends EventEmitter {
|
|
|
181
198
|
};
|
|
182
199
|
}
|
|
183
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Merge new config values into the active SDK config.
|
|
203
|
+
* @param {Object} newConfig - Config updates
|
|
204
|
+
* @returns {Object} Updated config
|
|
205
|
+
*/
|
|
206
|
+
updateConfig(newConfig) {
|
|
207
|
+
Object.assign(this.config, newConfig);
|
|
208
|
+
return this.getConfig();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Reload file config and re-apply current in-memory overrides.
|
|
213
|
+
* @returns {Promise<Object>} Updated config
|
|
214
|
+
*/
|
|
215
|
+
async init() {
|
|
216
|
+
let loadConfigFn = this.services.loadConfig || loadConfig;
|
|
217
|
+
let fileConfig = await loadConfigFn();
|
|
218
|
+
let currentConfig = {
|
|
219
|
+
...this.config
|
|
220
|
+
};
|
|
221
|
+
Object.assign(this.config, fileConfig, currentConfig);
|
|
222
|
+
return this.getConfig();
|
|
223
|
+
}
|
|
224
|
+
createUploader(options = {}) {
|
|
225
|
+
let {
|
|
226
|
+
upload: uploadConfig = this.config.upload,
|
|
227
|
+
...serviceOptions
|
|
228
|
+
} = options;
|
|
229
|
+
let createUploaderService = this.services.createUploader || ((uploaderOptions, activeConfig = this.config) => {
|
|
230
|
+
let {
|
|
231
|
+
upload: resolvedUploadConfig = activeConfig.upload,
|
|
232
|
+
...resolvedServiceOptions
|
|
233
|
+
} = uploaderOptions;
|
|
234
|
+
return createUploader({
|
|
235
|
+
apiKey: activeConfig.apiKey,
|
|
236
|
+
apiUrl: activeConfig.apiUrl,
|
|
237
|
+
upload: resolvedUploadConfig
|
|
238
|
+
}, resolvedServiceOptions);
|
|
239
|
+
});
|
|
240
|
+
return createUploaderService({
|
|
241
|
+
upload: uploadConfig,
|
|
242
|
+
...serviceOptions
|
|
243
|
+
}, this.config);
|
|
244
|
+
}
|
|
245
|
+
createTDDService(options = {}) {
|
|
246
|
+
let createTDDServiceInstance = this.services.createTDDService || ((tddOptions, activeConfig = this.config) => createTDDService(activeConfig, tddOptions));
|
|
247
|
+
return createTDDServiceInstance(options, this.config);
|
|
248
|
+
}
|
|
249
|
+
async startTDD(options = {}) {
|
|
250
|
+
let tddService = this.createTDDService(options);
|
|
251
|
+
return tddService.start(options);
|
|
252
|
+
}
|
|
253
|
+
|
|
184
254
|
/**
|
|
185
255
|
* Start the Vizzly server
|
|
186
256
|
* @returns {Promise<{port: number, url: string}>} Server information
|
|
@@ -193,25 +263,12 @@ export class VizzlySDK extends EventEmitter {
|
|
|
193
263
|
url: `http://localhost:${this.config.server?.port || 3000}`
|
|
194
264
|
};
|
|
195
265
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
screenshots: new Map(),
|
|
200
|
-
currentBuildId: null,
|
|
201
|
-
async addScreenshot(buildId, screenshot) {
|
|
202
|
-
if (!this.screenshots.has(buildId)) {
|
|
203
|
-
this.screenshots.set(buildId, []);
|
|
204
|
-
}
|
|
205
|
-
this.screenshots.get(buildId).push(screenshot);
|
|
206
|
-
},
|
|
207
|
-
getScreenshots(buildId) {
|
|
208
|
-
return this.screenshots.get(buildId) || [];
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
this.server = new ScreenshotServer(this.config, buildManager);
|
|
266
|
+
let createScreenshotServer = this.services.createScreenshotServer || createLocalScreenshotServer;
|
|
267
|
+
let buildManager = createLocalBuildManager();
|
|
268
|
+
this.server = createScreenshotServer(this.config, buildManager);
|
|
212
269
|
await this.server.start();
|
|
213
|
-
|
|
214
|
-
|
|
270
|
+
let port = this.config.server?.port || 3000;
|
|
271
|
+
let serverInfo = {
|
|
215
272
|
port,
|
|
216
273
|
url: `http://localhost:${port}`
|
|
217
274
|
};
|
|
@@ -230,31 +287,32 @@ export class VizzlySDK extends EventEmitter {
|
|
|
230
287
|
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
|
|
231
288
|
*/
|
|
232
289
|
async screenshot(name, imageBuffer, options = {}) {
|
|
233
|
-
if (
|
|
290
|
+
if (this.server?.isRunning?.() !== true) {
|
|
234
291
|
throw new VizzlyError('Server not running. Call start() first.', 'SERVER_NOT_RUNNING');
|
|
235
292
|
}
|
|
236
293
|
|
|
237
294
|
// Resolve Buffer or file path using shared utility
|
|
238
|
-
|
|
295
|
+
let buffer = resolveImageBuffer(imageBuffer, 'screenshot');
|
|
239
296
|
|
|
240
297
|
// Generate or use provided build ID
|
|
241
|
-
|
|
298
|
+
let buildId = options.buildId || this.currentBuildId || 'default';
|
|
242
299
|
this.currentBuildId = buildId;
|
|
243
300
|
|
|
244
301
|
// Convert Buffer to base64 for JSON transport
|
|
245
|
-
|
|
246
|
-
|
|
302
|
+
let imageBase64 = buffer.toString('base64');
|
|
303
|
+
let screenshotData = {
|
|
247
304
|
buildId,
|
|
248
305
|
name,
|
|
249
306
|
image: imageBase64,
|
|
250
307
|
type: 'base64',
|
|
251
|
-
properties: options
|
|
308
|
+
properties: createScreenshotProperties(options)
|
|
252
309
|
};
|
|
253
310
|
|
|
254
311
|
// POST to the local screenshot server
|
|
255
|
-
|
|
312
|
+
let serverUrl = `http://localhost:${this.config.server?.port || 3000}`;
|
|
313
|
+
let fetchFn = this.services.fetch || fetch;
|
|
256
314
|
try {
|
|
257
|
-
|
|
315
|
+
let response = await fetchFn(`${serverUrl}/screenshot`, {
|
|
258
316
|
method: 'POST',
|
|
259
317
|
headers: {
|
|
260
318
|
'Content-Type': 'application/json'
|
|
@@ -262,7 +320,7 @@ export class VizzlySDK extends EventEmitter {
|
|
|
262
320
|
body: JSON.stringify(screenshotData)
|
|
263
321
|
});
|
|
264
322
|
if (!response.ok) {
|
|
265
|
-
|
|
323
|
+
let errorData = await response.json().catch(() => ({
|
|
266
324
|
error: 'Unknown error'
|
|
267
325
|
}));
|
|
268
326
|
throw new VizzlyError(`Screenshot capture failed: ${errorData.error}`, 'SCREENSHOT_FAILED', {
|
|
@@ -295,23 +353,21 @@ export class VizzlySDK extends EventEmitter {
|
|
|
295
353
|
async upload(options = {}) {
|
|
296
354
|
if (!this.services?.uploader) {
|
|
297
355
|
this.services = this.services || {};
|
|
298
|
-
this.services.uploader = createUploader({
|
|
299
|
-
apiKey: this.config.apiKey,
|
|
300
|
-
apiUrl: this.config.apiUrl,
|
|
356
|
+
this.services.uploader = this.createUploader({
|
|
301
357
|
upload: this.config.upload
|
|
302
358
|
});
|
|
303
359
|
}
|
|
304
360
|
|
|
305
361
|
// Get the screenshots directory from config or default
|
|
306
|
-
|
|
307
|
-
|
|
362
|
+
let screenshotsDir = options.screenshotsDir || this.config?.upload?.screenshotsDir || './screenshots';
|
|
363
|
+
let uploadOptions = {
|
|
308
364
|
screenshotsDir,
|
|
309
365
|
buildName: options.buildName || this.config.buildName,
|
|
310
366
|
branch: options.branch || this.config.branch,
|
|
311
367
|
commit: options.commit || this.config.commit,
|
|
312
368
|
message: options.message || this.config.message,
|
|
313
369
|
environment: options.environment || this.config.environment || 'production',
|
|
314
|
-
threshold: options.threshold
|
|
370
|
+
threshold: options.threshold ?? this.config.threshold,
|
|
315
371
|
onProgress: progress => {
|
|
316
372
|
this.emit('upload:progress', progress);
|
|
317
373
|
if (options.onProgress) {
|
|
@@ -320,7 +376,7 @@ export class VizzlySDK extends EventEmitter {
|
|
|
320
376
|
}
|
|
321
377
|
};
|
|
322
378
|
try {
|
|
323
|
-
|
|
379
|
+
let result = await this.services.uploader.upload(uploadOptions);
|
|
324
380
|
this.emit('upload:completed', result);
|
|
325
381
|
return result;
|
|
326
382
|
} catch (error) {
|
|
@@ -340,13 +396,13 @@ export class VizzlySDK extends EventEmitter {
|
|
|
340
396
|
async compare(name, imageBuffer) {
|
|
341
397
|
if (!this.services?.tddService) {
|
|
342
398
|
this.services = this.services || {};
|
|
343
|
-
this.services.tddService = createTDDService(
|
|
399
|
+
this.services.tddService = this.createTDDService();
|
|
344
400
|
}
|
|
345
401
|
|
|
346
402
|
// Resolve Buffer or file path using shared utility
|
|
347
|
-
|
|
403
|
+
let buffer = resolveImageBuffer(imageBuffer, 'compare');
|
|
348
404
|
try {
|
|
349
|
-
|
|
405
|
+
let result = await this.services.tddService.compareScreenshot(name, buffer);
|
|
350
406
|
this.emit('comparison:completed', result);
|
|
351
407
|
return result;
|
|
352
408
|
} catch (error) {
|
|
@@ -358,10 +414,9 @@ export class VizzlySDK extends EventEmitter {
|
|
|
358
414
|
}
|
|
359
415
|
}
|
|
360
416
|
}
|
|
361
|
-
|
|
362
|
-
// Export service creators for advanced usage
|
|
363
|
-
export { createUploader } from '../services/uploader.js';
|
|
364
417
|
export { createTDDService } from '../tdd/tdd-service.js';
|
|
418
|
+
// Export service creators for advanced usage
|
|
419
|
+
export { createUploader } from '../uploader/index.js';
|
|
365
420
|
// Re-export key utilities and errors
|
|
366
421
|
export { loadConfig } from '../utils/config-loader.js';
|
|
367
422
|
export * as output from '../utils/output.js';
|
|
@@ -157,6 +157,16 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
|
|
|
157
157
|
const tddService = new TddService(config, workingDir, setBaseline);
|
|
158
158
|
const reportPath = join(workingDir, '.vizzly', 'report-data.json');
|
|
159
159
|
const detailsPath = join(workingDir, '.vizzly', 'comparison-details.json');
|
|
160
|
+
let clearJsonFile = path => {
|
|
161
|
+
if (existsSync(path)) {
|
|
162
|
+
unlinkSync(path);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
let prepareRunArtifacts = () => {
|
|
166
|
+
clearJsonFile(reportPath);
|
|
167
|
+
clearJsonFile(detailsPath);
|
|
168
|
+
tddService.clearRunData?.();
|
|
169
|
+
};
|
|
160
170
|
|
|
161
171
|
/**
|
|
162
172
|
* Read heavy comparison details from comparison-details.json
|
|
@@ -267,6 +277,7 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
|
|
|
267
277
|
};
|
|
268
278
|
const initialize = async () => {
|
|
269
279
|
output.debug('tdd', 'initializing local mode');
|
|
280
|
+
prepareRunArtifacts();
|
|
270
281
|
|
|
271
282
|
// In baseline update mode, skip all baseline loading/downloading
|
|
272
283
|
if (setBaseline) {
|
|
@@ -631,68 +642,33 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
|
|
|
631
642
|
let deletedBaselines = 0;
|
|
632
643
|
let deletedCurrents = 0;
|
|
633
644
|
let deletedDiffs = 0;
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if (
|
|
641
|
-
|
|
642
|
-
const {
|
|
643
|
-
unlinkSync
|
|
644
|
-
} = await import('node:fs');
|
|
645
|
-
unlinkSync(baselinePath);
|
|
646
|
-
deletedBaselines++;
|
|
647
|
-
// Silent deletion
|
|
648
|
-
} catch (error) {
|
|
649
|
-
output.warn(`Failed to delete baseline for ${comparison.name}: ${error.message}`);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
// Delete current screenshot if it exists
|
|
655
|
-
if (comparison.current) {
|
|
656
|
-
const currentPath = join(workingDir, '.vizzly', comparison.current.replace('/images/', ''));
|
|
657
|
-
if (existsSync(currentPath)) {
|
|
658
|
-
try {
|
|
659
|
-
const {
|
|
660
|
-
unlinkSync
|
|
661
|
-
} = await import('node:fs');
|
|
662
|
-
unlinkSync(currentPath);
|
|
663
|
-
deletedCurrents++;
|
|
664
|
-
// Silent deletion
|
|
665
|
-
} catch (error) {
|
|
666
|
-
output.warn(`Failed to delete current screenshot for ${comparison.name}: ${error.message}`);
|
|
667
|
-
}
|
|
645
|
+
let deleteResetFile = (imagePath, label, name) => {
|
|
646
|
+
if (!imagePath) return 0;
|
|
647
|
+
try {
|
|
648
|
+
let filePath = safePath(workingDir, '.vizzly', imagePath.replace('/images/', ''));
|
|
649
|
+
if (!existsSync(filePath)) return 0;
|
|
650
|
+
unlinkSync(filePath);
|
|
651
|
+
if (label === 'diff') {
|
|
652
|
+
output.debug(`Deleted diff for ${name}`);
|
|
668
653
|
}
|
|
654
|
+
return 1;
|
|
655
|
+
} catch (error) {
|
|
656
|
+
output.warn(`Failed to delete ${label} for ${name}: ${error.message}`);
|
|
657
|
+
return 0;
|
|
669
658
|
}
|
|
659
|
+
};
|
|
670
660
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
const {
|
|
677
|
-
unlinkSync
|
|
678
|
-
} = await import('node:fs');
|
|
679
|
-
unlinkSync(diffPath);
|
|
680
|
-
deletedDiffs++;
|
|
681
|
-
output.debug(`Deleted diff for ${comparison.name}`);
|
|
682
|
-
} catch (error) {
|
|
683
|
-
output.warn(`Failed to delete diff for ${comparison.name}: ${error.message}`);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
}
|
|
661
|
+
// Delete all baseline, current, and diff images
|
|
662
|
+
for (let comparison of reportData.comparisons) {
|
|
663
|
+
deletedBaselines += deleteResetFile(comparison.baseline, 'baseline', comparison.name);
|
|
664
|
+
deletedCurrents += deleteResetFile(comparison.current, 'current screenshot', comparison.name);
|
|
665
|
+
deletedDiffs += deleteResetFile(comparison.diff, 'diff', comparison.name);
|
|
687
666
|
}
|
|
688
667
|
|
|
689
668
|
// Delete baseline metadata
|
|
690
|
-
|
|
669
|
+
let metadataPath = join(workingDir, '.vizzly', 'baselines', 'metadata.json');
|
|
691
670
|
if (existsSync(metadataPath)) {
|
|
692
671
|
try {
|
|
693
|
-
const {
|
|
694
|
-
unlinkSync
|
|
695
|
-
} = await import('node:fs');
|
|
696
672
|
unlinkSync(metadataPath);
|
|
697
673
|
output.debug('Deleted baseline metadata');
|
|
698
674
|
} catch (error) {
|
|
@@ -72,6 +72,10 @@ export function createAssetsRouter() {
|
|
|
72
72
|
if (existsSync(fullImagePath)) {
|
|
73
73
|
try {
|
|
74
74
|
const imageData = readFileSync(fullImagePath);
|
|
75
|
+
// Images are rewritten in place between TDD runs, so disable browser caching.
|
|
76
|
+
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
|
|
77
|
+
res.setHeader('Pragma', 'no-cache');
|
|
78
|
+
res.setHeader('Expires', '0');
|
|
75
79
|
sendFile(res, imageData, 'image/png');
|
|
76
80
|
return true;
|
|
77
81
|
} catch (error) {
|