@vizzly-testing/cli 0.5.0 → 0.7.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 +55 -9
- package/dist/cli.js +15 -2
- package/dist/commands/finalize.js +72 -0
- package/dist/commands/run.js +59 -19
- package/dist/commands/tdd.js +6 -13
- package/dist/commands/upload.js +1 -0
- package/dist/server/handlers/tdd-handler.js +82 -8
- package/dist/services/api-service.js +14 -0
- package/dist/services/html-report-generator.js +377 -0
- package/dist/services/report-generator/report.css +355 -0
- package/dist/services/report-generator/viewer.js +100 -0
- package/dist/services/server-manager.js +3 -2
- package/dist/services/tdd-service.js +436 -66
- package/dist/services/test-runner.js +56 -28
- package/dist/services/uploader.js +3 -2
- package/dist/types/commands/finalize.d.ts +13 -0
- package/dist/types/server/handlers/tdd-handler.d.ts +18 -1
- package/dist/types/services/api-service.d.ts +6 -0
- package/dist/types/services/html-report-generator.d.ts +52 -0
- package/dist/types/services/report-generator/viewer.d.ts +0 -0
- package/dist/types/services/server-manager.d.ts +19 -1
- package/dist/types/services/tdd-service.d.ts +24 -3
- package/dist/types/services/uploader.d.ts +2 -1
- package/dist/types/utils/config-loader.d.ts +3 -0
- package/dist/types/utils/environment-config.d.ts +5 -0
- package/dist/types/utils/security.d.ts +29 -0
- package/dist/utils/config-loader.js +11 -1
- package/dist/utils/environment-config.js +9 -0
- package/dist/utils/security.js +154 -0
- package/docs/api-reference.md +27 -0
- package/docs/tdd-mode.md +58 -12
- package/docs/test-integration.md +69 -0
- package/package.json +3 -2
|
@@ -39,10 +39,11 @@ export class TestRunner extends BaseService {
|
|
|
39
39
|
screenshotsCaptured: 0
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
let buildUrl = null;
|
|
43
|
+
let screenshotCount = 0;
|
|
44
|
+
let testSuccess = false;
|
|
45
|
+
let testError = null;
|
|
42
46
|
try {
|
|
43
|
-
let buildUrl = null;
|
|
44
|
-
let screenshotCount = 0;
|
|
45
|
-
|
|
46
47
|
// Create build based on mode
|
|
47
48
|
buildId = await this.createBuild(options, tdd);
|
|
48
49
|
if (!tdd && buildId) {
|
|
@@ -62,7 +63,7 @@ export class TestRunner extends BaseService {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
// Start server with appropriate handler
|
|
65
|
-
await this.serverManager.start(buildId, tdd);
|
|
66
|
+
await this.serverManager.start(buildId, tdd, options.setBaseline);
|
|
66
67
|
|
|
67
68
|
// Forward server events
|
|
68
69
|
if (this.serverManager.server?.emitter) {
|
|
@@ -78,28 +79,46 @@ export class TestRunner extends BaseService {
|
|
|
78
79
|
VIZZLY_ENABLED: 'true',
|
|
79
80
|
VIZZLY_SET_BASELINE: options.setBaseline || options['set-baseline'] ? 'true' : 'false'
|
|
80
81
|
};
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
url: buildUrl,
|
|
89
|
-
testsPassed: 1,
|
|
90
|
-
testsFailed: 0,
|
|
91
|
-
screenshotsCaptured: screenshotCount
|
|
92
|
-
};
|
|
82
|
+
try {
|
|
83
|
+
await this.executeTestCommand(testCommand, env);
|
|
84
|
+
testSuccess = true;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
testError = error;
|
|
87
|
+
testSuccess = false;
|
|
88
|
+
}
|
|
93
89
|
} catch (error) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const executionTime = Date.now() - startTime;
|
|
98
|
-
await this.finalizeBuild(buildId, tdd, false, executionTime);
|
|
99
|
-
throw error;
|
|
90
|
+
// Error in setup phase
|
|
91
|
+
testError = error;
|
|
92
|
+
testSuccess = false;
|
|
100
93
|
} finally {
|
|
101
|
-
|
|
94
|
+
// Always finalize the build and stop the server
|
|
95
|
+
const executionTime = Date.now() - startTime;
|
|
96
|
+
if (buildId) {
|
|
97
|
+
try {
|
|
98
|
+
await this.finalizeBuild(buildId, tdd, testSuccess, executionTime);
|
|
99
|
+
} catch (finalizeError) {
|
|
100
|
+
this.logger.error('Failed to finalize build:', finalizeError);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
await this.serverManager.stop();
|
|
105
|
+
} catch (stopError) {
|
|
106
|
+
this.logger.error('Failed to stop server:', stopError);
|
|
107
|
+
}
|
|
102
108
|
}
|
|
109
|
+
|
|
110
|
+
// If there was a test error, throw it now (after cleanup)
|
|
111
|
+
if (testError) {
|
|
112
|
+
this.logger.error('Test run failed:', testError);
|
|
113
|
+
throw testError;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
buildId: buildId,
|
|
117
|
+
url: buildUrl,
|
|
118
|
+
testsPassed: testSuccess ? 1 : 0,
|
|
119
|
+
testsFailed: testSuccess ? 0 : 1,
|
|
120
|
+
screenshotsCaptured: screenshotCount
|
|
121
|
+
};
|
|
103
122
|
}
|
|
104
123
|
async createBuild(options, tdd) {
|
|
105
124
|
if (tdd) {
|
|
@@ -119,7 +138,8 @@ export class TestRunner extends BaseService {
|
|
|
119
138
|
environment: options.environment || 'test',
|
|
120
139
|
commit_sha: options.commit,
|
|
121
140
|
commit_message: options.message,
|
|
122
|
-
github_pull_request_number: options.pullRequestNumber
|
|
141
|
+
github_pull_request_number: options.pullRequestNumber,
|
|
142
|
+
parallel_id: options.parallelId
|
|
123
143
|
});
|
|
124
144
|
this.logger.debug(`Build created with ID: ${buildResult.id}`);
|
|
125
145
|
|
|
@@ -190,8 +210,11 @@ export class TestRunner extends BaseService {
|
|
|
190
210
|
this.testProcess.on('error', error => {
|
|
191
211
|
reject(new VizzlyError(`Failed to run test command: ${error.message}`), 'TEST_COMMAND_FAILED');
|
|
192
212
|
});
|
|
193
|
-
this.testProcess.on('exit', code => {
|
|
194
|
-
|
|
213
|
+
this.testProcess.on('exit', (code, signal) => {
|
|
214
|
+
// If process was killed by SIGINT, treat as interruption
|
|
215
|
+
if (signal === 'SIGINT') {
|
|
216
|
+
reject(new VizzlyError('Test command was interrupted', 'TEST_COMMAND_INTERRUPTED'));
|
|
217
|
+
} else if (code !== 0) {
|
|
195
218
|
reject(new VizzlyError(`Test command exited with code ${code}`, 'TEST_COMMAND_FAILED'));
|
|
196
219
|
} else {
|
|
197
220
|
resolve();
|
|
@@ -200,8 +223,13 @@ export class TestRunner extends BaseService {
|
|
|
200
223
|
});
|
|
201
224
|
}
|
|
202
225
|
async cancel() {
|
|
203
|
-
if (this.testProcess) {
|
|
204
|
-
this.testProcess.kill('
|
|
226
|
+
if (this.testProcess && !this.testProcess.killed) {
|
|
227
|
+
this.testProcess.kill('SIGKILL');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Stop server manager if running
|
|
231
|
+
if (this.serverManager) {
|
|
232
|
+
await this.serverManager.stop();
|
|
205
233
|
}
|
|
206
234
|
}
|
|
207
235
|
}
|
|
@@ -51,6 +51,7 @@ export function createUploader({
|
|
|
51
51
|
environment = 'production',
|
|
52
52
|
threshold,
|
|
53
53
|
pullRequestNumber,
|
|
54
|
+
parallelId,
|
|
54
55
|
onProgress = () => {}
|
|
55
56
|
}) {
|
|
56
57
|
try {
|
|
@@ -101,7 +102,8 @@ export function createUploader({
|
|
|
101
102
|
commit_message: message,
|
|
102
103
|
environment,
|
|
103
104
|
threshold,
|
|
104
|
-
github_pull_request_number: pullRequestNumber
|
|
105
|
+
github_pull_request_number: pullRequestNumber,
|
|
106
|
+
parallel_id: parallelId
|
|
105
107
|
};
|
|
106
108
|
const build = await api.createBuild(buildInfo);
|
|
107
109
|
const buildId = build.id;
|
|
@@ -219,7 +221,6 @@ export function createUploader({
|
|
|
219
221
|
if (build.status === 'failed') {
|
|
220
222
|
throw new UploadError(`Build failed: ${build.error || 'Unknown error'}`);
|
|
221
223
|
}
|
|
222
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
223
224
|
}
|
|
224
225
|
throw new TimeoutError(`Build timed out after ${timeout}ms`, {
|
|
225
226
|
buildId,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finalize command implementation
|
|
3
|
+
* @param {string} parallelId - Parallel ID to finalize
|
|
4
|
+
* @param {Object} options - Command options
|
|
5
|
+
* @param {Object} globalOptions - Global CLI options
|
|
6
|
+
*/
|
|
7
|
+
export function finalizeCommand(parallelId: string, options?: any, globalOptions?: any): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Validate finalize options
|
|
10
|
+
* @param {string} parallelId - Parallel ID to finalize
|
|
11
|
+
* @param {Object} options - Command options
|
|
12
|
+
*/
|
|
13
|
+
export function validateFinalizeOptions(parallelId: string, _options: any): string[];
|
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
export function createTddHandler(config: any, workingDir: any, baselineBuild: any, baselineComparison: any): {
|
|
1
|
+
export function createTddHandler(config: any, workingDir: any, baselineBuild: any, baselineComparison: any, setBaseline?: boolean): {
|
|
2
2
|
initialize: () => Promise<void>;
|
|
3
3
|
registerBuild: (buildId: any) => void;
|
|
4
4
|
handleScreenshot: (buildId: any, name: any, image: any, properties?: {}) => Promise<{
|
|
5
|
+
statusCode: number;
|
|
6
|
+
body: {
|
|
7
|
+
error: string;
|
|
8
|
+
details: any;
|
|
9
|
+
tddMode: boolean;
|
|
10
|
+
comparison?: undefined;
|
|
11
|
+
status?: undefined;
|
|
12
|
+
message?: undefined;
|
|
13
|
+
success?: undefined;
|
|
14
|
+
};
|
|
15
|
+
} | {
|
|
5
16
|
statusCode: number;
|
|
6
17
|
body: {
|
|
7
18
|
error: string;
|
|
@@ -12,6 +23,8 @@ export function createTddHandler(config: any, workingDir: any, baselineBuild: an
|
|
|
12
23
|
baseline: any;
|
|
13
24
|
current: any;
|
|
14
25
|
diff: any;
|
|
26
|
+
diffPercentage: any;
|
|
27
|
+
threshold: any;
|
|
15
28
|
};
|
|
16
29
|
tddMode: boolean;
|
|
17
30
|
status?: undefined;
|
|
@@ -29,6 +42,8 @@ export function createTddHandler(config: any, workingDir: any, baselineBuild: an
|
|
|
29
42
|
baseline: any;
|
|
30
43
|
current: any;
|
|
31
44
|
diff?: undefined;
|
|
45
|
+
diffPercentage?: undefined;
|
|
46
|
+
threshold?: undefined;
|
|
32
47
|
};
|
|
33
48
|
tddMode: boolean;
|
|
34
49
|
error?: undefined;
|
|
@@ -56,6 +71,8 @@ export function createTddHandler(config: any, workingDir: any, baselineBuild: an
|
|
|
56
71
|
baseline?: undefined;
|
|
57
72
|
current?: undefined;
|
|
58
73
|
diff?: undefined;
|
|
74
|
+
diffPercentage?: undefined;
|
|
75
|
+
threshold?: undefined;
|
|
59
76
|
};
|
|
60
77
|
tddMode: boolean;
|
|
61
78
|
error?: undefined;
|
|
@@ -76,4 +76,10 @@ export class ApiService {
|
|
|
76
76
|
* @returns {Promise<Object>} Token context data
|
|
77
77
|
*/
|
|
78
78
|
getTokenContext(): Promise<any>;
|
|
79
|
+
/**
|
|
80
|
+
* Finalize a parallel build
|
|
81
|
+
* @param {string} parallelId - Parallel ID to finalize
|
|
82
|
+
* @returns {Promise<Object>} Finalization result
|
|
83
|
+
*/
|
|
84
|
+
finalizeParallelBuild(parallelId: string): Promise<any>;
|
|
79
85
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export class HtmlReportGenerator {
|
|
2
|
+
constructor(workingDir: any, config: any);
|
|
3
|
+
workingDir: any;
|
|
4
|
+
config: any;
|
|
5
|
+
reportDir: string;
|
|
6
|
+
reportPath: string;
|
|
7
|
+
cssPath: string;
|
|
8
|
+
/**
|
|
9
|
+
* Sanitize HTML content to prevent XSS attacks
|
|
10
|
+
* @param {string} text - Text to sanitize
|
|
11
|
+
* @returns {string} Sanitized text
|
|
12
|
+
*/
|
|
13
|
+
sanitizeHtml(text: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Sanitize build info object
|
|
16
|
+
* @param {Object} buildInfo - Build information to sanitize
|
|
17
|
+
* @returns {Object} Sanitized build info
|
|
18
|
+
*/
|
|
19
|
+
sanitizeBuildInfo(buildInfo?: any): any;
|
|
20
|
+
/**
|
|
21
|
+
* Generate HTML report from TDD results
|
|
22
|
+
* @param {Object} results - TDD comparison results
|
|
23
|
+
* @param {Object} buildInfo - Build information
|
|
24
|
+
* @returns {string} Path to generated report
|
|
25
|
+
*/
|
|
26
|
+
generateReport(results: any, buildInfo?: any): string;
|
|
27
|
+
/**
|
|
28
|
+
* Process comparison data for HTML report
|
|
29
|
+
* @param {Object} comparison - Comparison object
|
|
30
|
+
* @returns {Object} Processed comparison data
|
|
31
|
+
*/
|
|
32
|
+
processComparison(comparison: any): any;
|
|
33
|
+
/**
|
|
34
|
+
* Get relative path from report directory to image file
|
|
35
|
+
* @param {string} imagePath - Absolute path to image
|
|
36
|
+
* @param {string} reportDir - Report directory path
|
|
37
|
+
* @returns {string|null} Relative path or null if invalid
|
|
38
|
+
*/
|
|
39
|
+
getRelativePath(imagePath: string, reportDir: string): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Generate the complete HTML template
|
|
42
|
+
* @param {Object} data - Report data
|
|
43
|
+
* @returns {string} HTML content
|
|
44
|
+
*/
|
|
45
|
+
generateHtmlTemplate(data: any): string;
|
|
46
|
+
/**
|
|
47
|
+
* Generate HTML for a single comparison
|
|
48
|
+
* @param {Object} comparison - Comparison data
|
|
49
|
+
* @returns {string} HTML content
|
|
50
|
+
*/
|
|
51
|
+
generateComparisonHtml(comparison: any): string;
|
|
52
|
+
}
|
|
File without changes
|
|
@@ -9,6 +9,17 @@ export class ServerManager extends BaseService {
|
|
|
9
9
|
initialize: () => Promise<void>;
|
|
10
10
|
registerBuild: (buildId: any) => void;
|
|
11
11
|
handleScreenshot: (buildId: any, name: any, image: any, properties?: {}) => Promise<{
|
|
12
|
+
statusCode: number;
|
|
13
|
+
body: {
|
|
14
|
+
error: string;
|
|
15
|
+
details: any;
|
|
16
|
+
tddMode: boolean;
|
|
17
|
+
comparison?: undefined;
|
|
18
|
+
status?: undefined;
|
|
19
|
+
message?: undefined;
|
|
20
|
+
success?: undefined;
|
|
21
|
+
};
|
|
22
|
+
} | {
|
|
12
23
|
statusCode: number;
|
|
13
24
|
body: {
|
|
14
25
|
error: string;
|
|
@@ -19,6 +30,8 @@ export class ServerManager extends BaseService {
|
|
|
19
30
|
baseline: any;
|
|
20
31
|
current: any;
|
|
21
32
|
diff: any;
|
|
33
|
+
diffPercentage: any;
|
|
34
|
+
threshold: any;
|
|
22
35
|
};
|
|
23
36
|
tddMode: boolean;
|
|
24
37
|
status?: undefined;
|
|
@@ -36,6 +49,8 @@ export class ServerManager extends BaseService {
|
|
|
36
49
|
baseline: any;
|
|
37
50
|
current: any;
|
|
38
51
|
diff?: undefined;
|
|
52
|
+
diffPercentage?: undefined;
|
|
53
|
+
threshold?: undefined;
|
|
39
54
|
};
|
|
40
55
|
tddMode: boolean;
|
|
41
56
|
error?: undefined;
|
|
@@ -63,6 +78,8 @@ export class ServerManager extends BaseService {
|
|
|
63
78
|
baseline?: undefined;
|
|
64
79
|
current?: undefined;
|
|
65
80
|
diff?: undefined;
|
|
81
|
+
diffPercentage?: undefined;
|
|
82
|
+
threshold?: undefined;
|
|
66
83
|
};
|
|
67
84
|
tddMode: boolean;
|
|
68
85
|
error?: undefined;
|
|
@@ -139,9 +156,10 @@ export class ServerManager extends BaseService {
|
|
|
139
156
|
cleanup: () => void;
|
|
140
157
|
};
|
|
141
158
|
emitter: EventEmitter<[never]>;
|
|
142
|
-
start(buildId?: any, tddMode?: boolean): Promise<void>;
|
|
159
|
+
start(buildId?: any, tddMode?: boolean, setBaseline?: boolean): Promise<void>;
|
|
143
160
|
buildId: any;
|
|
144
161
|
tddMode: boolean;
|
|
162
|
+
setBaseline: boolean;
|
|
145
163
|
createApiService(): Promise<import("./api-service.js").ApiService>;
|
|
146
164
|
get server(): {
|
|
147
165
|
emitter: EventEmitter<[never]>;
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export function createTDDService(config: any, options?: {}): TddService;
|
|
5
5
|
export class TddService {
|
|
6
|
-
constructor(config: any, workingDir?: string);
|
|
6
|
+
constructor(config: any, workingDir?: string, setBaseline?: boolean);
|
|
7
7
|
config: any;
|
|
8
|
+
setBaseline: boolean;
|
|
8
9
|
api: ApiService;
|
|
9
10
|
workingDir: string;
|
|
10
11
|
baselinePath: string;
|
|
@@ -14,6 +15,11 @@ export class TddService {
|
|
|
14
15
|
comparisons: any[];
|
|
15
16
|
threshold: any;
|
|
16
17
|
downloadBaselines(environment?: string, branch?: any, buildId?: any, comparisonId?: any): Promise<any>;
|
|
18
|
+
/**
|
|
19
|
+
* Handle local baseline logic (either load existing or prepare for new baselines)
|
|
20
|
+
* @returns {Promise<Object|null>} Baseline data or null if no local baselines exist
|
|
21
|
+
*/
|
|
22
|
+
handleLocalBaselines(): Promise<any | null>;
|
|
17
23
|
loadBaseline(): Promise<any>;
|
|
18
24
|
compareScreenshot(name: any, imageBuffer: any, properties?: {}): Promise<{
|
|
19
25
|
name: any;
|
|
@@ -32,7 +38,7 @@ export class TddService {
|
|
|
32
38
|
comparisons: any[];
|
|
33
39
|
baseline: any;
|
|
34
40
|
};
|
|
35
|
-
printResults(): {
|
|
41
|
+
printResults(): Promise<{
|
|
36
42
|
total: number;
|
|
37
43
|
passed: number;
|
|
38
44
|
failed: number;
|
|
@@ -40,12 +46,27 @@ export class TddService {
|
|
|
40
46
|
errors: number;
|
|
41
47
|
comparisons: any[];
|
|
42
48
|
baseline: any;
|
|
43
|
-
}
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Generate HTML report for TDD results
|
|
52
|
+
* @param {Object} results - TDD comparison results
|
|
53
|
+
*/
|
|
54
|
+
generateHtmlReport(results: any): Promise<string>;
|
|
55
|
+
/**
|
|
56
|
+
* Open HTML report in default browser
|
|
57
|
+
* @param {string} reportPath - Path to HTML report
|
|
58
|
+
*/
|
|
59
|
+
openReport(reportPath: string): Promise<void>;
|
|
44
60
|
/**
|
|
45
61
|
* Update baselines with current screenshots (accept changes)
|
|
46
62
|
* @returns {number} Number of baselines updated
|
|
47
63
|
*/
|
|
48
64
|
updateBaselines(): number;
|
|
65
|
+
/**
|
|
66
|
+
* Create a new baseline (used during --set-baseline mode)
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
private createNewBaseline;
|
|
49
70
|
/**
|
|
50
71
|
* Update a single baseline with current screenshot
|
|
51
72
|
* @private
|
|
@@ -8,7 +8,7 @@ export function createUploader({ apiKey, apiUrl, userAgent, command, upload: upl
|
|
|
8
8
|
command: any;
|
|
9
9
|
upload?: {};
|
|
10
10
|
}, options?: {}): {
|
|
11
|
-
upload: ({ screenshotsDir, buildName, branch, commit, message, environment, threshold, pullRequestNumber, onProgress, }: {
|
|
11
|
+
upload: ({ screenshotsDir, buildName, branch, commit, message, environment, threshold, pullRequestNumber, parallelId, onProgress, }: {
|
|
12
12
|
screenshotsDir: any;
|
|
13
13
|
buildName: any;
|
|
14
14
|
branch: any;
|
|
@@ -17,6 +17,7 @@ export function createUploader({ apiKey, apiUrl, userAgent, command, upload: upl
|
|
|
17
17
|
environment?: string;
|
|
18
18
|
threshold: any;
|
|
19
19
|
pullRequestNumber: any;
|
|
20
|
+
parallelId: any;
|
|
20
21
|
onProgress?: () => void;
|
|
21
22
|
}) => Promise<{
|
|
22
23
|
success: boolean;
|
|
@@ -37,6 +37,11 @@ export function getServerUrl(): string | undefined;
|
|
|
37
37
|
* @returns {string|undefined} Build ID
|
|
38
38
|
*/
|
|
39
39
|
export function getBuildId(): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Get parallel ID from environment
|
|
42
|
+
* @returns {string|undefined} Parallel ID
|
|
43
|
+
*/
|
|
44
|
+
export function getParallelId(): string | undefined;
|
|
40
45
|
/**
|
|
41
46
|
* Check if TDD mode is enabled
|
|
42
47
|
* @returns {boolean} Whether TDD mode is enabled
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitizes a screenshot name to prevent path traversal and ensure safe file naming
|
|
3
|
+
* @param {string} name - Original screenshot name
|
|
4
|
+
* @param {number} maxLength - Maximum allowed length (default: 255)
|
|
5
|
+
* @returns {string} Sanitized screenshot name
|
|
6
|
+
*/
|
|
7
|
+
export function sanitizeScreenshotName(name: string, maxLength?: number): string;
|
|
8
|
+
/**
|
|
9
|
+
* Validates that a path stays within the allowed working directory bounds
|
|
10
|
+
* @param {string} targetPath - Path to validate
|
|
11
|
+
* @param {string} workingDir - Working directory that serves as the security boundary
|
|
12
|
+
* @returns {string} Resolved and normalized path if valid
|
|
13
|
+
* @throws {Error} If path is invalid or outside bounds
|
|
14
|
+
*/
|
|
15
|
+
export function validatePathSecurity(targetPath: string, workingDir: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Safely constructs a path within the working directory
|
|
18
|
+
* @param {string} workingDir - Base working directory
|
|
19
|
+
* @param {...string} pathSegments - Path segments to join
|
|
20
|
+
* @returns {string} Safely constructed path
|
|
21
|
+
* @throws {Error} If resulting path would be outside working directory
|
|
22
|
+
*/
|
|
23
|
+
export function safePath(workingDir: string, ...pathSegments: string[]): string;
|
|
24
|
+
/**
|
|
25
|
+
* Validates screenshot properties object for safe values
|
|
26
|
+
* @param {Object} properties - Properties to validate
|
|
27
|
+
* @returns {Object} Validated properties object
|
|
28
|
+
*/
|
|
29
|
+
export function validateScreenshotProperties(properties?: any): any;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cosmiconfigSync } from 'cosmiconfig';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
-
import { getApiToken, getApiUrl } from './environment-config.js';
|
|
3
|
+
import { getApiToken, getApiUrl, getParallelId } from './environment-config.js';
|
|
4
4
|
const DEFAULT_CONFIG = {
|
|
5
5
|
// API Configuration
|
|
6
6
|
apiKey: getApiToken(),
|
|
@@ -25,6 +25,10 @@ const DEFAULT_CONFIG = {
|
|
|
25
25
|
// Comparison Configuration
|
|
26
26
|
comparison: {
|
|
27
27
|
threshold: 0.1
|
|
28
|
+
},
|
|
29
|
+
// TDD Configuration
|
|
30
|
+
tdd: {
|
|
31
|
+
openReport: false // Whether to auto-open HTML report in browser
|
|
28
32
|
}
|
|
29
33
|
};
|
|
30
34
|
export async function loadConfig(configPath = null, cliOverrides = {}) {
|
|
@@ -42,6 +46,9 @@ export async function loadConfig(configPath = null, cliOverrides = {}) {
|
|
|
42
46
|
},
|
|
43
47
|
comparison: {
|
|
44
48
|
...DEFAULT_CONFIG.comparison
|
|
49
|
+
},
|
|
50
|
+
tdd: {
|
|
51
|
+
...DEFAULT_CONFIG.tdd
|
|
45
52
|
}
|
|
46
53
|
};
|
|
47
54
|
|
|
@@ -55,8 +62,10 @@ export async function loadConfig(configPath = null, cliOverrides = {}) {
|
|
|
55
62
|
// 2. Override with environment variables
|
|
56
63
|
const envApiKey = getApiToken();
|
|
57
64
|
const envApiUrl = getApiUrl();
|
|
65
|
+
const envParallelId = getParallelId();
|
|
58
66
|
if (envApiKey) config.apiKey = envApiKey;
|
|
59
67
|
if (envApiUrl !== 'https://vizzly.dev') config.apiUrl = envApiUrl;
|
|
68
|
+
if (envParallelId) config.parallelId = envParallelId;
|
|
60
69
|
|
|
61
70
|
// 3. Apply CLI overrides (highest priority)
|
|
62
71
|
applyCLIOverrides(config, cliOverrides);
|
|
@@ -78,6 +87,7 @@ function applyCLIOverrides(config, cliOverrides = {}) {
|
|
|
78
87
|
if (cliOverrides.branch) config.build.branch = cliOverrides.branch;
|
|
79
88
|
if (cliOverrides.commit) config.build.commit = cliOverrides.commit;
|
|
80
89
|
if (cliOverrides.message) config.build.message = cliOverrides.message;
|
|
90
|
+
if (cliOverrides.parallelId) config.parallelId = cliOverrides.parallelId;
|
|
81
91
|
|
|
82
92
|
// Server overrides
|
|
83
93
|
if (cliOverrides.port) config.server.port = parseInt(cliOverrides.port, 10);
|
|
@@ -59,6 +59,14 @@ export function getBuildId() {
|
|
|
59
59
|
return process.env.VIZZLY_BUILD_ID;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Get parallel ID from environment
|
|
64
|
+
* @returns {string|undefined} Parallel ID
|
|
65
|
+
*/
|
|
66
|
+
export function getParallelId() {
|
|
67
|
+
return process.env.VIZZLY_PARALLEL_ID;
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
/**
|
|
63
71
|
* Check if TDD mode is enabled
|
|
64
72
|
* @returns {boolean} Whether TDD mode is enabled
|
|
@@ -88,6 +96,7 @@ export function getAllEnvironmentConfig() {
|
|
|
88
96
|
enabled: isVizzlyEnabled(),
|
|
89
97
|
serverUrl: getServerUrl(),
|
|
90
98
|
buildId: getBuildId(),
|
|
99
|
+
parallelId: getParallelId(),
|
|
91
100
|
tddMode: isTddMode()
|
|
92
101
|
};
|
|
93
102
|
}
|