@wdio/browserstack-service 7.25.4 → 7.27.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
- WebdriverIO Browserstack Service
1
+ WebdriverIO BrowserStack Service
2
2
  ==========
3
3
 
4
- > A WebdriverIO service that manages local tunnel and job metadata for Browserstack users.
4
+ > A WebdriverIO service that manages local tunnel and job metadata for BrowserStack users.
5
5
 
6
6
  ## Installation
7
7
 
@@ -16,7 +16,7 @@ Instructions on how to install `WebdriverIO` can be found [here.](https://webdri
16
16
 
17
17
  ## Configuration
18
18
 
19
- WebdriverIO has Browserstack support out of the box. You should simply set `user` and `key` in your `wdio.conf.js` file. This service plugin provides supports for [Browserstack Tunnel](https://www.browserstack.com/automate/node#setting-local-tunnel). Set `browserstackLocal: true` also to activate this feature.
19
+ WebdriverIO has BrowserStack support out of the box. You should set `user` and `key` in your `wdio.conf.js` file. This service plugin provides support for [BrowserStack](https://www.browserstack.com/automate/node#setting-local-tunnel) Tunnel](https://www.browserstack.com/automate/node#setting-local-tunnel). Set `browserstackLocal: true` also to activate this feature.
20
20
  Reporting of session status on BrowserStack will respect `strict` setting of Cucumber options.
21
21
 
22
22
  ```js
@@ -39,19 +39,13 @@ exports.config
39
39
  In order to authorize to the BrowserStack service your config needs to contain a [`user`](https://webdriver.io/docs/options#user) and [`key`](https://webdriver.io/docs/options#key) option.
40
40
 
41
41
  ### browserstackLocal
42
- Set this to true to enable routing connections from Browserstack cloud through your computer.
43
-
44
- Type: `Boolean`<br />
45
- Default: `false`
46
-
47
- ### preferScenarioName
48
- Cucumber only. Set this to true to enable updating the session name to the Scenario name if only a single Scenario was ran. Useful when running in parallel with [wdio-cucumber-parallel-execution](https://github.com/SimitTomar/wdio-cucumber-parallel-execution).
42
+ Set this to true to enable routing connections from BrowserStack cloud through your computer.
49
43
 
50
44
  Type: `Boolean`<br />
51
45
  Default: `false`
52
46
 
53
47
  ### forcedStop
54
- Set this to true to kill the browserstack process on complete, without waiting for the browserstack stop callback to be called. This is experimental and should not be used by all. Mostly necessary as a workaraound for [this issue](https://github.com/browserstack/browserstack-local-nodejs/issues/41).
48
+ Set this to true to kill the BrowserStack Local process on complete, without waiting for the BrowserStack Local stop callback to be called. This is experimental and should not be used by all. Mostly necessary as a workaraound for [this issue](https://github.com/browserstack/browserstack-local-nodejs/issues/41).
55
49
 
56
50
  Type: `Boolean`<br />
57
51
  Default: `false`
@@ -141,8 +135,53 @@ services: [
141
135
  ]
142
136
  ```
143
137
 
138
+ ### preferScenarioName
139
+
140
+ Cucumber only. Set the BrowserStack Automate session name to the Scenario name if only a single Scenario ran.
141
+ Useful when running in parallel with [wdio-cucumber-parallel-execution](https://github.com/SimitTomar/wdio-cucumber-parallel-execution).
142
+
143
+ Type: `Boolean`<br />
144
+ Default: `false`
145
+
146
+ ### sessionNameFormat
147
+
148
+ Customize the BrowserStack Automate session name format.
149
+
150
+ Type: `Function`<br />
151
+ Default (Cucumber/Jasmine): `(config, capabilities, suiteTitle) => suiteTitle`<br />
152
+ Default (Mocha): `(config, capabilities, suiteTitle, testTitle) => suiteTitle + ' - ' + testTitle`
153
+
154
+ ### sessionNameOmitTestTitle
155
+
156
+ Mocha only. Do not append the test title to the BrowserStack Automate session name.
157
+
158
+ Type: `Boolean`<br />
159
+ Default: `false`
160
+
161
+ ### sessionNamePrependTopLevelSuiteTitle
162
+
163
+ Mocha only. Prepend the top level suite title to the BrowserStack Automate session name.
164
+
165
+ Type: `Boolean`<br />
166
+ Default: `false`
167
+
168
+ ### setSessionName
169
+
170
+ Automatically set the BrowserStack Automate session name.
171
+
172
+ Type: `Boolean`<br />
173
+ Default: `true`
174
+
175
+ ### setSessionStatus
176
+
177
+ Automatically set the BrowserStack Automate session status (passed/failed).
178
+
179
+ Type: `Boolean`<br />
180
+ Default: `true`
181
+
144
182
  ### opts
145
- Specified optional will be passed down to BrowserstackLocal.
183
+
184
+ BrowserStack Local options.
146
185
 
147
186
  Type: `Object`<br />
148
187
  Default: `{}`
@@ -185,7 +224,7 @@ opts = { f: "/my/awesome/folder" };
185
224
 
186
225
  #### Force Start
187
226
 
188
- To kill other running Browserstack Local instances -
227
+ To kill other running BrowserStack Local instances -
189
228
 
190
229
  ```js
191
230
  opts = { force: "true" };
@@ -1,3 +1,5 @@
1
+ import type { BrowserstackConfig } from './types';
1
2
  export declare const BROWSER_DESCRIPTION: readonly ["device", "os", "osVersion", "os_version", "browserName", "browser", "browserVersion", "browser_version"];
2
3
  export declare const VALID_APP_EXTENSION: string[];
4
+ export declare const DEFAULT_OPTIONS: Partial<BrowserstackConfig>;
3
5
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,qHAStB,CAAA;AAEV,eAAO,MAAM,mBAAmB,UAI/B,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD,eAAO,MAAM,mBAAmB,qHAStB,CAAA;AAEV,eAAO,MAAM,mBAAmB,UAI/B,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,kBAAkB,CAGvD,CAAA"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VALID_APP_EXTENSION = exports.BROWSER_DESCRIPTION = void 0;
3
+ exports.DEFAULT_OPTIONS = exports.VALID_APP_EXTENSION = exports.BROWSER_DESCRIPTION = void 0;
4
4
  exports.BROWSER_DESCRIPTION = [
5
5
  'device',
6
6
  'os',
@@ -16,3 +16,7 @@ exports.VALID_APP_EXTENSION = [
16
16
  '.aab',
17
17
  '.ipa'
18
18
  ];
19
+ exports.DEFAULT_OPTIONS = {
20
+ setSessionName: true,
21
+ setSessionStatus: true
22
+ };
@@ -2,7 +2,7 @@ import * as BrowserstackLocalLauncher from 'browserstack-local';
2
2
  import type { Capabilities, Services, Options } from '@wdio/types';
3
3
  import { App, AppConfig, AppUploadResponse } from './types';
4
4
  import { BrowserstackConfig } from './types';
5
- declare type BrowserstackLocal = BrowserstackLocalLauncher.Local & {
5
+ type BrowserstackLocal = BrowserstackLocalLauncher.Local & {
6
6
  pid?: number;
7
7
  stop(callback: (err?: any) => void): void;
8
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAK5C,aAAK,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;IAI5E,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,OAAO;IALnB,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;gBAGzB,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IAiCjC,SAAS,CAAE,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IA6E5F,UAAU;IAmCJ,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,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAC,MAAM;CA+C9F"}
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,yBAAyB,MAAM,oBAAoB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAK5C,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;IAI5E,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,OAAO;IALnB,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;gBAGzB,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACzD,YAAY,EAAE,YAAY,CAAC,gBAAgB,EACnC,OAAO,EAAE,OAAO,CAAC,UAAU;IAiCjC,SAAS,CAAE,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB;IA6E5F,UAAU;IAmCJ,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,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAC,MAAM;CA+C9F"}
@@ -2,7 +2,6 @@ import type { Services, Capabilities, Options, Frameworks } from '@wdio/types';
2
2
  import type { Browser, MultiRemoteBrowser } from 'webdriverio';
3
3
  import { BrowserstackConfig, MultiRemoteAction } from './types';
4
4
  export default class BrowserstackService implements Services.ServiceInstance {
5
- private _options;
6
5
  private _caps;
7
6
  private _config;
8
7
  private _sessionBaseUrl;
@@ -10,22 +9,30 @@ export default class BrowserstackService implements Services.ServiceInstance {
10
9
  private _scenariosThatRan;
11
10
  private _failureStatuses;
12
11
  private _browser?;
12
+ private _suiteTitle?;
13
13
  private _fullTitle?;
14
- constructor(_options: BrowserstackConfig & Options.Testrunner, _caps: Capabilities.RemoteCapability, _config: Options.Testrunner);
14
+ private _options;
15
+ constructor(options: BrowserstackConfig & Options.Testrunner, _caps: Capabilities.RemoteCapability, _config: Options.Testrunner);
15
16
  _updateCaps(fn: (caps: Capabilities.Capabilities | Capabilities.DesiredCapabilities) => void): void;
17
+ beforeSession(config: Omit<Options.Testrunner, 'capabilities'>): void;
18
+ before(caps: Capabilities.RemoteCapability, specs: string[], browser: Browser<'async'> | MultiRemoteBrowser<'async'>): Promise<void>;
16
19
  /**
17
- * if no user and key is specified even though a browserstack service was
18
- * provided set user and key with values so that the session request
19
- * will fail
20
+ * Set the default job name at the suite level to make sure we account
21
+ * for the cases where there is a long running `before` function for a
22
+ * suite or one that can fail.
23
+ * Don't do this for Jasmine because `suite.title` is `Jasmine__TopLevel__Suite`
24
+ * and `suite.fullTitle` is `undefined`, so no alternative to use for the job name.
25
+ */
26
+ beforeSuite(suite: Frameworks.Suite): Promise<void>;
27
+ beforeTest(test: Frameworks.Test): Promise<void>;
28
+ /**
29
+ * For CucumberJS
20
30
  */
21
- beforeSession(config: Options.Testrunner): void;
22
- before(caps: Capabilities.RemoteCapability, specs: string[], browser: Browser<'async'> | MultiRemoteBrowser<'async'>): Promise<void>;
23
- beforeSuite(suite: Frameworks.Suite): void;
24
31
  beforeFeature(uri: unknown, feature: {
25
32
  name: string;
26
- }): Promise<any>;
33
+ }): Promise<void>;
27
34
  afterTest(test: Frameworks.Test, context: never, results: Frameworks.TestResult): void;
28
- after(result: number): Promise<any>;
35
+ after(result: number): Promise<void>;
29
36
  /**
30
37
  * For CucumberJS
31
38
  */
@@ -36,5 +43,6 @@ export default class BrowserstackService implements Services.ServiceInstance {
36
43
  _multiRemoteAction(action: MultiRemoteAction): Promise<any>;
37
44
  _update(sessionId: string, requestBody: any): import("got").CancelableRequest<import("got").Response<string>>;
38
45
  _printSessionURL(): Promise<void>;
46
+ private _setSessionName;
39
47
  }
40
48
  //# sourceMappingURL=service.d.ts.map
@@ -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;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAG9D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAmB,MAAM,SAAS,CAAA;AAIhF,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,QAAQ,CAAC,eAAe;IASpE,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IAVnB,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,gBAAgB,CAA4D;IACpF,OAAO,CAAC,QAAQ,CAAC,CAAgD;IACjE,OAAO,CAAC,UAAU,CAAC,CAAQ;gBAGf,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACjD,KAAK,EAAE,YAAY,CAAC,gBAAgB,EACpC,OAAO,EAAE,OAAO,CAAC,UAAU;IAYvC,WAAW,CAAE,EAAE,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,YAAY,GAAG,YAAY,CAAC,mBAAmB,KAAK,IAAI;IAU7F;;;;OAIG;IACH,aAAa,CAAE,MAAM,EAAE,OAAO,CAAC,UAAU;IAYzC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC;IAepH,WAAW,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAIpC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAKrD,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU;IAqB/E,KAAK,CAAE,MAAM,EAAE,MAAM;IAgBrB;;OAEG;IACH,aAAa,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAmBhC,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IA2BzD,cAAc,IAAI,OAAO;IAOzB,UAAU,CAAE,WAAW,EAAE,GAAG;IAU5B,kBAAkB,CAAE,MAAM,EAAE,iBAAiB;IAqB7C,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG;IAUrC,gBAAgB;CAsBzB"}
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;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAG9D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAmB,MAAM,SAAS,CAAA;AAKhF,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,QAAQ,CAAC,eAAe;IAYpE,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IAZnB,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,gBAAgB,CAA4D;IACpF,OAAO,CAAC,QAAQ,CAAC,CAAgD;IACjE,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAyC;gBAGrD,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EACxC,KAAK,EAAE,YAAY,CAAC,gBAAgB,EACpC,OAAO,EAAE,OAAO,CAAC,UAAU;IAavC,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;IAe/D,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC;IAepH;;;;;;OAMG;IACG,WAAW,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAQpC,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IAiBvC;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAKrD,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU;IAOzE,KAAK,CAAE,MAAM,EAAE,MAAM;IAkB3B;;OAEG;IACH,aAAa,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAmBhC,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAgCzD,cAAc,IAAI,OAAO;IAOzB,UAAU,CAAE,WAAW,EAAE,GAAG;IAU5B,kBAAkB,CAAE,MAAM,EAAE,iBAAiB;IAqB7C,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG;IAUrC,gBAAgB;YAuBR,eAAe;CAyBhC"}
package/build/service.js CHANGED
@@ -6,18 +6,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const logger_1 = __importDefault(require("@wdio/logger"));
7
7
  const got_1 = __importDefault(require("got"));
8
8
  const util_1 = require("./util");
9
+ const constants_1 = require("./constants");
9
10
  const log = (0, logger_1.default)('@wdio/browserstack-service');
10
11
  class BrowserstackService {
11
- constructor(_options, _caps, _config) {
12
- this._options = _options;
12
+ constructor(options, _caps, _config) {
13
13
  this._caps = _caps;
14
14
  this._config = _config;
15
15
  this._sessionBaseUrl = 'https://api.browserstack.com/automate/sessions';
16
16
  this._failReasons = [];
17
17
  this._scenariosThatRan = [];
18
18
  this._failureStatuses = ['failed', 'ambiguous', 'undefined', 'unknown'];
19
+ this._options = { ...constants_1.DEFAULT_OPTIONS, ...options };
19
20
  // added to maintain backward compatibility with webdriverIO v5
20
- this._config || (this._config = _options);
21
+ this._config || (this._config = this._options);
21
22
  // Cucumber specific
22
23
  const strict = Boolean(this._config.cucumberOpts && this._config.cucumberOpts.strict);
23
24
  // See https://github.com/cucumber/cucumber-js/blob/master/src/runtime/index.ts#L136
@@ -32,12 +33,10 @@ class BrowserstackService {
32
33
  }
33
34
  return fn(this._caps);
34
35
  }
35
- /**
36
- * if no user and key is specified even though a browserstack service was
37
- * provided set user and key with values so that the session request
38
- * will fail
39
- */
40
36
  beforeSession(config) {
37
+ // if no user and key is specified even though a browserstack service was
38
+ // provided set user and key with values so that the session request
39
+ // will fail
41
40
  if (!config.user) {
42
41
  config.user = 'NotSetUser';
43
42
  }
@@ -57,45 +56,62 @@ class BrowserstackService {
57
56
  this._scenariosThatRan = [];
58
57
  return this._printSessionURL();
59
58
  }
60
- beforeSuite(suite) {
61
- this._fullTitle = suite.title;
62
- }
63
- beforeFeature(uri, feature) {
64
- this._fullTitle = feature.name;
65
- return this._updateJob({ name: this._fullTitle });
59
+ /**
60
+ * Set the default job name at the suite level to make sure we account
61
+ * for the cases where there is a long running `before` function for a
62
+ * suite or one that can fail.
63
+ * Don't do this for Jasmine because `suite.title` is `Jasmine__TopLevel__Suite`
64
+ * and `suite.fullTitle` is `undefined`, so no alternative to use for the job name.
65
+ */
66
+ async beforeSuite(suite) {
67
+ this._suiteTitle = suite.title;
68
+ if (suite.title && suite.title !== 'Jasmine__TopLevel__Suite') {
69
+ await this._setSessionName(suite.title);
70
+ }
66
71
  }
67
- afterTest(test, context, results) {
68
- const { error, passed } = results;
69
- // Jasmine
72
+ async beforeTest(test) {
73
+ let suiteTitle = this._suiteTitle;
70
74
  if (test.fullName) {
75
+ // For Jasmine, `suite.title` is `Jasmine__TopLevel__Suite`.
76
+ // This tweak allows us to set the real suite name.
71
77
  const testSuiteName = test.fullName.slice(0, test.fullName.indexOf(test.description || '') - 1);
72
- if (this._fullTitle === 'Jasmine__TopLevel__Suite') {
73
- this._fullTitle = testSuiteName;
78
+ if (this._suiteTitle === 'Jasmine__TopLevel__Suite') {
79
+ suiteTitle = testSuiteName;
74
80
  }
75
- else if (this._fullTitle) {
76
- this._fullTitle = (0, util_1.getParentSuiteName)(this._fullTitle, testSuiteName);
81
+ else if (this._suiteTitle) {
82
+ suiteTitle = (0, util_1.getParentSuiteName)(this._suiteTitle, testSuiteName);
77
83
  }
78
84
  }
79
- else {
80
- // Mocha
81
- this._fullTitle = `${test.parent} - ${test.title}`;
82
- }
85
+ await this._setSessionName(suiteTitle, test);
86
+ }
87
+ /**
88
+ * For CucumberJS
89
+ */
90
+ beforeFeature(uri, feature) {
91
+ this._suiteTitle = feature.name;
92
+ return this._setSessionName(feature.name);
93
+ }
94
+ afterTest(test, context, results) {
95
+ const { error, passed } = results;
83
96
  if (!passed) {
84
97
  this._failReasons.push((error && error.message) || 'Unknown Error');
85
98
  }
86
99
  }
87
- after(result) {
100
+ async after(result) {
101
+ const { preferScenarioName, setSessionName, setSessionStatus } = this._options;
88
102
  // For Cucumber: Checks scenarios that ran (i.e. not skipped) on the session
89
103
  // Only 1 Scenario ran and option enabled => Redefine session name to Scenario's name
90
- if (this._options.preferScenarioName && this._scenariosThatRan.length === 1) {
104
+ if (preferScenarioName && this._scenariosThatRan.length === 1) {
91
105
  this._fullTitle = this._scenariosThatRan.pop();
92
106
  }
93
- const hasReasons = Boolean(this._failReasons.filter(Boolean).length);
94
- return this._updateJob({
95
- status: result === 0 ? 'passed' : 'failed',
96
- name: this._fullTitle,
97
- reason: hasReasons ? this._failReasons.join('\n') : undefined
98
- });
107
+ if (setSessionStatus) {
108
+ const hasReasons = this._failReasons.length > 0;
109
+ await this._updateJob({
110
+ status: result === 0 ? 'passed' : 'failed',
111
+ ...(setSessionName ? { name: this._fullTitle } : {}),
112
+ ...(hasReasons ? { reason: this._failReasons.join('\n') } : {})
113
+ });
114
+ }
99
115
  }
100
116
  /**
101
117
  * For CucumberJS
@@ -118,8 +134,9 @@ class BrowserstackService {
118
134
  if (!this._browser) {
119
135
  return Promise.resolve();
120
136
  }
121
- const hasReasons = Boolean(this._failReasons.filter(Boolean).length);
122
- let status = hasReasons ? 'failed' : 'passed';
137
+ const { setSessionName, setSessionStatus } = this._options;
138
+ const hasReasons = this._failReasons.length > 0;
139
+ const status = hasReasons ? 'failed' : 'passed';
123
140
  if (!this._browser.isMultiremote) {
124
141
  log.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${status}`);
125
142
  }
@@ -127,12 +144,15 @@ class BrowserstackService {
127
144
  const browserName = this._browser.instances.filter((browserName) => this._browser && this._browser[browserName].sessionId === newSessionId)[0];
128
145
  log.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${status}`);
129
146
  }
130
- await this._update(oldSessionId, {
131
- name: this._fullTitle,
132
- status,
133
- reason: hasReasons ? this._failReasons.join('\n') : undefined
134
- });
147
+ if (setSessionStatus) {
148
+ await this._update(oldSessionId, {
149
+ status,
150
+ ...(setSessionName ? { name: this._fullTitle } : {}),
151
+ ...(hasReasons ? { reason: this._failReasons.join('\n') } : {})
152
+ });
153
+ }
135
154
  this._scenariosThatRan = [];
155
+ delete this._suiteTitle;
136
156
  delete this._fullTitle;
137
157
  this._failReasons = [];
138
158
  await this._printSessionURL();
@@ -195,5 +215,24 @@ class BrowserstackService {
195
215
  log.info(`${browserString} session: ${response.body.automation_session.browser_url}`);
196
216
  });
197
217
  }
218
+ async _setSessionName(suiteTitle, test) {
219
+ if (!this._options.setSessionName || !suiteTitle) {
220
+ return;
221
+ }
222
+ let name = suiteTitle;
223
+ if (this._options.sessionNameFormat) {
224
+ name = this._options.sessionNameFormat(this._config, this._caps, suiteTitle, test === null || test === void 0 ? void 0 : test.title);
225
+ }
226
+ else if (test && !test.fullName) {
227
+ // Mocha
228
+ const pre = this._options.sessionNamePrependTopLevelSuiteTitle ? `${suiteTitle} - ` : '';
229
+ const post = !this._options.sessionNameOmitTestTitle ? ` - ${test.title}` : '';
230
+ name = `${pre}${test.parent}${post}`;
231
+ }
232
+ if (name !== this._fullTitle) {
233
+ this._fullTitle = name;
234
+ await this._updateJob({ name });
235
+ }
236
+ }
198
237
  }
199
238
  exports.default = BrowserstackService;
package/build/types.d.ts CHANGED
@@ -1,10 +1,11 @@
1
+ import type { Capabilities, Options } from '@wdio/types';
1
2
  export interface SessionResponse {
2
3
  automation_session: {
3
4
  browser_url: string;
4
5
  };
5
6
  }
6
- export declare type MultiRemoteAction = (sessionId: string, browserName?: string) => Promise<any>;
7
- export declare type AppConfig = {
7
+ export type MultiRemoteAction = (sessionId: string, browserName?: string) => Promise<any>;
8
+ export type AppConfig = {
8
9
  id?: string;
9
10
  path?: string;
10
11
  custom_id?: string;
@@ -20,30 +21,29 @@ export interface App {
20
21
  customId?: string;
21
22
  }
22
23
  export interface BrowserstackConfig {
23
- /**
24
- * Set this to true to enable routing connections from Browserstack cloud through your computer.
25
- * You will also need to set `browserstack.local` to true in browser capabilities.
26
- */
27
- browserstackLocal?: boolean;
28
24
  /**
29
25
  * Set this with app file path present locally on your device or
30
- * app hashed id returned after uploading app to Browserstack or
26
+ * app hashed id returned after uploading app to BrowserStack or
31
27
  * custom_id, sharable_id of the uploaded app
28
+ * @default undefined
32
29
  */
33
30
  app?: string | AppConfig;
34
31
  /**
35
- * Cucumber only. Set this to true to enable updating the session name to the Scenario name if only
36
- * a single Scenario was ran. Useful when running in parallel
37
- * with [wdio-cucumber-parallel-execution](https://github.com/SimitTomar/wdio-cucumber-parallel-execution).
32
+ * Enable routing connections from BrowserStack cloud through your computer.
33
+ * You will also need to set `browserstack.local` to true in browser capabilities.
34
+ * @default false
38
35
  */
39
- preferScenarioName?: boolean;
36
+ browserstackLocal?: boolean;
40
37
  /**
41
- * Set this to true to kill the browserstack process on complete, without waiting for the
42
- * browserstack stop callback to be called. This is experimental and should not be used by all.
38
+ * Kill the BrowserStack Local process on complete, without waiting for the
39
+ * BrowserStack Local stop callback to be called.
40
+ *
41
+ * __This is experimental and should not be used by all.__
42
+ * @default false
43
43
  */
44
44
  forcedStop?: boolean;
45
45
  /**
46
- * Specified optional will be passed down to BrowserstackLocal. For more details check out the
46
+ * BrowserStack Local options. For more details check out the
47
47
  * [`browserstack-local`](https://www.npmjs.com/package/browserstack-local#arguments) docs.
48
48
  *
49
49
  * @example
@@ -52,7 +52,39 @@ export interface BrowserstackConfig {
52
52
  * localIdentifier: 'some-identifier'
53
53
  * }
54
54
  * ```
55
+ * @default {}
55
56
  */
56
57
  opts?: Partial<import('browserstack-local').Options>;
58
+ /**
59
+ * Cucumber only. Set the BrowserStack Automate session name to the Scenario name if only a single Scenario ran.
60
+ * Useful when running in parallel with [wdio-cucumber-parallel-execution](https://github.com/SimitTomar/wdio-cucumber-parallel-execution).
61
+ * @default false
62
+ */
63
+ preferScenarioName?: boolean;
64
+ /**
65
+ * Customize the BrowserStack Automate session name format.
66
+ * @default undefined
67
+ */
68
+ sessionNameFormat?: (config: Options.Testrunner, capabilities: Capabilities.RemoteCapability, suiteTitle: string, testTitle?: string) => string;
69
+ /**
70
+ * Mocha only. Do not append the test title to the BrowserStack Automate session name.
71
+ * @default false
72
+ */
73
+ sessionNameOmitTestTitle?: boolean;
74
+ /**
75
+ * Mocha only. Prepend the top level suite title to the BrowserStack Automate session name.
76
+ * @default false
77
+ */
78
+ sessionNamePrependTopLevelSuiteTitle?: boolean;
79
+ /**
80
+ * Automatically set the BrowserStack Automate session name.
81
+ * @default true
82
+ */
83
+ setSessionName?: boolean;
84
+ /**
85
+ * Automatically set the BrowserStack Automate session status (passed/failed).
86
+ * @default true
87
+ */
88
+ setSessionStatus?: boolean;
57
89
  }
58
90
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAE5B,kBAAkB,EAAE;QAEhB,WAAW,EAAE,MAAM,CAAA;KACtB,CAAA;CACJ;AAED,oBAAY,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE1F,oBAAY,SAAS,GAAG;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,GAAG;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAAA;CACvD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAExD,MAAM,WAAW,eAAe;IAE5B,kBAAkB,EAAE;QAEhB,WAAW,EAAE,MAAM,CAAA;KACtB,CAAA;CACJ;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE1F,MAAM,MAAM,SAAS,GAAG;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,GAAG;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAAA;IACpD;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAChB,MAAM,EAAE,OAAO,CAAC,UAAU,EAC1B,YAAY,EAAE,YAAY,CAAC,gBAAgB,EAC3C,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,KACjB,MAAM,CAAA;IACX;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,oCAAoC,CAAC,EAAE,OAAO,CAAC;IAC/C;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/browserstack-service",
3
- "version": "7.25.4",
3
+ "version": "7.27.0",
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",
@@ -24,12 +24,12 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@types/node": "^18.0.0",
27
- "@wdio/logger": "7.19.0",
28
- "@wdio/types": "7.25.4",
27
+ "@wdio/logger": "7.26.0",
28
+ "@wdio/types": "7.26.0",
29
29
  "browserstack-local": "^1.4.5",
30
30
  "form-data": "^4.0.0",
31
31
  "got": "^11.0.2",
32
- "webdriverio": "7.25.4"
32
+ "webdriverio": "7.27.0"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@wdio/cli": "^5.0.0 || ^6.0.0 || ^7.0.0"
@@ -38,5 +38,5 @@
38
38
  "access": "public"
39
39
  },
40
40
  "types": "./build/index.d.ts",
41
- "gitHead": "7e41cd86779937722b6f824d10375b039aee620f"
41
+ "gitHead": "8b7701a7e782c6475b1218bcb60423a4c175309a"
42
42
  }