@wdio/browserstack-service 7.35.0 → 7.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/build/bstackLogger.d.ts +14 -0
  2. package/build/bstackLogger.d.ts.map +1 -0
  3. package/build/bstackLogger.js +52 -0
  4. package/build/cleanup.d.ts +6 -2
  5. package/build/cleanup.d.ts.map +1 -1
  6. package/build/cleanup.js +104 -12
  7. package/build/config.d.ts +23 -0
  8. package/build/config.d.ts.map +1 -0
  9. package/build/config.js +32 -0
  10. package/build/constants.d.ts +17 -0
  11. package/build/constants.d.ts.map +1 -1
  12. package/build/constants.js +34 -1
  13. package/build/crash-reporter.js +1 -1
  14. package/build/data-store.d.ts +3 -0
  15. package/build/data-store.d.ts.map +1 -0
  16. package/build/data-store.js +49 -0
  17. package/build/exitHandler.d.ts +4 -0
  18. package/build/exitHandler.d.ts.map +1 -0
  19. package/build/exitHandler.js +37 -0
  20. package/build/insights-handler.d.ts +5 -11
  21. package/build/insights-handler.d.ts.map +1 -1
  22. package/build/insights-handler.js +45 -106
  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 +127 -0
  26. package/build/launcher.d.ts +1 -2
  27. package/build/launcher.d.ts.map +1 -1
  28. package/build/launcher.js +21 -20
  29. package/build/reporter.d.ts +3 -3
  30. package/build/reporter.d.ts.map +1 -1
  31. package/build/reporter.js +10 -23
  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 +27 -48
  35. package/build/service.d.ts +1 -0
  36. package/build/service.d.ts.map +1 -1
  37. package/build/service.js +14 -6
  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 +120 -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 +46 -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 +228 -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 +47 -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 +17 -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 +110 -0
  56. package/build/types.d.ts +33 -7
  57. package/build/types.d.ts.map +1 -1
  58. package/build/util.d.ts +2 -6
  59. package/build/util.d.ts.map +1 -1
  60. package/build/util.js +60 -66
  61. package/package.json +3 -3
@@ -8,7 +8,7 @@ const logger_1 = __importDefault(require("@wdio/logger"));
8
8
  const uuid_1 = require("uuid");
9
9
  const reporter_1 = __importDefault(require("./reporter"));
10
10
  const util_1 = require("./util");
11
- const request_handler_1 = __importDefault(require("./request-handler"));
11
+ const listener_1 = __importDefault(require("./testOps/listener"));
12
12
  const constants_1 = require("./constants");
13
13
  const log = (0, logger_1.default)('@wdio/browserstack-service');
