@wdio/browserstack-service 8.10.4 → 8.10.6

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.
@@ -1 +1 @@
1
- {"version":3,"file":"insights-handler.d.ts","sourceRoot":"","sources":["../src/insights-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGzE,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAqBzE,cAAM,gBAAgB;IASL,OAAO,CAAC,QAAQ;IAAiF,OAAO,CAAC,UAAU,CAAC;IARjI,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,SAAS,CAA2D;IAC5E,OAAO,CAAC,cAAc,CAAC,CAAQ;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,oBAAoB,CAAoC;gBAE3C,QAAQ,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB,EAAE,aAAa,CAAC,EAAE,OAAO,EAAU,UAAU,CAAC,oBAAQ;IAezI,YAAY,CAAC,QAAQ,EAAE,MAAM;IAIvB,MAAM;IAiBN,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG;IAgB/C,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IAwD/D,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IASjC,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IASrE;;QAEI;IAEE,cAAc,CAAE,KAAK,EAAE,sBAAsB;IA4B7C,aAAa,CAAE,KAAK,EAAE,sBAAsB;IAI5C,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM;IAkBzD,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,YAAY;IA0BzF,aAAa,CACf,WAAW,SAA2C,EACtD,YAAY,SAA4C,GACzD,OAAO,CAAC,OAAO,CAAC;IASb,QAAQ;IAId;;OAEG;IACG,cAAc,CAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,IAAI,GAAG,sBAAsB;IA2DtI,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,YAAY;YAiBN,gBAAgB;YA6EhB,2BAA2B;IAmFzC,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,aAAa;CAMxB;AAGD,QAAA,MAAM,eAAe,EAAE,OAAO,gBAA0D,CAAA;AACxF,KAAK,eAAe,GAAG,gBAAgB,CAAA;AAEvC,eAAe,eAAe,CAAA"}
1
+ {"version":3,"file":"insights-handler.d.ts","sourceRoot":"","sources":["../src/insights-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGzE,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAsBzE,cAAM,gBAAgB;IASL,OAAO,CAAC,QAAQ;IAAiF,OAAO,CAAC,UAAU,CAAC;IARjI,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,SAAS,CAA2D;IAC5E,OAAO,CAAC,cAAc,CAAC,CAAQ;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,oBAAoB,CAAoC;gBAE3C,QAAQ,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB,EAAE,aAAa,CAAC,EAAE,OAAO,EAAU,UAAU,CAAC,oBAAQ;IAezI,YAAY,CAAC,QAAQ,EAAE,MAAM;IAIvB,MAAM;IAiBN,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG;IAgB/C,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IAoD/D,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IAYjC,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IAYrE;;QAEI;IAEE,cAAc,CAAE,KAAK,EAAE,sBAAsB;IA4B7C,aAAa,CAAE,KAAK,EAAE,sBAAsB;IAI5C,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM;IAkBzD,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,YAAY;IA0BzF,aAAa,CACf,WAAW,SAA2C,EACtD,YAAY,SAA4C,GACzD,OAAO,CAAC,OAAO,CAAC;IASb,QAAQ;IAId;;OAEG;IACG,cAAc,CAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,IAAI,GAAG,sBAAsB;IA4DtI,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,YAAY;YAiBN,gBAAgB;YA6EhB,2BAA2B;IAmFzC,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,aAAa;CAMxB;AAGD,QAAA,MAAM,eAAe,EAAE,OAAO,gBAA0D,CAAA;AACxF,KAAK,eAAe,GAAG,gBAAgB,CAAA;AAEvC,eAAe,eAAe,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
+ import TestReporter from './reporter.js';
3
4
  import { frameworkSupportsHook, getCloudProvider, getGitMetaData, getHookType, getScenarioExamples, getUniqueIdentifier, getUniqueIdentifierForCucumber, isBrowserstackSession, isScreenshotCommand, o11yClassErrorHandler, removeAnsiColors, sleep, uploadEventData } from './util.js';
4
5
  import RequestQueueHandler from './request-handler.js';
5
6
  import { DATA_SCREENSHOT_ENDPOINT, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS } from './constants.js';
@@ -73,9 +74,6 @@ class _InsightsHandler {
73
74
  };
74
75
  }
75
76
  await this.sendTestRunEvent(test, 'HookRunFinished', result);
76
- if (this._framework !== 'mocha') {
77
- return;
78
- }
79
77
  const hookType = getHookType(test.title);
80
78
  /*
81
79
  If any of the `beforeAll`, `beforeEach`, `afterEach` then the tests after the hook won't run in mocha (https://github.com/mochajs/mocha/issues/4392)
@@ -110,6 +108,9 @@ class _InsightsHandler {
110
108
  }
111
109
  }
112
110
  async beforeTest(test) {
111
+ if (this._framework !== 'mocha') {
112
+ return;
113
+ }
113
114
  const fullTitle = getUniqueIdentifier(test, this._framework);
114
115
  this._tests[fullTitle] = {
115
116
  uuid: uuidv4(),
@@ -118,6 +119,9 @@ class _InsightsHandler {
118
119
  await this.sendTestRunEvent(test, 'TestRunStarted');
119
120
  }
120
121
  async afterTest(test, result) {
122
+ if (this._framework !== 'mocha') {
123
+ return;
124
+ }
121
125
  const fullTitle = getUniqueIdentifier(test, this._framework);
122
126
  this._tests[fullTitle] = {
123
127
  ...(this._tests[fullTitle] || {}),
@@ -215,7 +219,8 @@ class _InsightsHandler {
215
219
  return;
216
220
  }
217
221
  const identifier = this.getIdentifier(test);
218
- if (!this._tests[identifier]) {
222
+ const testMeta = this._tests[identifier] || TestReporter.getTests()[identifier];
223
+ if (!testMeta) {
219
224
  return;
220
225
  }
221
226
  // log screenshot
@@ -223,7 +228,7 @@ class _InsightsHandler {
223
228
  await uploadEventData([{
224
229
  event_type: 'LogCreated',
225
230
  logs: [{
226
- test_run_uuid: this._tests[identifier].uuid,
231
+ test_run_uuid: testMeta.uuid,
227
232
  timestamp: new Date().toISOString(),
228
233
  message: args.result.value,
229
234
  kind: 'TEST_SCREENSHOT'
@@ -238,7 +243,7 @@ class _InsightsHandler {
238
243
  const req = this._requestQueueHandler.add({
239
244
  event_type: 'LogCreated',
240
245
  logs: [{
241
- test_run_uuid: this._tests[identifier].uuid,
246
+ test_run_uuid: testMeta.uuid,
242
247
  timestamp: new Date().toISOString(),
243
248
  kind: 'HTTP',
244
249
  http_response: {
@@ -1 +1 @@
1
- {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAG/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAavF,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;IAQ5E,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,OAAO;IATnB,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;gBAGrB,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IAqEjC,SAAS,CAAE,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IA0GtF,UAAU;IA2CV,UAAU,CAAC,GAAG,EAAC,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsBrD;;;OAGG;IACG,YAAY,CAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAyBhE,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAC,MAAM;IAqF3F,sBAAsB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IAyCrE;;;OAGG;IACH,oBAAoB;IA6BpB,sBAAsB,CAAC,QAAQ,CAAC,EAAC,MAAM,EAAE,SAAS,CAAC,EAAC,MAAM,EAAE,eAAe,CAAC,EAAC,MAAM;CAQtF"}
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAG/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAGlE,OAAO,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAavF,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;IAQ5E,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,OAAO;IATnB,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;gBAGrB,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IAyEjC,SAAS,CAAE,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IA0GtF,UAAU;IAsDV,UAAU,CAAC,GAAG,EAAC,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsBrD;;;OAGG;IACG,YAAY,CAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAyBhE,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAC,MAAM;IAqF3F,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
@@ -8,6 +8,7 @@ import { SevereServiceError } from 'webdriverio';
8
8
  import os from 'node:os';
9
9
  import * as BrowserstackLocalLauncher from 'browserstack-local';
10
10
  import logger from '@wdio/logger';
11
+ import PerformanceTester from './performance-tester.js';
11
12
  import { BSTACK_SERVICE_VERSION, VALID_APP_EXTENSION } from './constants.js';
12
13
  import { launchTestSession, shouldAddServiceVersion, stopBuildUpstream, getCiInfo, isBStackSession, } from './util.js';
13
14
  import CrashReporter from './crash-reporter.js';
@@ -75,6 +76,9 @@ export default class BrowserstackLauncherService {
75
76
  }
76
77
  });
77
78
  }
79
+ if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
80
+ PerformanceTester.startMonitoring('performance-report-launcher.csv');
81
+ }
78
82
  // by default observability will be true unless specified as false
79
83
  this._options.testObservability = this._options.testObservability === false ? false : true;
80
84
  if (this._options.testObservability
@@ -192,6 +196,15 @@ export default class BrowserstackLauncherService {
192
196
  if (process.env.BS_TESTOPS_BUILD_HASHED_ID) {
193
197
  console.log(`\nVisit https://observability.browserstack.com/builds/${process.env.BS_TESTOPS_BUILD_HASHED_ID} to view build report, insights, and many more debugging information all at one place!\n`);
194
198
  }
199
+ if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
200
+ await PerformanceTester.stopAndGenerate('performance-launcher.html');
201
+ PerformanceTester.calculateTimes(['launchTestSession', 'stopBuildUpstream']);
202
+ if (!process.env.START_TIME) {
203
+ return;
204
+ }
205
+ const duration = (new Date()).getTime() - (new Date(process.env.START_TIME)).getTime();
206
+ log.info(`Total duration is ${duration / 1000} s`);
207
+ }
195
208
  }
196
209
  if (!this.browserstackLocal || !this.browserstackLocal.isRunning()) {
197
210
  return;
@@ -0,0 +1,15 @@
1
+ /// <reference types="node" />
2
+ import { PerformanceObserver } from 'node:perf_hooks';
3
+ export default class PerformanceTester {
4
+ static _observer: PerformanceObserver;
5
+ static _csvWriter: any;
6
+ private static _events;
7
+ static started: boolean;
8
+ static startMonitoring(csvName?: string): void;
9
+ static getPerformance(): import("perf_hooks").Performance;
10
+ static calculateTimes(methods: string[]): number;
11
+ static stopAndGenerate(filename?: string): Promise<void>;
12
+ static generateReport(entries: PerformanceEntry[]): string;
13
+ static generateCSV(entries: PerformanceEntry[]): void;
14
+ }
15
+ //# sourceMappingURL=performance-tester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-tester.d.ts","sourceRoot":"","sources":["../src/performance-tester.ts"],"names":[],"mappings":";AAEA,OAAO,EAAe,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAMlE,MAAM,CAAC,OAAO,OAAO,iBAAiB;IAClC,MAAM,CAAC,SAAS,EAAE,mBAAmB,CAAA;IACrC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAA;IACtB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAyB;IAC/C,MAAM,CAAC,OAAO,UAAQ;IAEtB,MAAM,CAAC,eAAe,CAAC,OAAO,GAAE,MAAiC;IAiBjE,MAAM,CAAC,cAAc;IAIrB,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAI,MAAM;WAepC,eAAe,CAAC,QAAQ,GAAE,MAA+B;IAoBtE,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE;IAWjD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE;CAuBjD"}
@@ -0,0 +1,96 @@
1
+ import { createObjectCsvWriter } from 'csv-writer';
2
+ import fs from 'node:fs';
3
+ import { performance, PerformanceObserver } from 'node:perf_hooks';
4
+ import logger from '@wdio/logger';
5
+ import { sleep } from './util.js';
6
+ const log = logger('@wdio/browserstack-service');
7
+ class PerformanceTester {
8
+ static _observer;
9
+ static _csvWriter;
10
+ static _events = [];
11
+ static started = false;
12
+ static startMonitoring(csvName = 'performance-report.csv') {
13
+ this._observer = new PerformanceObserver(list => {
14
+ list.getEntries().forEach(entry => {
15
+ this._events.push(entry);
16
+ });
17
+ });
18
+ this._observer.observe({ buffered: true, entryTypes: ['function'] });
19
+ this.started = true;
20
+ this._csvWriter = createObjectCsvWriter({
21
+ path: csvName,
22
+ header: [
23
+ { id: 'name', title: 'Function Name' },
24
+ { id: 'time', title: 'Execution Time (ms)' }
25
+ ]
26
+ });
27
+ }
28
+ static getPerformance() {
29
+ return performance;
30
+ }
31
+ static calculateTimes(methods) {
32
+ const times = {};
33
+ this._events.map((entry) => {
34
+ if (!times[entry.name]) {
35
+ times[entry.name] = 0;
36
+ }
37
+ times[entry.name] += entry.duration;
38
+ });
39
+ const timeTaken = methods.reduce((a, c) => {
40
+ return times[c] + (a || 0);
41
+ }, 0);
42
+ log.info(`Time for ${methods} is `, timeTaken);
43
+ return timeTaken;
44
+ }
45
+ static async stopAndGenerate(filename = 'performance-own.html') {
46
+ if (!this.started) {
47
+ return;
48
+ }
49
+ await sleep(2000); // Wait to 2s just to finish any running callbacks for timerify
50
+ this._observer.disconnect();
51
+ this.started = false;
52
+ this.generateCSV(this._events);
53
+ const content = this.generateReport(this._events);
54
+ const path = process.cwd() + '/' + filename;
55
+ fs.writeFile(path, content, err => {
56
+ if (err) {
57
+ log.error('Error in writing html', err);
58
+ return;
59
+ }
60
+ log.info('Performance report is at ', path);
61
+ });
62
+ }
63
+ static generateReport(entries) {
64
+ let html = '<!DOCTYPE html><html><head><title>Performance Report</title></head><body>';
65
+ html += '<h1>Performance Report</h1>';
66
+ html += '<table><thead><tr><th>Function Name</th><th>Duration (ms)</th></tr></thead><tbody>';
67
+ entries.forEach((entry) => {
68
+ html += `<tr><td>${entry.name}</td><td>${entry.duration}</td></tr>`;
69
+ });
70
+ html += '</tbody></table></body></html>';
71
+ return html;
72
+ }
73
+ static generateCSV(entries) {
74
+ const times = {};
75
+ entries.map((entry) => {
76
+ if (!times[entry.name]) {
77
+ times[entry.name] = 0;
78
+ }
79
+ times[entry.name] += entry.duration;
80
+ return {
81
+ name: entry.name,
82
+ time: entry.duration
83
+ };
84
+ });
85
+ const dat = Object.entries(times).map(([key, value]) => {
86
+ return {
87
+ name: key,
88
+ time: value
89
+ };
90
+ });
91
+ this._csvWriter.writeRecords(dat)
92
+ .then(() => log.info('Performance CSV report generated successfully'))
93
+ .catch((error) => console.error(error));
94
+ }
95
+ }
96
+ export default PerformanceTester;
@@ -1,5 +1,6 @@
1
- import type { SuiteStats, TestStats, RunnerStats } from '@wdio/reporter';
1
+ import type { SuiteStats, TestStats, RunnerStats, HookStats } from '@wdio/reporter';
2
2
  import WDIOReporter from '@wdio/reporter';
3
+ import type { TestMeta } from './types.js';
3
4
  declare class _TestReporter extends WDIOReporter {
4
5
  private _capabilities;
5
6
  private _config?;
@@ -7,9 +8,23 @@ declare class _TestReporter extends WDIOReporter {
7
8
  private _sessionId?;
8
9
  private _suiteName?;
9
10
  private _requestQueueHandler;
10
- onRunnerStart(runnerStats: RunnerStats): void;
11
+ private _suites;
12
+ private static _tests;
13
+ private _gitConfigPath?;
14
+ private _gitConfigured;
15
+ onRunnerStart(runnerStats: RunnerStats): Promise<void>;
16
+ configureGit(): Promise<void>;
17
+ static getTests(): Record<string, TestMeta>;
11
18
  onSuiteStart(suiteStats: SuiteStats): void;
19
+ onSuiteEnd(): void;
20
+ needToSendData(testType?: string, event?: string): boolean;
21
+ onTestEnd(testStats: TestStats): Promise<void>;
22
+ onTestStart(testStats: TestStats): Promise<void>;
23
+ onHookStart(hookStats: HookStats): Promise<void>;
24
+ onHookEnd(hookStats: HookStats): Promise<void>;
25
+ getHookIdentifier(hookStats: HookStats): string;
12
26
  onTestSkip(testStats: TestStats): Promise<void>;
27
+ sendTestRunEvent(testStats: TestStats | HookStats, eventType: string): Promise<void>;
13
28
  }
14
29
  declare const TestReporter: typeof _TestReporter;
15
30
  type TestReporter = _TestReporter;
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACxE,OAAO,YAAY,MAAM,gBAAgB,CAAA;AASzC,cAAM,aAAc,SAAQ,YAAY;IACpC,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,OAAO,CAAC,CAAyC;IACzD,OAAO,CAAC,cAAc,CAAO;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,oBAAoB,CAAoC;IAEhE,aAAa,CAAE,WAAW,EAAE,WAAW;IASvC,YAAY,CAAE,UAAU,EAAE,UAAU;IAI9B,UAAU,CAAE,SAAS,EAAE,SAAS;CAgDzC;AAED,QAAA,MAAM,YAAY,EAAE,OAAO,aAAoD,CAAA;AAC/E,KAAK,YAAY,GAAG,aAAa,CAAA;AACjC,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AACnF,OAAO,YAAY,MAAM,gBAAgB,CAAA;AAMzC,OAAO,KAAK,EAAgC,QAAQ,EAAc,MAAM,YAAY,CAAA;AAapF,cAAM,aAAc,SAAQ,YAAY;IACpC,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,OAAO,CAAC,CAAyC;IACzD,OAAO,CAAC,cAAc,CAAO;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,oBAAoB,CAAoC;IAChE,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,MAAM,CAAC,MAAM,CAA+B;IACpD,OAAO,CAAC,cAAc,CAAC,CAAQ;IAC/B,OAAO,CAAC,cAAc,CAAiB;IAEjC,aAAa,CAAE,WAAW,EAAE,WAAW;IAUvC,YAAY;IAWlB,MAAM,CAAC,QAAQ;IAIf,YAAY,CAAE,UAAU,EAAE,UAAU;IAoBpC,UAAU;IAIV,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAe1C,SAAS,CAAC,SAAS,EAAE,SAAS;IAY9B,WAAW,CAAC,SAAS,EAAE,SAAS;IAchC,WAAW,CAAC,SAAS,EAAE,SAAS;IAchC,SAAS,CAAC,SAAS,EAAE,SAAS;IAepC,iBAAiB,CAAC,SAAS,EAAE,SAAS;IAIhC,UAAU,CAAE,SAAS,EAAE,SAAS;IAWhC,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM;CA+E7E;AAED,QAAA,MAAM,YAAY,EAAE,OAAO,aAAoD,CAAA;AAC/E,KAAK,YAAY,GAAG,aAAa,CAAA;AACjC,eAAe,YAAY,CAAA"}
package/build/reporter.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import path from 'node:path';
2
+ import logger from '@wdio/logger';
2
3
  import WDIOReporter from '@wdio/reporter';
4
+ import * as url from 'node:url';
3
5
  import { v4 as uuidv4 } from 'uuid';
4
- import { getCloudProvider, uploadEventData, getHierarchy, o11yClassErrorHandler } from './util.js';
6
+ import { getCloudProvider, uploadEventData, o11yClassErrorHandler, getGitMetaData, removeAnsiColors, getHookType } from './util.js';
5
7
  import RequestQueueHandler from './request-handler.js';
8
+ const log = logger('@wdio/browserstack-service');
6
9
  class _TestReporter extends WDIOReporter {
7
10
  _capabilities = {};
8
11
  _config;
@@ -10,43 +13,165 @@ class _TestReporter extends WDIOReporter {
10
13
  _sessionId;
11
14
  _suiteName;
12
15
  _requestQueueHandler = RequestQueueHandler.getInstance();
13
- onRunnerStart(runnerStats) {
16
+ _suites = [];
17
+ static _tests = {};
18
+ _gitConfigPath;
19
+ _gitConfigured = false;
20
+ async onRunnerStart(runnerStats) {
14
21
  this._capabilities = runnerStats.capabilities;
15
22
  this._config = runnerStats.config;
16
23
  this._sessionId = runnerStats.sessionId;
17
24
  if (typeof this._config.testObservability !== 'undefined') {
18
25
  this._observability = this._config.testObservability;
19
26
  }
27
+ await this.configureGit();
28
+ }
29
+ async configureGit() {
30
+ if (this._gitConfigured) {
31
+ return;
32
+ }
33
+ const gitMeta = await getGitMetaData();
34
+ if (gitMeta) {
35
+ this._gitConfigPath = gitMeta.root;
36
+ }
37
+ this._gitConfigured = true;
38
+ }
39
+ static getTests() {
40
+ return _TestReporter._tests;
20
41
  }
21
42
  onSuiteStart(suiteStats) {
22
- this._suiteName = suiteStats.file;
43
+ let filename = suiteStats.file;
44
+ if (this._config?.framework === 'jasmine') {
45
+ try {
46
+ if (suiteStats.file.startsWith('file://')) {
47
+ filename = url.fileURLToPath(suiteStats.file);
48
+ }
49
+ if (filename === 'unknown spec file') {
50
+ // Sometimes in cases where a file has two suites. Then the file name be unknown for second suite, so getting the filename from first suite
51
+ filename = this._suiteName || suiteStats.file;
52
+ }
53
+ }
54
+ catch (e) {
55
+ log.debug('Error in decoding file name of suite');
56
+ }
57
+ }
58
+ this._suiteName = filename;
59
+ this._suites.push(suiteStats);
60
+ }
61
+ onSuiteEnd() {
62
+ this._suites.pop();
63
+ }
64
+ needToSendData(testType, event) {
65
+ if (!this._observability) {
66
+ return false;
67
+ }
68
+ switch (this._config?.framework) {
69
+ case 'mocha':
70
+ return event === 'skip';
71
+ case 'cucumber':
72
+ return false;
73
+ case 'jasmine':
74
+ return event !== 'skip';
75
+ default:
76
+ return false;
77
+ }
78
+ }
79
+ async onTestEnd(testStats) {
80
+ if (!this.needToSendData('test', 'end')) {
81
+ return;
82
+ }
83
+ if (testStats.fullTitle === '<unknown test>') {
84
+ return;
85
+ }
86
+ testStats.end ||= new Date();
87
+ await this.sendTestRunEvent(testStats, 'TestRunFinished');
88
+ }
89
+ async onTestStart(testStats) {
90
+ if (!this.needToSendData('test', 'start')) {
91
+ return;
92
+ }
93
+ if (testStats.fullTitle === '<unknown test>') {
94
+ return;
95
+ }
96
+ _TestReporter._tests[testStats.fullTitle] = {
97
+ uuid: uuidv4(),
98
+ };
99
+ await this.sendTestRunEvent(testStats, 'TestRunStarted');
100
+ }
101
+ async onHookStart(hookStats) {
102
+ if (!this.needToSendData('hook', 'start')) {
103
+ return;
104
+ }
105
+ const identifier = this.getHookIdentifier(hookStats);
106
+ const hookId = uuidv4();
107
+ _TestReporter._tests[identifier] = {
108
+ uuid: hookId,
109
+ startedAt: (new Date()).toISOString()
110
+ };
111
+ await this.sendTestRunEvent(hookStats, 'HookRunStarted');
112
+ }
113
+ async onHookEnd(hookStats) {
114
+ if (!this.needToSendData('hook', 'end')) {
115
+ return;
116
+ }
117
+ const identifier = this.getHookIdentifier(hookStats);
118
+ if (_TestReporter._tests[identifier]) {
119
+ _TestReporter._tests[identifier].finishedAt = (new Date()).toISOString();
120
+ }
121
+ else {
122
+ _TestReporter._tests[identifier] = {
123
+ finishedAt: (new Date()).toISOString()
124
+ };
125
+ }
126
+ await this.sendTestRunEvent(hookStats, 'HookRunFinished');
127
+ }
128
+ getHookIdentifier(hookStats) {
129
+ return `${hookStats.title} for ${this._suites.at(-1)?.title}`;
23
130
  }
24
131
  async onTestSkip(testStats) {
25
132
  // cucumber steps call this method. We don't want step skipped state so skip for cucumber
133
+ if (!this.needToSendData('test', 'skip')) {
134
+ return;
135
+ }
136
+ testStats.start ||= new Date();
137
+ testStats.end ||= new Date();
138
+ await this.sendTestRunEvent(testStats, 'TestRunSkipped');
139
+ }
140
+ async sendTestRunEvent(testStats, eventType) {
26
141
  const framework = this._config?.framework;
27
- if (this._observability && framework !== 'cucumber') {
28
- const testData = {
29
- uuid: uuidv4(),
30
- type: testStats.type,
31
- name: testStats.title,
32
- body: {
33
- lang: 'webdriverio',
34
- code: null
35
- },
36
- scope: testStats.fullTitle,
37
- scopes: getHierarchy(testStats.fullTitle),
38
- identifier: testStats.fullTitle,
39
- file_name: this._suiteName ? path.relative(process.cwd(), this._suiteName) : undefined,
40
- location: this._suiteName ? path.relative(process.cwd(), this._suiteName) : undefined,
41
- started_at: (new Date()).toISOString(),
42
- framework: framework,
43
- finished_at: (new Date()).toISOString(),
44
- duration_in_ms: testStats._duration,
45
- retries: { limit: 0, attempts: 0 },
46
- result: testStats.state,
47
- };
142
+ const scopes = this._suites.map(s => s.title);
143
+ const identifier = testStats.type === 'test' ? testStats.fullTitle : this.getHookIdentifier(testStats);
144
+ const testMetaData = _TestReporter._tests[identifier];
145
+ const scope = testStats.type === 'test' ? testStats.fullTitle : `${this._suites[0].title} - ${testStats.title}`;
146
+ await this.configureGit();
147
+ const testData = {
148
+ uuid: testMetaData ? testMetaData.uuid : uuidv4(),
149
+ type: testStats.type,
150
+ name: testStats.title,
151
+ body: {
152
+ lang: 'webdriverio',
153
+ code: null
154
+ },
155
+ scope: scope,
156
+ scopes: scopes,
157
+ identifier: identifier,
158
+ file_name: this._suiteName ? path.relative(process.cwd(), this._suiteName) : undefined,
159
+ location: this._suiteName ? path.relative(process.cwd(), this._suiteName) : undefined,
160
+ vc_filepath: (this._gitConfigPath && this._suiteName) ? path.relative(this._gitConfigPath, this._suiteName) : undefined,
161
+ started_at: testStats.start && testStats.start.toISOString(),
162
+ finished_at: testStats.end && testStats.end.toISOString(),
163
+ framework: framework,
164
+ duration_in_ms: testStats._duration,
165
+ result: testStats.state,
166
+ };
167
+ if (testStats.type === 'test') {
168
+ testData.retries = { limit: testStats.retries || 0, attempts: testStats.retries || 0 };
169
+ }
170
+ if (eventType.startsWith('TestRun')) {
171
+ /* istanbul ignore next */
48
172
  const cloudProvider = getCloudProvider({ options: { hostname: this._config?.hostname } });
49
173
  testData.integrations = {};
174
+ /* istanbul ignore next */
50
175
  testData.integrations[cloudProvider] = {
51
176
  capabilities: this._capabilities,
52
177
  session_id: this._sessionId,
@@ -54,15 +179,36 @@ class _TestReporter extends WDIOReporter {
54
179
  browser_version: this._capabilities?.browserVersion,
55
180
  platform: this._capabilities?.platformName,
56
181
  };
57
- const uploadData = {
58
- event_type: 'TestRunFinished',
59
- test_run: testData
60
- };
61
- const req = this._requestQueueHandler.add(uploadData);
62
- if (req.proceed && req.data) {
63
- await uploadEventData(req.data, req.url);
182
+ }
183
+ if (eventType === 'TestRunFinished' || eventType === 'HookRunFinished') {
184
+ const { error } = testStats;
185
+ const failed = testStats.state === 'failed';
186
+ if (failed) {
187
+ testData.result = (error && error.message && error.message.includes('sync skip; aborting execution')) ? 'ignore' : 'failed';
188
+ if (error && testData.result !== 'skipped') {
189
+ testData.failure = [{ backtrace: [removeAnsiColors(error.message)] }]; // add all errors here
190
+ testData.failure_reason = removeAnsiColors(error.message);
191
+ testData.failure_type = error.message === null ? null : error.message.toString().match(/AssertionError/) ? 'AssertionError' : 'UnhandledError'; //verify if this is working
192
+ }
64
193
  }
65
194
  }
195
+ if (eventType === 'TestRunSkipped') {
196
+ eventType = 'TestRunFinished';
197
+ }
198
+ const uploadData = {
199
+ event_type: eventType,
200
+ };
201
+ if (eventType.match(/HookRun/)) {
202
+ testData.hook_type = testData.name?.toLowerCase() ? getHookType(testData.name.toLowerCase()) : 'undefined';
203
+ uploadData.hook_run = testData;
204
+ }
205
+ else {
206
+ uploadData.test_run = testData;
207
+ }
208
+ const req = this._requestQueueHandler.add(uploadData);
209
+ if (req.proceed && req.data) {
210
+ await uploadEventData(req.data, req.url);
211
+ }
66
212
  }
67
213
  }
68
214
  // https://github.com/microsoft/TypeScript/issues/6543
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAS9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAmB,MAAM,YAAY,CAAA;AACxF,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAQlF,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,QAAQ,CAAC,eAAe;IAiBpE,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IAjBnB,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,gBAAgB,CAA4D;IACpF,OAAO,CAAC,QAAQ,CAAC,CAAqB;IACtC,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,cAAc,CAAA;IACtB,OAAO,CAAC,YAAY,CAAC,CAA0C;IAC/D,OAAO,CAAC,gBAAgB,CAAC,CAAiB;gBAGtC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACxC,KAAK,EAAE,YAAY,CAAC,gBAAgB,EACpC,OAAO,EAAE,OAAO,CAAC,UAAU;IAkBvC,WAAW,CAAE,EAAE,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,YAAY,GAAG,YAAY,CAAC,mBAAmB,KAAK,IAAI;IAU7F,aAAa,CAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC;IAgBzD,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO;IA8C/F;;;;;;OAMG;IACG,WAAW,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IASpC,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG;IAO/C,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IAIjF,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IAoBjC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU;IAS/E,KAAK,CAAE,MAAM,EAAE,MAAM;IAqB3B;;OAEG;IAEG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAMjD;;;OAGG;IACG,cAAc,CAAE,KAAK,EAAE,sBAAsB;IAO7C,aAAa,CAAE,KAAK,EAAE,sBAAsB;IAsB5C,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM;IAKzD,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,YAAY;IAIzF,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAgCzD,cAAc,IAAI,OAAO;IAMzB,UAAU,CAAE,WAAW,EAAE,GAAG;IAU5B,kBAAkB,CAAE,MAAM,EAAE,iBAAiB;IAqB7C,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG;IAarC,gBAAgB;YAuBR,eAAe;IA0B7B,OAAO,CAAC,cAAc;YAIR,eAAe;CAqBhC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAU9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAmB,MAAM,YAAY,CAAA;AACxF,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAQlF,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,QAAQ,CAAC,eAAe;IAiBpE,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IAjBnB,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,gBAAgB,CAA4D;IACpF,OAAO,CAAC,QAAQ,CAAC,CAAqB;IACtC,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,cAAc,CAAA;IACtB,OAAO,CAAC,YAAY,CAAC,CAA0C;IAC/D,OAAO,CAAC,gBAAgB,CAAC,CAAiB;gBAGtC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACxC,KAAK,EAAE,YAAY,CAAC,gBAAgB,EACpC,OAAO,EAAE,OAAO,CAAC,UAAU;IAqBvC,WAAW,CAAE,EAAE,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,YAAY,GAAG,YAAY,CAAC,mBAAmB,KAAK,IAAI;IAU7F,aAAa,CAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC;IAgBzD,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO;IA8C/F;;;;;;OAMG;IACG,WAAW,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IASpC,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG;IAO/C,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IAIjF,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IAoBjC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU;IAS/E,KAAK,CAAE,MAAM,EAAE,MAAM;IA+B3B;;OAEG;IAEG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAMjD;;;OAGG;IACG,cAAc,CAAE,KAAK,EAAE,sBAAsB;IAO7C,aAAa,CAAE,KAAK,EAAE,sBAAsB;IAsB5C,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM;IAKzD,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,YAAY;IAIzF,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAgCzD,cAAc,IAAI,OAAO;IAMzB,UAAU,CAAE,WAAW,EAAE,GAAG;IAU5B,kBAAkB,CAAE,MAAM,EAAE,iBAAiB;IAqB7C,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG;IAarC,gBAAgB;YAuBR,eAAe;IA0B7B,OAAO,CAAC,cAAc;YAIR,eAAe;CAqBhC"}
package/build/service.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import logger from '@wdio/logger';
2
2
  import got from 'got';
3
+ import PerformanceTester from './performance-tester.js';
3
4
  import { getBrowserDescription, getBrowserCapabilities, isBrowserstackCapability, getParentSuiteName, isBrowserstackSession, } from './util.js';
4
5
  import InsightsHandler from './insights-handler.js';
5
6
  import TestReporter from './reporter.js';
@@ -31,6 +32,9 @@ export default class BrowserstackService {
31
32
  this._observability = this._options.testObservability;
32
33
  if (this._observability) {
33
34
  this._config.reporters?.push(TestReporter);
35
+ if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
36
+ PerformanceTester.startMonitoring('performance-report-service.csv');
37
+ }
34
38
  }
35
39
  // Cucumber specific
36
40
  const strict = Boolean(this._config.cucumberOpts && this._config.cucumberOpts.strict);
@@ -154,6 +158,15 @@ export default class BrowserstackService {
154
158
  }
155
159
  await this._insightsHandler?.uploadPending();
156
160
  await this._insightsHandler?.teardown();
161
+ if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
162
+ await PerformanceTester.stopAndGenerate('performance-service.html');
163
+ PerformanceTester.calculateTimes([
164
+ 'onRunnerStart', 'onSuiteStart', 'onSuiteEnd',
165
+ 'onTestStart', 'onTestEnd', 'onTestSkip', 'before',
166
+ 'beforeHook', 'afterHook', 'beforeTest', 'afterTest',
167
+ 'uploadPending', 'teardown', 'browserCommand'
168
+ ]);
169
+ }
157
170
  }
