@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,435 @@
|
|
|
1
|
+
const os = require('os');
|
|
2
|
+
const { normalizeBrowser, normalizeOS, normalizeDevice } = require('../../../utils/RunDataNormalizer');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Device and OS Detector for Playwright Tests
|
|
6
|
+
* Detects device type and operating system from Playwright project configuration
|
|
7
|
+
*/
|
|
8
|
+
class DeviceOsDetector {
|
|
9
|
+
/**
|
|
10
|
+
* Detect device type from Playwright project
|
|
11
|
+
* @param {Object} project - Playwright project object
|
|
12
|
+
* @returns {string} Device type (Desktop, Mobile, Tablet)
|
|
13
|
+
*/
|
|
14
|
+
static detectDevice(project) {
|
|
15
|
+
if (!project) return this.getDefaultDevice();
|
|
16
|
+
|
|
17
|
+
const name = (project.name || '').toLowerCase();
|
|
18
|
+
const userAgent = (project.use?.userAgent || '').toLowerCase();
|
|
19
|
+
const viewport = project.use?.viewport;
|
|
20
|
+
const isMobile = project.use?.isMobile;
|
|
21
|
+
const hasTouch = project.use?.hasTouch;
|
|
22
|
+
|
|
23
|
+
// Explicit mobile flag
|
|
24
|
+
if (isMobile === true) {
|
|
25
|
+
return normalizeDevice(this.detectMobileType(name, viewport));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Check project name for device indicators
|
|
29
|
+
if (this.isMobileDevice(name)) {
|
|
30
|
+
return normalizeDevice(this.detectMobileType(name, viewport));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (this.isTabletDevice(name)) {
|
|
34
|
+
return normalizeDevice('Tablet');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check user agent
|
|
38
|
+
if (userAgent) {
|
|
39
|
+
if (this.isMobileUserAgent(userAgent)) {
|
|
40
|
+
return normalizeDevice(this.detectMobileType(userAgent, viewport));
|
|
41
|
+
}
|
|
42
|
+
if (this.isTabletUserAgent(userAgent)) {
|
|
43
|
+
return normalizeDevice('Tablet');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check viewport size
|
|
48
|
+
if (viewport) {
|
|
49
|
+
if (this.isTabletViewport(viewport)) {
|
|
50
|
+
return normalizeDevice('Tablet');
|
|
51
|
+
}
|
|
52
|
+
if (this.isMobileViewport(viewport)) {
|
|
53
|
+
return normalizeDevice('Mobile');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check touch capability
|
|
58
|
+
if (hasTouch === true && viewport && this.isMobileViewport(viewport)) {
|
|
59
|
+
return normalizeDevice('Mobile');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return normalizeDevice('Desktop');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Detect mobile type (Mobile vs Tablet)
|
|
67
|
+
* @param {string} identifier - Name or user agent
|
|
68
|
+
* @param {Object} viewport - Viewport dimensions
|
|
69
|
+
* @returns {string} 'Mobile' or 'Tablet'
|
|
70
|
+
*/
|
|
71
|
+
static detectMobileType(identifier, viewport) {
|
|
72
|
+
const lower = (identifier || '').toLowerCase();
|
|
73
|
+
|
|
74
|
+
// Explicit tablet indicators
|
|
75
|
+
if (lower.includes('tablet') || lower.includes('ipad')) {
|
|
76
|
+
return 'Tablet';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check viewport if available
|
|
80
|
+
if (viewport) {
|
|
81
|
+
if (this.isTabletViewport(viewport)) {
|
|
82
|
+
return 'Tablet';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return 'Mobile';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if name indicates mobile device
|
|
91
|
+
* @param {string} name - Project name
|
|
92
|
+
* @returns {boolean} True if mobile
|
|
93
|
+
*/
|
|
94
|
+
static isMobileDevice(name) {
|
|
95
|
+
const mobileKeywords = [
|
|
96
|
+
'mobile', 'iphone', 'android', 'pixel', 'galaxy',
|
|
97
|
+
'xiaomi', 'huawei', 'moto', 'nexus', 'oneplus'
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
return mobileKeywords.some(keyword => name.includes(keyword));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if name indicates tablet device
|
|
105
|
+
* @param {string} name - Project name
|
|
106
|
+
* @returns {boolean} True if tablet
|
|
107
|
+
*/
|
|
108
|
+
static isTabletDevice(name) {
|
|
109
|
+
const tabletKeywords = [
|
|
110
|
+
'tablet', 'ipad', 'galaxy tab', 'kindle', 'surface'
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
return tabletKeywords.some(keyword => name.includes(keyword));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if user agent indicates mobile
|
|
118
|
+
* @param {string} userAgent - User agent string
|
|
119
|
+
* @returns {boolean} True if mobile
|
|
120
|
+
*/
|
|
121
|
+
static isMobileUserAgent(userAgent) {
|
|
122
|
+
const mobilePatterns = [
|
|
123
|
+
/mobile/i,
|
|
124
|
+
/android/i,
|
|
125
|
+
/iphone/i,
|
|
126
|
+
/ipod/i,
|
|
127
|
+
/blackberry/i,
|
|
128
|
+
/windows phone/i
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
return mobilePatterns.some(pattern => pattern.test(userAgent));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if user agent indicates tablet
|
|
136
|
+
* @param {string} userAgent - User agent string
|
|
137
|
+
* @returns {boolean} True if tablet
|
|
138
|
+
*/
|
|
139
|
+
static isTabletUserAgent(userAgent) {
|
|
140
|
+
const tabletPatterns = [
|
|
141
|
+
/ipad/i,
|
|
142
|
+
/tablet/i,
|
|
143
|
+
/kindle/i,
|
|
144
|
+
/playbook/i
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
return tabletPatterns.some(pattern => pattern.test(userAgent));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Check if viewport is mobile size
|
|
152
|
+
* @param {Object} viewport - Viewport object with width/height
|
|
153
|
+
* @returns {boolean} True if mobile size
|
|
154
|
+
*/
|
|
155
|
+
static isMobileViewport(viewport) {
|
|
156
|
+
if (!viewport || !viewport.width) return false;
|
|
157
|
+
|
|
158
|
+
// Typical mobile viewport width: 320-480px
|
|
159
|
+
return viewport.width >= 320 && viewport.width <= 480;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if viewport is tablet size
|
|
164
|
+
* @param {Object} viewport - Viewport object with width/height
|
|
165
|
+
* @returns {boolean} True if tablet size
|
|
166
|
+
*/
|
|
167
|
+
static isTabletViewport(viewport) {
|
|
168
|
+
if (!viewport || !viewport.width) return false;
|
|
169
|
+
|
|
170
|
+
// Typical tablet viewport width: 768-1024px
|
|
171
|
+
return viewport.width >= 600 && viewport.width <= 1024;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Detect OS from Playwright project
|
|
176
|
+
* @param {Object} project - Playwright project object
|
|
177
|
+
* @returns {string} Operating system name
|
|
178
|
+
*/
|
|
179
|
+
static detectOS(project) {
|
|
180
|
+
if (!project) return normalizeOS(this.getSystemOS());
|
|
181
|
+
|
|
182
|
+
// Priority 1: Check metadata.os for explicit OS specification
|
|
183
|
+
const explicitOS = project.use?.metadata?.os;
|
|
184
|
+
if (explicitOS && typeof explicitOS === 'string') {
|
|
185
|
+
return normalizeOS(explicitOS);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const name = (project.name || '').toLowerCase();
|
|
189
|
+
const userAgent = (project.use?.userAgent || '').toLowerCase();
|
|
190
|
+
|
|
191
|
+
// Priority 2: Check project name for OS indicators
|
|
192
|
+
const osFromName = this.extractOSFromName(name);
|
|
193
|
+
if (osFromName) return normalizeOS(osFromName);
|
|
194
|
+
|
|
195
|
+
// Priority 3: Check user agent for OS indicators
|
|
196
|
+
const osFromUA = this.extractOSFromUserAgent(userAgent);
|
|
197
|
+
if (osFromUA) return normalizeOS(osFromUA);
|
|
198
|
+
|
|
199
|
+
// Fallback to system OS
|
|
200
|
+
return normalizeOS(this.getSystemOS());
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Extract OS from project name
|
|
205
|
+
* @param {string} name - Project name
|
|
206
|
+
* @returns {string|null} OS name or null
|
|
207
|
+
*/
|
|
208
|
+
static extractOSFromName(name) {
|
|
209
|
+
const osMap = {
|
|
210
|
+
'windows7': 'Windows',
|
|
211
|
+
'win7': 'Windows',
|
|
212
|
+
'windows11': 'Windows',
|
|
213
|
+
'win11': 'Windows',
|
|
214
|
+
'windows10': 'Windows',
|
|
215
|
+
'win10': 'Windows',
|
|
216
|
+
'windows': 'Windows',
|
|
217
|
+
'macos': 'macOS',
|
|
218
|
+
'mac': 'macOS',
|
|
219
|
+
'darwin': 'macOS',
|
|
220
|
+
'linux': 'Linux',
|
|
221
|
+
'ubuntu': 'Ubuntu',
|
|
222
|
+
'android': 'Android',
|
|
223
|
+
'ios': 'macOS',
|
|
224
|
+
'iphone': 'macOS',
|
|
225
|
+
'ipad': 'macOS'
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
for (const [keyword, os] of Object.entries(osMap)) {
|
|
229
|
+
if (name.includes(keyword)) {
|
|
230
|
+
return os;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Extract OS from user agent
|
|
239
|
+
* @param {string} userAgent - User agent string
|
|
240
|
+
* @returns {string|null} OS name or null
|
|
241
|
+
*/
|
|
242
|
+
static extractOSFromUserAgent(userAgent) {
|
|
243
|
+
if (!userAgent) return null;
|
|
244
|
+
|
|
245
|
+
if (/windows/i.test(userAgent)) return 'Windows';
|
|
246
|
+
if (/mac os x/i.test(userAgent)) return 'macOS';
|
|
247
|
+
if (/macintosh/i.test(userAgent)) return 'macOS';
|
|
248
|
+
if (/android/i.test(userAgent)) return 'Android';
|
|
249
|
+
if (/ipad|iphone|ipod/i.test(userAgent)) return 'macOS';
|
|
250
|
+
if (/linux/i.test(userAgent)) return 'Linux';
|
|
251
|
+
if (/ubuntu/i.test(userAgent)) return 'Ubuntu';
|
|
252
|
+
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get system OS
|
|
258
|
+
* @returns {string} Current system OS
|
|
259
|
+
*/
|
|
260
|
+
static getSystemOS() {
|
|
261
|
+
const platform = os.platform();
|
|
262
|
+
const release = os.release();
|
|
263
|
+
|
|
264
|
+
const osMap = {
|
|
265
|
+
'win32': this.getWindowsVersion(release),
|
|
266
|
+
'darwin': 'macOS',
|
|
267
|
+
'linux': 'Linux'
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
return osMap[platform] || 'Unknown';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Get Windows version from release
|
|
275
|
+
* @param {string} release - OS release string
|
|
276
|
+
* @returns {string} Windows version (generic, will be normalized)
|
|
277
|
+
*/
|
|
278
|
+
static getWindowsVersion(release) {
|
|
279
|
+
// Return generic Windows - let normalizer handle version details
|
|
280
|
+
return 'Windows';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get default device type
|
|
285
|
+
* @returns {string} Default device type
|
|
286
|
+
*/
|
|
287
|
+
static getDefaultDevice() {
|
|
288
|
+
return normalizeDevice('Desktop');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Detect browser from Playwright project
|
|
293
|
+
* @param {Object} project - Playwright project object
|
|
294
|
+
* @param {Object} browserInstance - Optional Playwright browser instance for version detection
|
|
295
|
+
* @returns {string} Browser name (normalized)
|
|
296
|
+
*/
|
|
297
|
+
static detectBrowser(project, browserInstance = null) {
|
|
298
|
+
if (!project) return normalizeBrowser('Chromium');
|
|
299
|
+
|
|
300
|
+
// Check browserName property FIRST (takes precedence over project name)
|
|
301
|
+
// This allows explicit browser version strings like "chrome142" or "safari 18.7.2"
|
|
302
|
+
const browserName = project.use?.browserName;
|
|
303
|
+
let browserVersion = project.use?.metadata?.browserVersion;
|
|
304
|
+
|
|
305
|
+
// Auto-detect browser version if browser instance provided and no manual version
|
|
306
|
+
if (!browserVersion && browserInstance) {
|
|
307
|
+
browserVersion = this.extractBrowserVersion(browserInstance);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (browserName) {
|
|
311
|
+
const browserMap = {
|
|
312
|
+
'chromium': 'Chrome',
|
|
313
|
+
'firefox': 'Firefox',
|
|
314
|
+
'webkit': 'Safari'
|
|
315
|
+
};
|
|
316
|
+
// Map standard Playwright names to browser names
|
|
317
|
+
const mapped = browserMap[browserName.toLowerCase()] || browserName;
|
|
318
|
+
|
|
319
|
+
// If metadata.browserVersion is provided OR auto-detected, append it before normalization
|
|
320
|
+
// This allows: { browserName: 'chromium', metadata: { browserVersion: '142' } }
|
|
321
|
+
// or auto-detected from browser.version()
|
|
322
|
+
// to become "Chrome 142"
|
|
323
|
+
const browserWithVersion = browserVersion ? `${mapped} ${browserVersion}` : mapped;
|
|
324
|
+
|
|
325
|
+
return normalizeBrowser(browserWithVersion);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Fallback: Check project name for browser
|
|
329
|
+
const name = (project.name || '').toLowerCase();
|
|
330
|
+
if (name.includes('chrome') || name.includes('chromium')) {
|
|
331
|
+
return normalizeBrowser('Chrome');
|
|
332
|
+
}
|
|
333
|
+
if (name.includes('firefox') || name.includes('ff')) {
|
|
334
|
+
return normalizeBrowser('Firefox');
|
|
335
|
+
}
|
|
336
|
+
if (name.includes('webkit') || name.includes('safari')) {
|
|
337
|
+
return normalizeBrowser('Safari');
|
|
338
|
+
}
|
|
339
|
+
if (name.includes('edge')) {
|
|
340
|
+
return normalizeBrowser('Edge');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Default
|
|
344
|
+
return normalizeBrowser('Chrome');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Extract browser version from Playwright browser instance
|
|
349
|
+
* @param {Object} browserInstance - Playwright browser instance
|
|
350
|
+
* @returns {string|null} Major version number or null
|
|
351
|
+
*/
|
|
352
|
+
static extractBrowserVersion(browserInstance) {
|
|
353
|
+
try {
|
|
354
|
+
// Check if browser instance has version() method
|
|
355
|
+
if (!browserInstance || typeof browserInstance.version !== 'function') {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Note: browser.version() is synchronous in Playwright
|
|
360
|
+
const fullVersion = browserInstance.version();
|
|
361
|
+
|
|
362
|
+
if (!fullVersion || typeof fullVersion !== 'string') {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Extract major version (e.g., "140.0.6778.44" -> "140")
|
|
367
|
+
const versionMatch = fullVersion.match(/^(\d+)/);
|
|
368
|
+
if (versionMatch && versionMatch[1]) {
|
|
369
|
+
return versionMatch[1];
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return null;
|
|
373
|
+
} catch (error) {
|
|
374
|
+
// Silently fail - version detection is optional
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Get complete device info from Playwright project
|
|
381
|
+
* @param {Object} project - Playwright project object
|
|
382
|
+
* @param {Object} browserInstance - Optional Playwright browser instance for version detection
|
|
383
|
+
* @returns {Object} { device, os, browser }
|
|
384
|
+
*/
|
|
385
|
+
static getDeviceInfo(project, browserInstance = null) {
|
|
386
|
+
return {
|
|
387
|
+
device: this.detectDevice(project),
|
|
388
|
+
os: this.detectOS(project),
|
|
389
|
+
browser: this.detectBrowser(project, browserInstance)
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get device/OS matrix configurations from Playwright config
|
|
395
|
+
* Splits multi-project configs into separate run matrices
|
|
396
|
+
* @param {Array} projects - Array of Playwright project objects
|
|
397
|
+
* @returns {Array} Array of unique device/OS combinations
|
|
398
|
+
*/
|
|
399
|
+
static getMatrixConfigurations(projects) {
|
|
400
|
+
if (!Array.isArray(projects) || projects.length === 0) {
|
|
401
|
+
return [{
|
|
402
|
+
device: this.getDefaultDevice(),
|
|
403
|
+
os: this.getSystemOS(),
|
|
404
|
+
browsers: ['Chrome']
|
|
405
|
+
}];
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const configurations = new Map();
|
|
409
|
+
|
|
410
|
+
for (const project of projects) {
|
|
411
|
+
const device = this.detectDevice(project);
|
|
412
|
+
const os = this.detectOS(project);
|
|
413
|
+
const browser = this.detectBrowser(project);
|
|
414
|
+
|
|
415
|
+
const key = `${device}-${os}`;
|
|
416
|
+
|
|
417
|
+
if (!configurations.has(key)) {
|
|
418
|
+
configurations.set(key, {
|
|
419
|
+
device,
|
|
420
|
+
os,
|
|
421
|
+
browsers: []
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const config = configurations.get(key);
|
|
426
|
+
if (!config.browsers.includes(browser)) {
|
|
427
|
+
config.browsers.push(browser);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return Array.from(configurations.values());
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
module.exports = DeviceOsDetector;
|