14
14
  class _InsightsHandler {
@@ -18,7 +18,6 @@ class _InsightsHandler {
18
18
  this._tests = {};
19
19
  this._hooks = {};
20
20
  this._commands = {};
21
- this._requestQueueHandler = request_handler_1.default.getInstance();
22
21
  this._currentTest = {};
23
22
  this._currentHook = {};
24
23
  this._cucumberData = {
@@ -26,6 +25,7 @@ class _InsightsHandler {
26
25
  scenariosStarted: false,
27
26
  steps: []
28
27
  };
28
+ this.listener = listener_1.default.getInstance();
29
29
  this.appendTestItemLog = async (stdLog) => {
30
30
  try {
31
31
  if (this._currentHook.uuid && !this._currentHook.finished && (this._framework === 'mocha' || this._framework === 'cucumber')) {
@@ -35,17 +35,13 @@ class _InsightsHandler {
35
35
  stdLog.test_run_uuid = this._currentTest.uuid;
36
36
  }
37
37
  if (stdLog.hook_run_uuid || stdLog.test_run_uuid) {
38
- await (0, util_1.pushDataToQueue)({
39
- event_type: 'LogCreated',
40
- logs: [stdLog]
41
- });
38
+ this.listener.logCreated([stdLog]);
42
39
  }
43
40
  }
44
41
  catch (error) {
45
42
  log.debug(`Exception in uploading log data to Observability with error : ${error}`);
46
43
  }
47
44
  };
48
- this._requestQueueHandler.start();
49
45
  this._platformMeta = {
50
46
  browserName: browserCaps === null || browserCaps === void 0 ? void 0 : browserCaps.browserName,
51
47
  browserVersion: browserCaps === null || browserCaps === void 0 ? void 0 : browserCaps.browserVersion,
@@ -90,7 +86,7 @@ class _InsightsHandler {
90
86
  };
91
87
  this.setCurrentHook({ uuid: hookUUID });
92
88
  this.attachHookData(context, hookUUID);
93
- await this.sendTestRunEvent(test, 'HookRunStarted');
89
+ this.listener.hookStarted(this.getRunData(test, 'HookRunStarted'));
94
90
  }
95
91
  async afterHook(test, result) {
96
92
  if (!(0, util_1.frameworkSupportsHook)('after', this._framework)) {
@@ -111,7 +107,7 @@ class _InsightsHandler {
111
107
  };
112
108
  }
113
109
  this.setCurrentHook({ uuid: this._tests[fullTitle].uuid, finished: true });
114
- await this.sendTestRunEvent(test, 'HookRunFinished', result);
110
+ this.listener.hookFinished(this.getRunData(test, 'HookRunFinished', result));
115
111
  const hookType = (0, util_1.getHookType)(test.title);
116
112
  /*
117
113
  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)
@@ -128,7 +124,7 @@ class _InsightsHandler {
128
124
  startedAt: (new Date()).toISOString(),
129
125
  finishedAt: (new Date()).toISOString()
130
126
  };
131
- await this.sendTestRunEvent(skippedTest, 'TestRunSkipped');
127
+ this.listener.testFinished(this.getRunData(skippedTest, 'TestRunSkipped'));
132
128
  }
133
129
  };
134
130
  /*
@@ -157,7 +153,7 @@ class _InsightsHandler {
157
153
  uuid: uuid,
158
154
  startedAt: (new Date()).toISOString()
159
155
  };
160
- await this.sendTestRunEvent(test, 'TestRunStarted');
156
+ this.listener.testStarted(this.getRunData(test, 'TestRunStarted'));
161
157
  }
162
158
  async afterTest(test, result) {
163
159
  if (this._framework !== 'mocha')
@@ -167,7 +163,7 @@ class _InsightsHandler {
167
163
  ...(this._tests[fullTitle] || {}),
168
164
  finishedAt: (new Date()).toISOString()
169
165
  };
170
- await this.sendTestRunEvent(test, 'TestRunFinished', result);
166
+ this.listener.testFinished(this.getRunData(test, 'TestRunFinished', result));
171
167
  }
172
168
  /**
173
169
  * Cucumber Only
@@ -206,11 +202,11 @@ class _InsightsHandler {
206
202
  };
207
203
  }
208
204
  this._tests[uniqueId] = testMetaData;
209
- await this.sendTestRunEventForCucumber(world, 'TestRunStarted');
205
+ this.listener.testStarted(this.getTestRunDataForCucumber(world, 'TestRunStarted'));
210
206
  }
211
207
  async afterScenario(world) {
212
208
  this._cucumberData.scenario = undefined;
213
- await this.sendTestRunEventForCucumber(world, 'TestRunFinished');
209
+ this.listener.testFinished(this.getTestRunDataForCucumber(world, 'TestRunFinished'));
214
210
  }
215
211
  async beforeStep(step, scenario) {
216
212
  var _a;
@@ -286,7 +282,7 @@ class _InsightsHandler {
286
282
  };
287
283
  }),
288
284
  };
289
- await this.sendTestRunEventForCucumber(null, 'TestRunSkipped', testMetaData);
285
+ this.listener.testFinished(this.getTestRunDataForCucumber(null, 'TestRunSkipped', testMetaData));
290
286
  }
291
287
  async processCucumberHook(test, params, result) {
292
288
  const hookType = this.getCucumberHookType(test);
@@ -307,12 +303,12 @@ class _InsightsHandler {
307
303
  hookType: hookType
308
304
  };
309
305
  this._tests[hookId] = hookMetaData;
310
- await this.sendHookRunEvent(hookMetaData, 'HookRunStarted');
306
+ this.listener.hookStarted(this.getHookRunDataForCucumber(hookMetaData, 'HookRunStarted'));
311
307
  }
312
308
  else {
313
309
  this._tests[hookId].finishedAt = (new Date()).toISOString();
314
310
  this.setCurrentHook({ uuid: this._tests[hookId].uuid, finished: true });
315
- await this.sendHookRunEvent(this._tests[hookId], 'HookRunFinished', result);
311
+ this.listener.hookFinished(this.getHookRunDataForCucumber(this._tests[hookId], 'HookRunFinished', result));
316
312
  if (hookType === 'BEFORE_ALL' && result && !result.passed) {
317
313
  const { feature, uri } = this._cucumberData;
318
314
  if (!feature) {
@@ -333,21 +329,6 @@ class _InsightsHandler {
333
329
  }
334
330
  }
335
331
  }
336
- //@ts-ignore
337
- async uploadPending(waitTimeout = constants_1.DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = constants_1.DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
338
- if (this._requestQueueHandler.pendingUploads <= 0 || waitTimeout <= 0) {
339
- return;
340
- }
341
- await (0, util_1.sleep)(waitInterval);
342
- return this.uploadPending(waitTimeout - waitInterval);
343
- }
344
- async teardown() {
345
- this._requestQueueHandler.tearDownInvoked = true;
346
- await this._requestQueueHandler.shutdown();
347
- }
348
- /**
349
- * misc methods
350
- */
351
332
  async browserCommand(commandType, args, test) {
352
333
  if (commandType === 'client:beforeCommand') {
353
334
  this._commands[`${args.sessionId}_${args.method}_${args.endpoint}`] = args;
@@ -362,16 +343,13 @@ class _InsightsHandler {
362
343
  return;
363
344
  }
364
345
  // log screenshot
365
- if (Boolean(process.env.BS_TESTOPS_ALLOW_SCREENSHOTS) && (0, util_1.isScreenshotCommand)(args) && args.result.value) {
366
- await (0, util_1.uploadEventData)([{
367
- event_type: 'LogCreated',
368
- logs: [{
369
- test_run_uuid: testMeta.uuid,
370
- timestamp: new Date().toISOString(),
371
- message: args.result.value,
372
- kind: 'TEST_SCREENSHOT'
373
- }]
374
- }], constants_1.DATA_SCREENSHOT_ENDPOINT);
346
+ if (Boolean(process.env[constants_1.TESTOPS_SCREENSHOT_ENV]) && (0, util_1.isScreenshotCommand)(args) && args.result.value) {
347
+ await this.listener.onScreenshot([{
348
+ test_run_uuid: testMeta.uuid,
349
+ timestamp: new Date().toISOString(),
350
+ message: args.result.value,
351
+ kind: 'TEST_SCREENSHOT'
352
+ }]);
375
353
  }
376
354
  const dataKey = `${args.sessionId}_${args.method}_${args.endpoint}`;
377
355
  const requestData = this._commands[dataKey];
@@ -379,32 +357,17 @@ class _InsightsHandler {
379
357
  return;
380
358
  }
381
359
  // log http request
382
- const req = this._requestQueueHandler.add({
383
- event_type: 'LogCreated',
384
- logs: [{
385
- test_run_uuid: testMeta.uuid,
386
- timestamp: new Date().toISOString(),
387
- kind: 'HTTP',
388
- http_response: {
389
- path: requestData.endpoint,
390
- method: requestData.method,
391
- body: requestData.body,
392
- response: args.result
393
- }
394
- }]
395
- });
396
- if (req.proceed && req.data) {
397
- await (0, util_1.uploadEventData)(req.data, req.url);
398
- }
399
- }
400
- /*
401
- * private methods
402
- */
403
- async sendData(data) {
404
- const req = this._requestQueueHandler.add(data);
405
- if (req.proceed && req.data) {
406
- await (0, util_1.uploadEventData)(req.data, req.url);
407
- }
360
+ this.listener.logCreated([{
361
+ test_run_uuid: testMeta.uuid,
362
+ timestamp: new Date().toISOString(),
363
+ kind: 'HTTP',
364
+ http_response: {
365
+ path: requestData.endpoint,
366
+ method: requestData.method,
367
+ body: requestData.body,
368
+ response: args.result
369
+ }
370
+ }]);
408
371
  }
409
372
  attachHookData(context, hookId) {
410
373
  if (context.currentTest && context.currentTest.parent) {
@@ -542,7 +505,7 @@ class _InsightsHandler {
542
505
  }
543
506
  return;
544
507
  }
545
- async sendTestRunEvent(test, eventType, results) {
508
+ getRunData(test, eventType, results) {
546
509
  var _a;
547
510
  const fullTitle = (0, util_1.getUniqueIdentifier)(test, this._framework);
548
511
  const testMetaData = this._tests[fullTitle];
@@ -595,24 +558,14 @@ class _InsightsHandler {
595
558
  testData.result = 'skipped';
596
559
  eventType = 'TestRunFinished';
597
560
  }
598
- const uploadData = {
599
- event_type: eventType,
600
- };
601
561
  /* istanbul ignore if */
602
562
  if (eventType.match(/HookRun/)) {
603
563
  testData.hook_type = ((_a = testData.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) ? (0, util_1.getHookType)(testData.name.toLowerCase()) : 'undefined';
604
564
  testData.test_run_id = this.getTestRunId(test.ctx);
605
- uploadData.hook_run = testData;
606
- }
607
- else {
608
- uploadData.test_run = testData;
609
- }
610
- const req = this._requestQueueHandler.add(uploadData);
611
- if (req.proceed && req.data) {
612
- await (0, util_1.uploadEventData)(req.data, req.url);
613
565
  }
566
+ return testData;
614
567
  }
615
- async sendTestRunEventForCucumber(worldObj, eventType, testMetaData = null) {
568
+ getTestRunDataForCucumber(worldObj, eventType, testMetaData = null) {
616
569
  const world = worldObj;
617
570
  const dataHub = testMetaData ? testMetaData : (this._tests[(0, util_1.getUniqueIdentifierForCucumber)(world)] || {});
618
571
  const { feature, scenario, steps, uuid, startedAt, finishedAt } = dataHub;
@@ -686,18 +639,10 @@ class _InsightsHandler {
686
639
  }
687
640
  if (eventType === 'TestRunSkipped') {
688
641
  testData.result = 'skipped';
689
- eventType = 'TestRunFinished';
690
- }
691
- const uploadData = {
692
- event_type: eventType,
693
- test_run: testData
694
- };
695
- const req = this._requestQueueHandler.add(uploadData);
696
- if (req.proceed && req.data) {
697
- await (0, util_1.uploadEventData)(req.data, req.url);
698
642
  }
643
+ return testData;
699
644
  }
700
- async sendHookRunEvent(hookData, eventType, result) {
645
+ getHookRunDataForCucumber(hookData, eventType, result) {
701
646
  const { uri, feature } = this._cucumberData;
702
647
  const testData = {
703
648
  uuid: hookData.uuid,
@@ -734,24 +679,18 @@ class _InsightsHandler {
734
679
  testData.integrations[provider] = this.getIntegrationsObject();
735
680
  }
736
681
  }
737
- const uploadData = {
738
- event_type: eventType,
739
- hook_run: testData
740
- };
741
- const req = this._requestQueueHandler.add(uploadData);
742
- if (req.proceed && req.data) {
743
- await (0, util_1.uploadEventData)(req.data, req.url);
744
- }
682
+ return testData;
745
683
  }
746
684
  getIntegrationsObject() {
747
- var _a, _b, _c, _d, _e, _f;
685
+ var _a, _b;
686
+ const browserCaps = this._browser.capabilities;
748
687
  return {
749
- capabilities: (_a = this._platformMeta) === null || _a === void 0 ? void 0 : _a.caps,
750
- session_id: (_b = this._platformMeta) === null || _b === void 0 ? void 0 : _b.sessionId,
751
- browser: (_c = this._platformMeta) === null || _c === void 0 ? void 0 : _c.browserName,
752
- browser_version: (_d = this._platformMeta) === null || _d === void 0 ? void 0 : _d.browserVersion,
753
- platform: (_e = this._platformMeta) === null || _e === void 0 ? void 0 : _e.platformName,
754
- product: (_f = this._platformMeta) === null || _f === void 0 ? void 0 : _f.product
688
+ capabilities: browserCaps,
689
+ session_id: (_a = this._browser) === null || _a === void 0 ? void 0 : _a.sessionId,
690
+ browser: browserCaps === null || browserCaps === void 0 ? void 0 : browserCaps.browserName,
691
+ browser_version: browserCaps === null || browserCaps === void 0 ? void 0 : browserCaps.browserVersion,
692
+ platform: browserCaps === null || browserCaps === void 0 ? void 0 : browserCaps.platformName,
693
+ product: (_b = this._platformMeta) === null || _b === void 0 ? void 0 : _b.product
755
694
  };
756
695
  }
757
696
  getIdentifier(test) {
@@ -0,0 +1,6 @@
1
+ import type BrowserStackConfig from '../config';
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,WAAW,CAAA;AAsB/C,wBAAsB,SAAS,CAAC,MAAM,EAAE,kBAAkB,iBAEzD;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,127 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fireFunnelRequest = exports.saveFunnelData = exports.sendFinish = exports.sendStart = void 0;
7
+ const node_os_1 = __importDefault(require("node:os"));
8
+ const node_util_1 = __importDefault(require("node:util"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ const got_1 = __importDefault(require("got"));
12
+ const usageStats_1 = __importDefault(require("../testOps/usageStats"));
13
+ const bstackLogger_1 = require("../bstackLogger");
14
+ const constants_1 = require("../constants");
15
+ const data_store_1 = require("../data-store");
16
+ async function fireFunnelTestEvent(eventType, config) {
17
+ if (!config.userName || !config.accessKey) {
18
+ bstackLogger_1.BStackLogger.debug('username/accesskey not passed');
19
+ return;
20
+ }
21
+ try {
22
+ const data = buildEventData(eventType, config);
23
+ await fireFunnelRequest(data);
24
+ bstackLogger_1.BStackLogger.debug('Funnel event success');
25
+ if (eventType === 'SDKTestSuccessful') {
26
+ config.sentFunnelData();
27
+ }
28
+ }
29
+ catch (error) {
30
+ bstackLogger_1.BStackLogger.debug('Exception in sending funnel data: ' + error);
31
+ }
32
+ }
33
+ async function sendStart(config) {
34
+ await fireFunnelTestEvent('SDKTestAttempted', config);
35
+ }
36
+ exports.sendStart = sendStart;
37
+ async function sendFinish(config) {
38
+ await fireFunnelTestEvent('SDKTestSuccessful', config);
39
+ }
40
+ exports.sendFinish = sendFinish;
41
+ function saveFunnelData(eventType, config) {
42
+ const data = buildEventData(eventType, config);
43
+ bstackLogger_1.BStackLogger.ensureLogsFolder();
44
+ const filePath = node_path_1.default.join(bstackLogger_1.BStackLogger.logFolderPath, 'funnelData.json');
45
+ node_fs_1.default.writeFileSync(filePath, JSON.stringify(data));
46
+ return filePath;
47
+ }
48
+ exports.saveFunnelData = saveFunnelData;
49
+ // Called from two different process
50
+ async function fireFunnelRequest(data) {
51
+ bstackLogger_1.BStackLogger.debug('Sending SDK event with data ' + node_util_1.default.inspect(data, { depth: 6 }));
52
+ await got_1.default.post(constants_1.FUNNEL_INSTRUMENTATION_URL, {
53
+ headers: {
54
+ 'content-type': 'application/json'
55
+ }, username: data.userName, password: data.accessKey, json: data
56
+ });
57
+ }
58
+ exports.fireFunnelRequest = fireFunnelRequest;
59
+ function getProductList(config) {
60
+ const products = [];
61
+ if (config.testObservability.enabled) {
62
+ products.push('observability');
63
+ }
64
+ if (config.accessibility) {
65
+ products.push('accessibility');
66
+ }
67
+ if (config.percy) {
68
+ products.push('percy');
69
+ }
70
+ if (config.automate) {
71
+ products.push('automate');
72
+ }
73
+ if (config.appAutomate) {
74
+ products.push('app-automate');
75
+ }
76
+ return products;
77
+ }
78
+ function getProductMap(config) {
79
+ return {
80
+ 'observability': config.testObservability.enabled,
81
+ 'accessibility': config.accessibility,
82
+ 'percy': config.percy,
83
+ 'automate': config.automate,
84
+ 'app_automate': config.appAutomate
85
+ };
86
+ }
87
+ function buildEventData(eventType, config) {
88
+ const eventProperties = {
89
+ // Framework Details
90
+ language_framework: getLanguageFramework(config.framework),
91
+ referrer: getReferrer(config.framework),
92
+ language: 'WebdriverIO',
93
+ languageVersion: process.version,
94
+ // Build Details
95
+ buildName: config.buildName || 'undefined',
96
+ buildIdentifier: String(config.buildIdentifier),
97
+ // Host details
98
+ os: node_os_1.default.type() || 'unknown',
99
+ hostname: node_os_1.default.hostname() || 'unknown',
100
+ // Product Details
101
+ productMap: getProductMap(config),
102
+ product: getProductList(config),
103
+ };
104
+ if (eventType === 'SDKTestSuccessful') {
105
+ const workerData = (0, data_store_1.getDataFromWorkers)();
106
+ eventProperties.productUsage = getProductUsage(workerData);
107
+ }
108
+ return {
109
+ userName: config.userName,
110
+ accessKey: config.accessKey,
111
+ event_type: eventType,
112
+ detectedFramework: 'WebdriverIO-' + config.framework,
113
+ event_properties: eventProperties
114
+ };
115
+ }
116
+ function getProductUsage(workersData) {
117
+ return {
118
+ testObservability: usageStats_1.default.getInstance().getFormattedData(workersData)
119
+ };
120
+ }
121
+ function getLanguageFramework(framework) {
122
+ return 'WebdriverIO_' + framework;
123
+ }
124
+ function getReferrer(framework) {
125
+ const fullName = framework ? 'WebdriverIO-' + framework : 'WebdriverIO';
126
+ return `${fullName}/${constants_1.BSTACK_SERVICE_VERSION}`;
127
+ }
@@ -16,10 +16,9 @@ export default class BrowserstackLauncherService implements Services.ServiceInst
16
16
  private _accessibilityAutomation?;
17
17
  private _percy?;
18
18
  private _percyBestPlatformCaps?;
19
- _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
- setupExitHandlers(): void;
23
22
  onPrepare(config?: Options.Testrunner, capabilities?: Capabilities.RemoteCapabilities): Promise<unknown>;
24
23
  onComplete(): Promise<unknown>;
25
24
  setupPercy(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner, bsConfig: UserConfig): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAOlE,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAqBhG,KAAK,iBAAiB,GAAG,yBAAyB,CAAC,KAAK,GAAG;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CAC/C,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;IAC1D,oBAAoB,CAAC,EAAE,OAAO,CAAA;gBAGzB,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IAgGjC,aAAa,CAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG;IAaxC,iBAAiB;IAUX,SAAS,CAAE,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IAwJtF,UAAU;IAmEV,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU;IAuB7G,SAAS;IAYT,UAAU,CAAC,GAAG,EAAC,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkBrD;;;OAGG;IACG,YAAY,CAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAyBhE,qBAAqB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KAAE;IAiFvH,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAC,MAAM;IAoF3F,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;CAQtF"}
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAMlE,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AA8BhG,KAAK,iBAAiB,GAAG,yBAAyB,CAAC,KAAK,GAAG;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CAC/C,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;IAsGjC,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;IAqEV,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU;IAuB7G,SAAS;IAYT,UAAU,CAAC,GAAG,EAAC,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAqBrD;;;OAGG;IACG,YAAY,CAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAyBhE,qBAAqB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KAAE;IAiFvH,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAC,MAAM;IAoF3F,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;CAQtF"}
package/build/launcher.js CHANGED
@@ -36,7 +36,6 @@ const os_1 = __importDefault(require("os"));
36
36
  const webdriverio_1 = require("webdriverio");
37
37
  const BrowserstackLocalLauncher = __importStar(require("browserstack-local"));
38
38
  const logger_1 = __importDefault(require("@wdio/logger"));
39
- const node_child_process_1 = require("node:child_process");
40
39
  // @ts-ignore
41
40
  const package_json_1 = require("../package.json");
42
41
  const crash_reporter_1 = __importDefault(require("./crash-reporter"));
@@ -45,15 +44,19 @@ const constants_1 = require("./constants");
45
44
  const util_2 = require("./util");
46
45
  const performance_tester_1 = __importDefault(require("./performance-tester"));
47
46
  const PercyLogger_1 = require("./Percy/PercyLogger");
47
+ const exitHandler_1 = require("./exitHandler");
48
+ const config_1 = __importDefault(require("./config"));
49
+ const funnelInstrumentation_1 = require("./instrumentation/funnelInstrumentation");
48
50
  const log = (0, logger_1.default)('@wdio/browserstack-service');
49
51
  class BrowserstackLauncherService {
50
52
  constructor(_options, capabilities, _config) {
51
53
  this._options = _options;
52
54
  this._config = _config;
53
55
  PercyLogger_1.PercyLogger.clearLogFile();
56
+ (0, exitHandler_1.setupExitHandlers)();
54
57
  // added to maintain backward compatibility with webdriverIO v5
55
- this.setupExitHandlers();
56
58
  this._config || (this._config = _options);
59
+ this.browserStackConfig = config_1.default.getInstance(_options, _config);
57
60
  if (Array.isArray(capabilities)) {
58
61
  capabilities.forEach((capability) => {
59
62
  var _a, _b;
@@ -127,7 +130,9 @@ class BrowserstackLauncherService {
127
130
  }
128
131
  });
129
132
  }
130
- if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
133
+ this.browserStackConfig.buildIdentifier = this._buildIdentifier;
134
+ this.browserStackConfig.buildName = this._buildName;
135
+ if (process.env[constants_1.PERF_MEASUREMENT_ENV]) {
131
136
  performance_tester_1.default.startMonitoring('performance-report-launcher.csv');
132
137
  }
133
138
  this._accessibilityAutomation || (this._accessibilityAutomation = (0, util_2.isTrue)(this._options.accessibility));
@@ -136,8 +141,8 @@ class BrowserstackLauncherService {
136
141
  this._options.testObservability = this._options.testObservability == false ? false : true;
137
142
  if (this._options.testObservability &&
138
143
  // update files to run if it's a rerun
139
- process.env.BROWSERSTACK_RERUN && process.env.BROWSERSTACK_RERUN_TESTS) {
140
- this._config.specs = process.env.BROWSERSTACK_RERUN_TESTS.split(',');
144
+ process.env[constants_1.RERUN_ENV] && process.env[constants_1.RERUN_TESTS_ENV]) {
145
+ this._config.specs = process.env[constants_1.RERUN_TESTS_ENV].split(',');
141
146
  }
142
147
  try {
143
148
  crash_reporter_1.default.setConfigDetails(this._config, capabilities, this._options);
@@ -159,16 +164,9 @@ class BrowserstackLauncherService {
159
164
  PercyLogger_1.PercyLogger.error(`Error while setting best platform for Percy snapshot at worker start ${err}`);
160
165
  }
161
166
  }
162
- setupExitHandlers() {
163
- process.on('exit', (code) => {
164
- if (!!process.env.BS_TESTOPS_JWT && !this._testOpsBuildStopped) {
165
- const childProcess = (0, node_child_process_1.spawn)('node', [`${path_1.default.join(__dirname, 'cleanup.js')}`], { detached: true, stdio: 'inherit', env: { ...process.env } });
166
- childProcess.unref();
167
- process.exit(code);
168
- }
169
- });
170
- }
171
167
  async onPrepare(config, capabilities) {
168
+ // // Send Funnel start request
169
+ await (0, funnelInstrumentation_1.sendStart)(this.browserStackConfig);
172
170
  /**
173
171
  * Upload app to BrowserStack if valid file path to app is given.
174
172
  * Update app value of capability directly if app_url, custom_id, shareable_id is given
@@ -316,12 +314,12 @@ class BrowserstackLauncherService {
316
314
  if (this._options.testObservability) {
317
315
  log.debug('Sending stop launch event');
318
316
  await (0, util_2.stopBuildUpstream)();
319
- if (process.env.BS_TESTOPS_BUILD_HASHED_ID) {
320
- 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`);
321
- this._testOpsBuildStopped = true;
317
+ if (process.env[constants_1.TESTOPS_BUILD_ID_ENV]) {
318
+ console.log(`\nVisit https://observability.browserstack.com/builds/${process.env[constants_1.TESTOPS_BUILD_ID_ENV]} to view build report, insights, and many more debugging information all at one place!\n`);
319
+ this.browserStackConfig.testObservability.buildStopped = true;
322
320
  }
323
321
  }
324
- if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
322
+ if (process.env[constants_1.PERF_MEASUREMENT_ENV]) {
325
323
  await performance_tester_1.default.stopAndGenerate('performance-launcher.html');
326
324
  performance_tester_1.default.calculateTimes(['launchTestSession', 'stopBuildUpstream']);
327
325
  if (!process.env.START_TIME) {
@@ -334,6 +332,7 @@ class BrowserstackLauncherService {
334
332
  await this.stopPercy();
335
333
  }
336
334
  PercyLogger_1.PercyLogger.clearLogger();
335
+ await (0, funnelInstrumentation_1.sendFinish)(this.browserStackConfig);
337
336
  if (!this.browserstackLocal || !this.browserstackLocal.isRunning()) {
338
337
  return;
339
338
  }
@@ -402,8 +401,10 @@ class BrowserstackLauncherService {
402
401
  async _uploadApp(app) {
403
402
  log.info(`uploading app ${app.app} ${app.customId ? `and custom_id: ${app.customId}` : ''} to browserstack`);
404
403
  const form = new form_data_1.default();
405
- if (app.app)
406
- form.append('file', fs_1.default.createReadStream(app.app));
404
+ if (app.app) {
405
+ const fileName = path_1.default.basename(app.app);
406
+ form.append('file', fs_1.default.createReadStream(app.app), fileName);
407
+ }
407
408
  if (app.customId)
408
409
  form.append('custom_id', app.customId);
409
410
  const res = await got_1.default.post('https://api-cloud.browserstack.com/app-automate/upload', {
@@ -1,18 +1,18 @@
1
1
  import WDIOReporter, { SuiteStats, TestStats, RunnerStats, HookStats } from '@wdio/reporter';
2
- import type { CurrentRunInfo, StdLog, TestMeta } from './types';
2
+ import type { CurrentRunInfo, StdLog, TestData, TestMeta } from './types';
3
3
  declare class _TestReporter extends WDIOReporter {
4
4
  private _capabilities;
5
5
  private _config?;
6
6
  private _observability;
7
7
  private _sessionId?;
8
8
  private _suiteName?;
9
- private _requestQueueHandler;
10
9
  private _suites;
11
10
  private static _tests;
12
11
  private _gitConfigPath?;
13
12
  private _gitConfigured;
14
13
  private _currentHook;
15
14
  private _currentTest;
15
+ private listener;
16
16
  onRunnerStart(runnerStats: RunnerStats): Promise<void>;
17
17
  registerListeners(): void;
18
18
  appendTestItemLog(stdLog: StdLog): Promise<void>;
@@ -27,7 +27,7 @@ declare class _TestReporter extends WDIOReporter {
27
27
  onHookStart(hookStats: HookStats): Promise<void>;
28
28
  onHookEnd(hookStats: HookStats): Promise<void>;
29
29
  getHookIdentifier(hookStats: HookStats): string;
30
- sendTestRunEvent(testStats: TestStats | HookStats, eventType: string): Promise<void>;
30
+ getRunData(testStats: TestStats | HookStats, eventType: string): Promise<TestData>;
31
31
  onTestSkip(testStats: TestStats): Promise<void>;
32
32
  }
33
33
  declare const TestReporter: typeof _TestReporter;
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAO5F,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,EAAY,QAAQ,EAAc,MAAM,SAAS,CAAA;AAczG,cAAM,aAAc,SAAQ,YAAY;IACpC,OAAO,CAAC,aAAa,CAAgC;IACrD,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;IAEnC,aAAa,CAAE,WAAW,EAAE,WAAW;IAS7C,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;IAQ9B,WAAW,CAAC,SAAS,EAAE,SAAS;IAahC,WAAW,CAAC,SAAS,EAAE,SAAS;IAehC,SAAS,CAAC,SAAS,EAAE,SAAS;IAqBpC,iBAAiB,CAAC,SAAS,EAAE,SAAS;IAIhC,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAC,SAAS,EAAE,SAAS,EAAE,MAAM;IAkFlE,UAAU,CAAE,SAAS,EAAE,SAAS;CAQzC;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,YAAY,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAO5F,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAY7F,cAAM,aAAc,SAAQ,YAAY;IACpC,OAAO,CAAC,aAAa,CAAgC;IACrD,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,QAAQ,CAAyB;IAEnC,aAAa,CAAE,WAAW,EAAE,WAAW;IAS7C,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;IAQ9B,WAAW,CAAC,SAAS,EAAE,SAAS;IAahC,WAAW,CAAC,SAAS,EAAE,SAAS;IAehC,SAAS,CAAC,SAAS,EAAE,SAAS;IAqBpC,iBAAiB,CAAC,SAAS,EAAE,SAAS;IAIhC,UAAU,CAAC,SAAS,EAAE,SAAS,GAAC,SAAS,EAAE,SAAS,EAAE,MAAM;IAwE5D,UAAU,CAAE,SAAS,EAAE,SAAS;CAQzC;AAED,QAAA,MAAM,YAAY,EAAE,OAAO,aAAoD,CAAA;AAC/E,KAAK,YAAY,GAAG,aAAa,CAAA;AACjC,eAAe,YAAY,CAAA"}