@wdio/testingbot-service 9.0.0-alpha.78 → 9.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,MAAM,eAAe,CAAA;AAC9C,OAAO,iBAAiB,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,eAAe,iBAAiB,CAAA;AAChC,eAAO,MAAM,QAAQ,2BAAqB,CAAA;AAC1C,cAAc,YAAY,CAAA;AAE1B,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,aAAc,SAAQ,iBAAiB;SAAG;KACvD;CACJ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,MAAM,eAAe,CAAA;AAC9C,OAAO,iBAAiB,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,eAAe,iBAAiB,CAAA;AAChC,eAAO,MAAM,QAAQ,2BAAqB,CAAA;AAC1C,cAAc,YAAY,CAAA;AAE1B,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,aAAc,SAAQ,iBAAiB;SAAG;KACvD;CACJ"}
package/build/index.js CHANGED
@@ -1,6 +1,263 @@
1
- /* istanbul ignore file */
2
- import TestingBotLauncher from './launcher.js';
3
- import TestingBotService from './service.js';
4
- export default TestingBotService;
5
- export const launcher = TestingBotLauncher;
6
- export * from './types.js';
1
+ // src/launcher.ts
2
+ import { performance, PerformanceObserver } from "node:perf_hooks";
3
+ import { promisify } from "node:util";
4
+ import testingbotTunnel from "testingbot-tunnel-launcher";
5
+ import logger from "@wdio/logger";
6
+ var log = logger("@wdio/testingbot-service");
7
+ var TestingBotLauncher = class {
8
+ options;
9
+ tbTunnelOpts;
10
+ tunnel;
11
+ constructor(options) {
12
+ this.options = options;
13
+ }
14
+ async onPrepare(config, capabilities) {
15
+ if (!this.options.tbTunnel || !config.user || !config.key) {
16
+ return;
17
+ }
18
+ const tbTunnelIdentifier = this.options.tbTunnelOpts?.tunnelIdentifier || `TB-tunnel-${Math.random().toString().slice(2)}`;
19
+ this.tbTunnelOpts = Object.assign({
20
+ apiKey: config.user,
21
+ apiSecret: config.key,
22
+ "tunnel-identifier": tbTunnelIdentifier
23
+ }, this.options.tbTunnelOpts);
24
+ const capabilitiesEntries = Array.isArray(capabilities) ? capabilities.every((cap) => Object.values(cap).length > 0 && Object.values(cap).every((c) => typeof c === "object" && c.capabilities)) ? capabilities.flatMap((cap) => Object.values(cap)) : capabilities : Object.values(capabilities);
25
+ for (const capability of capabilitiesEntries) {
26
+ const caps = capability.capabilities || capability;
27
+ const c = caps.alwaysMatch || caps;
28
+ if (!c["tb:options"]) {
29
+ c["tb:options"] = {};
30
+ }
31
+ c["tb:options"]["tunnel-identifier"] = tbTunnelIdentifier;
32
+ }
33
+ const obs = new PerformanceObserver((list) => {
34
+ const entry = list.getEntries()[0];
35
+ log.info(`TestingBot tunnel successfully started after ${entry.duration}ms`);
36
+ });
37
+ obs.observe({ entryTypes: ["measure"] });
38
+ performance.mark("tbTunnelStart");
39
+ this.tunnel = await promisify(testingbotTunnel)(this.tbTunnelOpts);
40
+ performance.mark("tbTunnelEnd");
41
+ performance.measure("bootTime", "tbTunnelStart", "tbTunnelEnd");
42
+ }
43
+ /**
44
+ * Shut down the tunnel
45
+ * @returns {Promise} Resolved promise when tunnel is closed
46
+ */
47
+ onComplete() {
48
+ if (!this.tunnel) {
49
+ return;
50
+ }
51
+ return new Promise((resolve) => this.tunnel.close(resolve));
52
+ }
53
+ };
54
+
55
+ // src/service.ts
56
+ import logger2 from "@wdio/logger";
57
+ var log2 = logger2("@wdio/testingbot-service");
58
+ var jobDataProperties = ["name", "tags", "public", "build", "extra"];
59
+ var TestingBotService = class {
60
+ constructor(_options, _capabilities, _config) {
61
+ this._options = _options;
62
+ this._capabilities = _capabilities;
63
+ this._config = _config;
64
+ this._tbUser = this._config.user;
65
+ this._tbSecret = this._config.key;
66
+ this._isServiceEnabled = Boolean(this._tbUser && this._tbSecret);
67
+ }
68
+ _browser;
69
+ _isServiceEnabled;
70
+ _suiteTitle;
71
+ _tbSecret;
72
+ _tbUser;
73
+ _failures = 0;
74
+ _testCnt = 0;
75
+ before(caps, specs, browser) {
76
+ this._browser = browser;
77
+ }
78
+ /**
79
+ * Before suite
80
+ * @param {object} suite Suite
81
+ */
82
+ beforeSuite(suite) {
83
+ this._suiteTitle = suite.title;
84
+ }
85
+ /**
86
+ * Before test
87
+ * @param {object} test Test
88
+ */
89
+ beforeTest(test) {
90
+ if (!this._isServiceEnabled || !this._browser) {
91
+ return;
92
+ }
93
+ if (this._suiteTitle === "Jasmine__TopLevel__Suite") {
94
+ this._suiteTitle = test.fullName.slice(0, test.fullName.indexOf(test.title) - 1);
95
+ }
96
+ const context = (
97
+ /**
98
+ * Jasmine
99
+ */
100
+ test.fullName || /**
101
+ * Mocha
102
+ */
103
+ `${test.parent} - ${test.title}`
104
+ );
105
+ this._browser.execute("tb:test-context=" + context);
106
+ }
107
+ afterSuite(suite) {
108
+ if (Object.prototype.hasOwnProperty.call(suite, "error")) {
109
+ ++this._failures;
110
+ }
111
+ }
112
+ /**
113
+ * After test
114
+ * @param {object} test Test
115
+ */
116
+ afterTest(test, context, results) {
117
+ if (!results.passed) {
118
+ ++this._failures;
119
+ }
120
+ }
121
+ /**
122
+ * For CucumberJS
123
+ */
124
+ /**
125
+ * Before feature
126
+ * @param {string} uri
127
+ * @param {object} feature
128
+ */
129
+ beforeFeature(uri, feature) {
130
+ if (!this._isServiceEnabled || !this._browser) {
131
+ return;
132
+ }
133
+ this._suiteTitle = feature.name;
134
+ this._browser.execute("tb:test-context=Feature: " + this._suiteTitle);
135
+ }
136
+ /**
137
+ * Before scenario
138
+ * @param {string} uri
139
+ * @param {object} feature
140
+ * @param {object} scenario
141
+ */
142
+ beforeScenario(world) {
143
+ if (!this._isServiceEnabled || !this._browser) {
144
+ return;
145
+ }
146
+ const scenarioName = world.pickle.name;
147
+ this._browser.execute("tb:test-context=Scenario: " + scenarioName);
148
+ }
149
+ /**
150
+ *
151
+ * Runs before a Cucumber Scenario.
152
+ * @param world world object containing information on pickle and test step
153
+ * @param result result object containing
154
+ * @param result.passed true if scenario has passed
155
+ * @param result.error error stack if scenario failed
156
+ * @param result.duration duration of scenario in milliseconds
157
+ */
158
+ afterScenario(world, result) {
159
+ if (!result.passed) {
160
+ ++this._failures;
161
+ }
162
+ }
163
+ /**
164
+ * Update TestingBot info
165
+ * @return {Promise} Promise with result of updateJob method call
166
+ */
167
+ after(result) {
168
+ if (!this._isServiceEnabled || !this._browser) {
169
+ return;
170
+ }
171
+ let failures = this._failures;
172
+ if (this._config.mochaOpts?.bail && Boolean(result)) {
173
+ failures = 1;
174
+ }
175
+ const status = "status: " + (failures > 0 ? "failing" : "passing");
176
+ if (!this._browser.isMultiremote) {
177
+ log2.info(`Update job with sessionId ${this._browser.sessionId}, ${status}`);
178
+ return this.updateJob(this._browser.sessionId, failures);
179
+ }
180
+ const browser = this._browser;
181
+ return Promise.all(Object.keys(this._capabilities).map((browserName) => {
182
+ log2.info(`Update multiremote job for browser "${browserName}" and sessionId ${browser.getInstance(browserName).sessionId}, ${status}`);
183
+ return this.updateJob(browser.getInstance(browserName).sessionId, failures, false, browserName);
184
+ }));
185
+ }
186
+ onReload(oldSessionId, newSessionId) {
187
+ if (!this._isServiceEnabled || !this._browser) {
188
+ return;
189
+ }
190
+ const status = "status: " + (this._failures > 0 ? "failing" : "passing");
191
+ if (!this._browser.isMultiremote) {
192
+ log2.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${status}`);
193
+ return this.updateJob(oldSessionId, this._failures, true);
194
+ }
195
+ const browser = this._browser;
196
+ const browserName = browser.instances.filter(
197
+ (browserName2) => browser.getInstance(browserName2).sessionId === newSessionId
198
+ )[0];
199
+ log2.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${status}`);
200
+ return this.updateJob(oldSessionId, this._failures, true, browserName);
201
+ }
202
+ async updateJob(sessionId, failures, calledOnReload = false, browserName) {
203
+ if (!this._browser) {
204
+ return;
205
+ }
206
+ let headers = {
207
+ "Content-Type": "application/json; charset=utf-8"
208
+ };
209
+ if (this._tbUser && this._tbSecret) {
210
+ const encodedAuth = Buffer.from(`${this._tbUser}:${this._tbSecret}`, "utf8").toString("base64");
211
+ headers = {
212
+ ...headers,
213
+ Authorization: `Basic ${encodedAuth}`
214
+ };
215
+ }
216
+ const json = this.getBody(failures, calledOnReload, browserName);
217
+ this._failures = 0;
218
+ const response = await fetch(this.getRestUrl(sessionId), {
219
+ method: "PUT",
220
+ body: JSON.stringify(json),
221
+ headers
222
+ });
223
+ return await response.json();
224
+ }
225
+ /**
226
+ *
227
+ * @param {String} sessionId Session id
228
+ * @returns {String} TestingBot API URL
229
+ */
230
+ getRestUrl(sessionId) {
231
+ return `https://api.testingbot.com/v1/tests/${sessionId}`;
232
+ }
233
+ getBody(failures, calledOnReload = false, browserName) {
234
+ const body = { test: {} };
235
+ body.test.name = this._suiteTitle;
236
+ if ((calledOnReload || this._testCnt) && this._browser) {
237
+ let testCnt = ++this._testCnt;
238
+ if (this._browser.isMultiremote) {
239
+ testCnt = Math.ceil(testCnt / this._browser.instances.length);
240
+ }
241
+ body.test.name += ` (${testCnt})`;
242
+ }
243
+ for (const prop of jobDataProperties) {
244
+ if (!this._capabilities[prop]) {
245
+ continue;
246
+ }
247
+ body.test[prop] = this._capabilities[prop];
248
+ }
249
+ if (browserName) {
250
+ body.test.name = `${browserName}: ${body.test.name}`;
251
+ }
252
+ body.test.success = failures === 0 ? "1" : "0";
253
+ return body;
254
+ }
255
+ };
256
+
257
+ // src/index.ts
258
+ var src_default = TestingBotService;
259
+ var launcher = TestingBotLauncher;
260
+ export {
261
+ src_default as default,
262
+ launcher
263
+ };
@@ -5,7 +5,7 @@ export default class TestingBotLauncher implements Services.ServiceInstance {
5
5
  tbTunnelOpts: TunnelLauncherOptions;
6
6
  tunnel?: TestingbotTunnel;
7
7
  constructor(options: TestingbotOptions);
8
- onPrepare(config: Options.Testrunner, capabilities: Capabilities.RemoteCapabilities): Promise<void>;
8
+ onPrepare(config: Options.Testrunner, capabilities: Capabilities.TestrunnerCapabilities): Promise<void>;
9
9
  /**
10
10
  * Shut down the tunnel
11
11
  * @returns {Promise} Resolved promise when tunnel is closed
@@ -1 +1 @@
1
- {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAI5F,MAAM,CAAC,OAAO,OAAO,kBAAmB,YAAW,QAAQ,CAAC,eAAe;IACvE,OAAO,EAAE,iBAAiB,CAAA;IAC1B,YAAY,EAAG,qBAAqB,CAAA;IACpC,MAAM,CAAC,EAAE,gBAAgB,CAAA;gBACZ,OAAO,EAAE,iBAAiB;IAIjC,SAAS,CAAE,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,YAAY,CAAC,kBAAkB;IA+C1F;;;OAGG;IACH,UAAU;CAOb"}
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAI5F,MAAM,CAAC,OAAO,OAAO,kBAAmB,YAAW,QAAQ,CAAC,eAAe;IACvE,OAAO,EAAE,iBAAiB,CAAA;IAC1B,YAAY,EAAG,qBAAqB,CAAA;IACpC,MAAM,CAAC,EAAE,gBAAgB,CAAA;gBACZ,OAAO,EAAE,iBAAiB;IAIjC,SAAS,CAAE,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,YAAY,CAAC,sBAAsB;IA+C9F;;;OAGG;IACH,UAAU;CAOb"}
@@ -11,7 +11,7 @@ export default class TestingBotService implements Services.ServiceInstance {
11
11
  private _tbUser?;
12
12
  private _failures;
13
13
  private _testCnt;
14
- constructor(_options: TestingbotOptions, _capabilities: Capabilities.RemoteCapability, _config: Omit<Options.Testrunner, 'capabilities'>);
14
+ constructor(_options: TestingbotOptions, _capabilities: Capabilities.ResolvedTestrunnerCapabilities, _config: Options.Testrunner);
15
15
  before(caps: unknown, specs: unknown, browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser): void;
16
16
  /**
17
17
  * Before suite
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAKnD,MAAM,CAAC,OAAO,OAAO,iBAAkB,YAAW,QAAQ,CAAC,eAAe;IAUlE,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,OAAO;IAXnB,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,QAAQ,CAAI;gBAGR,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,YAAY,CAAC,gBAAgB,EAC5C,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC;IAQ7D,MAAM,CACF,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB;IAKjE;;;MAGE;IACF,WAAW,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAIpC;;;MAGE;IACF,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IA6BjC,UAAU,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAMnC;;;OAGG;IACH,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU;IAM9E;;OAEG;IAEH;;;;OAIG;IACH,aAAa,CAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAStD;;;;;OAKG;IACH,cAAc,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAQvC;;;;;;;;OAQG;IACH,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,YAAY;IAOtE;;;OAGG;IACH,KAAK,CAAE,MAAM,CAAC,EAAE,MAAM;IA6BtB,QAAQ,CAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAkB9C,SAAS,CAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,UAAQ,EAAE,WAAW,CAAC,EAAE,MAAM;IAyBlG;;;;OAIG;IACH,UAAU,CAAE,SAAS,EAAE,MAAM;IAI7B,OAAO,CAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,UAAQ,EAAE,WAAW,CAAC,EAAE,MAAM;;;CAmC1E"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAKnD,MAAM,CAAC,OAAO,OAAO,iBAAkB,YAAW,QAAQ,CAAC,eAAe;IAUlE,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,OAAO;IAXnB,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,QAAQ,CAAI;gBAGR,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,YAAY,CAAC,8BAA8B,EAC1D,OAAO,EAAE,OAAO,CAAC,UAAU;IAQvC,MAAM,CACF,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB;IAKjE;;;MAGE;IACF,WAAW,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAIpC;;;MAGE;IACF,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IA6BjC,UAAU,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAMnC;;;OAGG;IACH,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU;IAM9E;;OAEG;IAEH;;;;OAIG;IACH,aAAa,CAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAStD;;;;;OAKG;IACH,cAAc,CAAE,KAAK,EAAE,UAAU,CAAC,KAAK;IAQvC;;;;;;;;OAQG;IACH,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,YAAY;IAOtE;;;OAGG;IACH,KAAK,CAAE,MAAM,CAAC,EAAE,MAAM;IA6BtB,QAAQ,CAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAkB9C,SAAS,CAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,UAAQ,EAAE,WAAW,CAAC,EAAE,MAAM;IAyBlG;;;;OAIG;IACH,UAAU,CAAE,SAAS,EAAE,MAAM;IAI7B,OAAO,CAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,UAAQ,EAAE,WAAW,CAAC,EAAE,MAAM;cACxC,GAAG;;CAkCrC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/testingbot-service",
3
- "version": "9.0.0-alpha.78+fee2f8a88",
3
+ "version": "9.0.0",
4
4
  "description": "A WebdriverIO service that provides a better integration into TestingBot",
5
5
  "author": "Jochen Delabie <info@testingbot.com>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-testingbot-service",
@@ -25,22 +25,24 @@
25
25
  "type": "module",
26
26
  "types": "./build/index.d.ts",
27
27
  "exports": {
28
- ".": "./build/index.js",
29
- "./package.json": "./package.json"
28
+ ".": {
29
+ "types": "./build/index.d.ts",
30
+ "import": "./build/index.js"
31
+ }
30
32
  },
31
33
  "typeScriptVersion": "3.8.3",
32
34
  "dependencies": {
33
- "@wdio/logger": "9.0.0-alpha.78+fee2f8a88",
34
- "@wdio/types": "9.0.0-alpha.78+fee2f8a88",
35
+ "@wdio/logger": "9.0.0",
36
+ "@wdio/types": "9.0.0",
35
37
  "testingbot-tunnel-launcher": "^1.1.7",
36
- "webdriverio": "9.0.0-alpha.78+fee2f8a88"
38
+ "webdriverio": "9.0.0"
37
39
  },
38
40
  "devDependencies": {
39
41
  "@types/node": "^20.1.0",
40
- "@wdio/globals": "9.0.0-alpha.78+fee2f8a88"
42
+ "@wdio/globals": "9.0.0"
41
43
  },
42
44
  "publishConfig": {
43
45
  "access": "public"
44
46
  },
45
- "gitHead": "fee2f8a88d132537795eaf144abf1a7e242f99ff"
47
+ "gitHead": "957693463371a4cb329395dcdbce8fb0c930ab93"
46
48
  }
package/build/launcher.js DELETED
@@ -1,60 +0,0 @@
1
- import { performance, PerformanceObserver } from 'node:perf_hooks';
2
- import { promisify } from 'node:util';
3
- import testingbotTunnel from 'testingbot-tunnel-launcher';
4
- import logger from '@wdio/logger';
5
- const log = logger('@wdio/testingbot-service');
6
- export default class TestingBotLauncher {
7
- options;
8
- tbTunnelOpts;
9
- tunnel;
10
- constructor(options) {
11
- this.options = options;
12
- }
13
- async onPrepare(config, capabilities) {
14
- if (!this.options.tbTunnel || !config.user || !config.key) {
15
- return;
16
- }
17
- const tbTunnelIdentifier = (this.options.tbTunnelOpts?.tunnelIdentifier ||
18
- `TB-tunnel-${Math.random().toString().slice(2)}`);
19
- this.tbTunnelOpts = Object.assign({
20
- apiKey: config.user,
21
- apiSecret: config.key,
22
- 'tunnel-identifier': tbTunnelIdentifier,
23
- }, this.options.tbTunnelOpts);
24
- const capabilitiesEntries = Array.isArray(capabilities) ?
25
- capabilities.every(cap => Object.values(cap).length > 0 && Object.values(cap).every(c => typeof c === 'object' && c.capabilities)) ?
26
- capabilities.flatMap((cap) => Object.values(cap))
27
- : capabilities
28
- : Object.values(capabilities);
29
- for (const capability of capabilitiesEntries) {
30
- const caps = capability.capabilities || capability;
31
- const c = caps.alwaysMatch || caps;
32
- if (!c['tb:options']) {
33
- c['tb:options'] = {};
34
- }
35
- c['tb:options']['tunnel-identifier'] = tbTunnelIdentifier;
36
- }
37
- /**
38
- * measure TestingBot tunnel boot time
39
- */
40
- const obs = new PerformanceObserver((list) => {
41
- const entry = list.getEntries()[0];
42
- log.info(`TestingBot tunnel successfully started after ${entry.duration}ms`);
43
- });
44
- obs.observe({ entryTypes: ['measure'] });
45
- performance.mark('tbTunnelStart');
46
- this.tunnel = await promisify(testingbotTunnel)(this.tbTunnelOpts);
47
- performance.mark('tbTunnelEnd');
48
- performance.measure('bootTime', 'tbTunnelStart', 'tbTunnelEnd');
49
- }
50
- /**
51
- * Shut down the tunnel
52
- * @returns {Promise} Resolved promise when tunnel is closed
53
- */
54
- onComplete() {
55
- if (!this.tunnel) {
56
- return;
57
- }
58
- return new Promise(resolve => this.tunnel.close(resolve));
59
- }
60
- }
package/build/service.js DELETED
@@ -1,218 +0,0 @@
1
- import logger from '@wdio/logger';
2
- const log = logger('@wdio/testingbot-service');
3
- const jobDataProperties = ['name', 'tags', 'public', 'build', 'extra'];
4
- export default class TestingBotService {
5
- _options;
6
- _capabilities;
7
- _config;
8
- _browser;
9
- _isServiceEnabled;
10
- _suiteTitle;
11
- _tbSecret;
12
- _tbUser;
13
- _failures = 0;
14
- _testCnt = 0;
15
- constructor(_options, _capabilities, _config) {
16
- this._options = _options;
17
- this._capabilities = _capabilities;
18
- this._config = _config;
19
- this._tbUser = this._config.user;
20
- this._tbSecret = this._config.key;
21
- this._isServiceEnabled = Boolean(this._tbUser && this._tbSecret);
22
- }
23
- before(caps, specs, browser) {
24
- this._browser = browser;
25
- }
26
- /**
27
- * Before suite
28
- * @param {object} suite Suite
29
- */
30
- beforeSuite(suite) {
31
- this._suiteTitle = suite.title;
32
- }
33
- /**
34
- * Before test
35
- * @param {object} test Test
36
- */
37
- beforeTest(test) {
38
- if (!this._isServiceEnabled || !this._browser) {
39
- return;
40
- }
41
- /**
42
- * in jasmine we get Jasmine__TopLevel__Suite as title since service using test
43
- * framework hooks in order to execute async functions.
44
- * This tweak allows us to set the real suite name for jasmine jobs.
45
- */
46
- /* istanbul ignore if */
47
- if (this._suiteTitle === 'Jasmine__TopLevel__Suite') {
48
- this._suiteTitle = test.fullName.slice(0, test.fullName.indexOf(test.title) - 1);
49
- }
50
- const context = (
51
- /**
52
- * Jasmine
53
- */
54
- test.fullName ||
55
- /**
56
- * Mocha
57
- */
58
- `${test.parent} - ${test.title}`);
59
- this._browser.execute('tb:test-context=' + context);
60
- }
61
- afterSuite(suite) {
62
- if (Object.prototype.hasOwnProperty.call(suite, 'error')) {
63
- ++this._failures;
64
- }
65
- }
66
- /**
67
- * After test
68
- * @param {object} test Test
69
- */
70
- afterTest(test, context, results) {
71
- if (!results.passed) {
72
- ++this._failures;
73
- }
74
- }
75
- /**
76
- * For CucumberJS
77
- */
78
- /**
79
- * Before feature
80
- * @param {string} uri
81
- * @param {object} feature
82
- */
83
- beforeFeature(uri, feature) {
84
- if (!this._isServiceEnabled || !this._browser) {
85
- return;
86
- }
87
- this._suiteTitle = feature.name;
88
- this._browser.execute('tb:test-context=Feature: ' + this._suiteTitle);
89
- }
90
- /**
91
- * Before scenario
92
- * @param {string} uri
93
- * @param {object} feature
94
- * @param {object} scenario
95
- */
96
- beforeScenario(world) {
97
- if (!this._isServiceEnabled || !this._browser) {
98
- return;
99
- }
100
- const scenarioName = world.pickle.name;
101
- this._browser.execute('tb:test-context=Scenario: ' + scenarioName);
102
- }
103
- /**
104
- *
105
- * Runs before a Cucumber Scenario.
106
- * @param world world object containing information on pickle and test step
107
- * @param result result object containing
108
- * @param result.passed true if scenario has passed
109
- * @param result.error error stack if scenario failed
110
- * @param result.duration duration of scenario in milliseconds
111
- */
112
- afterScenario(world, result) {
113
- // check if scenario has failed
114
- if (!result.passed) {
115
- ++this._failures;
116
- }
117
- }
118
- /**
119
- * Update TestingBot info
120
- * @return {Promise} Promise with result of updateJob method call
121
- */
122
- after(result) {
123
- if (!this._isServiceEnabled || !this._browser) {
124
- return;
125
- }
126
- let failures = this._failures;
127
- /**
128
- * set failures if user has bail option set in which case afterTest and
129
- * afterSuite aren't executed before after hook
130
- */
131
- if (this._config.mochaOpts?.bail && Boolean(result)) {
132
- failures = 1;
133
- }
134
- const status = 'status: ' + (failures > 0 ? 'failing' : 'passing');
135
- if (!this._browser.isMultiremote) {
136
- log.info(`Update job with sessionId ${this._browser.sessionId}, ${status}`);
137
- return this.updateJob(this._browser.sessionId, failures);
138
- }
139
- const browser = this._browser;
140
- return Promise.all(Object.keys(this._capabilities).map((browserName) => {
141
- log.info(`Update multiremote job for browser "${browserName}" and sessionId ${browser.getInstance(browserName).sessionId}, ${status}`);
142
- return this.updateJob(browser.getInstance(browserName).sessionId, failures, false, browserName);
143
- }));
144
- }
145
- onReload(oldSessionId, newSessionId) {
146
- if (!this._isServiceEnabled || !this._browser) {
147
- return;
148
- }
149
- const status = 'status: ' + (this._failures > 0 ? 'failing' : 'passing');
150
- if (!this._browser.isMultiremote) {
151
- log.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${status}`);
152
- return this.updateJob(oldSessionId, this._failures, true);
153
- }
154
- const browser = this._browser;
155
- const browserName = browser.instances.filter((browserName) => browser.getInstance(browserName).sessionId === newSessionId)[0];
156
- log.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${status}`);
157
- return this.updateJob(oldSessionId, this._failures, true, browserName);
158
- }
159
- async updateJob(sessionId, failures, calledOnReload = false, browserName) {
160
- if (!this._browser) {
161
- return;
162
- }
163
- let headers = {
164
- 'Content-Type': 'application/json; charset=utf-8',
165
- };
166
- if (this._tbUser && this._tbSecret) {
167
- const encodedAuth = Buffer.from(`${this._tbUser}:${this._tbSecret}`, 'utf8').toString('base64');
168
- headers = {
169
- ...headers,
170
- Authorization: `Basic ${encodedAuth}`,
171
- };
172
- }
173
- const json = this.getBody(failures, calledOnReload, browserName);
174
- this._failures = 0;
175
- const response = await fetch(this.getRestUrl(sessionId), {
176
- method: 'PUT',
177
- body: JSON.stringify(json),
178
- headers
179
- });
180
- return await response.json();
181
- }
182
- /**
183
- *
184
- * @param {String} sessionId Session id
185
- * @returns {String} TestingBot API URL
186
- */
187
- getRestUrl(sessionId) {
188
- return `https://api.testingbot.com/v1/tests/${sessionId}`;
189
- }
190
- getBody(failures, calledOnReload = false, browserName) {
191
- const body = { test: {} };
192
- /**
193
- * set default values
194
- */
195
- body.test.name = this._suiteTitle;
196
- /**
197
- * add reload count to title if reload is used
198
- */
199
- if ((calledOnReload || this._testCnt) && this._browser) {
200
- let testCnt = ++this._testCnt;
201
- if (this._browser.isMultiremote) {
202
- testCnt = Math.ceil(testCnt / this._browser.instances.length);
203
- }
204
- body.test.name += ` (${testCnt})`;
205
- }
206
- for (const prop of jobDataProperties) {
207
- if (!this._capabilities[prop]) {
208
- continue;
209
- }
210
- body.test[prop] = this._capabilities[prop];
211
- }
212
- if (browserName) {
213
- body.test.name = `${browserName}: ${body.test.name}`;
214
- }
215
- body.test.success = failures === 0 ? '1' : '0';
216
- return body;
217
- }
218
- }
package/build/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
File without changes