@wdio/browserstack-service 7.32.4 → 7.33.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/accessibility-handler.d.ts +39 -0
- package/build/accessibility-handler.d.ts.map +1 -0
- package/build/accessibility-handler.js +258 -0
- package/build/constants.d.ts +3 -0
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +6 -2
- package/build/cucumber-types.d.ts +17 -0
- package/build/cucumber-types.d.ts.map +1 -1
- package/build/index.d.ts +5 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -1
- package/build/insights-handler.d.ts +19 -3
- package/build/insights-handler.d.ts.map +1 -1
- package/build/insights-handler.js +274 -17
- package/build/launcher.d.ts +4 -0
- package/build/launcher.d.ts.map +1 -1
- package/build/launcher.js +152 -0
- package/build/log4jsAppender.d.ts +2 -0
- package/build/log4jsAppender.d.ts.map +1 -0
- package/build/log4jsAppender.js +26 -0
- package/build/logPatcher.d.ts +13 -0
- package/build/logPatcher.d.ts.map +1 -0
- package/build/logPatcher.js +43 -0
- package/build/logReportingAPI.d.ts +12 -0
- package/build/logReportingAPI.d.ts.map +1 -0
- package/build/logReportingAPI.js +61 -0
- package/build/reporter.d.ts +6 -1
- package/build/reporter.d.ts.map +1 -1
- package/build/reporter.js +42 -1
- package/build/scripts/test-event-scripts.d.ts +10 -0
- package/build/scripts/test-event-scripts.d.ts.map +1 -0
- package/build/scripts/test-event-scripts.js +73 -0
- package/build/service.d.ts +5 -3
- package/build/service.d.ts.map +1 -1
- package/build/service.js +24 -4
- package/build/types.d.ts +34 -1
- package/build/types.d.ts.map +1 -1
- package/build/util.d.ts +32 -0
- package/build/util.d.ts.map +1 -1
- package/build/util.js +313 -2
- package/package.json +6 -5
|
@@ -4,11 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const logger_1 = __importDefault(require("@wdio/logger"));
|
|
7
8
|
const uuid_1 = require("uuid");
|
|
8
9
|
const reporter_1 = __importDefault(require("./reporter"));
|
|
9
10
|
const util_1 = require("./util");
|
|
10
11
|
const request_handler_1 = __importDefault(require("./request-handler"));
|
|
11
12
|
const constants_1 = require("./constants");
|
|
13
|
+
const log = (0, logger_1.default)('@wdio/browserstack-service');
|
|
12
14
|
class _InsightsHandler {
|
|
13
15
|
constructor(_browser, browserCaps, isAppAutomate, sessionId, _framework) {
|
|
14
16
|
this._browser = _browser;
|
|
@@ -17,6 +19,32 @@ class _InsightsHandler {
|
|
|
17
19
|
this._hooks = {};
|
|
18
20
|
this._commands = {};
|
|
19
21
|
this._requestQueueHandler = request_handler_1.default.getInstance();
|
|
22
|
+
this._currentTest = {};
|
|
23
|
+
this._currentHook = {};
|
|
24
|
+
this._cucumberData = {
|
|
25
|
+
stepsStarted: false,
|
|
26
|
+
scenariosStarted: false,
|
|
27
|
+
steps: []
|
|
28
|
+
};
|
|
29
|
+
this.appendTestItemLog = async (stdLog) => {
|
|
30
|
+
try {
|
|
31
|
+
if (this._currentHook.uuid && !this._currentHook.finished && (this._framework === 'mocha' || this._framework === 'cucumber')) {
|
|
32
|
+
stdLog.hook_run_uuid = this._currentHook.uuid;
|
|
33
|
+
}
|
|
34
|
+
else if (this._currentTest.uuid && (this._framework === 'mocha' || this._framework === 'cucumber')) {
|
|
35
|
+
stdLog.test_run_uuid = this._currentTest.uuid;
|
|
36
|
+
}
|
|
37
|
+
if (stdLog.hook_run_uuid || stdLog.test_run_uuid) {
|
|
38
|
+
await (0, util_1.pushDataToQueue)({
|
|
39
|
+
event_type: 'LogCreated',
|
|
40
|
+
logs: [stdLog]
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
log.debug(`Exception in uploading log data to Observability with error : ${error}`);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
20
48
|
this._requestQueueHandler.start();
|
|
21
49
|
this._platformMeta = {
|
|
22
50
|
browserName: browserCaps === null || browserCaps === void 0 ? void 0 : browserCaps.browserName,
|
|
@@ -26,6 +54,14 @@ class _InsightsHandler {
|
|
|
26
54
|
sessionId: sessionId,
|
|
27
55
|
product: isAppAutomate ? 'app-automate' : 'automate'
|
|
28
56
|
};
|
|
57
|
+
this.registerListeners();
|
|
58
|
+
}
|
|
59
|
+
registerListeners() {
|
|
60
|
+
if (!(this._framework === 'mocha' || this._framework === 'cucumber')) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
process.removeAllListeners(`bs:addLog:${process.pid}`);
|
|
64
|
+
process.on(`bs:addLog:${process.pid}`, this.appendTestItemLog.bind(this));
|
|
29
65
|
}
|
|
30
66
|
async before() {
|
|
31
67
|
if ((0, util_1.isBrowserstackSession)(this._browser)) {
|
|
@@ -40,19 +76,31 @@ class _InsightsHandler {
|
|
|
40
76
|
if (!(0, util_1.frameworkSupportsHook)('before', this._framework)) {
|
|
41
77
|
return;
|
|
42
78
|
}
|
|
79
|
+
const hookUUID = (0, uuid_1.v4)();
|
|
80
|
+
if (this._framework === 'cucumber') {
|
|
81
|
+
test = test;
|
|
82
|
+
await this.processCucumberHook(test, { event: 'before', hookUUID });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
test = test;
|
|
43
86
|
const fullTitle = (0, util_1.getUniqueIdentifier)(test, this._framework);
|
|
44
|
-
const hookId = (0, uuid_1.v4)();
|
|
45
87
|
this._tests[fullTitle] = {
|
|
46
|
-
uuid:
|
|
88
|
+
uuid: hookUUID,
|
|
47
89
|
startedAt: (new Date()).toISOString()
|
|
48
90
|
};
|
|
49
|
-
this.
|
|
91
|
+
this.setCurrentHook({ uuid: hookUUID });
|
|
92
|
+
this.attachHookData(context, hookUUID);
|
|
50
93
|
await this.sendTestRunEvent(test, 'HookRunStarted');
|
|
51
94
|
}
|
|
52
95
|
async afterHook(test, result) {
|
|
53
96
|
if (!(0, util_1.frameworkSupportsHook)('after', this._framework)) {
|
|
54
97
|
return;
|
|
55
98
|
}
|
|
99
|
+
if (this._framework === 'cucumber') {
|
|
100
|
+
await this.processCucumberHook(test, { event: 'after' }, result);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
test = test;
|
|
56
104
|
const fullTitle = (0, util_1.getUniqueIdentifier)(test, this._framework);
|
|
57
105
|
if (this._tests[fullTitle]) {
|
|
58
106
|
this._tests[fullTitle].finishedAt = (new Date()).toISOString();
|
|
@@ -62,6 +110,7 @@ class _InsightsHandler {
|
|
|
62
110
|
finishedAt: (new Date()).toISOString()
|
|
63
111
|
};
|
|
64
112
|
}
|
|
113
|
+
this.setCurrentHook({ uuid: this._tests[fullTitle].uuid, finished: true });
|
|
65
114
|
await this.sendTestRunEvent(test, 'HookRunFinished', result);
|
|
66
115
|
const hookType = (0, util_1.getHookType)(test.title);
|
|
67
116
|
/*
|
|
@@ -97,11 +146,15 @@ class _InsightsHandler {
|
|
|
97
146
|
}
|
|
98
147
|
}
|
|
99
148
|
async beforeTest(test) {
|
|
149
|
+
const uuid = (0, uuid_1.v4)();
|
|
150
|
+
this._currentTest = {
|
|
151
|
+
test, uuid
|
|
152
|
+
};
|
|
100
153
|
if (this._framework !== 'mocha')
|
|
101
154
|
return;
|
|
102
155
|
const fullTitle = (0, util_1.getUniqueIdentifier)(test, this._framework);
|
|
103
156
|
this._tests[fullTitle] = {
|
|
104
|
-
uuid:
|
|
157
|
+
uuid: uuid,
|
|
105
158
|
startedAt: (new Date()).toISOString()
|
|
106
159
|
};
|
|
107
160
|
await this.sendTestRunEvent(test, 'TestRunStarted');
|
|
@@ -119,13 +172,25 @@ class _InsightsHandler {
|
|
|
119
172
|
/**
|
|
120
173
|
* Cucumber Only
|
|
121
174
|
*/
|
|
175
|
+
async beforeFeature(uri, feature) {
|
|
176
|
+
this._cucumberData.scenariosStarted = false;
|
|
177
|
+
this._cucumberData.feature = feature;
|
|
178
|
+
this._cucumberData.uri = uri;
|
|
179
|
+
}
|
|
122
180
|
async beforeScenario(world) {
|
|
181
|
+
const uuid = (0, uuid_1.v4)();
|
|
182
|
+
this._currentTest = {
|
|
183
|
+
uuid
|
|
184
|
+
};
|
|
185
|
+
this._cucumberData.scenario = world.pickle;
|
|
186
|
+
this._cucumberData.scenariosStarted = true;
|
|
187
|
+
this._cucumberData.stepsStarted = false;
|
|
123
188
|
const pickleData = world.pickle;
|
|
124
189
|
const gherkinDocument = world.gherkinDocument;
|
|
125
190
|
const featureData = gherkinDocument.feature;
|
|
126
191
|
const uniqueId = (0, util_1.getUniqueIdentifierForCucumber)(world);
|
|
127
192
|
let testMetaData = {
|
|
128
|
-
uuid:
|
|
193
|
+
uuid: uuid,
|
|
129
194
|
startedAt: (new Date()).toISOString()
|
|
130
195
|
};
|
|
131
196
|
if (pickleData) {
|
|
@@ -144,10 +209,13 @@ class _InsightsHandler {
|
|
|
144
209
|
await this.sendTestRunEventForCucumber(world, 'TestRunStarted');
|
|
145
210
|
}
|
|
146
211
|
async afterScenario(world) {
|
|
212
|
+
this._cucumberData.scenario = undefined;
|
|
147
213
|
await this.sendTestRunEventForCucumber(world, 'TestRunFinished');
|
|
148
214
|
}
|
|
149
215
|
async beforeStep(step, scenario) {
|
|
150
216
|
var _a;
|
|
217
|
+
this._cucumberData.stepsStarted = true;
|
|
218
|
+
this._cucumberData.steps.push(step);
|
|
151
219
|
const uniqueId = (0, util_1.getUniqueIdentifierForCucumber)({ pickle: scenario });
|
|
152
220
|
let testMetaData = this._tests[uniqueId];
|
|
153
221
|
if (!testMetaData) {
|
|
@@ -168,6 +236,7 @@ class _InsightsHandler {
|
|
|
168
236
|
}
|
|
169
237
|
async afterStep(step, scenario, result) {
|
|
170
238
|
var _a;
|
|
239
|
+
this._cucumberData.steps.pop();
|
|
171
240
|
const uniqueId = (0, util_1.getUniqueIdentifierForCucumber)({ pickle: scenario });
|
|
172
241
|
let testMetaData = this._tests[uniqueId];
|
|
173
242
|
if (!testMetaData) {
|
|
@@ -195,6 +264,75 @@ class _InsightsHandler {
|
|
|
195
264
|
}
|
|
196
265
|
this._tests[uniqueId] = testMetaData;
|
|
197
266
|
}
|
|
267
|
+
async sendScenarioObjectSkipped(scenario, feature, uri) {
|
|
268
|
+
const testMetaData = {
|
|
269
|
+
uuid: (0, uuid_1.v4)(),
|
|
270
|
+
startedAt: (new Date()).toISOString(),
|
|
271
|
+
finishedAt: (new Date()).toISOString(),
|
|
272
|
+
scenario: {
|
|
273
|
+
name: scenario.name
|
|
274
|
+
},
|
|
275
|
+
feature: {
|
|
276
|
+
path: uri,
|
|
277
|
+
name: feature.name,
|
|
278
|
+
description: feature.description
|
|
279
|
+
},
|
|
280
|
+
steps: scenario.steps.map((step) => {
|
|
281
|
+
return {
|
|
282
|
+
id: step.id,
|
|
283
|
+
text: step.text,
|
|
284
|
+
keyword: step.keyword,
|
|
285
|
+
result: 'skipped',
|
|
286
|
+
};
|
|
287
|
+
}),
|
|
288
|
+
};
|
|
289
|
+
await this.sendTestRunEventForCucumber(null, 'TestRunSkipped', testMetaData);
|
|
290
|
+
}
|
|
291
|
+
async processCucumberHook(test, params, result) {
|
|
292
|
+
const hookType = this.getCucumberHookType(test);
|
|
293
|
+
if (!hookType) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const { event, hookUUID } = params;
|
|
297
|
+
const hookId = this.getCucumberHookUniqueId(hookType, test);
|
|
298
|
+
if (!hookId) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (event === 'before') {
|
|
302
|
+
this.setCurrentHook({ uuid: hookUUID });
|
|
303
|
+
const hookMetaData = {
|
|
304
|
+
uuid: hookUUID,
|
|
305
|
+
startedAt: (new Date()).toISOString(),
|
|
306
|
+
testRunId: this._currentTest.uuid,
|
|
307
|
+
hookType: hookType
|
|
308
|
+
};
|
|
309
|
+
this._tests[hookId] = hookMetaData;
|
|
310
|
+
await this.sendHookRunEvent(hookMetaData, 'HookRunStarted');
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
this._tests[hookId].finishedAt = (new Date()).toISOString();
|
|
314
|
+
this.setCurrentHook({ uuid: this._tests[hookId].uuid, finished: true });
|
|
315
|
+
await this.sendHookRunEvent(this._tests[hookId], 'HookRunFinished', result);
|
|
316
|
+
if (hookType === 'BEFORE_ALL' && result && !result.passed) {
|
|
317
|
+
const { feature, uri } = this._cucumberData;
|
|
318
|
+
if (!feature) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
feature.children.map(async (childObj) => {
|
|
322
|
+
if (childObj.rule) {
|
|
323
|
+
childObj.rule.children.map(async (scenarioObj) => {
|
|
324
|
+
if (scenarioObj.scenario) {
|
|
325
|
+
await this.sendScenarioObjectSkipped(scenarioObj.scenario, feature, uri);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
else if (childObj.scenario) {
|
|
330
|
+
await this.sendScenarioObjectSkipped(childObj.scenario, feature, uri);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
198
336
|
//@ts-ignore
|
|
199
337
|
async uploadPending(waitTimeout = constants_1.DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = constants_1.DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
|
|
200
338
|
if (this._requestQueueHandler.pendingUploads <= 0 || waitTimeout <= 0) {
|
|
@@ -261,6 +399,12 @@ class _InsightsHandler {
|
|
|
261
399
|
/*
|
|
262
400
|
* private methods
|
|
263
401
|
*/
|
|
402
|
+
async sendData(data) {
|
|
403
|
+
const req = this._requestQueueHandler.add(data);
|
|
404
|
+
if (req.proceed && req.data) {
|
|
405
|
+
await (0, util_1.uploadEventData)(req.data, req.url);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
264
408
|
attachHookData(context, hookId) {
|
|
265
409
|
if (context.currentTest && context.currentTest.parent) {
|
|
266
410
|
const parentTest = `${context.currentTest.parent.title} - ${context.currentTest.title}`;
|
|
@@ -294,6 +438,63 @@ class _InsightsHandler {
|
|
|
294
438
|
}
|
|
295
439
|
return false;
|
|
296
440
|
}
|
|
441
|
+
getCucumberHookType(test) {
|
|
442
|
+
var _a;
|
|
443
|
+
let hookType = null;
|
|
444
|
+
if (!test) {
|
|
445
|
+
hookType = this._cucumberData.scenariosStarted ? 'AFTER_ALL' : 'BEFORE_ALL';
|
|
446
|
+
}
|
|
447
|
+
else if (!this._cucumberData.stepsStarted) {
|
|
448
|
+
hookType = 'BEFORE_EACH';
|
|
449
|
+
}
|
|
450
|
+
else if (((_a = this._cucumberData.steps) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
451
|
+
// beforeStep or afterStep
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
hookType = 'AFTER_EACH';
|
|
455
|
+
}
|
|
456
|
+
return hookType;
|
|
457
|
+
}
|
|
458
|
+
getCucumberHookName(hookType) {
|
|
459
|
+
var _a, _b;
|
|
460
|
+
switch (hookType) {
|
|
461
|
+
case 'BEFORE_EACH':
|
|
462
|
+
case 'AFTER_EACH':
|
|
463
|
+
return `${hookType} for ${(_a = this._cucumberData.scenario) === null || _a === void 0 ? void 0 : _a.name}`;
|
|
464
|
+
case 'BEFORE_ALL':
|
|
465
|
+
case 'AFTER_ALL':
|
|
466
|
+
return `${hookType} for ${(_b = this._cucumberData.feature) === null || _b === void 0 ? void 0 : _b.name}`;
|
|
467
|
+
}
|
|
468
|
+
return '';
|
|
469
|
+
}
|
|
470
|
+
getCucumberHookUniqueId(hookType, hook) {
|
|
471
|
+
switch (hookType) {
|
|
472
|
+
case 'BEFORE_EACH':
|
|
473
|
+
case 'AFTER_EACH':
|
|
474
|
+
return hook.hookId;
|
|
475
|
+
case 'BEFORE_ALL':
|
|
476
|
+
case 'AFTER_ALL':
|
|
477
|
+
// Can only work for single beforeAll or afterAll
|
|
478
|
+
return `${hookType} for ${this.getCucumberFeatureUniqueId()}`;
|
|
479
|
+
}
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
getCucumberFeatureUniqueId() {
|
|
483
|
+
const { uri, feature } = this._cucumberData;
|
|
484
|
+
return `${uri}:${feature === null || feature === void 0 ? void 0 : feature.name}`;
|
|
485
|
+
}
|
|
486
|
+
setCurrentHook(hookDetails) {
|
|
487
|
+
if (hookDetails.finished) {
|
|
488
|
+
if (this._currentHook.uuid === hookDetails.uuid) {
|
|
489
|
+
this._currentHook.finished = true;
|
|
490
|
+
}
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
this._currentHook = {
|
|
494
|
+
uuid: hookDetails.uuid,
|
|
495
|
+
finished: false
|
|
496
|
+
};
|
|
497
|
+
}
|
|
297
498
|
/*
|
|
298
499
|
* Get hierarchy info
|
|
299
500
|
*/
|
|
@@ -410,13 +611,19 @@ class _InsightsHandler {
|
|
|
410
611
|
await (0, util_1.uploadEventData)(req.data, req.url);
|
|
411
612
|
}
|
|
412
613
|
}
|
|
413
|
-
async sendTestRunEventForCucumber(
|
|
414
|
-
const
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
const examples = (0, util_1.getScenarioExamples)(world);
|
|
418
|
-
|
|
419
|
-
|
|
614
|
+
async sendTestRunEventForCucumber(worldObj, eventType, testMetaData = null) {
|
|
615
|
+
const world = worldObj;
|
|
616
|
+
const dataHub = testMetaData ? testMetaData : (this._tests[(0, util_1.getUniqueIdentifierForCucumber)(world)] || {});
|
|
617
|
+
const { feature, scenario, steps, uuid, startedAt, finishedAt } = dataHub;
|
|
618
|
+
const examples = !testMetaData ? (0, util_1.getScenarioExamples)(world) : undefined;
|
|
619
|
+
let fullNameWithExamples;
|
|
620
|
+
if (!testMetaData) {
|
|
621
|
+
fullNameWithExamples = examples
|
|
622
|
+
? world.pickle.name + ' (' + examples.join(', ') + ')'
|
|
623
|
+
: world.pickle.name;
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
fullNameWithExamples = (scenario === null || scenario === void 0 ? void 0 : scenario.name) || '';
|
|
420
627
|
}
|
|
421
628
|
let testData = {
|
|
422
629
|
uuid: uuid,
|
|
@@ -443,7 +650,7 @@ class _InsightsHandler {
|
|
|
443
650
|
examples: examples
|
|
444
651
|
}
|
|
445
652
|
};
|
|
446
|
-
if (eventType == 'TestRunStarted') {
|
|
653
|
+
if (eventType == 'TestRunStarted' || eventType === 'TestRunSkipped') {
|
|
447
654
|
testData.integrations = {};
|
|
448
655
|
if (this._browser && this._platformMeta) {
|
|
449
656
|
const provider = (0, util_1.getCloudProvider)(this._browser);
|
|
@@ -451,7 +658,7 @@ class _InsightsHandler {
|
|
|
451
658
|
}
|
|
452
659
|
}
|
|
453
660
|
/* istanbul ignore if */
|
|
454
|
-
if (world.result) {
|
|
661
|
+
if (world === null || world === void 0 ? void 0 : world.result) {
|
|
455
662
|
let result = world.result.status.toLowerCase();
|
|
456
663
|
if (result !== 'passed' && result !== 'failed') {
|
|
457
664
|
result = 'skipped'; // mark UNKNOWN/UNDEFINED/AMBIGUOUS/PENDING as skipped
|
|
@@ -464,8 +671,8 @@ class _InsightsHandler {
|
|
|
464
671
|
{
|
|
465
672
|
'backtrace': [world.result.message ? (0, util_1.removeAnsiColors)(world.result.message) : 'unknown']
|
|
466
673
|
}
|
|
467
|
-
]
|
|
468
|
-
|
|
674
|
+
];
|
|
675
|
+
testData.failure_reason = world.result.message ? (0, util_1.removeAnsiColors)(world.result.message) : world.result.message;
|
|
469
676
|
if (world.result.message) {
|
|
470
677
|
testData.failure_type = world.result.message.match(/AssertionError/)
|
|
471
678
|
? 'AssertionError'
|
|
@@ -473,9 +680,13 @@ class _InsightsHandler {
|
|
|
473
680
|
}
|
|
474
681
|
}
|
|
475
682
|
}
|
|
476
|
-
if (world.pickle) {
|
|
683
|
+
if (world === null || world === void 0 ? void 0 : world.pickle) {
|
|
477
684
|
testData.tags = world.pickle.tags.map(({ name }) => (name));
|
|
478
685
|
}
|
|
686
|
+
if (eventType === 'TestRunSkipped') {
|
|
687
|
+
testData.result = 'skipped';
|
|
688
|
+
eventType = 'TestRunFinished';
|
|
689
|
+
}
|
|
479
690
|
const uploadData = {
|
|
480
691
|
event_type: eventType,
|
|
481
692
|
test_run: testData
|
|
@@ -485,6 +696,52 @@ class _InsightsHandler {
|
|
|
485
696
|
await (0, util_1.uploadEventData)(req.data, req.url);
|
|
486
697
|
}
|
|
487
698
|
}
|
|
699
|
+
async sendHookRunEvent(hookData, eventType, result) {
|
|
700
|
+
const { uri, feature } = this._cucumberData;
|
|
701
|
+
const testData = {
|
|
702
|
+
uuid: hookData.uuid,
|
|
703
|
+
type: 'hook',
|
|
704
|
+
name: this.getCucumberHookName(hookData.hookType),
|
|
705
|
+
body: {
|
|
706
|
+
lang: 'webdriverio',
|
|
707
|
+
code: null
|
|
708
|
+
},
|
|
709
|
+
started_at: hookData.startedAt,
|
|
710
|
+
finished_at: hookData.finishedAt,
|
|
711
|
+
hook_type: hookData.hookType,
|
|
712
|
+
test_run_id: hookData.testRunId,
|
|
713
|
+
scope: feature === null || feature === void 0 ? void 0 : feature.name,
|
|
714
|
+
scopes: [(feature === null || feature === void 0 ? void 0 : feature.name) || ''],
|
|
715
|
+
file_name: uri ? path_1.default.relative(process.cwd(), uri) : undefined,
|
|
716
|
+
location: uri ? path_1.default.relative(process.cwd(), uri) : undefined,
|
|
717
|
+
vc_filepath: (this._gitConfigPath && uri) ? path_1.default.relative(this._gitConfigPath, uri) : undefined,
|
|
718
|
+
result: 'pending',
|
|
719
|
+
framework: this._framework
|
|
720
|
+
};
|
|
721
|
+
if (eventType === 'HookRunFinished' && result) {
|
|
722
|
+
testData.result = result.passed ? 'passed' : 'failed';
|
|
723
|
+
testData.retries = result.retries;
|
|
724
|
+
testData.duration_in_ms = result.duration;
|
|
725
|
+
if (!result.passed) {
|
|
726
|
+
Object.assign(testData, (0, util_1.getFailureObject)(result.error));
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (eventType === 'HookRunStarted') {
|
|
730
|
+
testData.integrations = {};
|
|
731
|
+
if (this._browser && this._platformMeta) {
|
|
732
|
+
const provider = (0, util_1.getCloudProvider)(this._browser);
|
|
733
|
+
testData.integrations[provider] = this.getIntegrationsObject();
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
const uploadData = {
|
|
737
|
+
event_type: eventType,
|
|
738
|
+
hook_run: testData
|
|
739
|
+
};
|
|
740
|
+
const req = this._requestQueueHandler.add(uploadData);
|
|
741
|
+
if (req.proceed && req.data) {
|
|
742
|
+
await (0, util_1.uploadEventData)(req.data, req.url);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
488
745
|
getIntegrationsObject() {
|
|
489
746
|
var _a, _b, _c, _d, _e, _f;
|
|
490
747
|
return {
|
package/build/launcher.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export default class BrowserstackLauncherService implements Services.ServiceInst
|
|
|
13
13
|
private _projectName?;
|
|
14
14
|
private _buildTag?;
|
|
15
15
|
private _buildIdentifier?;
|
|
16
|
+
private _accessibilityAutomation?;
|
|
16
17
|
constructor(_options: BrowserstackConfig & Options.Testrunner, capabilities: Capabilities.RemoteCapability, _config: Options.Testrunner);
|
|
17
18
|
onPrepare(config?: Options.Testrunner, capabilities?: Capabilities.RemoteCapabilities): Promise<unknown>;
|
|
18
19
|
onComplete(): Promise<unknown>;
|
|
@@ -22,6 +23,9 @@ export default class BrowserstackLauncherService implements Services.ServiceInst
|
|
|
22
23
|
* <object>: only "path" and "custom_id" should coexist as multiple properties.
|
|
23
24
|
*/
|
|
24
25
|
_validateApp(appConfig: AppConfig | string): Promise<App>;
|
|
26
|
+
_updateObjectTypeCaps(capabilities?: Capabilities.RemoteCapabilities, capType?: string, value?: {
|
|
27
|
+
[key: string]: any;
|
|
28
|
+
}): void;
|
|
25
29
|
_updateCaps(capabilities?: Capabilities.RemoteCapabilities, capType?: string, value?: string): void;
|
|
26
30
|
_handleBuildIdentifier(capabilities?: Capabilities.RemoteCapabilities): void;
|
|
27
31
|
/**
|
package/build/launcher.d.ts.map
CHANGED
|
@@ -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;AAKlE,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;
|
|
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;AAKlE,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAkBpF,KAAK,iBAAiB,GAAG,yBAAyB,CAAC,KAAK,GAAG;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;CAC7C,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,2BAA4B,YAAW,QAAQ,CAAC,eAAe;IAS5E,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,OAAO;IAVnB,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;gBAG9B,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IA8FjC,SAAS,CAAE,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IA4ItF,UAAU;IA4DV,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"}
|
package/build/launcher.js
CHANGED
|
@@ -57,6 +57,12 @@ class BrowserstackLauncherService {
|
|
|
57
57
|
const extensionCaps = Object.keys(capability).filter((cap) => cap.includes(':'));
|
|
58
58
|
if (extensionCaps.length) {
|
|
59
59
|
capability['bstack:options'] = { wdioService: package_json_1.version };
|
|
60
|
+
if (!(0, util_2.isUndefined)(capability['browserstack.accessibility'])) {
|
|
61
|
+
this._accessibilityAutomation || (this._accessibilityAutomation = (0, util_2.isTrue)(capability['browserstack.accessibility']));
|
|
62
|
+
}
|
|
63
|
+
else if ((0, util_2.isTrue)(this._options.accessibility)) {
|
|
64
|
+
capability['bstack:options'].accessibility = true;
|
|
65
|
+
}
|
|
60
66
|
}
|
|
61
67
|
else if ((0, util_2.shouldAddServiceVersion)(this._config, this._options.testObservability)) {
|
|
62
68
|
capability['browserstack.wdioService'] = package_json_1.version;
|
|
@@ -71,6 +77,12 @@ class BrowserstackLauncherService {
|
|
|
71
77
|
this._projectName = capability['bstack:options'].projectName;
|
|
72
78
|
this._buildTag = capability['bstack:options'].buildTag;
|
|
73
79
|
this._buildIdentifier = capability['bstack:options'].buildIdentifier;
|
|
80
|
+
if (!(0, util_2.isUndefined)(capability['bstack:options'].accessibility)) {
|
|
81
|
+
this._accessibilityAutomation || (this._accessibilityAutomation = (0, util_2.isTrue)(capability['bstack:options'].accessibility));
|
|
82
|
+
}
|
|
83
|
+
else if ((0, util_2.isTrue)(this._options.accessibility)) {
|
|
84
|
+
capability['bstack:options'].accessibility = ((0, util_2.isTrue)(this._options.accessibility));
|
|
85
|
+
}
|
|
74
86
|
}
|
|
75
87
|
});
|
|
76
88
|
}
|
|
@@ -81,6 +93,12 @@ class BrowserstackLauncherService {
|
|
|
81
93
|
const extensionCaps = Object.keys(caps.capabilities).filter((cap) => cap.includes(':'));
|
|
82
94
|
if (extensionCaps.length) {
|
|
83
95
|
caps.capabilities['bstack:options'] = { wdioService: package_json_1.version };
|
|
96
|
+
if (!(0, util_2.isUndefined)(caps.capabilities['browserstack.accessibility'])) {
|
|
97
|
+
this._accessibilityAutomation || (this._accessibilityAutomation = (0, util_2.isTrue)(caps.capabilities['browserstack.accessibility']));
|
|
98
|
+
}
|
|
99
|
+
else if ((0, util_2.isTrue)(this._options.accessibility)) {
|
|
100
|
+
caps.capabilities['bstack:options'] = { wdioService: package_json_1.version, accessibility: ((0, util_2.isTrue)(this._options.accessibility)) };
|
|
101
|
+
}
|
|
84
102
|
}
|
|
85
103
|
else if ((0, util_2.shouldAddServiceVersion)(this._config, this._options.testObservability)) {
|
|
86
104
|
caps.capabilities['browserstack.wdioService'] = package_json_1.version;
|
|
@@ -95,12 +113,20 @@ class BrowserstackLauncherService {
|
|
|
95
113
|
this._projectName = bstackOptions.projectName;
|
|
96
114
|
this._buildTag = bstackOptions.buildTag;
|
|
97
115
|
this._buildIdentifier = bstackOptions.buildIdentifier;
|
|
116
|
+
if (!(0, util_2.isUndefined)(bstackOptions.accessibility)) {
|
|
117
|
+
this._accessibilityAutomation || (this._accessibilityAutomation = (0, util_2.isTrue)(bstackOptions.accessibility));
|
|
118
|
+
}
|
|
119
|
+
else if ((0, util_2.isTrue)(this._options.accessibility)) {
|
|
120
|
+
bstackOptions.accessibility = (0, util_2.isTrue)(this._options.accessibility);
|
|
121
|
+
}
|
|
98
122
|
}
|
|
99
123
|
});
|
|
100
124
|
}
|
|
101
125
|
if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
|
|
102
126
|
performance_tester_1.default.startMonitoring('performance-report-launcher.csv');
|
|
103
127
|
}
|
|
128
|
+
this._accessibilityAutomation || (this._accessibilityAutomation = (0, util_2.isTrue)(this._options.accessibility));
|
|
129
|
+
this._options.accessibility = this._accessibilityAutomation;
|
|
104
130
|
// by default observability will be true unless specified as false
|
|
105
131
|
this._options.testObservability = this._options.testObservability == false ? false : true;
|
|
106
132
|
if (this._options.testObservability &&
|
|
@@ -161,6 +187,37 @@ class BrowserstackLauncherService {
|
|
|
161
187
|
* e.g., ${BUILD_NUMBER} and ${DATE_TIME}
|
|
162
188
|
*/
|
|
163
189
|
this._handleBuildIdentifier(capabilities);
|
|
190
|
+
// remove accessibilityOptions from the capabilities if present
|
|
191
|
+
this._updateObjectTypeCaps(capabilities, 'accessibilityOptions');
|
|
192
|
+
if (this._accessibilityAutomation) {
|
|
193
|
+
const scannerVersion = await (0, util_2.createAccessibilityTestRun)(this._options, this._config, {
|
|
194
|
+
projectName: this._projectName,
|
|
195
|
+
buildName: this._buildName,
|
|
196
|
+
buildTag: this._buildTag,
|
|
197
|
+
bstackServiceVersion: package_json_1.version,
|
|
198
|
+
buildIdentifier: this._buildIdentifier,
|
|
199
|
+
accessibilityOptions: this._options.accessibilityOptions
|
|
200
|
+
});
|
|
201
|
+
if (scannerVersion) {
|
|
202
|
+
process.env.BSTACK_A11Y_SCANNER_VERSION = scannerVersion;
|
|
203
|
+
}
|
|
204
|
+
log.debug(`Accessibility scannerVersion ${scannerVersion}`);
|
|
205
|
+
}
|
|
206
|
+
if (this._options.accessibilityOptions) {
|
|
207
|
+
const filteredOpts = Object.keys(this._options.accessibilityOptions)
|
|
208
|
+
.filter(key => !constants_1.NOT_ALLOWED_KEYS_IN_CAPS.includes(key))
|
|
209
|
+
.reduce((opts, key) => {
|
|
210
|
+
var _a;
|
|
211
|
+
return {
|
|
212
|
+
...opts,
|
|
213
|
+
[key]: (_a = this._options.accessibilityOptions) === null || _a === void 0 ? void 0 : _a[key]
|
|
214
|
+
};
|
|
215
|
+
}, {});
|
|
216
|
+
this._updateObjectTypeCaps(capabilities, 'accessibilityOptions', filteredOpts);
|
|
217
|
+
}
|
|
218
|
+
else if ((0, util_2.isAccessibilityAutomationSession)(this._accessibilityAutomation)) {
|
|
219
|
+
this._updateObjectTypeCaps(capabilities, 'accessibilityOptions', {});
|
|
220
|
+
}
|
|
164
221
|
if (this._options.testObservability) {
|
|
165
222
|
log.debug('Sending launch start event');
|
|
166
223
|
await (0, util_2.launchTestSession)(this._options, this._config, {
|
|
@@ -212,6 +269,11 @@ class BrowserstackLauncherService {
|
|
|
212
269
|
});
|
|
213
270
|
}
|
|
214
271
|
async onComplete() {
|
|
272
|
+
if ((0, util_2.isAccessibilityAutomationSession)(this._accessibilityAutomation)) {
|
|
273
|
+
await (0, util_2.stopAccessibilityTestRun)().catch((error) => {
|
|
274
|
+
log.error(`Exception in stop accessibility test run: ${error}`);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
215
277
|
if (this._options.testObservability) {
|
|
216
278
|
log.debug('Sending stop launch event');
|
|
217
279
|
await (0, util_2.stopBuildUpstream)();
|
|
@@ -299,6 +361,96 @@ class BrowserstackLauncherService {
|
|
|
299
361
|
}
|
|
300
362
|
return app;
|
|
301
363
|
}
|
|
364
|
+
_updateObjectTypeCaps(capabilities, capType, value) {
|
|
365
|
+
try {
|
|
366
|
+
if (Array.isArray(capabilities)) {
|
|
367
|
+
capabilities
|
|
368
|
+
.flatMap((c) => {
|
|
369
|
+
if (Object.values(c).length > 0 && Object.values(c).every(c => typeof c === 'object' && c.capabilities)) {
|
|
370
|
+
return Object.values(c).map((o) => o.capabilities);
|
|
371
|
+
}
|
|
372
|
+
return c;
|
|
373
|
+
})
|
|
374
|
+
.forEach((capability) => {
|
|
375
|
+
if (!capability['bstack:options']) {
|
|
376
|
+
const extensionCaps = Object.keys(capability).filter((cap) => cap.includes(':'));
|
|
377
|
+
if (extensionCaps.length) {
|
|
378
|
+
if (capType === 'accessibilityOptions' && value) {
|
|
379
|
+
capability['bstack:options'] = { accessibilityOptions: value };
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
else if (capType === 'accessibilityOptions') {
|
|
383
|
+
if (value) {
|
|
384
|
+
const accessibilityOpts = { ...value };
|
|
385
|
+
if (capability === null || capability === void 0 ? void 0 : capability.accessibility) {
|
|
386
|
+
accessibilityOpts.authToken = process.env.BSTACK_A11Y_JWT;
|
|
387
|
+
accessibilityOpts.scannerVersion = process.env.BSTACK_A11Y_SCANNER_VERSION;
|
|
388
|
+
}
|
|
389
|
+
capability['browserstack.accessibilityOptions'] = accessibilityOpts;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
delete capability['browserstack.accessibilityOptions'];
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
else if (capType === 'accessibilityOptions') {
|
|
397
|
+
if (value) {
|
|
398
|
+
const accessibilityOpts = { ...value };
|
|
399
|
+
if (capability['bstack:options'].accessibility) {
|
|
400
|
+
accessibilityOpts.authToken = process.env.BSTACK_A11Y_JWT;
|
|
401
|
+
accessibilityOpts.scannerVersion = process.env.BSTACK_A11Y_SCANNER_VERSION;
|
|
402
|
+
}
|
|
403
|
+
capability['bstack:options'].accessibilityOptions = accessibilityOpts;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
delete capability['bstack:options'].accessibilityOptions;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
else if (typeof capabilities === 'object') {
|
|
412
|
+
Object.entries(capabilities).forEach(([, caps]) => {
|
|
413
|
+
if (!caps.capabilities['bstack:options']) {
|
|
414
|
+
const extensionCaps = Object.keys(caps.capabilities).filter((cap) => cap.includes(':'));
|
|
415
|
+
if (extensionCaps.length) {
|
|
416
|
+
if (capType === 'accessibilityOptions' && value) {
|
|
417
|
+
caps.capabilities['bstack:options'] = { accessibilityOptions: value };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
else if (capType === 'accessibilityOptions') {
|
|
421
|
+
if (value) {
|
|
422
|
+
const accessibilityOpts = { ...value };
|
|
423
|
+
if (caps.capabilities['browserstack.accessibility']) {
|
|
424
|
+
accessibilityOpts.authToken = process.env.BSTACK_A11Y_JWT;
|
|
425
|
+
accessibilityOpts.scannerVersion = process.env.BSTACK_A11Y_SCANNER_VERSION;
|
|
426
|
+
}
|
|
427
|
+
caps.capabilities['browserstack.accessibilityOptions'] = accessibilityOpts;
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
delete caps.capabilities['browserstack.accessibilityOptions'];
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else if (capType === 'accessibilityOptions') {
|
|
435
|
+
if (value) {
|
|
436
|
+
const accessibilityOpts = { ...value };
|
|
437
|
+
if (caps.capabilities['bstack:options'].accessibility) {
|
|
438
|
+
accessibilityOpts.authToken = process.env.BSTACK_A11Y_JWT;
|
|
439
|
+
accessibilityOpts.scannerVersion = process.env.BSTACK_A11Y_SCANNER_VERSION;
|
|
440
|
+
}
|
|
441
|
+
caps.capabilities['bstack:options'].accessibilityOptions = accessibilityOpts;
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
delete caps.capabilities['bstack:options'].accessibilityOptions;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
log.debug(`Exception while retrieving capability value. Error - ${error}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
302
454
|
_updateCaps(capabilities, capType, value) {
|
|
303
455
|
if (Array.isArray(capabilities)) {
|
|
304
456
|
capabilities.forEach((capability) => {
|