@wdio/browserstack-service 7.34.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 (85) hide show
  1. package/build/Percy/Percy-Handler.d.ts +34 -0
  2. package/build/Percy/Percy-Handler.d.ts.map +1 -0
  3. package/build/Percy/Percy-Handler.js +187 -0
  4. package/build/Percy/Percy.d.ts +24 -0
  5. package/build/Percy/Percy.d.ts.map +1 -0
  6. package/build/Percy/Percy.js +128 -0
  7. package/build/Percy/PercyBinary.d.ts +17 -0
  8. package/build/Percy/PercyBinary.d.ts.map +1 -0
  9. package/build/Percy/PercyBinary.js +151 -0
  10. package/build/Percy/PercyCaptureMap.d.ts +9 -0
  11. package/build/Percy/PercyCaptureMap.d.ts.map +1 -0
  12. package/build/Percy/PercyCaptureMap.js +46 -0
  13. package/build/Percy/PercyHelper.d.ts +8 -0
  14. package/build/Percy/PercyHelper.d.ts.map +1 -0
  15. package/build/Percy/PercyHelper.js +78 -0
  16. package/build/Percy/PercyLogger.d.ts +15 -0
  17. package/build/Percy/PercyLogger.d.ts.map +1 -0
  18. package/build/Percy/PercyLogger.js +76 -0
  19. package/build/Percy/PercySDK.d.ts +4 -0
  20. package/build/Percy/PercySDK.d.ts.map +1 -0
  21. package/build/Percy/PercySDK.js +42 -0
  22. package/build/bstackLogger.d.ts +14 -0
  23. package/build/bstackLogger.d.ts.map +1 -0
  24. package/build/bstackLogger.js +52 -0
  25. package/build/cleanup.d.ts +6 -2
  26. package/build/cleanup.d.ts.map +1 -1
  27. package/build/cleanup.js +104 -12
  28. package/build/config.d.ts +23 -0
  29. package/build/config.d.ts.map +1 -0
  30. package/build/config.js +32 -0
  31. package/build/constants.d.ts +20 -0
  32. package/build/constants.d.ts.map +1 -1
  33. package/build/constants.js +45 -1
  34. package/build/crash-reporter.js +1 -1
  35. package/build/data-store.d.ts +3 -0
  36. package/build/data-store.d.ts.map +1 -0
  37. package/build/data-store.js +49 -0
  38. package/build/exitHandler.d.ts +4 -0
  39. package/build/exitHandler.d.ts.map +1 -0
  40. package/build/exitHandler.js +37 -0
  41. package/build/index.d.ts +2 -0
  42. package/build/index.d.ts.map +1 -1
  43. package/build/index.js +15 -1
  44. package/build/insights-handler.d.ts +5 -11
  45. package/build/insights-handler.d.ts.map +1 -1
  46. package/build/insights-handler.js +45 -106
  47. package/build/instrumentation/funnelInstrumentation.d.ts +6 -0
  48. package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -0
  49. package/build/instrumentation/funnelInstrumentation.js +127 -0
  50. package/build/launcher.d.ts +8 -4
  51. package/build/launcher.d.ts.map +1 -1
  52. package/build/launcher.js +87 -18
  53. package/build/reporter.d.ts +3 -3
  54. package/build/reporter.d.ts.map +1 -1
  55. package/build/reporter.js +10 -23
  56. package/build/request-handler.d.ts +5 -13
  57. package/build/request-handler.d.ts.map +1 -1
  58. package/build/request-handler.js +27 -48
  59. package/build/service.d.ts +3 -0
  60. package/build/service.d.ts.map +1 -1
  61. package/build/service.js +50 -18
  62. package/build/testOps/featureStats.d.ts +45 -0
  63. package/build/testOps/featureStats.d.ts.map +1 -0
  64. package/build/testOps/featureStats.js +120 -0
  65. package/build/testOps/featureUsage.d.ts +22 -0
  66. package/build/testOps/featureUsage.d.ts.map +1 -0
  67. package/build/testOps/featureUsage.js +46 -0
  68. package/build/testOps/listener.d.ts +33 -0
  69. package/build/testOps/listener.d.ts.map +1 -0
  70. package/build/testOps/listener.js +228 -0
  71. package/build/testOps/requestUtils.d.ts +4 -0
  72. package/build/testOps/requestUtils.d.ts.map +1 -0
  73. package/build/testOps/requestUtils.js +47 -0
  74. package/build/testOps/testOpsConfig.d.ts +11 -0
  75. package/build/testOps/testOpsConfig.d.ts.map +1 -0
  76. package/build/testOps/testOpsConfig.js +17 -0
  77. package/build/testOps/usageStats.d.ts +404 -0
  78. package/build/testOps/usageStats.d.ts.map +1 -0
  79. package/build/testOps/usageStats.js +110 -0
  80. package/build/types.d.ts +48 -7
  81. package/build/types.d.ts.map +1 -1
  82. package/build/util.d.ts +4 -6
  83. package/build/util.d.ts.map +1 -1
  84. package/build/util.js +82 -67
  85. package/package.json +7 -4
