@appliqation/automation-sdk 2.1.11 → 2.3.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 +0 -0
- package/README.md +509 -7
- package/package.json +2 -2
- package/src/AppliqationClient.js +47 -2
- package/src/constants.js +0 -0
- package/src/core/AuthManager.js +0 -0
- package/src/core/HttpClient.js +52 -0
- package/src/index.d.ts +0 -0
- package/src/index.js +0 -0
- package/src/playwright/JwtBrowserAuth.js +0 -0
- package/src/playwright/fixture.js +0 -0
- package/src/playwright/global-setup.js +43 -0
- package/src/playwright/global-teardown.js +0 -0
- package/src/playwright/helpers/jwt-browser-auth.js +0 -0
- package/src/playwright/index.js +0 -0
- package/src/reporters/cypress/CypressReporter.js +49 -2
- package/src/reporters/cypress/UuidExtractor.js +0 -0
- package/src/reporters/cypress/index.js +0 -0
- package/src/reporters/jest/JestReporter.js +49 -2
- package/src/reporters/jest/UuidExtractor.js +0 -0
- package/src/reporters/jest/index.js +0 -0
- package/src/reporters/playwright/AppliqationReporter.js +734 -26
- package/src/reporters/playwright/helpers/DeviceOsDetector.js +0 -0
- package/src/reporters/playwright/helpers/UuidExtractor.js +8 -3
- package/src/reporters/playwright/index.d.ts +0 -0
- package/src/reporters/playwright/index.js +0 -0
- package/src/services/OrphanTestService.js +0 -0
- package/src/services/ResultService.js +193 -24
- package/src/services/RunMatrixService.js +44 -0
- package/src/services/TaggingService.js +241 -0
- package/src/utils/PayloadBuilder.js +0 -0
- package/src/utils/RunDataNormalizer.js +0 -0
- package/src/utils/UuidValidator.js +0 -0
- package/src/utils/errors.js +0 -0
- package/src/utils/index.js +0 -0
- package/src/utils/logger.js +0 -0
- package/src/utils/mapAppqUuid.js +0 -0
- package/src/utils/validator.js +0 -0
package/src/core/HttpClient.js
CHANGED
|
@@ -254,6 +254,58 @@ class HttpClient {
|
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Delete a test run
|
|
259
|
+
* @param {string} runId - Run ID to delete
|
|
260
|
+
* @param {string} reason - Reason for deletion (for audit logging)
|
|
261
|
+
* @returns {Promise<Object>} Deletion result
|
|
262
|
+
*/
|
|
263
|
+
async deleteRun(runId, reason = 'sdk_cleanup') {
|
|
264
|
+
const maxRetries = 3;
|
|
265
|
+
const retryDelays = [500, 1000, 2000]; // ms - exponential backoff
|
|
266
|
+
|
|
267
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
268
|
+
try {
|
|
269
|
+
logger.debug('Deleting run', { runId, reason, attempt: attempt + 1 });
|
|
270
|
+
|
|
271
|
+
const response = await this.delete(`/api/automation/run/${runId}/delete`, {
|
|
272
|
+
data: { reason }
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
if (attempt > 0) {
|
|
276
|
+
logger.info('Run deletion succeeded after retry', { runId, attempt: attempt + 1 });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return response;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
const is404 = error.response?.status === 404;
|
|
282
|
+
const isLastAttempt = attempt === maxRetries;
|
|
283
|
+
|
|
284
|
+
// Only retry on 404 (run not found yet - possible race condition)
|
|
285
|
+
if (is404 && !isLastAttempt) {
|
|
286
|
+
const delay = retryDelays[attempt];
|
|
287
|
+
logger.warn('Run not found, retrying deletion...', {
|
|
288
|
+
runId,
|
|
289
|
+
attempt: attempt + 1,
|
|
290
|
+
maxRetries: maxRetries + 1,
|
|
291
|
+
retryAfterMs: delay
|
|
292
|
+
});
|
|
293
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Final attempt failed or non-404 error - throw
|
|
298
|
+
logger.error('Failed to delete run', {
|
|
299
|
+
error: error.message,
|
|
300
|
+
runId,
|
|
301
|
+
status: error.response?.status,
|
|
302
|
+
attempts: attempt + 1
|
|
303
|
+
});
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
257
309
|
/**
|
|
258
310
|
* Set authorization header
|
|
259
311
|
* @param {string} token - Authorization token
|
package/src/index.d.ts
CHANGED
|
File without changes
|
package/src/index.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -29,6 +29,43 @@ const fs = require('fs');
|
|
|
29
29
|
const path = require('path');
|
|
30
30
|
const { DEFAULT_APPLIQATION_BASE_URL } = require('../constants');
|
|
31
31
|
|
|
32
|
+
function toBoolean(value) {
|
|
33
|
+
if (value === undefined || value === null) return undefined;
|
|
34
|
+
if (typeof value === 'boolean') return value;
|
|
35
|
+
const normalized = String(value).trim().toLowerCase();
|
|
36
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
37
|
+
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function parseCliEnableFlag() {
|
|
42
|
+
const argv = process.argv || [];
|
|
43
|
+
for (let i = 0; i < argv.length; i++) {
|
|
44
|
+
const arg = argv[i];
|
|
45
|
+
if (arg.startsWith('--appq=')) {
|
|
46
|
+
return toBoolean(arg.split('=')[1]);
|
|
47
|
+
}
|
|
48
|
+
if (arg === '--appq') {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (arg.startsWith('--enable-appq=')) {
|
|
52
|
+
return toBoolean(arg.split('=')[1]);
|
|
53
|
+
}
|
|
54
|
+
if (arg === '--enable-appq') {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveEnableAppq(config) {
|
|
62
|
+
const cliValue = parseCliEnableFlag();
|
|
63
|
+
const envValue = process.env.APPLIQATION_ENABLE ?? process.env.APPQ ?? process.env.APPLIQATION_APPQ;
|
|
64
|
+
const configValue = config?.enableAppq ?? config?.options?.enableAppq;
|
|
65
|
+
const resolved = toBoolean(configValue) ?? toBoolean(cliValue) ?? toBoolean(envValue);
|
|
66
|
+
return resolved !== undefined ? resolved : true;
|
|
67
|
+
}
|
|
68
|
+
|
|
32
69
|
/**
|
|
33
70
|
* Setup JWT-based browser authentication
|
|
34
71
|
*
|
|
@@ -40,11 +77,17 @@ async function globalSetup(config) {
|
|
|
40
77
|
|
|
41
78
|
// Extract SDK configuration from reporter config or use env
|
|
42
79
|
const sdkConfig = extractSDKConfig(config);
|
|
80
|
+
sdkConfig.enableAppq = resolveEnableAppq(sdkConfig);
|
|
43
81
|
|
|
44
82
|
// Display startup information
|
|
45
83
|
console.log(`🌍 Environment: ${sdkConfig.environment || 'Not specified'}`);
|
|
46
84
|
console.log(`🔗 Test App URL: ${sdkConfig.appUrl || 'Not specified'}`);
|
|
47
85
|
|
|
86
|
+
if (sdkConfig.enableAppq === false) {
|
|
87
|
+
console.log('⚠️ Appq disabled via flag. Skipping JWT setup and backend calls.\n');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
48
91
|
// Show Run ID and Timestamp only in DEBUG mode
|
|
49
92
|
if (process.env.LOG_LEVEL === 'DEBUG') {
|
|
50
93
|
const crypto = require('crypto');
|
|
File without changes
|
|
File without changes
|
package/src/playwright/index.js
CHANGED
|
File without changes
|
|
@@ -2,6 +2,43 @@ const AppliqationClient = require('../../AppliqationClient');
|
|
|
2
2
|
const UuidExtractor = require('./UuidExtractor');
|
|
3
3
|
const logger = require('../../utils/logger');
|
|
4
4
|
|
|
5
|
+
function toBoolean(value) {
|
|
6
|
+
if (value === undefined || value === null) return undefined;
|
|
7
|
+
if (typeof value === 'boolean') return value;
|
|
8
|
+
const normalized = String(value).trim().toLowerCase();
|
|
9
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
10
|
+
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseCliEnableFlag() {
|
|
15
|
+
const argv = process.argv || [];
|
|
16
|
+
for (let i = 0; i < argv.length; i++) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg.startsWith('--appq=')) {
|
|
19
|
+
return toBoolean(arg.split('=')[1]);
|
|
20
|
+
}
|
|
21
|
+
if (arg === '--appq') {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (arg.startsWith('--enable-appq=')) {
|
|
25
|
+
return toBoolean(arg.split('=')[1]);
|
|
26
|
+
}
|
|
27
|
+
if (arg === '--enable-appq') {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function resolveEnableAppq(config) {
|
|
35
|
+
const cliValue = parseCliEnableFlag();
|
|
36
|
+
const envValue = process.env.APPLIQATION_ENABLE ?? process.env.APPQ ?? process.env.APPLIQATION_APPQ;
|
|
37
|
+
const configValue = config?.enableAppq ?? config?.options?.enableAppq;
|
|
38
|
+
const resolved = toBoolean(configValue) ?? toBoolean(cliValue) ?? toBoolean(envValue);
|
|
39
|
+
return resolved !== undefined ? resolved : true;
|
|
40
|
+
}
|
|
41
|
+
|
|
5
42
|
/**
|
|
6
43
|
* Appliqation Reporter for Cypress
|
|
7
44
|
*
|
|
@@ -39,7 +76,8 @@ class CypressReporter {
|
|
|
39
76
|
title: config.title || process.env.APPLIQATION_RUN_TITLE,
|
|
40
77
|
autoCreateRun: config.autoCreateRun !== false,
|
|
41
78
|
logLevel: config.logLevel || 'info',
|
|
42
|
-
submitOrphans: config.submitOrphans !== false
|
|
79
|
+
submitOrphans: config.submitOrphans !== false,
|
|
80
|
+
enableAppq: resolveEnableAppq(config)
|
|
43
81
|
};
|
|
44
82
|
|
|
45
83
|
// Validate required config
|
|
@@ -55,10 +93,15 @@ class CypressReporter {
|
|
|
55
93
|
projectKey: this.config.projectKey,
|
|
56
94
|
title: this.config.title,
|
|
57
95
|
options: {
|
|
58
|
-
logLevel: this.config.logLevel
|
|
96
|
+
logLevel: this.config.logLevel,
|
|
97
|
+
enableAppq: this.config.enableAppq
|
|
59
98
|
}
|
|
60
99
|
});
|
|
61
100
|
|
|
101
|
+
if (this.config.enableAppq === false) {
|
|
102
|
+
logger.warn('Appq disabled via flag. Runs/results will not be sent to Appliqation.');
|
|
103
|
+
}
|
|
104
|
+
|
|
62
105
|
// Test result storage
|
|
63
106
|
this.testResults = [];
|
|
64
107
|
this.orphanTests = [];
|
|
@@ -360,6 +403,10 @@ class CypressReporter {
|
|
|
360
403
|
* Validate configuration
|
|
361
404
|
*/
|
|
362
405
|
validateConfig() {
|
|
406
|
+
if (this.config.enableAppq === false) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
363
410
|
const required = ['baseUrl', 'apiKey', 'projectKey'];
|
|
364
411
|
const missing = required.filter(key => !this.config[key]);
|
|
365
412
|
|
|
File without changes
|
|
File without changes
|
|
@@ -2,6 +2,43 @@ const AppliqationClient = require('../../AppliqationClient');
|
|
|
2
2
|
const UuidExtractor = require('./UuidExtractor');
|
|
3
3
|
const logger = require('../../utils/logger');
|
|
4
4
|
|
|
5
|
+
function toBoolean(value) {
|
|
6
|
+
if (value === undefined || value === null) return undefined;
|
|
7
|
+
if (typeof value === 'boolean') return value;
|
|
8
|
+
const normalized = String(value).trim().toLowerCase();
|
|
9
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
10
|
+
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseCliEnableFlag() {
|
|
15
|
+
const argv = process.argv || [];
|
|
16
|
+
for (let i = 0; i < argv.length; i++) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg.startsWith('--appq=')) {
|
|
19
|
+
return toBoolean(arg.split('=')[1]);
|
|
20
|
+
}
|
|
21
|
+
if (arg === '--appq') {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (arg.startsWith('--enable-appq=')) {
|
|
25
|
+
return toBoolean(arg.split('=')[1]);
|
|
26
|
+
}
|
|
27
|
+
if (arg === '--enable-appq') {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function resolveEnableAppq(config) {
|
|
35
|
+
const cliValue = parseCliEnableFlag();
|
|
36
|
+
const envValue = process.env.APPLIQATION_ENABLE ?? process.env.APPQ ?? process.env.APPLIQATION_APPQ;
|
|
37
|
+
const configValue = config?.enableAppq ?? config?.options?.enableAppq;
|
|
38
|
+
const resolved = toBoolean(configValue) ?? toBoolean(cliValue) ?? toBoolean(envValue);
|
|
39
|
+
return resolved !== undefined ? resolved : true;
|
|
40
|
+
}
|
|
41
|
+
|
|
5
42
|
/**
|
|
6
43
|
* Appliqation Reporter for Jest
|
|
7
44
|
*
|
|
@@ -39,7 +76,8 @@ class JestReporter {
|
|
|
39
76
|
title: options.title || process.env.APPLIQATION_RUN_TITLE,
|
|
40
77
|
autoCreateRun: options.autoCreateRun !== false,
|
|
41
78
|
logLevel: options.logLevel || 'info',
|
|
42
|
-
submitOrphans: options.submitOrphans !== false
|
|
79
|
+
submitOrphans: options.submitOrphans !== false,
|
|
80
|
+
enableAppq: resolveEnableAppq(options)
|
|
43
81
|
};
|
|
44
82
|
|
|
45
83
|
// Validate required config
|
|
@@ -55,10 +93,15 @@ class JestReporter {
|
|
|
55
93
|
projectKey: this.config.projectKey,
|
|
56
94
|
title: this.config.title,
|
|
57
95
|
options: {
|
|
58
|
-
logLevel: this.config.logLevel
|
|
96
|
+
logLevel: this.config.logLevel,
|
|
97
|
+
enableAppq: this.config.enableAppq
|
|
59
98
|
}
|
|
60
99
|
});
|
|
61
100
|
|
|
101
|
+
if (this.config.enableAppq === false) {
|
|
102
|
+
logger.warn('Appq disabled via flag. Runs/results will not be sent to Appliqation.');
|
|
103
|
+
}
|
|
104
|
+
|
|
62
105
|
// Test result storage
|
|
63
106
|
this.testResults = [];
|
|
64
107
|
this.orphanTests = [];
|
|
@@ -339,6 +382,10 @@ class JestReporter {
|
|
|
339
382
|
* Validate configuration
|
|
340
383
|
*/
|
|
341
384
|
validateConfig() {
|
|
385
|
+
if (this.config.enableAppq === false) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
342
389
|
const required = ['baseUrl', 'apiKey', 'projectKey'];
|
|
343
390
|
const missing = required.filter(key => !this.config[key]);
|
|
344
391
|
|
|
File without changes
|
|
File without changes
|