@vizzly-testing/cli 0.19.2 → 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/client/index.js +0 -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 -249
- 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/types/client.d.ts +4 -2
- package/dist/types/index.d.ts +5 -0
- package/dist/uploader/core.js +396 -0
- package/dist/uploader/index.js +11 -0
- package/dist/uploader/operations.js +412 -0
- package/dist/utils/config-schema.js +8 -3
- 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 -1429
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Runner Operations - Test execution operations with dependency injection
|
|
3
|
+
*
|
|
4
|
+
* Each operation takes its dependencies as parameters:
|
|
5
|
+
* - spawn: child_process.spawn for executing commands
|
|
6
|
+
* - serverManager: for starting/stopping screenshot server
|
|
7
|
+
* - buildManager: for local build management (TDD mode)
|
|
8
|
+
* - apiClient: for API builds and finalization
|
|
9
|
+
* - output: for logging
|
|
10
|
+
*
|
|
11
|
+
* This makes them trivially testable without mocking modules.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { buildApiBuildPayload, buildClientOptions, buildDisabledEnv, buildDisabledRunResult, buildRunResult, buildSpawnOptions, buildTestEnv, hasApiKey, normalizeSetBaseline, shouldDisableVizzly, validateDaemonMode, validateTestCommand } from './core.js';
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Build Operations
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create a build (either locally for TDD or via API)
|
|
22
|
+
* @param {Object} options - Options
|
|
23
|
+
* @param {Object} options.runOptions - Run options (buildName, branch, etc.)
|
|
24
|
+
* @param {boolean} options.tdd - Whether in TDD mode
|
|
25
|
+
* @param {Object} options.config - Configuration object
|
|
26
|
+
* @param {Object} options.deps - Dependencies
|
|
27
|
+
* @param {Object} options.deps.buildManager - Build manager for local builds
|
|
28
|
+
* @param {Function} options.deps.createApiClient - API client factory
|
|
29
|
+
* @param {Function} options.deps.createApiBuild - API build creation function
|
|
30
|
+
* @param {Object} options.deps.output - Output utilities
|
|
31
|
+
* @returns {Promise<string>} Build ID
|
|
32
|
+
*/
|
|
33
|
+
export async function createBuild({
|
|
34
|
+
runOptions,
|
|
35
|
+
tdd,
|
|
36
|
+
config,
|
|
37
|
+
deps
|
|
38
|
+
}) {
|
|
39
|
+
let {
|
|
40
|
+
buildManager,
|
|
41
|
+
createApiClient,
|
|
42
|
+
createApiBuild,
|
|
43
|
+
output
|
|
44
|
+
} = deps;
|
|
45
|
+
if (tdd) {
|
|
46
|
+
// TDD mode: create local build
|
|
47
|
+
let build = await buildManager.createBuild(runOptions);
|
|
48
|
+
output.debug('build', `created ${build.id.substring(0, 8)}`);
|
|
49
|
+
return build.id;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// API mode: create build via API
|
|
53
|
+
let clientOptions = buildClientOptions(config);
|
|
54
|
+
if (!clientOptions) {
|
|
55
|
+
throw new Error('No API key available for build creation');
|
|
56
|
+
}
|
|
57
|
+
let client = createApiClient(clientOptions);
|
|
58
|
+
let payload = buildApiBuildPayload(runOptions, config.comparison);
|
|
59
|
+
let buildResult = await createApiBuild(client, payload);
|
|
60
|
+
output.debug('build', `created ${buildResult.id}`);
|
|
61
|
+
return buildResult.id;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get build URL from API
|
|
66
|
+
* @param {Object} options - Options
|
|
67
|
+
* @param {string} options.buildId - Build ID
|
|
68
|
+
* @param {Object} options.config - Configuration object
|
|
69
|
+
* @param {Object} options.deps - Dependencies
|
|
70
|
+
* @param {Function} options.deps.createApiClient - API client factory
|
|
71
|
+
* @param {Function} options.deps.getBuild - Get build function
|
|
72
|
+
* @param {Object} options.deps.output - Output utilities
|
|
73
|
+
* @returns {Promise<string|null>} Build URL or null
|
|
74
|
+
*/
|
|
75
|
+
export async function fetchBuildUrl({
|
|
76
|
+
buildId,
|
|
77
|
+
config,
|
|
78
|
+
deps
|
|
79
|
+
}) {
|
|
80
|
+
let {
|
|
81
|
+
createApiClient,
|
|
82
|
+
getBuild,
|
|
83
|
+
output
|
|
84
|
+
} = deps;
|
|
85
|
+
let clientOptions = buildClientOptions(config);
|
|
86
|
+
if (!clientOptions) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
let client = createApiClient(clientOptions);
|
|
91
|
+
let build = await getBuild(client, buildId);
|
|
92
|
+
return build.url || null;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
output.debug('build', 'could not retrieve url', {
|
|
95
|
+
error: error.message
|
|
96
|
+
});
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Finalize a build
|
|
103
|
+
* @param {Object} options - Options
|
|
104
|
+
* @param {string} options.buildId - Build ID
|
|
105
|
+
* @param {boolean} options.tdd - Whether in TDD mode
|
|
106
|
+
* @param {boolean} options.success - Whether tests passed
|
|
107
|
+
* @param {number} options.executionTime - Execution time in ms
|
|
108
|
+
* @param {Object} options.config - Configuration object
|
|
109
|
+
* @param {Object} options.deps - Dependencies
|
|
110
|
+
* @param {Object} options.deps.serverManager - Server manager
|
|
111
|
+
* @param {Function} options.deps.createApiClient - API client factory
|
|
112
|
+
* @param {Function} options.deps.finalizeApiBuild - API finalize function
|
|
113
|
+
* @param {Object} options.deps.output - Output utilities
|
|
114
|
+
* @param {Function} [options.deps.onFinalizeFailed] - Callback for finalize failure
|
|
115
|
+
*/
|
|
116
|
+
export async function finalizeBuild({
|
|
117
|
+
buildId,
|
|
118
|
+
tdd,
|
|
119
|
+
success,
|
|
120
|
+
executionTime,
|
|
121
|
+
config,
|
|
122
|
+
deps
|
|
123
|
+
}) {
|
|
124
|
+
let {
|
|
125
|
+
serverManager,
|
|
126
|
+
createApiClient,
|
|
127
|
+
finalizeApiBuild,
|
|
128
|
+
output,
|
|
129
|
+
onFinalizeFailed
|
|
130
|
+
} = deps;
|
|
131
|
+
if (!buildId) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
if (tdd) {
|
|
136
|
+
// TDD mode: use server handler to finalize (local-only)
|
|
137
|
+
if (serverManager.server?.finishBuild) {
|
|
138
|
+
await serverManager.server.finishBuild(buildId);
|
|
139
|
+
output.debug('build', 'finalized', {
|
|
140
|
+
success
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
// API mode: flush uploads first, then finalize build
|
|
145
|
+
if (serverManager.server?.finishBuild) {
|
|
146
|
+
await serverManager.server.finishBuild(buildId);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Then update build status via API
|
|
150
|
+
let clientOptions = buildClientOptions(config);
|
|
151
|
+
if (clientOptions) {
|
|
152
|
+
let client = createApiClient(clientOptions);
|
|
153
|
+
await finalizeApiBuild(client, buildId, success, executionTime);
|
|
154
|
+
output.debug('build', 'finalized via api', {
|
|
155
|
+
success
|
|
156
|
+
});
|
|
157
|
+
} else {
|
|
158
|
+
output.warn(`No API service available to finalize build ${buildId}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
// Don't fail the entire run if build finalization fails
|
|
163
|
+
output.warn(`Failed to finalize build ${buildId}:`, error.message);
|
|
164
|
+
if (onFinalizeFailed) {
|
|
165
|
+
onFinalizeFailed({
|
|
166
|
+
buildId,
|
|
167
|
+
error: error.message,
|
|
168
|
+
stack: error.stack
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ============================================================================
|
|
175
|
+
// Test Execution Operations
|
|
176
|
+
// ============================================================================
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Execute a test command
|
|
180
|
+
* @param {Object} options - Options
|
|
181
|
+
* @param {string} options.command - Test command to execute
|
|
182
|
+
* @param {Object} options.env - Environment variables
|
|
183
|
+
* @param {Object} options.deps - Dependencies
|
|
184
|
+
* @param {Function} options.deps.spawn - Spawn function
|
|
185
|
+
* @param {Function} options.deps.createError - Error factory
|
|
186
|
+
* @returns {Promise<{ process: Object }>} Spawned process reference
|
|
187
|
+
*/
|
|
188
|
+
export function executeTestCommand({
|
|
189
|
+
command,
|
|
190
|
+
env,
|
|
191
|
+
deps
|
|
192
|
+
}) {
|
|
193
|
+
let {
|
|
194
|
+
spawn,
|
|
195
|
+
createError
|
|
196
|
+
} = deps;
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
let spawnOptions = buildSpawnOptions(env);
|
|
199
|
+
let testProcess = spawn(command, spawnOptions);
|
|
200
|
+
testProcess.on('error', error => {
|
|
201
|
+
reject(createError(`Failed to run test command: ${error.message}`, 'TEST_COMMAND_FAILED'));
|
|
202
|
+
});
|
|
203
|
+
testProcess.on('exit', (code, signal) => {
|
|
204
|
+
if (signal === 'SIGINT') {
|
|
205
|
+
reject(createError('Test command was interrupted', 'TEST_COMMAND_INTERRUPTED'));
|
|
206
|
+
} else if (code !== 0) {
|
|
207
|
+
reject(createError(`Test command exited with code ${code}`, 'TEST_COMMAND_FAILED'));
|
|
208
|
+
} else {
|
|
209
|
+
resolve({
|
|
210
|
+
process: testProcess
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Return process reference for cancellation
|
|
216
|
+
resolve.__process = testProcess;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// High-Level Run Operations
|
|
222
|
+
// ============================================================================
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Run tests with Vizzly integration
|
|
226
|
+
* @param {Object} options - Options
|
|
227
|
+
* @param {Object} options.runOptions - Run options (testCommand, tdd, etc.)
|
|
228
|
+
* @param {Object} options.config - Configuration object
|
|
229
|
+
* @param {Object} options.deps - Dependencies
|
|
230
|
+
* @returns {Promise<Object>} Run result
|
|
231
|
+
*/
|
|
232
|
+
export async function runTests({
|
|
233
|
+
runOptions,
|
|
234
|
+
config,
|
|
235
|
+
deps
|
|
236
|
+
}) {
|
|
237
|
+
let {
|
|
238
|
+
serverManager,
|
|
239
|
+
buildManager,
|
|
240
|
+
spawn,
|
|
241
|
+
createApiClient,
|
|
242
|
+
createApiBuild,
|
|
243
|
+
getBuild,
|
|
244
|
+
finalizeApiBuild,
|
|
245
|
+
createError,
|
|
246
|
+
output,
|
|
247
|
+
onBuildCreated,
|
|
248
|
+
onServerReady,
|
|
249
|
+
onFinalizeFailed
|
|
250
|
+
} = deps;
|
|
251
|
+
let {
|
|
252
|
+
testCommand,
|
|
253
|
+
tdd,
|
|
254
|
+
allowNoToken
|
|
255
|
+
} = runOptions;
|
|
256
|
+
let startTime = Date.now();
|
|
257
|
+
|
|
258
|
+
// Validate test command
|
|
259
|
+
let validation = validateTestCommand(testCommand);
|
|
260
|
+
if (!validation.valid) {
|
|
261
|
+
throw createError(validation.error, 'TEST_COMMAND_MISSING');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Check if we should skip Vizzly integration entirely
|
|
265
|
+
if (shouldDisableVizzly({
|
|
266
|
+
allowNoToken,
|
|
267
|
+
hasApiKey: hasApiKey(config),
|
|
268
|
+
tdd
|
|
269
|
+
})) {
|
|
270
|
+
let env = buildDisabledEnv();
|
|
271
|
+
await executeTestCommand({
|
|
272
|
+
command: testCommand,
|
|
273
|
+
env,
|
|
274
|
+
deps: {
|
|
275
|
+
spawn,
|
|
276
|
+
createError
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
return buildDisabledRunResult();
|
|
280
|
+
}
|
|
281
|
+
let buildId = null;
|
|
282
|
+
let buildUrl = null;
|
|
283
|
+
let screenshotCount = 0;
|
|
284
|
+
let testSuccess = false;
|
|
285
|
+
let testError = null;
|
|
286
|
+
try {
|
|
287
|
+
// Create build
|
|
288
|
+
buildId = await createBuild({
|
|
289
|
+
runOptions,
|
|
290
|
+
tdd,
|
|
291
|
+
config,
|
|
292
|
+
deps: {
|
|
293
|
+
buildManager,
|
|
294
|
+
createApiClient,
|
|
295
|
+
createApiBuild,
|
|
296
|
+
output
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Get build URL for API mode
|
|
301
|
+
if (!tdd && buildId) {
|
|
302
|
+
buildUrl = await fetchBuildUrl({
|
|
303
|
+
buildId,
|
|
304
|
+
config,
|
|
305
|
+
deps: {
|
|
306
|
+
createApiClient,
|
|
307
|
+
getBuild,
|
|
308
|
+
output
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
if (buildUrl) {
|
|
312
|
+
output.info(`Build URL: ${buildUrl}`);
|
|
313
|
+
}
|
|
314
|
+
if (onBuildCreated) {
|
|
315
|
+
onBuildCreated({
|
|
316
|
+
buildId,
|
|
317
|
+
url: buildUrl
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Start server
|
|
323
|
+
let setBaseline = normalizeSetBaseline(runOptions);
|
|
324
|
+
await serverManager.start(buildId, tdd, setBaseline);
|
|
325
|
+
if (onServerReady) {
|
|
326
|
+
onServerReady({
|
|
327
|
+
port: config.server?.port,
|
|
328
|
+
buildId,
|
|
329
|
+
tdd
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Execute test command
|
|
334
|
+
let env = buildTestEnv({
|
|
335
|
+
port: config.server?.port,
|
|
336
|
+
buildId,
|
|
337
|
+
setBaseline
|
|
338
|
+
});
|
|
339
|
+
try {
|
|
340
|
+
await executeTestCommand({
|
|
341
|
+
command: testCommand,
|
|
342
|
+
env,
|
|
343
|
+
deps: {
|
|
344
|
+
spawn,
|
|
345
|
+
createError
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
testSuccess = true;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
testError = error;
|
|
351
|
+
testSuccess = false;
|
|
352
|
+
}
|
|
353
|
+
} catch (error) {
|
|
354
|
+
testError = error;
|
|
355
|
+
testSuccess = false;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Get TDD results before stopping the server
|
|
359
|
+
let tddResults = null;
|
|
360
|
+
if (tdd) {
|
|
361
|
+
try {
|
|
362
|
+
tddResults = await serverManager.getTddResults?.();
|
|
363
|
+
if (tddResults) {
|
|
364
|
+
screenshotCount = tddResults.total || 0;
|
|
365
|
+
}
|
|
366
|
+
} catch (tddError) {
|
|
367
|
+
output.debug('tdd', 'failed to get results', {
|
|
368
|
+
error: tddError.message
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Always finalize and cleanup
|
|
374
|
+
try {
|
|
375
|
+
let executionTime = Date.now() - startTime;
|
|
376
|
+
if (buildId) {
|
|
377
|
+
try {
|
|
378
|
+
await finalizeBuild({
|
|
379
|
+
buildId,
|
|
380
|
+
tdd,
|
|
381
|
+
success: testSuccess,
|
|
382
|
+
executionTime,
|
|
383
|
+
config,
|
|
384
|
+
deps: {
|
|
385
|
+
serverManager,
|
|
386
|
+
createApiClient,
|
|
387
|
+
finalizeApiBuild,
|
|
388
|
+
output,
|
|
389
|
+
onFinalizeFailed
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
} catch (finalizeError) {
|
|
393
|
+
output.error('Failed to finalize build:', finalizeError);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// In API mode, get actual screenshot count from handler after flush
|
|
398
|
+
if (!tdd && serverManager.server?.getScreenshotCount) {
|
|
399
|
+
screenshotCount = serverManager.server.getScreenshotCount(buildId) || 0;
|
|
400
|
+
}
|
|
401
|
+
} finally {
|
|
402
|
+
try {
|
|
403
|
+
await serverManager.stop();
|
|
404
|
+
} catch (stopError) {
|
|
405
|
+
output.error('Failed to stop server:', stopError);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Throw test error after cleanup
|
|
410
|
+
if (testError) {
|
|
411
|
+
output.error('Test run failed:', testError);
|
|
412
|
+
throw testError;
|
|
413
|
+
}
|
|
414
|
+
return buildRunResult({
|
|
415
|
+
buildId,
|
|
416
|
+
buildUrl,
|
|
417
|
+
testSuccess,
|
|
418
|
+
screenshotCount,
|
|
419
|
+
tddResults
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Initialize daemon server (TDD mode only)
|
|
425
|
+
* @param {Object} options - Options
|
|
426
|
+
* @param {Object} options.initOptions - Init options
|
|
427
|
+
* @param {Object} options.deps - Dependencies
|
|
428
|
+
* @param {Object} options.deps.serverManager - Server manager
|
|
429
|
+
* @param {Function} options.deps.createError - Error factory
|
|
430
|
+
* @param {Object} options.deps.output - Output utilities
|
|
431
|
+
* @param {Function} [options.deps.onServerReady] - Server ready callback
|
|
432
|
+
*/
|
|
433
|
+
export async function initializeDaemon({
|
|
434
|
+
initOptions,
|
|
435
|
+
deps
|
|
436
|
+
}) {
|
|
437
|
+
let {
|
|
438
|
+
serverManager,
|
|
439
|
+
createError,
|
|
440
|
+
output,
|
|
441
|
+
onServerReady
|
|
442
|
+
} = deps;
|
|
443
|
+
let validation = validateDaemonMode(initOptions);
|
|
444
|
+
if (!validation.valid) {
|
|
445
|
+
throw createError(validation.error, 'INVALID_MODE');
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
let setBaseline = normalizeSetBaseline(initOptions);
|
|
449
|
+
await serverManager.start(null, true, setBaseline);
|
|
450
|
+
if (onServerReady) {
|
|
451
|
+
onServerReady({
|
|
452
|
+
port: initOptions.port,
|
|
453
|
+
mode: 'daemon',
|
|
454
|
+
tdd: true
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
} catch (error) {
|
|
458
|
+
output.error('Failed to initialize TDD daemon server:', error);
|
|
459
|
+
throw error;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Cancel running tests
|
|
465
|
+
* @param {Object} options - Options
|
|
466
|
+
* @param {Object|null} options.testProcess - Running test process
|
|
467
|
+
* @param {Object} options.deps - Dependencies
|
|
468
|
+
* @param {Object} options.deps.serverManager - Server manager
|
|
469
|
+
*/
|
|
470
|
+
export async function cancelTests({
|
|
471
|
+
testProcess,
|
|
472
|
+
deps
|
|
473
|
+
}) {
|
|
474
|
+
let {
|
|
475
|
+
serverManager
|
|
476
|
+
} = deps;
|
|
477
|
+
if (testProcess && !testProcess.killed) {
|
|
478
|
+
testProcess.kill('SIGKILL');
|
|
479
|
+
}
|
|
480
|
+
if (serverManager) {
|
|
481
|
+
await serverManager.stop();
|
|
482
|
+
}
|
|
483
|
+
}
|
package/dist/types/client.d.ts
CHANGED
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
* await vizzlyScreenshot('homepage', './screenshots/homepage.png');
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
|
-
* // With properties and
|
|
26
|
+
* // With properties and comparison settings
|
|
27
27
|
* await vizzlyScreenshot('checkout-form', screenshot, {
|
|
28
28
|
* properties: { browser: 'chrome', viewport: '1920x1080' },
|
|
29
|
-
* threshold: 5
|
|
29
|
+
* threshold: 5,
|
|
30
|
+
* minClusterSize: 10
|
|
30
31
|
* });
|
|
31
32
|
*/
|
|
32
33
|
export function vizzlyScreenshot(
|
|
@@ -35,6 +36,7 @@ export function vizzlyScreenshot(
|
|
|
35
36
|
options?: {
|
|
36
37
|
properties?: Record<string, unknown>;
|
|
37
38
|
threshold?: number;
|
|
39
|
+
minClusterSize?: number;
|
|
38
40
|
fullPage?: boolean;
|
|
39
41
|
}
|
|
40
42
|
): Promise<void>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ export interface VizzlyConfig {
|
|
|
54
54
|
upload?: UploadConfig;
|
|
55
55
|
comparison?: ComparisonConfig;
|
|
56
56
|
tdd?: TddConfig;
|
|
57
|
+
/** Custom properties for baseline matching (e.g., ['theme', 'device']) */
|
|
58
|
+
signatureProperties?: string[];
|
|
57
59
|
plugins?: string[];
|
|
58
60
|
parallelId?: string;
|
|
59
61
|
baselineBuildId?: string;
|
|
@@ -72,6 +74,7 @@ export interface VizzlyConfig {
|
|
|
72
74
|
export interface ScreenshotOptions {
|
|
73
75
|
properties?: Record<string, unknown>;
|
|
74
76
|
threshold?: number;
|
|
77
|
+
minClusterSize?: number;
|
|
75
78
|
fullPage?: boolean;
|
|
76
79
|
buildId?: string;
|
|
77
80
|
}
|
|
@@ -97,6 +100,7 @@ export interface ComparisonResult {
|
|
|
97
100
|
properties: Record<string, unknown>;
|
|
98
101
|
signature: string;
|
|
99
102
|
threshold?: number;
|
|
103
|
+
minClusterSize?: number;
|
|
100
104
|
diffPercentage?: number;
|
|
101
105
|
diffCount?: number;
|
|
102
106
|
error?: string;
|
|
@@ -465,6 +469,7 @@ export function vizzlyScreenshot(
|
|
|
465
469
|
options?: {
|
|
466
470
|
properties?: Record<string, unknown>;
|
|
467
471
|
threshold?: number;
|
|
472
|
+
minClusterSize?: number;
|
|
468
473
|
fullPage?: boolean;
|
|
469
474
|
}
|
|
470
475
|
): Promise<void>;
|