package/build/service.js CHANGED
@@ -12,6 +12,10 @@ const util_1 = require("./util");
12
12
  const reporter_1 = __importDefault(require("./reporter"));
13
13
  const performance_tester_1 = __importDefault(require("./performance-tester"));
14
14
  const accessibility_handler_1 = __importDefault(require("./accessibility-handler"));
15
+ const Percy_Handler_1 = __importDefault(require("./Percy/Percy-Handler"));
16
+ const listener_1 = __importDefault(require("./testOps/listener"));
17
+ const data_store_1 = require("./data-store");
18
+ const usageStats_1 = __importDefault(require("./testOps/usageStats"));
15
19
  const log = (0, logger_1.default)('@wdio/browserstack-service');
16
20
  class BrowserstackService {
17
21
  constructor(options, _caps, _config) {
@@ -28,10 +32,11 @@ class BrowserstackService {
28
32
  this._config || (this._config = this._options);
29
33
  this._observability = this._options.testObservability;
30
34
  this._accessibility = this._options.accessibility;
35
+ this._percy = this._options.percy;
31
36
  this._turboScale = this._options.turboScale;
32
37
  if (this._observability) {
33
38
  (_a = this._config.reporters) === null || _a === void 0 ? void 0 : _a.push(reporter_1.default);
34
- if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
39
+ if (process.env[constants_1.PERF_MEASUREMENT_ENV]) {
35
40
  performance_tester_1.default.startMonitoring('performance-report-service.csv');
36
41
  }
37
42
  }
@@ -44,6 +49,9 @@ class BrowserstackService {
44
49
  if (strict) {
45
50
  this._failureStatuses.push('pending');
46
51
  }
52
+ if (process.env.WDIO_WORKER_ID === process.env.BEST_PLATFORM_CID) {
53
+ process.env.PERCY_SNAPSHOT = 'true';
54
+ }
47
55
  }
48
56
  _updateCaps(fn) {
49
57
  const multiRemoteCap = this._caps;
@@ -77,29 +85,43 @@ class BrowserstackService {
77
85
  this._sessionBaseUrl = 'https://api.browserstack.com/automate-turboscale/v1/sessions';
78
86
  }
79
87
  this._scenariosThatRan = [];
80
- if (this._observability && this._browser) {
88
+ if (this._browser) {
89
+ if (this._percy) {
90
+ this._percyHandler = new Percy_Handler_1.default(this._options.percyCaptureMode, this._browser, this._caps, this._isAppAutomate(), this._config.framework);
91
+ this._percyHandler.before();
92
+ }
81
93
  try {
82
- (0, util_1.patchConsoleLogs)();
83
- this._insightsHandler = new insights_handler_1.default(this._browser, this._browser.capabilities, this._isAppAutomate(), this._browser.sessionId, this._config.framework);
84
- await this._insightsHandler.before();
94
+ if (this._observability) {
95
+ (0, util_1.patchConsoleLogs)();
96
+ this._insightsHandler = new insights_handler_1.default(this._browser, this._browser.capabilities, this._isAppAutomate(), this._browser.sessionId, this._config.framework);
97
+ await this._insightsHandler.before();
98
+ }
85
99
  /**
86
100
  * register command event
87
101
  */
88
102
  this._browser.on('command', async (command) => {
89
- var _a, _b;
90
- return await ((_a = this._insightsHandler) === null || _a === void 0 ? void 0 : _a.browserCommand('client:beforeCommand', Object.assign(command, { sessionId: (_b = this._browser) === null || _b === void 0 ? void 0 : _b.sessionId }), this._currentTest));
103
+ var _a, _b, _c, _d;
104
+ if (this._observability) {
105
+ await ((_a = this._insightsHandler) === null || _a === void 0 ? void 0 : _a.browserCommand('client:beforeCommand', Object.assign(command, { sessionId: (_b = this._browser) === null || _b === void 0 ? void 0 : _b.sessionId }), this._currentTest));
106
+ }
107
+ await ((_c = this._percyHandler) === null || _c === void 0 ? void 0 : _c.browserBeforeCommand(Object.assign(command, { sessionId: (_d = this._browser) === null || _d === void 0 ? void 0 : _d.sessionId })));
91
108
  });
92
109
  /**
93
110
  * register result event
94
111
  */
95
112
  this._browser.on('result', async (result) => {
96
- var _a, _b;
97
- return await ((_a = this._insightsHandler) === null || _a === void 0 ? void 0 : _a.browserCommand('client:afterCommand', Object.assign(result, { sessionId: (_b = this._browser) === null || _b === void 0 ? void 0 : _b.sessionId }), this._currentTest));
113
+ var _a, _b, _c, _d;
114
+ if (this._observability) {
115
+ await ((_a = this._insightsHandler) === null || _a === void 0 ? void 0 : _a.browserCommand('client:afterCommand', Object.assign(result, { sessionId: (_b = this._browser) === null || _b === void 0 ? void 0 : _b.sessionId }), this._currentTest));
116
+ }
117
+ (_c = this._percyHandler) === null || _c === void 0 ? void 0 : _c.browserAfterCommand(Object.assign(result, { sessionId: (_d = this._browser) === null || _d === void 0 ? void 0 : _d.sessionId }));
98
118
  });
99
119
  }
100
120
  catch (err) {
101
121
  log.error(`Error in service class before function: ${err}`);
102
- crash_reporter_1.default.uploadCrashReport(`Error in service class before function: ${err}`, err && err.stack);
122
+ if (this._observability) {
123
+ crash_reporter_1.default.uploadCrashReport(`Error in service class before function: ${err}`, err && err.stack);
124
+ }
103
125
  }
104
126
  }
105
127
  if (this._browser && (0, util_1.isBrowserstackSession)(this._browser)) {
@@ -159,17 +181,18 @@ class BrowserstackService {
159
181
  await ((_c = this._accessibilityHandler) === null || _c === void 0 ? void 0 : _c.beforeTest(suiteTitle, test));
160
182
  }
161
183
  async afterTest(test, context, results) {
162
- var _a, _b;
184
+ var _a, _b, _c;
163
185
  this._specsRan = true;
164
186
  const { error, passed } = results;
165
187
  if (!passed) {
166
188
  this._failReasons.push((error && error.message) || 'Unknown Error');
167
189
  }
168
190
  await ((_a = this._insightsHandler) === null || _a === void 0 ? void 0 : _a.afterTest(test, results));
169
- await ((_b = this._accessibilityHandler) === null || _b === void 0 ? void 0 : _b.afterTest(this._suiteTitle, test));
191
+ await ((_b = this._percyHandler) === null || _b === void 0 ? void 0 : _b.afterTest());
192
+ await ((_c = this._accessibilityHandler) === null || _c === void 0 ? void 0 : _c.afterTest(this._suiteTitle, test));
170
193
  }
171
194
  async after(result) {
172
- var _a, _b;
195
+ var _a;
173
196
  const { preferScenarioName, setSessionName, setSessionStatus } = this._options;
174
197
  // For Cucumber: Checks scenarios that ran (i.e. not skipped) on the session
175
198
  // Only 1 Scenario ran and option enabled => Redefine session name to Scenario's name
@@ -184,9 +207,10 @@ class BrowserstackService {
184
207
  ...(hasReasons ? { reason: this._failReasons.join('\n') } : {})
185
208
  });
186
209
  }
187
- await ((_a = this._insightsHandler) === null || _a === void 0 ? void 0 : _a.uploadPending());
188
- await ((_b = this._insightsHandler) === null || _b === void 0 ? void 0 : _b.teardown());
189
- if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
210
+ await listener_1.default.getInstance().onWorkerEnd();
211
+ await ((_a = this._percyHandler) === null || _a === void 0 ? void 0 : _a.teardown());
212
+ this.saveWorkerData();
213
+ if (process.env[constants_1.PERF_MEASUREMENT_ENV]) {
190
214
  await performance_tester_1.default.stopAndGenerate('performance-service.html');
191
215
  performance_tester_1.default.calculateTimes([
192
216
  'onRunnerStart', 'onSuiteStart', 'onSuiteEnd',
@@ -219,7 +243,7 @@ class BrowserstackService {
219
243
  await this._setAnnotation(`Scenario: ${scenarioName}`);
220
244
  }
221
245
  async afterScenario(world) {
222
- var _a, _b, _c;
246
+ var _a, _b, _c, _d;
223
247
  this._specsRan = true;
224
248
  const status = (_a = world.result) === null || _a === void 0 ? void 0 : _a.status.toLowerCase();
225
249
  if (status !== 'skipped') {
@@ -233,7 +257,8 @@ class BrowserstackService {
233
257
  this._failReasons.push(exception);
234
258
  }
235
259
  await ((_b = this._insightsHandler) === null || _b === void 0 ? void 0 : _b.afterScenario(world));
236
- await ((_c = this._accessibilityHandler) === null || _c === void 0 ? void 0 : _c.afterScenario(world));
260
+ await ((_c = this._percyHandler) === null || _c === void 0 ? void 0 : _c.afterScenario());
261
+ await ((_d = this._accessibilityHandler) === null || _d === void 0 ? void 0 : _d.afterScenario(world));
237
262
  }
238
263
  async beforeStep(step, scenario) {
239
264
  var _a;
@@ -348,6 +373,7 @@ class BrowserstackService {
348
373
  });
349
374
  }
350
375
  async _setSessionName(suiteTitle, test) {
376
+ var _a;
351
377
  if (!this._options.setSessionName || !suiteTitle) {
352
378
  return;
353
379
  }
@@ -361,6 +387,7 @@ class BrowserstackService {
361
387
  const post = !this._options.sessionNameOmitTestTitle ? ` - ${test.title}` : '';
362
388
  name = `${pre}${test.parent}${post}`;
363
389
  }
390
+ (_a = this._percyHandler) === null || _a === void 0 ? void 0 : _a._setSessionName(name);
364
391
  if (name !== this._fullTitle) {
365
392
  this._fullTitle = name;
366
393
  await this._updateJob({ name });
@@ -384,5 +411,10 @@ class BrowserstackService {
384
411
  }
385
412
  return (await this._browser.execute(script));
386
413
  }
414
+ saveWorkerData() {
415
+ (0, data_store_1.saveWorkerData)({
416
+ usageStats: usageStats_1.default.getInstance().getDataToSave()
417
+ });
418
+ }
387
419
  }
388
420
  exports.default = BrowserstackService;
@@ -0,0 +1,45 @@
1
+ import type { FeatureStatsOverview } from '../types';
2
+ interface FeatureStatsMap {
3
+ [groupId: string]: FeatureStats;
4
+ }
5
+ interface JSONConversionSettings {
6
+ omitGroups?: boolean;
7
+ onlyGroups?: boolean;
8
+ nestedGroups?: boolean;
9
+ }
10
+ declare class FeatureStats {
11
+ private triggeredCount;
12
+ private sentCount;
13
+ private failedCount;
14
+ private groups;
15
+ mark(status: string, groupId: string): void;
16
+ triggered(groupId?: string): void;
17
+ sent(groupId?: string): void;
18
+ failed(groupId?: string): void;
19
+ success(groupId?: string): void;
20
+ createGroup(groupId: string): FeatureStats;
21
+ getTriggeredCount(): number;
22
+ getSentCount(): number;
23
+ getFailedCount(): number;
24
+ getUsageForGroup(groupId: string): FeatureStats;
25
+ getOverview(): FeatureStatsOverview;
26
+ getGroups(): FeatureStatsMap;
27
+ add(featureStats: FeatureStats): void;
28
+ toJSON(config?: JSONConversionSettings): {
29
+ triggeredCount: number;
30
+ sentCount: number;
31
+ failedCount: number;
32
+ } | {
33
+ groups: Record<string, FeatureStatsOverview>;
34
+ triggeredCount: number;
35
+ sentCount: number;
36
+ failedCount: number;
37
+ } | {
38
+ [x: string]: FeatureStatsOverview;
39
+ } | {
40
+ groups: Record<string, FeatureStatsOverview>;
41
+ };
42
+ static fromJSON(json: any): FeatureStats;
43
+ }
44
+ export default FeatureStats;
45
+ //# sourceMappingURL=featureStats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"featureStats.d.ts","sourceRoot":"","sources":["../../src/testOps/featureStats.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAGpD,UAAU,eAAe;IACrB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC;CACnC;AAED,UAAU,sBAAsB;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,cAAM,YAAY;IACd,OAAO,CAAC,cAAc,CAAY;IAClC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,MAAM,CAAsB;IAE7B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAkB3C,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAOjC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAO5B,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAO9B,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAI/B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY;IAO1C,iBAAiB,IAAI,MAAM;IAI3B,YAAY,IAAI,MAAM;IAItB,cAAc,IAAI,MAAM;IAIxB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY;IAI/C,WAAW,IAAI,oBAAoB;IAInC,SAAS,IAAI,eAAe;IAI5B,GAAG,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI;IAarC,MAAM,CAAC,MAAM,GAAE,sBAA2B;;;;;;;;;;;;;;WAqBnC,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,YAAY;CAkBlD;AAED,eAAe,YAAY,CAAA"}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const bstackLogger_1 = require("../bstackLogger");
4
+ const util_1 = require("../util");
5
+ class FeatureStats {
6
+ constructor() {
7
+ this.triggeredCount = 0;
8
+ this.sentCount = 0;
9
+ this.failedCount = 0;
10
+ this.groups = {};
11
+ }
12
+ mark(status, groupId) {
13
+ switch (status) {
14
+ case 'triggered':
15
+ this.triggered(groupId);
16
+ break;
17
+ case 'success':
18
+ case 'sent':
19
+ this.sent(groupId);
20
+ break;
21
+ case 'failed':
22
+ this.failed(groupId);
23
+ break;
24
+ default:
25
+ bstackLogger_1.BStackLogger.debug('Request to mark usage for unknown status - ' + status);
26
+ break;
27
+ }
28
+ }
29
+ triggered(groupId) {
30
+ this.triggeredCount += 1;
31
+ if (groupId) {
32
+ this.createGroup(groupId).triggered();
33
+ }
34
+ }
35
+ sent(groupId) {
36
+ this.sentCount += 1;
37
+ if (groupId) {
38
+ this.createGroup(groupId).sent();
39
+ }
40
+ }
41
+ failed(groupId) {
42
+ this.failedCount += 1;
43
+ if (groupId) {
44
+ this.createGroup(groupId).failed();
45
+ }
46
+ }
47
+ success(groupId) {
48
+ this.sent(groupId);
49
+ }
50
+ createGroup(groupId) {
51
+ if (!this.groups[groupId]) {
52
+ this.groups[groupId] = new FeatureStats();
53
+ }
54
+ return this.groups[groupId];
55
+ }
56
+ getTriggeredCount() {
57
+ return this.triggeredCount;
58
+ }
59
+ getSentCount() {
60
+ return this.sentCount;
61
+ }
62
+ getFailedCount() {
63
+ return this.failedCount;
64
+ }
65
+ getUsageForGroup(groupId) {
66
+ return this.groups[groupId] || new FeatureStats();
67
+ }
68
+ getOverview() {
69
+ return { triggeredCount: this.triggeredCount, sentCount: this.sentCount, failedCount: this.failedCount };
70
+ }
71
+ getGroups() {
72
+ return this.groups;
73
+ }
74
+ add(featureStats) {
75
+ this.triggeredCount += featureStats.getTriggeredCount();
76
+ this.sentCount += featureStats.getSentCount();
77
+ this.failedCount += featureStats.getFailedCount();
78
+ Object.entries(featureStats.getGroups()).forEach(([groupId, group]) => {
79
+ this.createGroup(groupId).add(group);
80
+ });
81
+ }
82
+ // omitGroups: true/false -> Include groups or not
83
+ // onlyGroups: true/false -> data includes only groups
84
+ // nestedGroups: true/false -> groups will be nested in groups if true
85
+ toJSON(config = {}) {
86
+ const overviewData = !config.onlyGroups ? {
87
+ triggeredCount: this.triggeredCount,
88
+ sentCount: this.sentCount,
89
+ failedCount: this.failedCount
90
+ } : {};
91
+ const groupsData = {};
92
+ if (!config.omitGroups) {
93
+ Object.entries(this.groups).forEach(([groupId, group]) => {
94
+ groupsData[groupId] = group.toJSON(); // Currently Nested groups are only overviews
95
+ });
96
+ }
97
+ const group = config.nestedGroups ? { groups: groupsData } : groupsData;
98
+ return {
99
+ ...overviewData,
100
+ ...group
101
+ };
102
+ }
103
+ static fromJSON(json) {
104
+ const stats = new FeatureStats();
105
+ if (!json || (0, util_1.isObjectEmpty)(json)) {
106
+ return stats;
107
+ }
108
+ stats.triggeredCount = json.triggeredCount;
109
+ stats.sentCount = json.sentCount;
110
+ stats.failedCount = json.failedCount;
111
+ if (!json.groups) {
112
+ return stats;
113
+ }
114
+ Object.entries(json.groups).forEach(([groupId, group]) => {
115
+ stats.groups[groupId] = FeatureStats.fromJSON(group);
116
+ });
117
+ return stats;
118
+ }
119
+ }
120
+ exports.default = FeatureStats;
@@ -0,0 +1,22 @@
1
+ declare class FeatureUsage {
2
+ private isTriggered?;
3
+ private status?;
4
+ private error?;
5
+ constructor(isTriggered?: boolean);
6
+ getTriggered(): boolean | undefined;
7
+ setTriggered(triggered: boolean): void;
8
+ setStatus(status: string): void;
9
+ setError(error: string): void;
10
+ triggered(): void;
11
+ failed(e: unknown): void;
12
+ success(): void;
13
+ getStatus(): string | undefined;
14
+ getError(): string | undefined;
15
+ toJSON(): {
16
+ isTriggered: boolean | undefined;
17
+ status: string | undefined;
18
+ error: string | undefined;
19
+ };
20
+ }
21
+ export default FeatureUsage;
22
+ //# sourceMappingURL=featureUsage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"featureUsage.d.ts","sourceRoot":"","sources":["../../src/testOps/featureUsage.ts"],"names":[],"mappings":"AAEA,cAAM,YAAY;IACd,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAC,CAAQ;IACvB,OAAO,CAAC,KAAK,CAAC,CAAQ;gBAEV,WAAW,CAAC,EAAE,OAAO;IAM1B,YAAY,IAAI,OAAO,GAAG,SAAS;IAInC,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAItC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,SAAS,IAAI,IAAI;IAIjB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAKxB,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,MAAM,GAAG,SAAS;IAI/B,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,MAAM;;;;;CAOhB;AAED,eAAe,YAAY,CAAA"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const util_1 = require("../util");
4
+ class FeatureUsage {
5
+ constructor(isTriggered) {
6
+ if (isTriggered !== undefined) {
7
+ this.isTriggered = isTriggered;
8
+ }
9
+ }
10
+ getTriggered() {
11
+ return this.isTriggered;
12
+ }
13
+ setTriggered(triggered) {
14
+ this.isTriggered = triggered;
15
+ }
16
+ setStatus(status) {
17
+ this.status = status;
18
+ }
19
+ setError(error) {
20
+ this.error = error;
21
+ }
22
+ triggered() {
23
+ this.isTriggered = true;
24
+ }
25
+ failed(e) {
26
+ this.status = 'failed';
27
+ this.error = (0, util_1.getErrorString)(e);
28
+ }
29
+ success() {
30
+ this.status = 'success';
31
+ }
32
+ getStatus() {
33
+ return this.status;
34
+ }
35
+ getError() {
36
+ return this.error;
37
+ }
38
+ toJSON() {
39
+ return {
40
+ isTriggered: this.isTriggered,
41
+ status: this.status,
42
+ error: this.error
43
+ };
44
+ }
45
+ }
46
+ exports.default = FeatureUsage;
@@ -0,0 +1,33 @@
1
+ import type { CBTData, LogData, ScreenshotLog, TestData } from '../types';
2
+ declare class Listener {
3
+ private static instance;
4
+ private readonly usageStats;
5
+ private readonly testStartedStats;
6
+ private readonly testFinishedStats;
7
+ private readonly hookStartedStats;
8
+ private readonly hookFinishedStats;
9
+ private readonly cbtSessionStats;
10
+ private readonly logEvents;
11
+ private requestBatcher?;
12
+ private pendingUploads;
13
+ private constructor();
14
+ static getInstance(): Listener;
15
+ onWorkerEnd(): Promise<void>;
16
+ uploadPending(waitTimeout?: number, waitInterval?: number): Promise<unknown>;
17
+ teardown(): Promise<void>;
18
+ hookStarted(hookData: TestData): void;
19
+ hookFinished(hookData: TestData): void;
20
+ testStarted(testData: TestData): void;
21
+ testFinished(testData: TestData): void;
22
+ logCreated(logs: LogData[]): void;
23
+ onScreenshot(jsonArray: ScreenshotLog[]): Promise<void>;
24
+ cbtSessionCreated(data: CBTData): void;
25
+ private markLogs;
26
+ private getResult;
27
+ private sendBatchEvents;
28
+ private eventsFailed;
29
+ private eventsSuccess;
30
+ private getEventForHook;
31
+ }
32
+ export default Listener;
33
+ //# sourceMappingURL=listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../src/testOps/listener.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAc,MAAM,UAAU,CAAA;AAWrF,cAAM,QAAQ;IACV,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAClE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiD;IAClF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAkD;IACpF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiD;IAClF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAkD;IACpF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgD;IAChF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IACnE,OAAO,CAAC,cAAc,CAAC,CAAqB;IAC5C,OAAO,CAAC,cAAc,CAAI;IAG1B,OAAO;WAGO,WAAW,IAAI,QAAQ;IAOxB,WAAW;IASlB,aAAa,CAAC,WAAW,SAA2C,EAAE,YAAY,SAA4C,GAAG,OAAO,CAAC,OAAO,CAAC;IASjJ,QAAQ;IASP,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAUrC,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAUtC,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAUrC,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAUtC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAY3B,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE;IAgB7C,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAU7C,OAAO,CAAC,QAAQ;IAgBhB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,eAAe;CAK1B;AAED,eAAe,QAAQ,CAAA"}
@@ -0,0 +1,228 @@
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
+ const usageStats_1 = __importDefault(require("./usageStats"));
7
+ const request_handler_1 = __importDefault(require("../request-handler"));
8
+ const util_1 = require("../util");
9
+ const constants_1 = require("../constants");
10
+ const requestUtils_1 = require("./requestUtils");
11
+ const bstackLogger_1 = require("../bstackLogger");
12
+ class Listener {
13
+ // Making the constructor private to use singleton pattern
14
+ constructor() {
15
+ this.usageStats = usageStats_1.default.getInstance();
16
+ this.testStartedStats = this.usageStats.testStartedStats;
17
+ this.testFinishedStats = this.usageStats.testFinishedStats;
18
+ this.hookStartedStats = this.usageStats.hookStartedStats;
19
+ this.hookFinishedStats = this.usageStats.hookFinishedStats;
20
+ this.cbtSessionStats = this.usageStats.cbtSessionStats;
21
+ this.logEvents = this.usageStats.logStats;
22
+ this.pendingUploads = 0;
23
+ }
24
+ static getInstance() {
25
+ if (!Listener.instance) {
26
+ Listener.instance = new Listener();
27
+ }
28
+ return Listener.instance;
29
+ }
30
+ async onWorkerEnd() {
31
+ try {
32
+ await this.uploadPending();
33
+ await this.teardown();
34
+ }
35
+ catch (e) {
36
+ bstackLogger_1.BStackLogger.debug('Exception in onWorkerEnd: ' + e);
37
+ }
38
+ }
39
+ async uploadPending(waitTimeout = constants_1.DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = constants_1.DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
40
+ if ((this.pendingUploads <= 0) || waitTimeout <= 0) {
41
+ return;
42
+ }
43
+ await (0, util_1.sleep)(waitInterval);
44
+ return this.uploadPending(waitTimeout - waitInterval);
45
+ }
46
+ async teardown() {
47
+ var _a;
48
+ bstackLogger_1.BStackLogger.debug('teardown started');
49
+ if (this.requestBatcher) {
50
+ this.requestBatcher.tearDownInvoked = true;
51
+ }
52
+ await ((_a = this.requestBatcher) === null || _a === void 0 ? void 0 : _a.shutdown());
53
+ bstackLogger_1.BStackLogger.debug('teardown ended');
54
+ }
55
+ hookStarted(hookData) {
56
+ try {
57
+ this.hookStartedStats.triggered();
58
+ this.sendBatchEvents(this.getEventForHook('HookRunStarted', hookData));
59
+ }
60
+ catch (e) {
61
+ this.hookStartedStats.failed();
62
+ throw e;
63
+ }
64
+ }
65
+ hookFinished(hookData) {
66
+ try {
67
+ this.hookFinishedStats.triggered(hookData.result);
68
+ this.sendBatchEvents(this.getEventForHook('HookRunFinished', hookData));
69
+ }
70
+ catch (e) {
71
+ this.hookFinishedStats.failed(hookData.result);
72
+ throw e;
73
+ }
74
+ }
75
+ testStarted(testData) {
76
+ try {
77
+ this.testStartedStats.triggered();
78
+ this.sendBatchEvents(this.getEventForHook('TestRunStarted', testData));
79
+ }
80
+ catch (e) {
81
+ this.testStartedStats.failed();
82
+ throw e;
83
+ }
84
+ }
85
+ testFinished(testData) {
86
+ try {
87
+ this.testFinishedStats.triggered(testData.result);
88
+ this.sendBatchEvents(this.getEventForHook('TestRunFinished', testData));
89
+ }
90
+ catch (e) {
91
+ this.testFinishedStats.failed(testData.result);
92
+ throw e;
93
+ }
94
+ }
95
+ logCreated(logs) {
96
+ try {
97
+ this.markLogs('triggered', logs);
98
+ this.sendBatchEvents({
99
+ event_type: 'LogCreated', logs: logs
100
+ });
101
+ }
102
+ catch (e) {
103
+ this.markLogs('failed', logs);
104
+ throw e;
105
+ }
106
+ }
107
+ async onScreenshot(jsonArray) {
108
+ try {
109
+ this.markLogs('triggered', jsonArray);
110
+ this.pendingUploads += 1;
111
+ await (0, requestUtils_1.sendScreenshots)([{
112
+ event_type: 'LogCreated', logs: jsonArray
113
+ }]);
114
+ this.markLogs('success', jsonArray);
115
+ }
116
+ catch (e) {
117
+ this.markLogs('failed', jsonArray);
118
+ throw e;
119
+ }
120
+ finally {
121
+ this.pendingUploads -= 1;
122
+ }
123
+ }
124
+ cbtSessionCreated(data) {
125
+ try {
126
+ this.cbtSessionStats.triggered();
127
+ this.sendBatchEvents({ event_type: 'CBTSessionCreated', test_run: data });
128
+ }
129
+ catch (e) {
130
+ this.cbtSessionStats.failed();
131
+ throw e;
132
+ }
133
+ }
134
+ markLogs(status, data) {
135
+ if (!data) {
136
+ bstackLogger_1.BStackLogger.debug('No log data');
137
+ return;
138
+ }
139
+ try {
140
+ for (const _log of data) {
141
+ const kind = _log.kind;
142
+ this.logEvents.mark(status, constants_1.LOG_KIND_USAGE_MAP[kind] || kind);
143
+ }
144
+ }
145
+ catch (e) {
146
+ bstackLogger_1.BStackLogger.debug('Exception in marking logs status ' + e);
147
+ throw e;
148
+ }
149
+ }
150
+ getResult(jsonObject, kind) {
151
+ const runStr = kind === 'test' ? 'test_run' : 'hook_run';
152
+ const runData = jsonObject[runStr];
153
+ return runData === null || runData === void 0 ? void 0 : runData.result;
154
+ }
155
+ sendBatchEvents(jsonObject) {
156
+ if (!this.requestBatcher) {
157
+ this.requestBatcher = request_handler_1.default.getInstance(async (data) => {
158
+ bstackLogger_1.BStackLogger.debug('callback: called with events ' + data.length);
159
+ try {
160
+ this.pendingUploads += 1;
161
+ await (0, util_1.batchAndPostEvents)(constants_1.DATA_BATCH_ENDPOINT, 'BATCH_DATA', data);
162
+ bstackLogger_1.BStackLogger.debug('callback: marking events success ' + data.length);
163
+ this.eventsSuccess(data);
164
+ }
165
+ catch (e) {
166
+ bstackLogger_1.BStackLogger.debug('callback: marking events failed ' + data.length);
167
+ this.eventsFailed(data);
168
+ }
169
+ finally {
170
+ this.pendingUploads -= 1;
171
+ }
172
+ });
173
+ }
174
+ this.requestBatcher.add(jsonObject);
175
+ }
176
+ eventsFailed(events) {
177
+ for (const event of events) {
178
+ const eventType = event.event_type;
179
+ if (eventType === 'TestRunStarted') {
180
+ this.testStartedStats.failed();
181
+ }
182
+ else if (eventType === 'TestRunFinished') {
183
+ this.testFinishedStats.failed(this.getResult(event, 'test'));
184
+ }
185
+ else if (eventType === 'HookRunStarted') {
186
+ this.hookStartedStats.failed();
187
+ }
188
+ else if (eventType === 'HookRunFinished') {
189
+ this.hookFinishedStats.failed(this.getResult(event, 'hook'));
190
+ }
191
+ else if (eventType === 'CBTSessionCreated') {
192
+ this.cbtSessionStats.failed();
193
+ }
194
+ else if (eventType === 'LogCreated') {
195
+ this.markLogs('failed', event.logs);
196
+ }
197
+ }
198
+ }
199
+ eventsSuccess(events) {
200
+ for (const event of events) {
201
+ const eventType = event.event_type;
202
+ if (eventType === 'TestRunStarted') {
203
+ this.testStartedStats.success();
204
+ }
205
+ else if (eventType === 'TestRunFinished') {
206
+ this.testFinishedStats.success(this.getResult(event, 'test'));
207
+ }
208
+ else if (eventType === 'HookRunStarted') {
209
+ this.hookStartedStats.success();
210
+ }
211
+ else if (eventType === 'HookRunFinished') {
212
+ this.hookFinishedStats.success(this.getResult(event, 'hook'));
213
+ }
214
+ else if (eventType === 'CBTSessionCreated') {
215
+ this.cbtSessionStats.success();
216
+ }
217
+ else if (eventType === 'LogCreated') {
218
+ this.markLogs('success', event.logs);
219
+ }
220
+ }
221
+ }
222
+ getEventForHook(eventType, data) {
223
+ return {
224
+ event_type: eventType, [data.type === 'hook' ? 'hook_run' : 'test_run']: data
225
+ };
226
+ }
227
+ }
228
+ exports.default = Listener;