@wdio/browserstack-service 7.26.0 → 7.28.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 +52 -13
- package/build/constants.d.ts +2 -0
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +5 -1
- package/build/launcher.d.ts +1 -1
- package/build/launcher.d.ts.map +1 -1
- package/build/service.d.ts +29 -10
- package/build/service.d.ts.map +1 -1
- package/build/service.js +116 -41
- package/build/types.d.ts +47 -15
- package/build/types.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
WebdriverIO
|
|
1
|
+
WebdriverIO BrowserStack Service
|
|
2
2
|
==========
|
|
3
3
|
|
|
4
|
-
> A WebdriverIO service that manages local tunnel and job metadata for
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
227
|
+
To kill other running BrowserStack Local instances -
|
|
189
228
|
|
|
190
229
|
```js
|
|
191
230
|
opts = { force: "true" };
|
package/build/constants.d.ts
CHANGED
|
@@ -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
|
package/build/constants.d.ts.map
CHANGED
|
@@ -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"}
|
package/build/constants.js
CHANGED
|
@@ -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
|
+
};
|
package/build/launcher.d.ts
CHANGED
|
@@ -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
|
-
|
|
5
|
+
type BrowserstackLocal = BrowserstackLocalLauncher.Local & {
|
|
6
6
|
pid?: number;
|
|
7
7
|
stop(callback: (err?: any) => void): void;
|
|
8
8
|
};
|
package/build/launcher.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/build/service.d.ts
CHANGED
|
@@ -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,39 @@ 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
|
-
|
|
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
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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<
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Runs before a Cucumber Scenario.
|
|
36
|
+
* @param world world object containing information on pickle and test step
|
|
37
|
+
*/
|
|
38
|
+
beforeScenario(world: Frameworks.World): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* For CucumberJS
|
|
41
|
+
*/
|
|
42
|
+
beforeStep(step: Frameworks.PickleStep): Promise<void>;
|
|
27
43
|
afterTest(test: Frameworks.Test, context: never, results: Frameworks.TestResult): void;
|
|
28
|
-
after(result: number): Promise<
|
|
44
|
+
after(result: number): Promise<void>;
|
|
29
45
|
/**
|
|
30
46
|
* For CucumberJS
|
|
31
47
|
*/
|
|
@@ -36,5 +52,8 @@ export default class BrowserstackService implements Services.ServiceInstance {
|
|
|
36
52
|
_multiRemoteAction(action: MultiRemoteAction): Promise<any>;
|
|
37
53
|
_update(sessionId: string, requestBody: any): import("got").CancelableRequest<import("got").Response<string>>;
|
|
38
54
|
_printSessionURL(): Promise<void>;
|
|
55
|
+
private _setSessionName;
|
|
56
|
+
private _setAnnotation;
|
|
57
|
+
private _executeCommand;
|
|
39
58
|
}
|
|
40
59
|
//# sourceMappingURL=service.d.ts.map
|
package/build/service.d.ts.map
CHANGED
|
@@ -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;
|
|
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;IAkBvC;;OAEG;IACG,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAM3D;;;OAGG;IACG,cAAc,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAK7C;;OAEG;IACG,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU;IAK7C,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;IA0B7B,OAAO,CAAC,cAAc;YAIR,eAAe;CAqBhC"}
|
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(
|
|
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,80 @@ class BrowserstackService {
|
|
|
57
56
|
this._scenariosThatRan = [];
|
|
58
57
|
return this._printSessionURL();
|
|
59
58
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
async beforeTest(test) {
|
|
73
|
+
var _a;
|
|
74
|
+
let suiteTitle = this._suiteTitle;
|
|
70
75
|
if (test.fullName) {
|
|
76
|
+
// For Jasmine, `suite.title` is `Jasmine__TopLevel__Suite`.
|
|
77
|
+
// This tweak allows us to set the real suite name.
|
|
71
78
|
const testSuiteName = test.fullName.slice(0, test.fullName.indexOf(test.description || '') - 1);
|
|
72
|
-
if (this.
|
|
73
|
-
|
|
79
|
+
if (this._suiteTitle === 'Jasmine__TopLevel__Suite') {
|
|
80
|
+
suiteTitle = testSuiteName;
|
|
74
81
|
}
|
|
75
|
-
else if (this.
|
|
76
|
-
|
|
82
|
+
else if (this._suiteTitle) {
|
|
83
|
+
suiteTitle = (0, util_1.getParentSuiteName)(this._suiteTitle, testSuiteName);
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
86
|
+
await this._setSessionName(suiteTitle, test);
|
|
87
|
+
await this._setAnnotation(`Test: ${(_a = test.fullName) !== null && _a !== void 0 ? _a : test.title}`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* For CucumberJS
|
|
91
|
+
*/
|
|
92
|
+
async beforeFeature(uri, feature) {
|
|
93
|
+
this._suiteTitle = feature.name;
|
|
94
|
+
await this._setSessionName(feature.name);
|
|
95
|
+
await this._setAnnotation(`Feature: ${feature.name}`);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Runs before a Cucumber Scenario.
|
|
99
|
+
* @param world world object containing information on pickle and test step
|
|
100
|
+
*/
|
|
101
|
+
async beforeScenario(world) {
|
|
102
|
+
const scenarioName = world.pickle.name || 'unknown scenario';
|
|
103
|
+
await this._setAnnotation(`Scenario: ${scenarioName}`);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* For CucumberJS
|
|
107
|
+
*/
|
|
108
|
+
async beforeStep(step) {
|
|
109
|
+
const { keyword, text } = step;
|
|
110
|
+
await this._setAnnotation(`Step: ${keyword}${text}`);
|
|
111
|
+
}
|
|
112
|
+
afterTest(test, context, results) {
|
|
113
|
+
const { error, passed } = results;
|
|
83
114
|
if (!passed) {
|
|
84
115
|
this._failReasons.push((error && error.message) || 'Unknown Error');
|
|
85
116
|
}
|
|
86
117
|
}
|
|
87
|
-
after(result) {
|
|
118
|
+
async after(result) {
|
|
119
|
+
const { preferScenarioName, setSessionName, setSessionStatus } = this._options;
|
|
88
120
|
// For Cucumber: Checks scenarios that ran (i.e. not skipped) on the session
|
|
89
121
|
// Only 1 Scenario ran and option enabled => Redefine session name to Scenario's name
|
|
90
|
-
if (
|
|
122
|
+
if (preferScenarioName && this._scenariosThatRan.length === 1) {
|
|
91
123
|
this._fullTitle = this._scenariosThatRan.pop();
|
|
92
124
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
125
|
+
if (setSessionStatus) {
|
|
126
|
+
const hasReasons = this._failReasons.length > 0;
|
|
127
|
+
await this._updateJob({
|
|
128
|
+
status: result === 0 ? 'passed' : 'failed',
|
|
129
|
+
...(setSessionName ? { name: this._fullTitle } : {}),
|
|
130
|
+
...(hasReasons ? { reason: this._failReasons.join('\n') } : {})
|
|
131
|
+
});
|
|
132
|
+
}
|
|
99
133
|
}
|
|
100
134
|
/**
|
|
101
135
|
* For CucumberJS
|
|
@@ -118,8 +152,9 @@ class BrowserstackService {
|
|
|
118
152
|
if (!this._browser) {
|
|
119
153
|
return Promise.resolve();
|
|
120
154
|
}
|
|
121
|
-
const
|
|
122
|
-
|
|
155
|
+
const { setSessionName, setSessionStatus } = this._options;
|
|
156
|
+
const hasReasons = this._failReasons.length > 0;
|
|
157
|
+
const status = hasReasons ? 'failed' : 'passed';
|
|
123
158
|
if (!this._browser.isMultiremote) {
|
|
124
159
|
log.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${status}`);
|
|
125
160
|
}
|
|
@@ -127,12 +162,15 @@ class BrowserstackService {
|
|
|
127
162
|
const browserName = this._browser.instances.filter((browserName) => this._browser && this._browser[browserName].sessionId === newSessionId)[0];
|
|
128
163
|
log.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${status}`);
|
|
129
164
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
165
|
+
if (setSessionStatus) {
|
|
166
|
+
await this._update(oldSessionId, {
|
|
167
|
+
status,
|
|
168
|
+
...(setSessionName ? { name: this._fullTitle } : {}),
|
|
169
|
+
...(hasReasons ? { reason: this._failReasons.join('\n') } : {})
|
|
170
|
+
});
|
|
171
|
+
}
|
|
135
172
|
this._scenariosThatRan = [];
|
|
173
|
+
delete this._suiteTitle;
|
|
136
174
|
delete this._fullTitle;
|
|
137
175
|
this._failReasons = [];
|
|
138
176
|
await this._printSessionURL();
|
|
@@ -160,7 +198,7 @@ class BrowserstackService {
|
|
|
160
198
|
return action(_browser.sessionId);
|
|
161
199
|
}
|
|
162
200
|
return Promise.all(_browser.instances
|
|
163
|
-
.filter(browserName => {
|
|
201
|
+
.filter((browserName) => {
|
|
164
202
|
const cap = (0, util_1.getBrowserCapabilities)(_browser, this._caps, browserName);
|
|
165
203
|
return (0, util_1.isBrowserstackCapability)(cap);
|
|
166
204
|
})
|
|
@@ -195,5 +233,42 @@ class BrowserstackService {
|
|
|
195
233
|
log.info(`${browserString} session: ${response.body.automation_session.browser_url}`);
|
|
196
234
|
});
|
|
197
235
|
}
|
|
236
|
+
async _setSessionName(suiteTitle, test) {
|
|
237
|
+
if (!this._options.setSessionName || !suiteTitle) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
let name = suiteTitle;
|
|
241
|
+
if (this._options.sessionNameFormat) {
|
|
242
|
+
name = this._options.sessionNameFormat(this._config, this._caps, suiteTitle, test === null || test === void 0 ? void 0 : test.title);
|
|
243
|
+
}
|
|
244
|
+
else if (test && !test.fullName) {
|
|
245
|
+
// Mocha
|
|
246
|
+
const pre = this._options.sessionNamePrependTopLevelSuiteTitle ? `${suiteTitle} - ` : '';
|
|
247
|
+
const post = !this._options.sessionNameOmitTestTitle ? ` - ${test.title}` : '';
|
|
248
|
+
name = `${pre}${test.parent}${post}`;
|
|
249
|
+
}
|
|
250
|
+
if (name !== this._fullTitle) {
|
|
251
|
+
this._fullTitle = name;
|
|
252
|
+
await this._updateJob({ name });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
_setAnnotation(data) {
|
|
256
|
+
return this._executeCommand('annotate', { data, level: 'info' });
|
|
257
|
+
}
|
|
258
|
+
async _executeCommand(action, args) {
|
|
259
|
+
if (!this._browser) {
|
|
260
|
+
return Promise.resolve();
|
|
261
|
+
}
|
|
262
|
+
const cmd = { action, ...(args ? { arguments: args } : {}) };
|
|
263
|
+
const script = `browserstack_executor: ${JSON.stringify(cmd)}`;
|
|
264
|
+
if (this._browser.isMultiremote) {
|
|
265
|
+
const multiRemoteBrowser = this._browser;
|
|
266
|
+
return Promise.all(Object.keys(this._caps).map(async (browserName) => {
|
|
267
|
+
const browser = multiRemoteBrowser[browserName];
|
|
268
|
+
return (await browser.execute(script));
|
|
269
|
+
}));
|
|
270
|
+
}
|
|
271
|
+
return (await this._browser.execute(script));
|
|
272
|
+
}
|
|
198
273
|
}
|
|
199
274
|
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
|
|
7
|
-
export
|
|
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
|
|
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
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
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
|
-
|
|
36
|
+
browserstackLocal?: boolean;
|
|
40
37
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
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
|
-
*
|
|
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
|
package/build/types.d.ts.map
CHANGED
|
@@ -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,
|
|
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.
|
|
3
|
+
"version": "7.28.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",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"browserstack-local": "^1.4.5",
|
|
30
30
|
"form-data": "^4.0.0",
|
|
31
31
|
"got": "^11.0.2",
|
|
32
|
-
"webdriverio": "7.
|
|
32
|
+
"webdriverio": "7.28.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": "
|
|
41
|
+
"gitHead": "09be73a21a3241d65c92269ff2ca7cec2d49b5fc"
|
|
42
42
|
}
|