@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.
- package/build/Percy/Percy-Handler.d.ts +34 -0
- package/build/Percy/Percy-Handler.d.ts.map +1 -0
- package/build/Percy/Percy-Handler.js +187 -0
- package/build/Percy/Percy.d.ts +24 -0
- package/build/Percy/Percy.d.ts.map +1 -0
- package/build/Percy/Percy.js +128 -0
- package/build/Percy/PercyBinary.d.ts +17 -0
- package/build/Percy/PercyBinary.d.ts.map +1 -0
- package/build/Percy/PercyBinary.js +151 -0
- package/build/Percy/PercyCaptureMap.d.ts +9 -0
- package/build/Percy/PercyCaptureMap.d.ts.map +1 -0
- package/build/Percy/PercyCaptureMap.js +46 -0
- package/build/Percy/PercyHelper.d.ts +8 -0
- package/build/Percy/PercyHelper.d.ts.map +1 -0
- package/build/Percy/PercyHelper.js +78 -0
- package/build/Percy/PercyLogger.d.ts +15 -0
- package/build/Percy/PercyLogger.d.ts.map +1 -0
- package/build/Percy/PercyLogger.js +76 -0
- package/build/Percy/PercySDK.d.ts +4 -0
- package/build/Percy/PercySDK.d.ts.map +1 -0
- package/build/Percy/PercySDK.js +42 -0
- package/build/bstackLogger.d.ts +14 -0
- package/build/bstackLogger.d.ts.map +1 -0
- package/build/bstackLogger.js +52 -0
- package/build/cleanup.d.ts +6 -2
- package/build/cleanup.d.ts.map +1 -1
- package/build/cleanup.js +104 -12
- package/build/config.d.ts +23 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +32 -0
- package/build/constants.d.ts +20 -0
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +45 -1
- package/build/crash-reporter.js +1 -1
- package/build/data-store.d.ts +3 -0
- package/build/data-store.d.ts.map +1 -0
- package/build/data-store.js +49 -0
- package/build/exitHandler.d.ts +4 -0
- package/build/exitHandler.d.ts.map +1 -0
- package/build/exitHandler.js +37 -0
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +15 -1
- package/build/insights-handler.d.ts +5 -11
- package/build/insights-handler.d.ts.map +1 -1
- package/build/insights-handler.js +45 -106
- package/build/instrumentation/funnelInstrumentation.d.ts +6 -0
- package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -0
- package/build/instrumentation/funnelInstrumentation.js +127 -0
- package/build/launcher.d.ts +8 -4
- package/build/launcher.d.ts.map +1 -1
- package/build/launcher.js +87 -18
- package/build/reporter.d.ts +3 -3
- package/build/reporter.d.ts.map +1 -1
- package/build/reporter.js +10 -23
- package/build/request-handler.d.ts +5 -13
- package/build/request-handler.d.ts.map +1 -1
- package/build/request-handler.js +27 -48
- package/build/service.d.ts +3 -0
- package/build/service.d.ts.map +1 -1
- package/build/service.js +50 -18
- package/build/testOps/featureStats.d.ts +45 -0
- package/build/testOps/featureStats.d.ts.map +1 -0
- package/build/testOps/featureStats.js +120 -0
- package/build/testOps/featureUsage.d.ts +22 -0
- package/build/testOps/featureUsage.d.ts.map +1 -0
- package/build/testOps/featureUsage.js +46 -0
- package/build/testOps/listener.d.ts +33 -0
- package/build/testOps/listener.d.ts.map +1 -0
- package/build/testOps/listener.js +228 -0
- package/build/testOps/requestUtils.d.ts +4 -0
- package/build/testOps/requestUtils.d.ts.map +1 -0
- package/build/testOps/requestUtils.js +47 -0
- package/build/testOps/testOpsConfig.d.ts +11 -0
- package/build/testOps/testOpsConfig.d.ts.map +1 -0
- package/build/testOps/testOpsConfig.js +17 -0
- package/build/testOps/usageStats.d.ts +404 -0
- package/build/testOps/usageStats.d.ts.map +1 -0
- package/build/testOps/usageStats.js +110 -0
- package/build/types.d.ts +48 -7
- package/build/types.d.ts.map +1 -1
- package/build/util.d.ts +4 -6
- package/build/util.d.ts.map +1 -1
- package/build/util.js +82 -67
- 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.
|
|
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.
|
|
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
|
-
(
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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 (
|
|
188
|
-
await ((
|
|
189
|
-
|
|
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.
|
|
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;
|