@appliqation/automation-sdk 2.1.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/LICENSE +21 -0
- package/README.md +441 -0
- package/package.json +107 -0
- package/src/AppliqationClient.js +562 -0
- package/src/constants.js +245 -0
- package/src/core/AuthManager.js +353 -0
- package/src/core/HttpClient.js +475 -0
- package/src/index.d.ts +333 -0
- package/src/index.js +26 -0
- package/src/playwright/JwtBrowserAuth.js +240 -0
- package/src/playwright/fixture.js +92 -0
- package/src/playwright/global-setup.js +243 -0
- package/src/playwright/helpers/jwt-browser-auth.js +227 -0
- package/src/playwright/index.js +16 -0
- package/src/reporters/cypress/CypressReporter.js +387 -0
- package/src/reporters/cypress/UuidExtractor.js +139 -0
- package/src/reporters/cypress/index.js +30 -0
- package/src/reporters/jest/JestReporter.js +361 -0
- package/src/reporters/jest/UuidExtractor.js +174 -0
- package/src/reporters/jest/index.js +28 -0
- package/src/reporters/playwright/AppliqationReporter.js +654 -0
- package/src/reporters/playwright/helpers/DeviceOsDetector.js +435 -0
- package/src/reporters/playwright/helpers/UuidExtractor.js +290 -0
- package/src/reporters/playwright/index.d.ts +96 -0
- package/src/reporters/playwright/index.js +14 -0
- package/src/services/OrphanTestService.js +74 -0
- package/src/services/ResultService.js +252 -0
- package/src/services/RunMatrixService.js +309 -0
- package/src/utils/PayloadBuilder.js +280 -0
- package/src/utils/RunDataNormalizer.js +335 -0
- package/src/utils/UuidValidator.js +102 -0
- package/src/utils/errors.js +217 -0
- package/src/utils/index.js +17 -0
- package/src/utils/logger.js +124 -0
- package/src/utils/mapAppqUuid.js +83 -0
- package/src/utils/validator.js +157 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
const AppliqationClient = require('../../AppliqationClient');
|
|
2
|
+
const UuidExtractor = require('./UuidExtractor');
|
|
3
|
+
const logger = require('../../utils/logger');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Appliqation Reporter for Cypress
|
|
7
|
+
*
|
|
8
|
+
* Integrates with Cypress via setupNodeEvents hooks to automatically
|
|
9
|
+
* report test results to Appliqation platform.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // cypress.config.js
|
|
13
|
+
* const { CypressReporter } = require('@appliqation/automation-sdk/cypress');
|
|
14
|
+
*
|
|
15
|
+
* module.exports = defineConfig({
|
|
16
|
+
* e2e: {
|
|
17
|
+
* setupNodeEvents(on, config) {
|
|
18
|
+
* CypressReporter(on, {
|
|
19
|
+
* baseUrl: process.env.APPLIQATION_BASE_URL,
|
|
20
|
+
* apiKey: process.env.APPLIQATION_API_KEY,
|
|
21
|
+
* projectKey: process.env.APPLIQATION_PROJECT_KEY,
|
|
22
|
+
* scenarioId: parseInt(process.env.APPLIQATION_SCENARIO_ID),
|
|
23
|
+
* environment: process.env.APPLIQATION_ENVIRONMENT || 'Local',
|
|
24
|
+
* title: process.env.APPLIQATION_RUN_TITLE
|
|
25
|
+
* });
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* });
|
|
29
|
+
*/
|
|
30
|
+
class CypressReporter {
|
|
31
|
+
constructor(config) {
|
|
32
|
+
this.config = {
|
|
33
|
+
baseUrl: config.baseUrl,
|
|
34
|
+
apiKey: config.apiKey,
|
|
35
|
+
projectKey: config.projectKey,
|
|
36
|
+
scenarioId: config.scenarioId,
|
|
37
|
+
testSetId: config.testSetId,
|
|
38
|
+
environment: config.environment || 'Local',
|
|
39
|
+
title: config.title || process.env.APPLIQATION_RUN_TITLE,
|
|
40
|
+
autoCreateRun: config.autoCreateRun !== false,
|
|
41
|
+
logLevel: config.logLevel || 'info',
|
|
42
|
+
submitOrphans: config.submitOrphans !== false
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Validate required config
|
|
46
|
+
this.validateConfig();
|
|
47
|
+
|
|
48
|
+
// Set logger level
|
|
49
|
+
logger.setLevel(this.config.logLevel);
|
|
50
|
+
|
|
51
|
+
// Initialize Appliqation client
|
|
52
|
+
this.client = new AppliqationClient({
|
|
53
|
+
baseUrl: this.config.baseUrl,
|
|
54
|
+
apiKey: this.config.apiKey,
|
|
55
|
+
projectKey: this.config.projectKey,
|
|
56
|
+
title: this.config.title,
|
|
57
|
+
options: {
|
|
58
|
+
logLevel: this.config.logLevel
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Test result storage
|
|
63
|
+
this.testResults = [];
|
|
64
|
+
this.orphanTests = [];
|
|
65
|
+
this.runId = null;
|
|
66
|
+
this.runCreated = false;
|
|
67
|
+
|
|
68
|
+
logger.info('Appliqation Cypress Reporter initialized', {
|
|
69
|
+
environment: this.config.environment,
|
|
70
|
+
scenarioId: this.config.scenarioId,
|
|
71
|
+
autoCreateRun: this.config.autoCreateRun
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Register Cypress event handlers
|
|
77
|
+
* @param {Object} on - Cypress event registration function
|
|
78
|
+
*/
|
|
79
|
+
register(on) {
|
|
80
|
+
// Event: Before all specs run
|
|
81
|
+
on('before:run', async (details) => {
|
|
82
|
+
await this.onBeforeRun(details);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Event: After each spec file completes
|
|
86
|
+
on('after:spec', async (spec, results) => {
|
|
87
|
+
await this.onAfterSpec(spec, results);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Event: After all specs complete
|
|
91
|
+
on('after:run', async (results) => {
|
|
92
|
+
await this.onAfterRun(results);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
logger.debug('Cypress event handlers registered');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Called before test run starts
|
|
100
|
+
*/
|
|
101
|
+
async onBeforeRun(details) {
|
|
102
|
+
try {
|
|
103
|
+
logger.info('Cypress test run starting...', {
|
|
104
|
+
browser: details.browser?.displayName,
|
|
105
|
+
specs: details.specs?.length
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (this.config.autoCreateRun) {
|
|
109
|
+
await this.createRun(details);
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
logger.error('Error in before:run hook', { error: error.message });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create Appliqation run matrix
|
|
118
|
+
*/
|
|
119
|
+
async createRun(details) {
|
|
120
|
+
try {
|
|
121
|
+
const browser = details.browser?.displayName || details.browser?.name || 'Cypress';
|
|
122
|
+
const platform = details.system?.platform || process.platform;
|
|
123
|
+
const os = this.detectOS(platform);
|
|
124
|
+
|
|
125
|
+
const runOptions = {
|
|
126
|
+
scenarioId: this.config.scenarioId,
|
|
127
|
+
testSetId: this.config.testSetId,
|
|
128
|
+
environment: this.config.environment,
|
|
129
|
+
browsers: [browser],
|
|
130
|
+
device: 'Desktop',
|
|
131
|
+
os: os,
|
|
132
|
+
title: this.config.title || `Automation Run - ${new Date().toISOString()}`
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
logger.info('Creating run matrix...', runOptions);
|
|
136
|
+
|
|
137
|
+
const run = await this.client.createRun(runOptions);
|
|
138
|
+
this.runId = run.runId;
|
|
139
|
+
this.runCreated = true;
|
|
140
|
+
|
|
141
|
+
logger.info('Run matrix created successfully', {
|
|
142
|
+
runId: this.runId,
|
|
143
|
+
browser: browser
|
|
144
|
+
});
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.error('Failed to create run matrix', { error: error.message });
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Called after each spec file completes
|
|
153
|
+
*/
|
|
154
|
+
async onAfterSpec(spec, results) {
|
|
155
|
+
try {
|
|
156
|
+
logger.debug('Processing spec results', {
|
|
157
|
+
spec: spec.relative,
|
|
158
|
+
tests: results.tests?.length
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (!results.tests || results.tests.length === 0) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Extract results from all tests in this spec
|
|
166
|
+
for (const test of results.tests) {
|
|
167
|
+
await this.processTest(test, results.stats.startedAt);
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
logger.error('Error processing spec results', {
|
|
171
|
+
spec: spec.relative,
|
|
172
|
+
error: error.message
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Process individual test result
|
|
179
|
+
*/
|
|
180
|
+
async processTest(test, startedAt) {
|
|
181
|
+
try {
|
|
182
|
+
// Extract UUID from test
|
|
183
|
+
const uuid = UuidExtractor.extractUuid(test);
|
|
184
|
+
|
|
185
|
+
if (!uuid) {
|
|
186
|
+
// Track orphan test
|
|
187
|
+
this.orphanTests.push({
|
|
188
|
+
title: test.title.join(' > '),
|
|
189
|
+
status: this.mapCypressStatus(test.state),
|
|
190
|
+
file: test.file || 'unknown',
|
|
191
|
+
timestamp: new Date().toISOString()
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
logger.warn('No UUID found for test', { title: test.title.join(' > ') });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Prepare result
|
|
199
|
+
const result = {
|
|
200
|
+
uuid: uuid,
|
|
201
|
+
runId: this.runId,
|
|
202
|
+
status: this.mapCypressStatus(test.state),
|
|
203
|
+
browser: 'Cypress',
|
|
204
|
+
environment: this.config.environment,
|
|
205
|
+
comment: this.buildComment(test),
|
|
206
|
+
parent_uuid: null // Cypress doesn't have nested tests like Playwright
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
this.testResults.push(result);
|
|
210
|
+
|
|
211
|
+
logger.debug('Test result prepared', {
|
|
212
|
+
uuid: uuid,
|
|
213
|
+
status: result.status,
|
|
214
|
+
title: test.title.join(' > ')
|
|
215
|
+
});
|
|
216
|
+
} catch (error) {
|
|
217
|
+
logger.error('Error processing test', {
|
|
218
|
+
title: test.title,
|
|
219
|
+
error: error.message
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Called after all tests complete
|
|
226
|
+
*/
|
|
227
|
+
async onAfterRun(results) {
|
|
228
|
+
try {
|
|
229
|
+
logger.info('Cypress test run completed', {
|
|
230
|
+
tests: this.testResults.length,
|
|
231
|
+
orphans: this.orphanTests.length
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Submit all test results
|
|
235
|
+
if (this.testResults.length > 0 && this.runId) {
|
|
236
|
+
await this.submitResults();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Submit orphan tests
|
|
240
|
+
if (this.orphanTests.length > 0 && this.config.submitOrphans && this.runId) {
|
|
241
|
+
await this.submitOrphanTests();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Print summary
|
|
245
|
+
this.printSummary(results);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
logger.error('Error in after:run hook', { error: error.message });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Submit test results to Appliqation
|
|
253
|
+
*/
|
|
254
|
+
async submitResults() {
|
|
255
|
+
try {
|
|
256
|
+
logger.info(`Submitting ${this.testResults.length} test results...`);
|
|
257
|
+
|
|
258
|
+
const summary = await this.client.submitBatch(this.testResults, {
|
|
259
|
+
batchSize: 50,
|
|
260
|
+
retryFailures: true
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
logger.info('Results submitted successfully', {
|
|
264
|
+
success: summary.success,
|
|
265
|
+
failed: summary.failed,
|
|
266
|
+
total: summary.total
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
return summary;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
logger.error('Failed to submit results', { error: error.message });
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Submit orphan tests
|
|
278
|
+
*/
|
|
279
|
+
async submitOrphanTests() {
|
|
280
|
+
try {
|
|
281
|
+
logger.info(`Logging ${this.orphanTests.length} orphan tests...`);
|
|
282
|
+
|
|
283
|
+
await this.client.logOrphanTests(this.runId, this.orphanTests);
|
|
284
|
+
|
|
285
|
+
logger.info('Orphan tests logged successfully');
|
|
286
|
+
} catch (error) {
|
|
287
|
+
logger.error('Failed to log orphan tests', { error: error.message });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Map Cypress test status to Appliqation status
|
|
293
|
+
*/
|
|
294
|
+
mapCypressStatus(cypressStatus) {
|
|
295
|
+
const statusMap = {
|
|
296
|
+
'passed': 'passed',
|
|
297
|
+
'failed': 'failed',
|
|
298
|
+
'pending': 'skipped',
|
|
299
|
+
'skipped': 'skipped'
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
return statusMap[cypressStatus] || 'skipped';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Build comment from test details
|
|
307
|
+
*/
|
|
308
|
+
buildComment(test) {
|
|
309
|
+
const comments = [];
|
|
310
|
+
|
|
311
|
+
if (test.displayError) {
|
|
312
|
+
comments.push(`Error: ${test.displayError}`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (test.duration) {
|
|
316
|
+
comments.push(`Duration: ${test.duration}ms`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (test.attempts && test.attempts.length > 1) {
|
|
320
|
+
comments.push(`Attempts: ${test.attempts.length}`);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return comments.length > 0 ? comments.join(' | ') : null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Detect OS from platform
|
|
328
|
+
*/
|
|
329
|
+
detectOS(platform) {
|
|
330
|
+
if (!platform) return 'Unknown';
|
|
331
|
+
|
|
332
|
+
const platformLower = platform.toLowerCase();
|
|
333
|
+
|
|
334
|
+
if (platformLower.includes('darwin')) return 'macOS';
|
|
335
|
+
if (platformLower.includes('win')) return 'Windows';
|
|
336
|
+
if (platformLower.includes('linux')) return 'Linux';
|
|
337
|
+
|
|
338
|
+
return platform;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Print test summary
|
|
343
|
+
*/
|
|
344
|
+
printSummary(results) {
|
|
345
|
+
console.log('\n' + '='.repeat(60));
|
|
346
|
+
console.log('📊 Appliqation Cypress Reporter Summary');
|
|
347
|
+
console.log('='.repeat(60));
|
|
348
|
+
console.log(`Environment: ${this.config.environment}`);
|
|
349
|
+
console.log(`Run ID: ${this.runId || 'N/A'}`);
|
|
350
|
+
console.log(`Tests Submitted: ${this.testResults.length}`);
|
|
351
|
+
console.log(`Orphan Tests: ${this.orphanTests.length}`);
|
|
352
|
+
console.log(`Total Tests: ${results.totalTests || 0}`);
|
|
353
|
+
console.log(`Passed: ${results.totalPassed || 0}`);
|
|
354
|
+
console.log(`Failed: ${results.totalFailed || 0}`);
|
|
355
|
+
console.log(`Skipped: ${results.totalSkipped || 0}`);
|
|
356
|
+
console.log('='.repeat(60) + '\n');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Validate configuration
|
|
361
|
+
*/
|
|
362
|
+
validateConfig() {
|
|
363
|
+
const required = ['baseUrl', 'apiKey', 'projectKey'];
|
|
364
|
+
const missing = required.filter(key => !this.config[key]);
|
|
365
|
+
|
|
366
|
+
if (missing.length > 0) {
|
|
367
|
+
throw new Error(`Missing required config: ${missing.join(', ')}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Note: scenarioId and testSetId are now optional
|
|
371
|
+
// If neither is provided, will default to 0 for generic automation runs
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Factory function for Cypress setupNodeEvents
|
|
377
|
+
* @param {Object} on - Cypress event registration function
|
|
378
|
+
* @param {Object} config - Reporter configuration
|
|
379
|
+
*/
|
|
380
|
+
function setupCypressReporter(on, config) {
|
|
381
|
+
const reporter = new CypressReporter(config);
|
|
382
|
+
reporter.register(on);
|
|
383
|
+
return reporter;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
module.exports = setupCypressReporter;
|
|
387
|
+
module.exports.CypressReporter = CypressReporter;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const UuidValidator = require('../../utils/UuidValidator');
|
|
2
|
+
const logger = require('../../utils/logger');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* UUID Extractor for Cypress Tests
|
|
6
|
+
*
|
|
7
|
+
* Extracts Appliqation test case UUIDs from Cypress tests.
|
|
8
|
+
* Supports multiple UUID assignment methods.
|
|
9
|
+
*/
|
|
10
|
+
class UuidExtractor {
|
|
11
|
+
/**
|
|
12
|
+
* Extract UUID from Cypress test
|
|
13
|
+
*
|
|
14
|
+
* Supports multiple UUID formats:
|
|
15
|
+
* 1. Test config property: it('test', { uuid: '1154-...' }, () => {})
|
|
16
|
+
* 2. Test title with UUID: it('1154-... - should login', () => {})
|
|
17
|
+
* 3. Custom metadata (if available in future Cypress versions)
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} test - Cypress test object
|
|
20
|
+
* @returns {string|null} - Extracted UUID or null
|
|
21
|
+
*/
|
|
22
|
+
static extractUuid(test) {
|
|
23
|
+
try {
|
|
24
|
+
// Method 1: Check test config for uuid property
|
|
25
|
+
if (test.config && test.config.uuid) {
|
|
26
|
+
const uuid = test.config.uuid;
|
|
27
|
+
if (UuidValidator.validate(uuid)) {
|
|
28
|
+
logger.debug('UUID extracted from test config', { uuid });
|
|
29
|
+
return uuid;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Method 2: Check test title for UUID
|
|
34
|
+
// Title can be array in Cypress (suite hierarchy)
|
|
35
|
+
const fullTitle = Array.isArray(test.title) ? test.title.join(' ') : test.title;
|
|
36
|
+
|
|
37
|
+
if (fullTitle) {
|
|
38
|
+
const uuidFromTitle = this.extractUuidFromString(fullTitle);
|
|
39
|
+
if (uuidFromTitle) {
|
|
40
|
+
logger.debug('UUID extracted from test title', { uuid: uuidFromTitle });
|
|
41
|
+
return uuidFromTitle;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Method 3: Check individual title parts if it's an array
|
|
46
|
+
if (Array.isArray(test.title)) {
|
|
47
|
+
for (const titlePart of test.title) {
|
|
48
|
+
const uuidFromPart = this.extractUuidFromString(titlePart);
|
|
49
|
+
if (uuidFromPart) {
|
|
50
|
+
logger.debug('UUID extracted from title part', { uuid: uuidFromPart });
|
|
51
|
+
return uuidFromPart;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// No UUID found
|
|
57
|
+
return null;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logger.error('Error extracting UUID from Cypress test', {
|
|
60
|
+
error: error.message,
|
|
61
|
+
test: test.title
|
|
62
|
+
});
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Extract UUID from string using regex pattern
|
|
69
|
+
*
|
|
70
|
+
* @param {string} str - String to search
|
|
71
|
+
* @returns {string|null} - Extracted UUID or null
|
|
72
|
+
*/
|
|
73
|
+
static extractUuidFromString(str) {
|
|
74
|
+
if (!str || typeof str !== 'string') {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Pattern: nid-uuid format (e.g., "1154-7a17b809-0ff9-4ba1-9322-4eb2a49abfc5")
|
|
79
|
+
const uuidPattern = /(\d+)-([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i;
|
|
80
|
+
const match = str.match(uuidPattern);
|
|
81
|
+
|
|
82
|
+
if (match && match[0]) {
|
|
83
|
+
const uuid = match[0];
|
|
84
|
+
if (UuidValidator.validate(uuid)) {
|
|
85
|
+
return uuid;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Extract all UUIDs from a collection of tests
|
|
94
|
+
*
|
|
95
|
+
* @param {Array} tests - Array of Cypress test objects
|
|
96
|
+
* @returns {Object} - { uuids: [...], orphans: [...] }
|
|
97
|
+
*/
|
|
98
|
+
static extractFromTests(tests) {
|
|
99
|
+
const results = {
|
|
100
|
+
uuids: [],
|
|
101
|
+
orphans: []
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (!Array.isArray(tests)) {
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const test of tests) {
|
|
109
|
+
const uuid = this.extractUuid(test);
|
|
110
|
+
|
|
111
|
+
if (uuid) {
|
|
112
|
+
results.uuids.push({
|
|
113
|
+
uuid: uuid,
|
|
114
|
+
test: test
|
|
115
|
+
});
|
|
116
|
+
} else {
|
|
117
|
+
results.orphans.push({
|
|
118
|
+
title: Array.isArray(test.title) ? test.title.join(' > ') : test.title,
|
|
119
|
+
test: test
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return results;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Validate if test has a valid UUID
|
|
129
|
+
*
|
|
130
|
+
* @param {Object} test - Cypress test object
|
|
131
|
+
* @returns {boolean} - True if test has valid UUID
|
|
132
|
+
*/
|
|
133
|
+
static hasValidUuid(test) {
|
|
134
|
+
const uuid = this.extractUuid(test);
|
|
135
|
+
return uuid !== null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = UuidExtractor;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Appliqation Cypress Reporter
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* // cypress.config.js
|
|
6
|
+
* const { defineConfig } = require('cypress');
|
|
7
|
+
* const { CypressReporter } = require('@appliqation/automation-sdk/cypress');
|
|
8
|
+
*
|
|
9
|
+
* module.exports = defineConfig({
|
|
10
|
+
* e2e: {
|
|
11
|
+
* setupNodeEvents(on, config) {
|
|
12
|
+
* CypressReporter(on, {
|
|
13
|
+
* baseUrl: process.env.APPLIQATION_BASE_URL,
|
|
14
|
+
* apiKey: process.env.APPLIQATION_API_KEY,
|
|
15
|
+
* projectKey: process.env.APPLIQATION_PROJECT_KEY,
|
|
16
|
+
* scenarioId: parseInt(process.env.APPLIQATION_SCENARIO_ID),
|
|
17
|
+
* environment: process.env.APPLIQATION_ENVIRONMENT || 'Local',
|
|
18
|
+
* title: process.env.APPLIQATION_RUN_TITLE
|
|
19
|
+
* });
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const CypressReporter = require('./CypressReporter');
|
|
26
|
+
const UuidExtractor = require('./UuidExtractor');
|
|
27
|
+
|
|
28
|
+
module.exports = CypressReporter;
|
|
29
|
+
module.exports.CypressReporter = CypressReporter;
|
|
30
|
+
module.exports.UuidExtractor = UuidExtractor;
|