158
171
  /**
159
172
  * For CucumberJS
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
package/build/util.js CHANGED
@@ -8,6 +8,7 @@ import logger from '@wdio/logger';
8
8
  import got, { HTTPError } from 'got';
9
9
  import gitRepoInfo from 'git-repo-info';
10
10
  import gitconfig from 'gitconfiglocal';
11
+ import PerformanceTester from './performance-tester.js';
11
12
  import { BROWSER_DESCRIPTION, DATA_ENDPOINT, DATA_EVENT_ENDPOINT, DATA_SCREENSHOT_ENDPOINT } from './constants.js';
12
13
  import RequestQueueHandler from './request-handler.js';
13
14
  import CrashReporter from './crash-reporter.js';
@@ -92,7 +93,11 @@ function processError(error, fn, args) {
92
93
  export function o11yErrorHandler(fn) {
93
94
  return function (...args) {
94
95
  try {
95
- const result = fn(...args);
96
+ let functionToHandle = fn;
97
+ if (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT) {
98
+ functionToHandle = PerformanceTester.getPerformance().timerify(functionToHandle);
99
+ }
100
+ const result = functionToHandle(...args);
96
101
  if (result instanceof Promise) {
97
102
  return result.catch(error => processError(error, fn, args));
98
103
  }
@@ -116,7 +121,7 @@ export function o11yClassErrorHandler(errorClass) {
116
121
  writable: true,
117
122
  value: function (...args) {
118
123
  try {
119
- const result = method.call(this, ...args);
124
+ const result = (process.env.BROWSERSTACK_O11Y_PERF_MEASUREMENT ? PerformanceTester.getPerformance().timerify(method) : method).call(this, ...args);
120
125
  if (result instanceof Promise) {
121
126
  return result.catch(error => processError(error, method, args));
122
127
  }
@@ -591,9 +596,6 @@ export function frameworkSupportsHook(hook, framework) {
591
596
  if (framework === 'mocha' && (hook === 'before' || hook === 'after' || hook === 'beforeEach' || hook === 'afterEach')) {
592
597
  return true;
593
598
  }
594
- if (framework === 'jasmine' && (hook === 'beforeEach' || hook === 'afterEach')) {
595
- return true;
596
- }
597
599
  return false;
598
600
  }
599
601
  export const sleep = (ms = 100) => new Promise((resolve) => setTimeout(resolve, ms));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/browserstack-service",
3
- "version": "8.10.4",
3
+ "version": "8.10.6",
4
4
  "description": "WebdriverIO service for better Browserstack integration",
5
5
  "author": "Adam Bjerstedt <abjerstedt@gmail.com>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-browserstack-service",
@@ -31,16 +31,17 @@
31
31
  "typeScriptVersion": "3.8.3",
32
32
  "dependencies": {
33
33
  "@types/gitconfiglocal": "^2.0.1",
34
- "@wdio/logger": "8.6.6",
35
- "@wdio/reporter": "8.10.4",
34
+ "@wdio/logger": "8.10.6",
35
+ "@wdio/reporter": "8.10.6",
36
36
  "@wdio/types": "8.10.4",
37
37
  "browserstack-local": "^1.5.1",
38
+ "csv-writer": "^1.6.0",
38
39
  "form-data": "^4.0.0",
39
40
  "git-repo-info": "^2.1.1",
40
41
  "gitconfiglocal": "^2.1.0",
41
- "got": "^12.1.0",
42
+ "got": "^ 12.6.1",
42
43
  "uuid": "^8.3.2",
43
- "webdriverio": "8.10.4"
44
+ "webdriverio": "8.10.6"
44
45
  },
45
46
  "peerDependencies": {
46
47
  "@wdio/cli": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
@@ -51,5 +52,5 @@
51
52
  "publishConfig": {
52
53
  "access": "public"
53
54
  },
54
- "gitHead": "a8371338e89da4e7cc7e5a9dd0aaccf44776b04c"
55
+ "gitHead": "7ef166aa0e77e4efbb18fe627301403fcf514578"
55
56
  }