@wdio/browserstack-service 8.32.4 → 8.33.1
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/build/bstackLogger.d.ts +2 -1
- package/build/bstackLogger.d.ts.map +1 -1
- package/build/bstackLogger.js +6 -3
- package/build/cleanup.d.ts +5 -1
- package/build/cleanup.d.ts.map +1 -1
- package/build/cleanup.js +72 -7
- package/build/config.d.ts +23 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +39 -0
- package/build/constants.d.ts +14 -0
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +22 -0
- package/build/crash-reporter.js +2 -2
- package/build/data-store.d.ts +4 -0
- package/build/data-store.d.ts.map +1 -0
- package/build/data-store.js +41 -0
- package/build/exitHandler.d.ts +4 -0
- package/build/exitHandler.d.ts.map +1 -0
- package/build/exitHandler.js +32 -0
- package/build/insights-handler.d.ts +5 -8
- package/build/insights-handler.d.ts.map +1 -1
- package/build/insights-handler.js +40 -93
- package/build/instrumentation/funnelInstrumentation.d.ts +6 -0
- package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -0
- package/build/instrumentation/funnelInstrumentation.js +119 -0
- package/build/launcher.d.ts +1 -1
- package/build/launcher.d.ts.map +1 -1
- package/build/launcher.js +22 -13
- package/build/reporter.d.ts +3 -3
- package/build/reporter.d.ts.map +1 -1
- package/build/reporter.js +11 -27
- package/build/request-handler.d.ts +5 -13
- package/build/request-handler.d.ts.map +1 -1
- package/build/request-handler.js +30 -48
- package/build/service.d.ts +1 -0
- package/build/service.d.ts.map +1 -1
- package/build/service.js +13 -5
- package/build/testOps/featureStats.d.ts +45 -0
- package/build/testOps/featureStats.d.ts.map +1 -0
- package/build/testOps/featureStats.js +116 -0
- package/build/testOps/featureUsage.d.ts +22 -0
- package/build/testOps/featureUsage.d.ts.map +1 -0
- package/build/testOps/featureUsage.js +47 -0
- package/build/testOps/listener.d.ts +33 -0
- package/build/testOps/listener.d.ts.map +1 -0
- package/build/testOps/listener.js +222 -0
- package/build/testOps/requestUtils.d.ts +4 -0
- package/build/testOps/requestUtils.d.ts.map +1 -0
- package/build/testOps/requestUtils.js +39 -0
- package/build/testOps/testOpsConfig.d.ts +11 -0
- package/build/testOps/testOpsConfig.d.ts.map +1 -0
- package/build/testOps/testOpsConfig.js +19 -0
- package/build/testOps/usageStats.d.ts +404 -0
- package/build/testOps/usageStats.d.ts.map +1 -0
- package/build/testOps/usageStats.js +114 -0
- package/build/types.d.ts +33 -7
- package/build/types.d.ts.map +1 -1
- package/build/util.d.ts +3 -7
- package/build/util.d.ts.map +1 -1
- package/build/util.js +57 -77
- package/package.json +4 -4
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { v4 as uuidv4 } from 'uuid';
|
|
3
3
|
import TestReporter from './reporter.js';
|
|
4
|
-
import { frameworkSupportsHook, getCloudProvider, getFailureObject, getGitMetaData, getHookType, getPlatformVersion, getScenarioExamples, getUniqueIdentifier, getUniqueIdentifierForCucumber, isBrowserstackSession, isScreenshotCommand, o11yClassErrorHandler,
|
|
5
|
-
import RequestQueueHandler from './request-handler.js';
|
|
6
|
-
import { DATA_SCREENSHOT_ENDPOINT, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS } from './constants.js';
|
|
4
|
+
import { frameworkSupportsHook, getCloudProvider, getFailureObject, getGitMetaData, getHookType, getPlatformVersion, getScenarioExamples, getUniqueIdentifier, getUniqueIdentifierForCucumber, isBrowserstackSession, isScreenshotCommand, o11yClassErrorHandler, removeAnsiColors, } from './util.js';
|
|
7
5
|
import { BStackLogger } from './bstackLogger.js';
|
|
6
|
+
import Listener from './testOps/listener.js';
|
|
7
|
+
import { TESTOPS_SCREENSHOT_ENV } from './constants.js';
|
|
8
8
|
class _InsightsHandler {
|
|
9
9
|
_browser;
|
|
10
10
|
_framework;
|
|
@@ -14,7 +14,6 @@ class _InsightsHandler {
|
|
|
14
14
|
_commands = {};
|
|
15
15
|
_gitConfigPath;
|
|
16
16
|
_suiteFile;
|
|
17
|
-
_requestQueueHandler = RequestQueueHandler.getInstance();
|
|
18
17
|
_currentTest = {};
|
|
19
18
|
_currentHook = {};
|
|
20
19
|
_cucumberData = {
|
|
@@ -23,10 +22,10 @@ class _InsightsHandler {
|
|
|
23
22
|
steps: []
|
|
24
23
|
};
|
|
25
24
|
_userCaps = {};
|
|
25
|
+
listener = Listener.getInstance();
|
|
26
26
|
constructor(_browser, isAppAutomate, _framework, _userCaps) {
|
|
27
27
|
this._browser = _browser;
|
|
28
28
|
this._framework = _framework;
|
|
29
|
-
this._requestQueueHandler.start();
|
|
30
29
|
const caps = this._browser.capabilities;
|
|
31
30
|
const sessionId = this._browser.sessionId;
|
|
32
31
|
this._platformMeta = {
|
|
@@ -142,7 +141,7 @@ class _InsightsHandler {
|
|
|
142
141
|
};
|
|
143
142
|
}),
|
|
144
143
|
};
|
|
145
|
-
|
|
144
|
+
this.listener.testFinished(this.getTestRunDataForCucumber(null, 'TestRunSkipped', testMetaData));
|
|
146
145
|
}
|
|
147
146
|
async processCucumberHook(test, params, result) {
|
|
148
147
|
const hookType = this.getCucumberHookType(test);
|
|
@@ -163,12 +162,12 @@ class _InsightsHandler {
|
|
|
163
162
|
hookType: hookType
|
|
164
163
|
};
|
|
165
164
|
this._tests[hookId] = hookMetaData;
|
|
166
|
-
|
|
165
|
+
this.listener.hookStarted(this.getHookRunDataForCucumber(hookMetaData, 'HookRunStarted'));
|
|
167
166
|
}
|
|
168
167
|
else {
|
|
169
168
|
this._tests[hookId].finishedAt = (new Date()).toISOString();
|
|
170
169
|
this.setCurrentHook({ uuid: this._tests[hookId].uuid, finished: true });
|
|
171
|
-
|
|
170
|
+
this.listener.hookFinished(this.getHookRunDataForCucumber(this._tests[hookId], 'HookRunFinished', result));
|
|
172
171
|
if (hookType === 'BEFORE_ALL' && result && !result.passed) {
|
|
173
172
|
const { feature, uri } = this._cucumberData;
|
|
174
173
|
if (!feature) {
|
|
@@ -207,7 +206,7 @@ class _InsightsHandler {
|
|
|
207
206
|
};
|
|
208
207
|
this.setCurrentHook({ uuid: hookUUID });
|
|
209
208
|
this.attachHookData(context, hookUUID);
|
|
210
|
-
|
|
209
|
+
this.listener.hookStarted(this.getRunData(test, 'HookRunStarted'));
|
|
211
210
|
}
|
|
212
211
|
async afterHook(test, result) {
|
|
213
212
|
if (!frameworkSupportsHook('after', this._framework)) {
|
|
@@ -228,7 +227,7 @@ class _InsightsHandler {
|
|
|
228
227
|
};
|
|
229
228
|
}
|
|
230
229
|
this.setCurrentHook({ uuid: this._tests[fullTitle].uuid, finished: true });
|
|
231
|
-
|
|
230
|
+
this.listener.hookFinished(this.getRunData(test, 'HookRunFinished', result));
|
|
232
231
|
const hookType = getHookType(test.title);
|
|
233
232
|
/*
|
|
234
233
|
If any of the `beforeAll`, `beforeEach`, `afterEach` then the tests after the hook won't run in mocha (https://github.com/mochajs/mocha/issues/4392)
|
|
@@ -245,7 +244,7 @@ class _InsightsHandler {
|
|
|
245
244
|
startedAt: (new Date()).toISOString(),
|
|
246
245
|
finishedAt: (new Date()).toISOString()
|
|
247
246
|
};
|
|
248
|
-
|
|
247
|
+
this.listener.testFinished(this.getRunData(skippedTest, 'TestRunSkipped'));
|
|
249
248
|
}
|
|
250
249
|
};
|
|
251
250
|
/*
|
|
@@ -262,7 +261,7 @@ class _InsightsHandler {
|
|
|
262
261
|
await sendSuiteSkipped(test.ctx.test.parent);
|
|
263
262
|
}
|
|
264
263
|
}
|
|
265
|
-
|
|
264
|
+
getHookRunDataForCucumber(hookData, eventType, result) {
|
|
266
265
|
const { uri, feature } = this._cucumberData;
|
|
267
266
|
const testData = {
|
|
268
267
|
uuid: hookData.uuid,
|
|
@@ -299,14 +298,7 @@ class _InsightsHandler {
|
|
|
299
298
|
testData.integrations[provider] = this.getIntegrationsObject();
|
|
300
299
|
}
|
|
301
300
|
}
|
|
302
|
-
|
|
303
|
-
event_type: eventType,
|
|
304
|
-
hook_run: testData
|
|
305
|
-
};
|
|
306
|
-
const req = this._requestQueueHandler.add(uploadData);
|
|
307
|
-
if (req.proceed && req.data) {
|
|
308
|
-
await uploadEventData(req.data, req.url);
|
|
309
|
-
}
|
|
301
|
+
return testData;
|
|
310
302
|
}
|
|
311
303
|
async beforeTest(test) {
|
|
312
304
|
const uuid = uuidv4();
|
|
@@ -321,7 +313,7 @@ class _InsightsHandler {
|
|
|
321
313
|
uuid,
|
|
322
314
|
startedAt: (new Date()).toISOString()
|
|
323
315
|
};
|
|
324
|
-
|
|
316
|
+
this.listener.testStarted(this.getRunData(test, 'TestRunStarted'));
|
|
325
317
|
}
|
|
326
318
|
async afterTest(test, result) {
|
|
327
319
|
if (this._framework !== 'mocha') {
|
|
@@ -332,7 +324,8 @@ class _InsightsHandler {
|
|
|
332
324
|
...(this._tests[fullTitle] || {}),
|
|
333
325
|
finishedAt: (new Date()).toISOString()
|
|
334
326
|
};
|
|
335
|
-
|
|
327
|
+
BStackLogger.debug('calling testFinished');
|
|
328
|
+
this.listener.testFinished(this.getRunData(test, 'TestRunFinished', result));
|
|
336
329
|
}
|
|
337
330
|
/**
|
|
338
331
|
* Cucumber Only
|
|
@@ -371,11 +364,11 @@ class _InsightsHandler {
|
|
|
371
364
|
};
|
|
372
365
|
}
|
|
373
366
|
this._tests[uniqueId] = testMetaData;
|
|
374
|
-
|
|
367
|
+
this.listener.testStarted(this.getTestRunDataForCucumber(world, 'TestRunStarted'));
|
|
375
368
|
}
|
|
376
369
|
async afterScenario(world) {
|
|
377
370
|
this._cucumberData.scenario = undefined;
|
|
378
|
-
|
|
371
|
+
this.listener.testFinished(this.getTestRunDataForCucumber(world, 'TestRunFinished'));
|
|
379
372
|
}
|
|
380
373
|
async beforeStep(step, scenario) {
|
|
381
374
|
this._cucumberData.stepsStarted = true;
|
|
@@ -417,17 +410,6 @@ class _InsightsHandler {
|
|
|
417
410
|
}
|
|
418
411
|
this._tests[uniqueId] = testMetaData;
|
|
419
412
|
}
|
|
420
|
-
async uploadPending(waitTimeout = DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
|
|
421
|
-
if (this._requestQueueHandler.pendingUploads <= 0 || waitTimeout <= 0) {
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
await sleep(waitInterval);
|
|
425
|
-
return this.uploadPending(waitTimeout - waitInterval);
|
|
426
|
-
}
|
|
427
|
-
async teardown() {
|
|
428
|
-
RequestQueueHandler.tearDownInvoked = true;
|
|
429
|
-
await this._requestQueueHandler.shutdown();
|
|
430
|
-
}
|
|
431
413
|
/**
|
|
432
414
|
* misc methods
|
|
433
415
|
*/
|
|
@@ -440,22 +422,13 @@ class _InsightsHandler {
|
|
|
440
422
|
stdLog.test_run_uuid = this._currentTest.uuid;
|
|
441
423
|
}
|
|
442
424
|
if (stdLog.hook_run_uuid || stdLog.test_run_uuid) {
|
|
443
|
-
|
|
444
|
-
event_type: 'LogCreated',
|
|
445
|
-
logs: [stdLog]
|
|
446
|
-
});
|
|
425
|
+
this.listener.logCreated([stdLog]);
|
|
447
426
|
}
|
|
448
427
|
}
|
|
449
428
|
catch (error) {
|
|
450
429
|
BStackLogger.debug(`Exception in uploading log data to Observability with error : ${error}`);
|
|
451
430
|
}
|
|
452
431
|
};
|
|
453
|
-
async sendData(data) {
|
|
454
|
-
const req = this._requestQueueHandler.add(data);
|
|
455
|
-
if (req.proceed && req.data) {
|
|
456
|
-
await uploadEventData(req.data, req.url);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
432
|
async browserCommand(commandType, args, test) {
|
|
460
433
|
const dataKey = `${args.sessionId}_${args.method}_${args.endpoint}`;
|
|
461
434
|
if (commandType === 'client:beforeCommand') {
|
|
@@ -473,39 +446,30 @@ class _InsightsHandler {
|
|
|
473
446
|
// log screenshot
|
|
474
447
|
const body = 'body' in args ? args.body : undefined;
|
|
475
448
|
const result = 'result' in args ? args.result : undefined;
|
|
476
|
-
if (Boolean(process.env
|
|
477
|
-
await
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
kind: 'TEST_SCREENSHOT'
|
|
484
|
-
}]
|
|
485
|
-
}], DATA_SCREENSHOT_ENDPOINT);
|
|
449
|
+
if (Boolean(process.env[TESTOPS_SCREENSHOT_ENV]) && isScreenshotCommand(args) && result?.value) {
|
|
450
|
+
await this.listener.onScreenshot([{
|
|
451
|
+
test_run_uuid: testMeta.uuid,
|
|
452
|
+
timestamp: new Date().toISOString(),
|
|
453
|
+
message: result.value,
|
|
454
|
+
kind: 'TEST_SCREENSHOT'
|
|
455
|
+
}]);
|
|
486
456
|
}
|
|
487
457
|
const requestData = this._commands[dataKey];
|
|
488
458
|
if (!requestData) {
|
|
489
459
|
return;
|
|
490
460
|
}
|
|
491
461
|
// log http request
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}
|
|
504
|
-
}]
|
|
505
|
-
});
|
|
506
|
-
if (req.proceed && req.data) {
|
|
507
|
-
await uploadEventData(req.data, req.url);
|
|
508
|
-
}
|
|
462
|
+
this.listener.logCreated([{
|
|
463
|
+
test_run_uuid: testMeta.uuid,
|
|
464
|
+
timestamp: new Date().toISOString(),
|
|
465
|
+
kind: 'HTTP',
|
|
466
|
+
http_response: {
|
|
467
|
+
path: requestData.endpoint,
|
|
468
|
+
method: requestData.method,
|
|
469
|
+
body,
|
|
470
|
+
response: result
|
|
471
|
+
}
|
|
472
|
+
}]);
|
|
509
473
|
}
|
|
510
474
|
/*
|
|
511
475
|
* private methods
|
|
@@ -563,7 +527,7 @@ class _InsightsHandler {
|
|
|
563
527
|
}
|
|
564
528
|
return value.reverse();
|
|
565
529
|
}
|
|
566
|
-
|
|
530
|
+
getRunData(test, eventType, results) {
|
|
567
531
|
const fullTitle = getUniqueIdentifier(test, this._framework);
|
|
568
532
|
const testMetaData = this._tests[fullTitle];
|
|
569
533
|
const filename = test.file || this._suiteFile;
|
|
@@ -616,22 +580,12 @@ class _InsightsHandler {
|
|
|
616
580
|
testData.result = 'skipped';
|
|
617
581
|
eventType = 'TestRunFinished';
|
|
618
582
|
}
|
|
619
|
-
const uploadData = {
|
|
620
|
-
event_type: eventType,
|
|
621
|
-
};
|
|
622
583
|
/* istanbul ignore if */
|
|
623
584
|
if (eventType.match(/HookRun/)) {
|
|
624
585
|
testData.hook_type = testData.name?.toLowerCase() ? getHookType(testData.name.toLowerCase()) : 'undefined';
|
|
625
586
|
testData.test_run_id = this.getTestRunId(test.ctx);
|
|
626
|
-
uploadData.hook_run = testData;
|
|
627
|
-
}
|
|
628
|
-
else {
|
|
629
|
-
uploadData.test_run = testData;
|
|
630
|
-
}
|
|
631
|
-
const req = this._requestQueueHandler.add(uploadData);
|
|
632
|
-
if (req.proceed && req.data) {
|
|
633
|
-
await uploadEventData(req.data, req.url);
|
|
634
587
|
}
|
|
588
|
+
return testData;
|
|
635
589
|
}
|
|
636
590
|
getTestRunId(context) {
|
|
637
591
|
if (!context) {
|
|
@@ -664,7 +618,7 @@ class _InsightsHandler {
|
|
|
664
618
|
}
|
|
665
619
|
return;
|
|
666
620
|
}
|
|
667
|
-
|
|
621
|
+
getTestRunDataForCucumber(worldObj, eventType, testMetaData = null) {
|
|
668
622
|
const world = worldObj;
|
|
669
623
|
const dataHub = testMetaData ? testMetaData : (this._tests[getUniqueIdentifierForCucumber(world)] || {});
|
|
670
624
|
const { feature, scenario, steps, uuid, startedAt, finishedAt } = dataHub;
|
|
@@ -740,14 +694,7 @@ class _InsightsHandler {
|
|
|
740
694
|
testData.result = 'skipped';
|
|
741
695
|
eventType = 'TestRunFinished';
|
|
742
696
|
}
|
|
743
|
-
|
|
744
|
-
event_type: eventType,
|
|
745
|
-
test_run: testData
|
|
746
|
-
};
|
|
747
|
-
const req = this._requestQueueHandler.add(uploadData);
|
|
748
|
-
if (req.proceed && req.data) {
|
|
749
|
-
await uploadEventData(req.data, req.url);
|
|
750
|
-
}
|
|
697
|
+
return testData;
|
|
751
698
|
}
|
|
752
699
|
getIntegrationsObject() {
|
|
753
700
|
const caps = this._browser?.capabilities;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type BrowserStackConfig from '../config.js';
|
|
2
|
+
export declare function sendStart(config: BrowserStackConfig): Promise<void>;
|
|
3
|
+
export declare function sendFinish(config: BrowserStackConfig): Promise<void>;
|
|
4
|
+
export declare function saveFunnelData(eventType: string, config: BrowserStackConfig): string;
|
|
5
|
+
export declare function fireFunnelRequest(data: any): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=funnelInstrumentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"funnelInstrumentation.d.ts","sourceRoot":"","sources":["../../src/instrumentation/funnelInstrumentation.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,kBAAkB,MAAM,cAAc,CAAA;AAsBlD,wBAAsB,SAAS,CAAC,MAAM,EAAE,kBAAkB,iBAIzD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,kBAAkB,iBAE1D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAOpF;AAGD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import util from 'node:util';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import got from 'got';
|
|
6
|
+
import UsageStats from '../testOps/usageStats.js';
|
|
7
|
+
import { BStackLogger } from '../bstackLogger.js';
|
|
8
|
+
import { BSTACK_SERVICE_VERSION, FUNNEL_INSTRUMENTATION_URL } from '../constants.js';
|
|
9
|
+
import { getDataFromWorkers, removeWorkersDataDir } from '../data-store.js';
|
|
10
|
+
async function fireFunnelTestEvent(eventType, config) {
|
|
11
|
+
if (!config.userName || !config.accessKey) {
|
|
12
|
+
BStackLogger.debug('username/accesskey not passed');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const data = buildEventData(eventType, config);
|
|
17
|
+
await fireFunnelRequest(data);
|
|
18
|
+
BStackLogger.debug('Funnel event success');
|
|
19
|
+
if (eventType === 'SDKTestSuccessful') {
|
|
20
|
+
config.sentFunnelData();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
BStackLogger.debug('Exception in sending funnel data: ' + error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function sendStart(config) {
|
|
28
|
+
// Remove Workers folder if exists
|
|
29
|
+
removeWorkersDataDir();
|
|
30
|
+
await fireFunnelTestEvent('SDKTestAttempted', config);
|
|
31
|
+
}
|
|
32
|
+
export async function sendFinish(config) {
|
|
33
|
+
await fireFunnelTestEvent('SDKTestSuccessful', config);
|
|
34
|
+
}
|
|
35
|
+
export function saveFunnelData(eventType, config) {
|
|
36
|
+
const data = buildEventData(eventType, config);
|
|
37
|
+
BStackLogger.ensureLogsFolder();
|
|
38
|
+
const filePath = path.join(BStackLogger.logFolderPath, 'funnelData.json');
|
|
39
|
+
fs.writeFileSync(filePath, JSON.stringify(data));
|
|
40
|
+
return filePath;
|
|
41
|
+
}
|
|
42
|
+
// Called from two different process
|
|
43
|
+
export async function fireFunnelRequest(data) {
|
|
44
|
+
BStackLogger.debug('Sending SDK event with data ' + util.inspect(data, { depth: 6 }));
|
|
45
|
+
await got.post(FUNNEL_INSTRUMENTATION_URL, {
|
|
46
|
+
headers: {
|
|
47
|
+
'content-type': 'application/json'
|
|
48
|
+
}, username: data.userName, password: data.accessKey, json: data
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function getProductList(config) {
|
|
52
|
+
const products = [];
|
|
53
|
+
if (config.testObservability.enabled) {
|
|
54
|
+
products.push('observability');
|
|
55
|
+
}
|
|
56
|
+
if (config.accessibility) {
|
|
57
|
+
products.push('accessibility');
|
|
58
|
+
}
|
|
59
|
+
if (config.percy) {
|
|
60
|
+
products.push('percy');
|
|
61
|
+
}
|
|
62
|
+
if (config.automate) {
|
|
63
|
+
products.push('automate');
|
|
64
|
+
}
|
|
65
|
+
if (config.appAutomate) {
|
|
66
|
+
products.push('app-automate');
|
|
67
|
+
}
|
|
68
|
+
return products;
|
|
69
|
+
}
|
|
70
|
+
function getProductMap(config) {
|
|
71
|
+
return {
|
|
72
|
+
'observability': config.testObservability.enabled,
|
|
73
|
+
'accessibility': config.accessibility,
|
|
74
|
+
'percy': config.percy,
|
|
75
|
+
'automate': config.automate,
|
|
76
|
+
'app_automate': config.appAutomate
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function buildEventData(eventType, config) {
|
|
80
|
+
const eventProperties = {
|
|
81
|
+
// Framework Details
|
|
82
|
+
language_framework: getLanguageFramework(config.framework),
|
|
83
|
+
referrer: getReferrer(config.framework),
|
|
84
|
+
language: 'WebdriverIO',
|
|
85
|
+
languageVersion: process.version,
|
|
86
|
+
// Build Details
|
|
87
|
+
buildName: config.buildName || 'undefined',
|
|
88
|
+
buildIdentifier: String(config.buildIdentifier),
|
|
89
|
+
// Host details
|
|
90
|
+
os: os.type() || 'unknown',
|
|
91
|
+
hostname: os.hostname() || 'unknown',
|
|
92
|
+
// Product Details
|
|
93
|
+
productMap: getProductMap(config),
|
|
94
|
+
product: getProductList(config),
|
|
95
|
+
};
|
|
96
|
+
if (eventType === 'SDKTestSuccessful') {
|
|
97
|
+
const workerData = getDataFromWorkers();
|
|
98
|
+
eventProperties.productUsage = getProductUsage(workerData);
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
userName: config.userName,
|
|
102
|
+
accessKey: config.accessKey,
|
|
103
|
+
event_type: eventType,
|
|
104
|
+
detectedFramework: 'WebdriverIO-' + config.framework,
|
|
105
|
+
event_properties: eventProperties
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function getProductUsage(workersData) {
|
|
109
|
+
return {
|
|
110
|
+
testObservability: UsageStats.getInstance().getFormattedData(workersData)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function getLanguageFramework(framework) {
|
|
114
|
+
return 'WebdriverIO_' + framework;
|
|
115
|
+
}
|
|
116
|
+
function getReferrer(framework) {
|
|
117
|
+
const fullName = framework ? 'WebdriverIO-' + framework : 'WebdriverIO';
|
|
118
|
+
return `${fullName}/${BSTACK_SERVICE_VERSION}`;
|
|
119
|
+
}
|
package/build/launcher.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export default class BrowserstackLauncherService implements Services.ServiceInst
|
|
|
16
16
|
private _accessibilityAutomation?;
|
|
17
17
|
private _percy?;
|
|
18
18
|
private _percyBestPlatformCaps?;
|
|
19
|
-
|
|
19
|
+
private readonly browserStackConfig;
|
|
20
20
|
constructor(_options: BrowserstackConfig & Options.Testrunner, capabilities: Capabilities.RemoteCapability, _config: Options.Testrunner);
|
|
21
21
|
onWorkerStart(cid: any, caps: any): Promise<void>;
|
|
22
22
|
onPrepare(config?: Options.Testrunner, capabilities?: Capabilities.RemoteCapabilities): Promise<unknown>;
|
package/build/launcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAKlE,OAAO,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAKlE,OAAO,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAgCnG,KAAK,iBAAiB,GAAG,yBAAyB,CAAC,KAAK,GAAG;IACvD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAA;CAC9C,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,2BAA4B,YAAW,QAAQ,CAAC,eAAe;IAY5E,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,OAAO;IAbnB,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,YAAY,CAAC,CAAQ;IAC7B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,gBAAgB,CAAC,CAAQ;IACjC,OAAO,CAAC,wBAAwB,CAAC,CAAS;IAC1C,OAAO,CAAC,MAAM,CAAC,CAAO;IACtB,OAAO,CAAC,sBAAsB,CAAC,CAAkC;IACjE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;gBAG3C,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IAgHjC,aAAa,CAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG;IAalC,SAAS,CAAE,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IA2JtF,UAAU;IA6EV,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU;IAwB7G,SAAS;IAYT,UAAU,CAAC,GAAG,EAAC,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAuBrD;;;OAGG;IACG,YAAY,CAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAyB1D,kBAAkB;IAOxB,qBAAqB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE;IAiFtH,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IA2F5F,sBAAsB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IAyCrE;;;OAGG;IACH,oBAAoB;IA6BpB,sBAAsB,CAAC,QAAQ,CAAC,EAAC,MAAM,EAAE,SAAS,CAAC,EAAC,MAAM,EAAE,eAAe,CAAC,EAAC,MAAM;IASnF,mBAAmB;CAQtB"}
|
package/build/launcher.js
CHANGED
|
@@ -10,12 +10,15 @@ import { SevereServiceError } from 'webdriverio';
|
|
|
10
10
|
import * as BrowserstackLocalLauncher from 'browserstack-local';
|
|
11
11
|
import PerformanceTester from './performance-tester.js';
|
|
12
12
|
import { startPercy, stopPercy, getBestPlatformForPercySnapshot } from './Percy/PercyHelper.js';
|
|
13
|
-
import { BSTACK_SERVICE_VERSION, NOT_ALLOWED_KEYS_IN_CAPS, VALID_APP_EXTENSION } from './constants.js';
|
|
14
|
-
import { launchTestSession, createAccessibilityTestRun, shouldAddServiceVersion, stopBuildUpstream, getCiInfo, isBStackSession, isUndefined, isAccessibilityAutomationSession, stopAccessibilityTestRun, isTrue, getBrowserStackUser, getBrowserStackKey, uploadLogs, ObjectsAreEqual,
|
|
13
|
+
import { BSTACK_SERVICE_VERSION, NOT_ALLOWED_KEYS_IN_CAPS, PERF_MEASUREMENT_ENV, RERUN_ENV, RERUN_TESTS_ENV, TESTOPS_BUILD_ID_ENV, VALID_APP_EXTENSION } from './constants.js';
|
|
14
|
+
import { launchTestSession, createAccessibilityTestRun, shouldAddServiceVersion, stopBuildUpstream, getCiInfo, isBStackSession, isUndefined, isAccessibilityAutomationSession, stopAccessibilityTestRun, isTrue, getBrowserStackUser, getBrowserStackKey, uploadLogs, ObjectsAreEqual, } from './util.js';
|
|
15
15
|
import CrashReporter from './crash-reporter.js';
|
|
16
16
|
import { BStackLogger } from './bstackLogger.js';
|
|
17
17
|
import { PercyLogger } from './Percy/PercyLogger.js';
|
|
18
18
|
import { FileStream } from './fileStream.js';
|
|
19
|
+
import { sendStart, sendFinish } from './instrumentation/funnelInstrumentation.js';
|
|
20
|
+
import BrowserStackConfig from './config.js';
|
|
21
|
+
import { setupExitHandlers } from './exitHandler.js';
|
|
19
22
|
export default class BrowserstackLauncherService {
|
|
20
23
|
_options;
|
|
21
24
|
_config;
|
|
@@ -27,7 +30,7 @@ export default class BrowserstackLauncherService {
|
|
|
27
30
|
_accessibilityAutomation;
|
|
28
31
|
_percy;
|
|
29
32
|
_percyBestPlatformCaps;
|
|
30
|
-
|
|
33
|
+
browserStackConfig;
|
|
31
34
|
constructor(_options, capabilities, _config) {
|
|
32
35
|
this._options = _options;
|
|
33
36
|
this._config = _config;
|
|
@@ -36,6 +39,7 @@ export default class BrowserstackLauncherService {
|
|
|
36
39
|
setupExitHandlers();
|
|
37
40
|
// added to maintain backward compatibility with webdriverIO v5
|
|
38
41
|
this._config || (this._config = _options);
|
|
42
|
+
this.browserStackConfig = BrowserStackConfig.getInstance(_options, _config);
|
|
39
43
|
if (Array.isArray(capabilities)) {
|
|
40
44
|
capabilities
|
|
41
45
|
.flatMap((c) => {
|
|
@@ -117,18 +121,20 @@ export default class BrowserstackLauncherService {
|
|
|
117
121
|
}
|
|
118
122
|
});
|
|
119
123
|
}
|
|
120
|
-
|
|
124
|
+
this.browserStackConfig.buildIdentifier = this._buildIdentifier;
|
|
125
|
+
this.browserStackConfig.buildName = this._buildName;
|
|
126
|
+
if (process.env[PERF_MEASUREMENT_ENV]) {
|
|
121
127
|
PerformanceTester.startMonitoring('performance-report-launcher.csv');
|
|
122
128
|
}
|
|
123
129
|
this._accessibilityAutomation ||= isTrue(this._options.accessibility);
|
|
124
130
|
this._options.accessibility = this._accessibilityAutomation;
|
|
125
131
|
// by default observability will be true unless specified as false
|
|
126
|
-
this._options.testObservability = this._options.testObservability
|
|
132
|
+
this._options.testObservability = this._options.testObservability !== false;
|
|
127
133
|
if (this._options.testObservability
|
|
128
134
|
&&
|
|
129
135
|
// update files to run if it's a rerun
|
|
130
|
-
process.env
|
|
131
|
-
this._config.specs = process.env.
|
|
136
|
+
process.env[RERUN_ENV] && process.env[RERUN_TESTS_ENV]) {
|
|
137
|
+
this._config.specs = process.env[RERUN_TESTS_ENV].split(',');
|
|
132
138
|
}
|
|
133
139
|
try {
|
|
134
140
|
CrashReporter.setConfigDetails(this._config, capabilities, this._options);
|
|
@@ -151,6 +157,8 @@ export default class BrowserstackLauncherService {
|
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
159
|
async onPrepare(config, capabilities) {
|
|
160
|
+
// // Send Funnel start request
|
|
161
|
+
await sendStart(this.browserStackConfig);
|
|
154
162
|
/**
|
|
155
163
|
* Upload app to BrowserStack if valid file path to app is given.
|
|
156
164
|
* Update app value of capability directly if app_url, custom_id, shareable_id is given
|
|
@@ -297,11 +305,11 @@ export default class BrowserstackLauncherService {
|
|
|
297
305
|
if (this._options.testObservability) {
|
|
298
306
|
BStackLogger.debug('Sending stop launch event');
|
|
299
307
|
await stopBuildUpstream();
|
|
300
|
-
if (process.env
|
|
301
|
-
console.log(`\nVisit https://observability.browserstack.com/builds/${process.env
|
|
308
|
+
if (process.env[TESTOPS_BUILD_ID_ENV]) {
|
|
309
|
+
console.log(`\nVisit https://observability.browserstack.com/builds/${process.env[TESTOPS_BUILD_ID_ENV]} to view build report, insights, and many more debugging information all at one place!\n`);
|
|
302
310
|
}
|
|
303
|
-
|
|
304
|
-
if (process.env
|
|
311
|
+
this.browserStackConfig.testObservability.buildStopped = true;
|
|
312
|
+
if (process.env[PERF_MEASUREMENT_ENV]) {
|
|
305
313
|
await PerformanceTester.stopAndGenerate('performance-launcher.html');
|
|
306
314
|
PerformanceTester.calculateTimes(['launchTestSession', 'stopBuildUpstream']);
|
|
307
315
|
if (!process.env.START_TIME) {
|
|
@@ -317,6 +325,7 @@ export default class BrowserstackLauncherService {
|
|
|
317
325
|
catch (error) {
|
|
318
326
|
BStackLogger.debug(`Failed to upload BrowserStack WDIO Service logs ${error}`);
|
|
319
327
|
}
|
|
328
|
+
await sendFinish(this.browserStackConfig);
|
|
320
329
|
BStackLogger.clearLogger();
|
|
321
330
|
if (this._options.percy) {
|
|
322
331
|
await this.stopPercy();
|
|
@@ -718,8 +727,8 @@ export default class BrowserstackLauncherService {
|
|
|
718
727
|
fs.writeFileSync(filePath, JSON.stringify(jsonContent));
|
|
719
728
|
}
|
|
720
729
|
_getClientBuildUuid() {
|
|
721
|
-
if (process.env
|
|
722
|
-
return process.env
|
|
730
|
+
if (process.env[TESTOPS_BUILD_ID_ENV]) {
|
|
731
|
+
return process.env[TESTOPS_BUILD_ID_ENV];
|
|
723
732
|
}
|
|
724
733
|
const uuid = uuidv4();
|
|
725
734
|
BStackLogger.logToFile(`If facing any issues, please contact BrowserStack support with the Build Run Id - ${uuid}`, 'info');
|
package/build/reporter.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { SuiteStats, TestStats, RunnerStats, HookStats } from '@wdio/reporter';
|
|
2
2
|
import WDIOReporter from '@wdio/reporter';
|
|
3
3
|
import type { CurrentRunInfo, StdLog } from './types.js';
|
|
4
|
-
import type { TestMeta } from './types.js';
|
|
4
|
+
import type { TestData, TestMeta } from './types.js';
|
|
5
5
|
declare class _TestReporter extends WDIOReporter {
|
|
6
6
|
private _capabilities;
|
|
7
7
|
private _config?;
|
|
8
8
|
private _observability;
|
|
9
9
|
private _sessionId?;
|
|
10
10
|
private _suiteName?;
|
|
11
|
-
private _requestQueueHandler;
|
|
12
11
|
private _suites;
|
|
13
12
|
private static _tests;
|
|
14
13
|
private _gitConfigPath?;
|
|
@@ -16,6 +15,7 @@ declare class _TestReporter extends WDIOReporter {
|
|
|
16
15
|
private _currentHook;
|
|
17
16
|
private _currentTest;
|
|
18
17
|
private _userCaps?;
|
|
18
|
+
private listener;
|
|
19
19
|
onRunnerStart(runnerStats: RunnerStats): Promise<void>;
|
|
20
20
|
private getUserCaps;
|
|
21
21
|
registerListeners(): void;
|
|
@@ -32,7 +32,7 @@ declare class _TestReporter extends WDIOReporter {
|
|
|
32
32
|
onHookEnd(hookStats: HookStats): Promise<void>;
|
|
33
33
|
getHookIdentifier(hookStats: HookStats): string;
|
|
34
34
|
onTestSkip(testStats: TestStats): Promise<void>;
|
|
35
|
-
|
|
35
|
+
getRunData(testStats: TestStats | HookStats, eventType: string): Promise<TestData>;
|
|
36
36
|
}
|
|
37
37
|
declare const TestReporter: typeof _TestReporter;
|
|
38
38
|
type TestReporter = _TestReporter;
|
package/build/reporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AACnF,OAAO,YAAY,MAAM,gBAAgB,CAAA;AAKzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AACnF,OAAO,YAAY,MAAM,gBAAgB,CAAA;AAKzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExD,OAAO,KAAK,EAAsB,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAaxE,cAAM,aAAc,SAAQ,YAAY;IACpC,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,OAAO,CAAC,CAAyC;IACzD,OAAO,CAAC,cAAc,CAAO;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,MAAM,CAAC,MAAM,CAA+B;IACpD,OAAO,CAAC,cAAc,CAAC,CAAQ;IAC/B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,SAAS,CAAC,CAAoC;IACtD,OAAO,CAAC,QAAQ,CAAyB;IAEnC,aAAa,CAAE,WAAW,EAAE,WAAW;IAY7C,OAAO,CAAC,WAAW;IAInB,iBAAiB;IAQJ,iBAAiB,CAAC,MAAM,EAAE,MAAM;IAW7C,cAAc,CAAC,WAAW,EAAE,cAAc;IAapC,YAAY;IAWlB,MAAM,CAAC,QAAQ;IAIf,YAAY,CAAE,UAAU,EAAE,UAAU;IAoBpC,UAAU;IAIV,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAe1C,SAAS,CAAC,SAAS,EAAE,SAAS;IAY9B,WAAW,CAAC,SAAS,EAAE,SAAS;IAgBhC,WAAW,CAAC,SAAS,EAAE,SAAS;IAehC,SAAS,CAAC,SAAS,EAAE,SAAS;IAoBpC,iBAAiB,CAAC,SAAS,EAAE,SAAS;IAIhC,UAAU,CAAE,SAAS,EAAE,SAAS;IAWhC,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;CAmE3F;AAED,QAAA,MAAM,YAAY,EAAE,OAAO,aAAoD,CAAA;AAC/E,KAAK,YAAY,GAAG,aAAa,CAAA;AACjC,eAAe,YAAY,CAAA"}
|