@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.
Files changed (38) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +509 -7
  3. package/package.json +2 -2
  4. package/src/AppliqationClient.js +47 -2
  5. package/src/constants.js +0 -0
  6. package/src/core/AuthManager.js +0 -0
  7. package/src/core/HttpClient.js +52 -0
  8. package/src/index.d.ts +0 -0
  9. package/src/index.js +0 -0
  10. package/src/playwright/JwtBrowserAuth.js +0 -0
  11. package/src/playwright/fixture.js +0 -0
  12. package/src/playwright/global-setup.js +43 -0
  13. package/src/playwright/global-teardown.js +0 -0
  14. package/src/playwright/helpers/jwt-browser-auth.js +0 -0
  15. package/src/playwright/index.js +0 -0
  16. package/src/reporters/cypress/CypressReporter.js +49 -2
  17. package/src/reporters/cypress/UuidExtractor.js +0 -0
  18. package/src/reporters/cypress/index.js +0 -0
  19. package/src/reporters/jest/JestReporter.js +49 -2
  20. package/src/reporters/jest/UuidExtractor.js +0 -0
  21. package/src/reporters/jest/index.js +0 -0
  22. package/src/reporters/playwright/AppliqationReporter.js +734 -26
  23. package/src/reporters/playwright/helpers/DeviceOsDetector.js +0 -0
  24. package/src/reporters/playwright/helpers/UuidExtractor.js +8 -3
  25. package/src/reporters/playwright/index.d.ts +0 -0
  26. package/src/reporters/playwright/index.js +0 -0
  27. package/src/services/OrphanTestService.js +0 -0
  28. package/src/services/ResultService.js +193 -24
  29. package/src/services/RunMatrixService.js +44 -0
  30. package/src/services/TaggingService.js +241 -0
  31. package/src/utils/PayloadBuilder.js +0 -0
  32. package/src/utils/RunDataNormalizer.js +0 -0
  33. package/src/utils/UuidValidator.js +0 -0
  34. package/src/utils/errors.js +0 -0
  35. package/src/utils/index.js +0 -0
  36. package/src/utils/logger.js +0 -0
  37. package/src/utils/mapAppqUuid.js +0 -0
  38. package/src/utils/validator.js +0 -0
@@ -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
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