@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,290 @@
|
|
|
1
|
+
const UuidValidator = require('../../../utils/UuidValidator');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* UUID Extractor for Playwright Tests
|
|
5
|
+
* Extracts Appliqation test UUIDs from various locations in Playwright test metadata
|
|
6
|
+
*/
|
|
7
|
+
class UuidExtractor {
|
|
8
|
+
/**
|
|
9
|
+
* Extract UUID from Playwright test
|
|
10
|
+
* Searches in order: test.id, test tags, test title, test annotations
|
|
11
|
+
* @param {Object} test - Playwright test object
|
|
12
|
+
* @returns {string|null} UUID or null if not found
|
|
13
|
+
*/
|
|
14
|
+
static extractFromTest(test) {
|
|
15
|
+
if (!test) return null;
|
|
16
|
+
|
|
17
|
+
// 1. Check test.id directly (if user sets it)
|
|
18
|
+
if (test.id && UuidValidator.validate(test.id)) {
|
|
19
|
+
return test.id;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 2. Check test tags (@uuid-123-xxx-xxx-xxx)
|
|
23
|
+
const tagUuid = this.extractFromTags(test.tags || []);
|
|
24
|
+
if (tagUuid) return tagUuid;
|
|
25
|
+
|
|
26
|
+
// 3. Check test title (extract UUID from title string)
|
|
27
|
+
const titleUuid = this.extractFromTitle(test.title);
|
|
28
|
+
if (titleUuid) return titleUuid;
|
|
29
|
+
|
|
30
|
+
// 4. Check test annotations
|
|
31
|
+
const annotationUuid = this.extractFromAnnotations(test.annotations || []);
|
|
32
|
+
if (annotationUuid) return annotationUuid;
|
|
33
|
+
|
|
34
|
+
// 5. Check test location (file path or test name)
|
|
35
|
+
const locationUuid = this.extractFromLocation(test.location);
|
|
36
|
+
if (locationUuid) return locationUuid;
|
|
37
|
+
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extract UUID from test tags
|
|
43
|
+
* Supports formats:
|
|
44
|
+
* - @uuid:123-xxx-xxx-xxx
|
|
45
|
+
* - @appliqation:123-xxx-xxx-xxx
|
|
46
|
+
* - @123-xxx-xxx-xxx
|
|
47
|
+
* @param {Array<string>} tags - Array of test tags
|
|
48
|
+
* @returns {string|null} UUID or null
|
|
49
|
+
*/
|
|
50
|
+
static extractFromTags(tags) {
|
|
51
|
+
if (!Array.isArray(tags) || tags.length === 0) return null;
|
|
52
|
+
|
|
53
|
+
for (const tag of tags) {
|
|
54
|
+
if (!tag || typeof tag !== 'string') continue;
|
|
55
|
+
|
|
56
|
+
// Remove @ prefix if present
|
|
57
|
+
const cleanTag = tag.startsWith('@') ? tag.substring(1) : tag;
|
|
58
|
+
|
|
59
|
+
// Check for uuid: or appliqation: prefix
|
|
60
|
+
const prefixMatch = cleanTag.match(/^(?:uuid|appliqation):(.+)$/i);
|
|
61
|
+
if (prefixMatch) {
|
|
62
|
+
const uuid = prefixMatch[1];
|
|
63
|
+
if (UuidValidator.validate(uuid)) {
|
|
64
|
+
return uuid;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check if tag itself is a UUID
|
|
69
|
+
if (UuidValidator.validate(cleanTag)) {
|
|
70
|
+
return cleanTag;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extract UUID from test title
|
|
79
|
+
* Supports formats:
|
|
80
|
+
* - "Test name [123-xxx-xxx-xxx]"
|
|
81
|
+
* - "Test name (123-xxx-xxx-xxx)"
|
|
82
|
+
* - "Test name | 123-xxx-xxx-xxx"
|
|
83
|
+
* - "123-xxx-xxx-xxx | Test name"
|
|
84
|
+
* @param {string} title - Test title
|
|
85
|
+
* @returns {string|null} UUID or null
|
|
86
|
+
*/
|
|
87
|
+
static extractFromTitle(title) {
|
|
88
|
+
if (!title || typeof title !== 'string') return null;
|
|
89
|
+
|
|
90
|
+
// Pattern 1: [UUID] or (UUID) at the end
|
|
91
|
+
const bracketMatch = title.match(/[\[\(](\d+-[a-f0-9-]+)[\]\)]$/i);
|
|
92
|
+
if (bracketMatch && UuidValidator.validate(bracketMatch[1])) {
|
|
93
|
+
return bracketMatch[1];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Pattern 2: | UUID or UUID | at the beginning or end
|
|
97
|
+
const pipeMatch = title.match(/(?:^|\|)\s*(\d+-[a-f0-9-]+)\s*(?:\||$)/i);
|
|
98
|
+
if (pipeMatch && UuidValidator.validate(pipeMatch[1])) {
|
|
99
|
+
return pipeMatch[1];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Pattern 3: UUID anywhere in the string
|
|
103
|
+
const anywhereMatch = title.match(/\b(\d+-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})\b/i);
|
|
104
|
+
if (anywhereMatch && UuidValidator.validate(anywhereMatch[1])) {
|
|
105
|
+
return anywhereMatch[1];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Extract UUID from test annotations
|
|
113
|
+
* Looks for annotations with type 'uuid' or 'appliqation'
|
|
114
|
+
* @param {Array<Object>} annotations - Array of annotation objects
|
|
115
|
+
* @returns {string|null} UUID or null
|
|
116
|
+
*/
|
|
117
|
+
static extractFromAnnotations(annotations) {
|
|
118
|
+
if (!Array.isArray(annotations) || annotations.length === 0) return null;
|
|
119
|
+
|
|
120
|
+
for (const annotation of annotations) {
|
|
121
|
+
if (!annotation || typeof annotation !== 'object') continue;
|
|
122
|
+
|
|
123
|
+
// Check annotation type
|
|
124
|
+
if (annotation.type === 'uuid' || annotation.type === 'appliqation' || annotation.type === 'appliqation-uuid') {
|
|
125
|
+
const uuid = annotation.description || annotation.value;
|
|
126
|
+
if (uuid && UuidValidator.validate(uuid)) {
|
|
127
|
+
return uuid;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check annotation description for UUID
|
|
132
|
+
if (annotation.description) {
|
|
133
|
+
const uuid = this.extractFromTitle(annotation.description);
|
|
134
|
+
if (uuid) return uuid;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Extract UUID from test location (file path or test name)
|
|
143
|
+
* @param {Object} location - Test location object
|
|
144
|
+
* @returns {string|null} UUID or null
|
|
145
|
+
*/
|
|
146
|
+
static extractFromLocation(location) {
|
|
147
|
+
if (!location || typeof location !== 'object') return null;
|
|
148
|
+
|
|
149
|
+
// Check file path for UUID
|
|
150
|
+
if (location.file) {
|
|
151
|
+
const fileMatch = location.file.match(/(\d+-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i);
|
|
152
|
+
if (fileMatch && UuidValidator.validate(fileMatch[1])) {
|
|
153
|
+
return fileMatch[1];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Extract all UUIDs from test suite (for parent-child relationships)
|
|
162
|
+
* @param {Object} test - Playwright test object
|
|
163
|
+
* @returns {Array<string>} Array of UUIDs (child first, parents after)
|
|
164
|
+
*/
|
|
165
|
+
static extractHierarchy(test) {
|
|
166
|
+
const uuids = [];
|
|
167
|
+
|
|
168
|
+
if (!test) return uuids;
|
|
169
|
+
|
|
170
|
+
// Get current test UUID
|
|
171
|
+
const testUuid = this.extractFromTest(test);
|
|
172
|
+
if (testUuid) {
|
|
173
|
+
uuids.push(testUuid);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Get parent suite UUIDs
|
|
177
|
+
let currentSuite = test.parent;
|
|
178
|
+
while (currentSuite) {
|
|
179
|
+
const suiteUuid = this.extractFromTest(currentSuite);
|
|
180
|
+
if (suiteUuid) {
|
|
181
|
+
uuids.push(suiteUuid);
|
|
182
|
+
}
|
|
183
|
+
currentSuite = currentSuite.parent;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return uuids;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Create orphan test entry from Playwright test
|
|
191
|
+
* @param {Object} test - Playwright test object
|
|
192
|
+
* @param {Object} result - Test result object
|
|
193
|
+
* @param {string} browser - Browser name
|
|
194
|
+
* @returns {Object} Orphan test entry
|
|
195
|
+
*/
|
|
196
|
+
static createOrphanEntry(test, result, browser) {
|
|
197
|
+
return {
|
|
198
|
+
test_title: test.title || 'Unknown Test',
|
|
199
|
+
test_file: test.location?.file || 'unknown',
|
|
200
|
+
browser: browser || 'unknown',
|
|
201
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
202
|
+
reason: 'No UUID annotation found',
|
|
203
|
+
framework: 'playwright',
|
|
204
|
+
additional_info: {
|
|
205
|
+
projectName: test.parent?.project?.name,
|
|
206
|
+
duration: result?.duration,
|
|
207
|
+
status: result?.status,
|
|
208
|
+
tags: test.tags
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Validate and extract UUID with detailed error info
|
|
215
|
+
* @param {Object} test - Playwright test object
|
|
216
|
+
* @returns {Object} { uuid, found, locations }
|
|
217
|
+
*/
|
|
218
|
+
static extractWithDetails(test) {
|
|
219
|
+
const locations = {
|
|
220
|
+
id: false,
|
|
221
|
+
tags: false,
|
|
222
|
+
title: false,
|
|
223
|
+
annotations: false,
|
|
224
|
+
location: false
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
let uuid = null;
|
|
228
|
+
|
|
229
|
+
// Check all locations
|
|
230
|
+
if (test.id && UuidValidator.validate(test.id)) {
|
|
231
|
+
uuid = test.id;
|
|
232
|
+
locations.id = true;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!uuid) {
|
|
236
|
+
const tagUuid = this.extractFromTags(test.tags || []);
|
|
237
|
+
if (tagUuid) {
|
|
238
|
+
uuid = tagUuid;
|
|
239
|
+
locations.tags = true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!uuid) {
|
|
244
|
+
const titleUuid = this.extractFromTitle(test.title);
|
|
245
|
+
if (titleUuid) {
|
|
246
|
+
uuid = titleUuid;
|
|
247
|
+
locations.title = true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!uuid) {
|
|
252
|
+
const annotationUuid = this.extractFromAnnotations(test.annotations || []);
|
|
253
|
+
if (annotationUuid) {
|
|
254
|
+
uuid = annotationUuid;
|
|
255
|
+
locations.annotations = true;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (!uuid) {
|
|
260
|
+
const locationUuid = this.extractFromLocation(test.location);
|
|
261
|
+
if (locationUuid) {
|
|
262
|
+
uuid = locationUuid;
|
|
263
|
+
locations.location = true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
uuid,
|
|
269
|
+
found: uuid !== null,
|
|
270
|
+
locations
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Get extraction suggestions for test without UUID
|
|
276
|
+
* @param {Object} test - Playwright test object
|
|
277
|
+
* @returns {Array<string>} Suggestions for adding UUID
|
|
278
|
+
*/
|
|
279
|
+
static getSuggestions(test) {
|
|
280
|
+
const suggestions = [];
|
|
281
|
+
|
|
282
|
+
suggestions.push(`Add UUID as tag: test('${test.title}', { tag: '@uuid:123-xxx-...' }, async ({ page }) => { ... })`);
|
|
283
|
+
suggestions.push(`Add UUID in title: test('[123-xxx-...] ${test.title}', async ({ page }) => { ... })`);
|
|
284
|
+
suggestions.push(`Add UUID as annotation: test.use({ annotation: { type: 'uuid', description: '123-xxx-...' } })`);
|
|
285
|
+
|
|
286
|
+
return suggestions;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
module.exports = UuidExtractor;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript definitions for @appliqation/automation-sdk/playwright
|
|
3
|
+
* @version 2.1.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
Reporter,
|
|
8
|
+
FullConfig,
|
|
9
|
+
Suite,
|
|
10
|
+
TestCase,
|
|
11
|
+
TestResult,
|
|
12
|
+
FullResult
|
|
13
|
+
} from '@playwright/test/reporter';
|
|
14
|
+
|
|
15
|
+
import type { AppliqationConfig } from '../../index';
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Playwright Reporter Configuration
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for the Appliqation Playwright Reporter
|
|
23
|
+
*/
|
|
24
|
+
export interface AppliqationReporterConfig extends AppliqationConfig {
|
|
25
|
+
/** Log level for reporter (default: 'INFO') */
|
|
26
|
+
logLevel?: 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
|
|
27
|
+
|
|
28
|
+
/** Log orphan tests without UUID mappings (default: true) */
|
|
29
|
+
logOrphans?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// Appliqation Playwright Reporter
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Playwright reporter for Appliqation integration
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // playwright.config.ts
|
|
42
|
+
* import { AppliqationReporter } from '@appliqation/automation-sdk/playwright';
|
|
43
|
+
*
|
|
44
|
+
* export default {
|
|
45
|
+
* reporter: [
|
|
46
|
+
* ['list'],
|
|
47
|
+
* [AppliqationReporter, {
|
|
48
|
+
* baseUrl: process.env.APPLIQATION_BASE_URL,
|
|
49
|
+
* apiKey: process.env.APPLIQATION_API_KEY,
|
|
50
|
+
* projectKey: process.env.APPLIQATION_PROJECT_KEY,
|
|
51
|
+
* scenarioId: 0,
|
|
52
|
+
* environment: 'Local',
|
|
53
|
+
* logLevel: 'INFO'
|
|
54
|
+
* }]
|
|
55
|
+
* ]
|
|
56
|
+
* };
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export class AppliqationReporter implements Reporter {
|
|
60
|
+
/**
|
|
61
|
+
* Create a new Appliqation Playwright Reporter
|
|
62
|
+
* @param config - Reporter configuration
|
|
63
|
+
*/
|
|
64
|
+
constructor(config: AppliqationReporterConfig);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Called once before running tests
|
|
68
|
+
*/
|
|
69
|
+
onBegin(config: FullConfig, suite: Suite): Promise<void>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Called after a test has been started
|
|
73
|
+
*/
|
|
74
|
+
onTestBegin?(test: TestCase, result: TestResult): void;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Called after a test has been finished
|
|
78
|
+
*/
|
|
79
|
+
onTestEnd?(test: TestCase, result: TestResult): void;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Called after all tests have been run
|
|
83
|
+
*/
|
|
84
|
+
onEnd(result: FullResult): Promise<void>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Process error
|
|
88
|
+
*/
|
|
89
|
+
onError?(error: Error): void;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// Exports
|
|
94
|
+
// ============================================================================
|
|
95
|
+
|
|
96
|
+
export default AppliqationReporter;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Appliqation Playwright Reporter
|
|
3
|
+
* Main export for Playwright integration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const AppliqationReporter = require('./AppliqationReporter');
|
|
7
|
+
const UuidExtractor = require('./helpers/UuidExtractor');
|
|
8
|
+
const DeviceOsDetector = require('./helpers/DeviceOsDetector');
|
|
9
|
+
|
|
10
|
+
module.exports = AppliqationReporter;
|
|
11
|
+
module.exports.AppliqationReporter = AppliqationReporter;
|
|
12
|
+
module.exports.UuidExtractor = UuidExtractor;
|
|
13
|
+
module.exports.DeviceOsDetector = DeviceOsDetector;
|
|
14
|
+
module.exports.default = AppliqationReporter;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const logger = require('../utils/logger');
|
|
2
|
+
|
|
3
|
+
class OrphanTestService {
|
|
4
|
+
constructor(httpClient) {
|
|
5
|
+
this.http = httpClient;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Log orphan tests (tests without UUID mappings)
|
|
10
|
+
* @param {string} runId - Run ID
|
|
11
|
+
* @param {Array} orphanTests - Array of orphan test objects
|
|
12
|
+
* @returns {Promise<Object>} Response from server
|
|
13
|
+
*/
|
|
14
|
+
async log(runId, orphanTests) {
|
|
15
|
+
if (!orphanTests || orphanTests.length === 0) {
|
|
16
|
+
logger.debug('No orphan tests to log');
|
|
17
|
+
return {
|
|
18
|
+
success: true,
|
|
19
|
+
logged: 0
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
logger.info(`Logging ${orphanTests.length} orphan tests for run ${runId}`);
|
|
25
|
+
|
|
26
|
+
const payload = {
|
|
27
|
+
run_id: runId,
|
|
28
|
+
orphan_tests: orphanTests.map(test => ({
|
|
29
|
+
test_title: test.test_title || test.title || 'Unknown Test',
|
|
30
|
+
test_file: test.test_file || test.file || 'unknown',
|
|
31
|
+
browser: test.browser || 'unknown',
|
|
32
|
+
timestamp: test.timestamp || Math.floor(Date.now() / 1000),
|
|
33
|
+
reason: test.reason || 'No UUID annotation found',
|
|
34
|
+
framework: test.framework || 'unknown'
|
|
35
|
+
}))
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const response = await this.http.post('/api/automation/orphan-tests', payload);
|
|
39
|
+
|
|
40
|
+
logger.info('Orphan tests logged successfully', {
|
|
41
|
+
runId,
|
|
42
|
+
count: response.logged || orphanTests.length
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return response;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.error('Failed to log orphan tests', {
|
|
48
|
+
error: error.message,
|
|
49
|
+
runId,
|
|
50
|
+
count: orphanTests.length
|
|
51
|
+
});
|
|
52
|
+
throw new Error(`Failed to log orphan tests: ${error.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create formatted orphan test entry
|
|
58
|
+
* @param {Object} test - Test object
|
|
59
|
+
* @param {string} reason - Reason for being orphaned
|
|
60
|
+
* @returns {Object} Formatted orphan test
|
|
61
|
+
*/
|
|
62
|
+
createOrphanEntry(test, reason = 'No UUID annotation found') {
|
|
63
|
+
return {
|
|
64
|
+
test_title: test.title || test.name || 'Unknown Test',
|
|
65
|
+
test_file: test.file || test.location?.file || 'unknown',
|
|
66
|
+
browser: test.browser || 'unknown',
|
|
67
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
68
|
+
reason: reason,
|
|
69
|
+
framework: test.framework || 'unknown'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = OrphanTestService;
|