@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.
Files changed (61) hide show
  1. package/build/bstackLogger.d.ts +2 -1
  2. package/build/bstackLogger.d.ts.map +1 -1
  3. package/build/bstackLogger.js +6 -3
  4. package/build/cleanup.d.ts +5 -1
  5. package/build/cleanup.d.ts.map +1 -1
  6. package/build/cleanup.js +72 -7
  7. package/build/config.d.ts +23 -0
  8. package/build/config.d.ts.map +1 -0
  9. package/build/config.js +39 -0
  10. package/build/constants.d.ts +14 -0
  11. package/build/constants.d.ts.map +1 -1
  12. package/build/constants.js +22 -0
  13. package/build/crash-reporter.js +2 -2
  14. package/build/data-store.d.ts +4 -0
  15. package/build/data-store.d.ts.map +1 -0
  16. package/build/data-store.js +41 -0
  17. package/build/exitHandler.d.ts +4 -0
  18. package/build/exitHandler.d.ts.map +1 -0
  19. package/build/exitHandler.js +32 -0
  20. package/build/insights-handler.d.ts +5 -8
  21. package/build/insights-handler.d.ts.map +1 -1
  22. package/build/insights-handler.js +40 -93
  23. package/build/instrumentation/funnelInstrumentation.d.ts +6 -0
  24. package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -0
  25. package/build/instrumentation/funnelInstrumentation.js +119 -0
  26. package/build/launcher.d.ts +1 -1
  27. package/build/launcher.d.ts.map +1 -1
  28. package/build/launcher.js +22 -13
  29. package/build/reporter.d.ts +3 -3
  30. package/build/reporter.d.ts.map +1 -1
  31. package/build/reporter.js +11 -27
  32. package/build/request-handler.d.ts +5 -13
  33. package/build/request-handler.d.ts.map +1 -1
  34. package/build/request-handler.js +30 -48
  35. package/build/service.d.ts +1 -0
  36. package/build/service.d.ts.map +1 -1
  37. package/build/service.js +13 -5
  38. package/build/testOps/featureStats.d.ts +45 -0
  39. package/build/testOps/featureStats.d.ts.map +1 -0
  40. package/build/testOps/featureStats.js +116 -0
  41. package/build/testOps/featureUsage.d.ts +22 -0
  42. package/build/testOps/featureUsage.d.ts.map +1 -0
  43. package/build/testOps/featureUsage.js +47 -0
  44. package/build/testOps/listener.d.ts +33 -0
  45. package/build/testOps/listener.d.ts.map +1 -0
  46. package/build/testOps/listener.js +222 -0
  47. package/build/testOps/requestUtils.d.ts +4 -0
  48. package/build/testOps/requestUtils.d.ts.map +1 -0
  49. package/build/testOps/requestUtils.js +39 -0
  50. package/build/testOps/testOpsConfig.d.ts +11 -0
  51. package/build/testOps/testOpsConfig.d.ts.map +1 -0
  52. package/build/testOps/testOpsConfig.js +19 -0
  53. package/build/testOps/usageStats.d.ts +404 -0
  54. package/build/testOps/usageStats.d.ts.map +1 -0
  55. package/build/testOps/usageStats.js +114 -0
  56. package/build/types.d.ts +33 -7
  57. package/build/types.d.ts.map +1 -1
  58. package/build/util.d.ts +3 -7
  59. package/build/util.d.ts.map +1 -1
  60. package/build/util.js +57 -77
  61. 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, pushDataToQueue, removeAnsiColors, sleep, uploadEventData } from './util.js';
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
- await this.sendTestRunEventForCucumber(null, 'TestRunSkipped', testMetaData);
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
- await this.sendHookRunEvent(hookMetaData, 'HookRunStarted');
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
- await this.sendHookRunEvent(this._tests[hookId], 'HookRunFinished', result);
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
- await this.sendTestRunEvent(test, 'HookRunStarted');
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
- await this.sendTestRunEvent(test, 'HookRunFinished', result);
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
- await this.sendTestRunEvent(skippedTest, 'TestRunSkipped');
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
- async sendHookRunEvent(hookData, eventType, result) {
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
- const uploadData = {
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
- await this.sendTestRunEvent(test, 'TestRunStarted');
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
- await this.sendTestRunEvent(test, 'TestRunFinished', result);
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
- await this.sendTestRunEventForCucumber(world, 'TestRunStarted');
367
+ this.listener.testStarted(this.getTestRunDataForCucumber(world, 'TestRunStarted'));
375
368
  }
376
369
  async afterScenario(world) {
377
370
  this._cucumberData.scenario = undefined;
378
- await this.sendTestRunEventForCucumber(world, 'TestRunFinished');
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
- await pushDataToQueue({
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.BS_TESTOPS_ALLOW_SCREENSHOTS) && isScreenshotCommand(args) && result?.value) {
477
- await uploadEventData([{
478
- event_type: 'LogCreated',
479
- logs: [{
480
- test_run_uuid: testMeta.uuid,
481
- timestamp: new Date().toISOString(),
482
- message: result.value,
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
- const req = this._requestQueueHandler.add({
493
- event_type: 'LogCreated',
494
- logs: [{
495
- test_run_uuid: testMeta.uuid,
496
- timestamp: new Date().toISOString(),
497
- kind: 'HTTP',
498
- http_response: {
499
- path: requestData.endpoint,
500
- method: requestData.method,
501
- body,
502
- response: result
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
- async sendTestRunEvent(test, eventType, results) {
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
- async sendTestRunEventForCucumber(worldObj, eventType, testMetaData = null) {
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
- const uploadData = {
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
+ }
@@ -16,7 +16,7 @@ export default class BrowserstackLauncherService implements Services.ServiceInst
16
16
  private _accessibilityAutomation?;
17
17
  private _percy?;
18
18
  private _percyBestPlatformCaps?;
19
- static _testOpsBuildStopped?: boolean;
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>;
@@ -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;AAyBnG,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,OAAc,oBAAoB,CAAC,EAAE,OAAO,CAAA;gBAGhC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IA2GjC,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;IAwJtF,UAAU;IA4EV,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"}
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, setupExitHandlers } from './util.js';
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
- static _testOpsBuildStopped;
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
- if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
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 === false ? false : true;
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.BROWSERSTACK_RERUN && process.env.BROWSERSTACK_RERUN_TESTS) {
131
- this._config.specs = process.env.BROWSERSTACK_RERUN_TESTS.split(',');
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.BS_TESTOPS_BUILD_HASHED_ID) {
301
- console.log(`\nVisit https://observability.browserstack.com/builds/${process.env.BS_TESTOPS_BUILD_HASHED_ID} to view build report, insights, and many more debugging information all at one place!\n`);
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
- BrowserstackLauncherService._testOpsBuildStopped = true;
304
- if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
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.BS_TESTOPS_BUILD_HASHED_ID) {
722
- return process.env.BS_TESTOPS_BUILD_HASHED_ID;
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');
@@ -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
- sendTestRunEvent(testStats: TestStats | HookStats, eventType: string): Promise<void>;
35
+ getRunData(testStats: TestStats | HookStats, eventType: string): Promise<TestData>;
36
36
  }
37
37
  declare const TestReporter: typeof _TestReporter;
38
38
  type TestReporter = _TestReporter;
@@ -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,EAAgC,QAAQ,EAAc,MAAM,YAAY,CAAA;AAcpF,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,oBAAoB,CAAoC;IAChE,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;IAEhD,aAAa,CAAE,WAAW,EAAE,WAAW;IAY7C,OAAO,CAAC,WAAW;IAInB,iBAAiB;IAQJ,iBAAiB,CAAC,MAAM,EAAE,MAAM;IAc7C,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,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM;CAgF7E;AAED,QAAA,MAAM,YAAY,EAAE,OAAO,aAAoD,CAAA;AAC/E,KAAK,YAAY,GAAG,aAAa,CAAA;AACjC,eAAe,YAAY,CAAA"}
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"}