@wdio/runner 8.28.4 → 8.28.7

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.
@@ -23,7 +23,7 @@ export default class BrowserFramework implements Omit<TestFramework, 'init'> {
23
23
  sessionId?: string;
24
24
  }, _specs: string[], _capabilities: Capabilities.RemoteCapability, _reporter: BaseReporter);
25
25
  /**
26
- * always return true as it is unrelevant for component testing
26
+ * always return true as it is irrelevant for component testing
27
27
  */
28
28
  hasTests(): boolean;
29
29
  init(): TestFramework;
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,YAAY,EAAgB,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAA;AAGzG,OAAO,KAAK,YAAY,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAyB,MAAM,YAAY,CAAA;AAMtE,KAAK,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC,GAAG;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAO9G,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,cAAc,EAAE,cAAc,EAAE,CAAA;QAChC,cAAc,EAAE,GAAG,EAAE,CAAA;QACrB,gBAAgB,EAAE,MAAM,CAAA;QACxB,YAAY,CAAC,EAAE,OAAO,CAAA;KACzB;CACJ;AAID,MAAM,CAAC,OAAO,OAAO,gBAAiB,YAAW,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;;IAKpE,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,SAAS;gBAJT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,UAAU,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EACpD,MAAM,EAAE,MAAM,EAAE,EAChB,aAAa,EAAE,YAAY,CAAC,gBAAgB,EAC5C,SAAS,EAAE,YAAY;IASnC;;OAEG;IACH,QAAQ;IAIR,IAAI;IAIE,GAAG;IAuVT,MAAM,CAAC,IAAI,CAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,gBAAgB,EAAE,QAAQ,EAAE,YAAY;CAItH"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,YAAY,EAAgB,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAA;AAGzG,OAAO,KAAK,YAAY,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAyB,MAAM,YAAY,CAAA;AAOtE,KAAK,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC,GAAG;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAQ9G,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,cAAc,EAAE,cAAc,EAAE,CAAA;QAChC,cAAc,EAAE,GAAG,EAAE,CAAA;QACrB,gBAAgB,EAAE,MAAM,CAAA;QACxB,YAAY,CAAC,EAAE,OAAO,CAAA;KACzB;CACJ;AAED,MAAM,CAAC,OAAO,OAAO,gBAAiB,YAAW,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;;IAMpE,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,SAAS;gBAJT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,UAAU,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EACpD,MAAM,EAAE,MAAM,EAAE,EAChB,aAAa,EAAE,YAAY,CAAC,gBAAgB,EAC5C,SAAS,EAAE,YAAY;IAiBnC;;OAEG;IACH,QAAQ;IAIR,IAAI;IAIE,GAAG;IAgVT,MAAM,CAAC,IAAI,CAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,gBAAgB,EAAE,QAAQ,EAAE,YAAY;CAItH"}
package/build/browser.js CHANGED
@@ -8,16 +8,17 @@ import { MESSAGE_TYPES } from '@wdio/types';
8
8
  import { transformExpectArgs } from './utils.js';
9
9
  const log = logger('@wdio/runner');
10
10
  const sep = '\n - ';
11
+ const ERROR_CHECK_INTERVAL = 500;
11
12
  const DEFAULT_TIMEOUT = 60 * 1000;
12
- const sleep = (ms = 100) => new Promise((resolve) => setTimeout(resolve, ms));
13
13
  export default class BrowserFramework {
14
14
  _cid;
15
15
  _config;
16
16
  _specs;
17
17
  _capabilities;
18
18
  _reporter;
19
- #inDebugMode = false;
20
19
  #runnerOptions; // `any` here because we don't want to create a dependency to @wdio/browser-runner
20
+ #testStatePromise;
21
+ #resolveTestStatePromise;
21
22
  constructor(_cid, _config, _specs, _capabilities, _reporter) {
22
23
  this._cid = _cid;
23
24
  this._config = _config;
@@ -28,9 +29,16 @@ export default class BrowserFramework {
28
29
  process.on('message', this.#processMessage.bind(this));
29
30
  const [, runnerOptions] = Array.isArray(_config.runner) ? _config.runner : [];
30
31
  this.#runnerOptions = runnerOptions || {};
32
+ /**
33
+ * create promise to resolve test state which is being sent through the socket
34
+ * connection from the browser through the main process to the worker
35
+ */
36
+ this.#testStatePromise = new Promise((resolve) => {
37
+ this.#resolveTestStatePromise = resolve;
38
+ });
31
39
  }
32
40
  /**
33
- * always return true as it is unrelevant for component testing
41
+ * always return true as it is irrelevant for component testing
34
42
  */
35
43
  hasTests() {
36
44
  return true;
@@ -89,46 +97,14 @@ export default class BrowserFramework {
89
97
  /**
90
98
  * wait for test results or page errors
91
99
  */
92
- let state = {};
93
- const now = Date.now();
94
- await browser.waitUntil(async () => {
95
- while (typeof state.failures !== 'number' && (!state.errors || state.errors.length === 0)) {
96
- if ((Date.now() - now) > timeout) {
97
- return false;
98
- }
99
- await sleep();
100
- /**
101
- * don't fetch events if user has called debug command
102
- */
103
- if (this.#inDebugMode) {
104
- continue;
105
- }
106
- state = await browser?.execute(function fetchExecutionState() {
107
- const failures = window.__wdioEvents__ && window.__wdioEvents__.length > 0
108
- ? window.__wdioFailures__
109
- : null;
110
- let viteError;
111
- const viteErrorElem = document.querySelector('vite-error-overlay');
112
- if (viteErrorElem && viteErrorElem.shadowRoot) {
113
- const errorElements = Array.from(viteErrorElem.shadowRoot.querySelectorAll('pre'));
114
- if (errorElements.length) {
115
- viteError = [{ message: errorElements.map((elem) => elem.innerText).join('\n') }];
116
- }
117
- }
118
- const loadError = (typeof window.__wdioErrors__ === 'undefined' &&
119
- document.title !== 'WebdriverIO Browser Test' &&
120
- !document.querySelector('mocha-framework'))
121
- ? [{ message: `Failed to load test page (title = "${document.title}", source: ${document.documentElement.innerHTML})` }]
122
- : null;
123
- const errors = viteError || window.__wdioErrors__ || loadError;
124
- return { failures, errors, hasViteError: Boolean(viteError) };
125
- }).catch((err) => ({ errors: [{ message: err.message }] }));
126
- }
127
- return true;
128
- }, {
129
- timeoutMsg: 'browser test timed out',
130
- timeout
131
- });
100
+ const testTimeout = setTimeout(() => this.#onTestTimeout(`Timed out after ${timeout / 1000}s waiting for test results`), timeout);
101
+ /**
102
+ * run checks for errors here to avoid breakage in communication with the browser
103
+ */
104
+ const errorInterval = setInterval(this.#checkForTestError.bind(this), ERROR_CHECK_INTERVAL);
105
+ const state = await this.#testStatePromise;
106
+ clearTimeout(testTimeout);
107
+ clearInterval(errorInterval);
132
108
  /**
133
109
  * capture coverage if enabled
134
110
  */
@@ -144,6 +120,9 @@ export default class BrowserFramework {
144
120
  };
145
121
  process.send(workerEvent);
146
122
  }
123
+ /**
124
+ * let runner fail if we detect an error
125
+ */
147
126
  if (state.errors?.length) {
148
127
  const errors = state.errors.map((ev) => state.hasViteError
149
128
  ? `${ev.message}\n${(ev.error ? ev.error.split('\n').slice(1).join('\n') : '')}`
@@ -165,15 +144,10 @@ export default class BrowserFramework {
165
144
  });
166
145
  return 1;
167
146
  }
168
- await this.#fetchEvents(browser, spec);
169
- return state.failures || 0;
170
- }
171
- async #fetchEvents(browser, spec) {
172
147
  /**
173
- * populate events to the reporter
148
+ * report browser events to WebdriverIO reporter
174
149
  */
175
- const events = await browser.execute(() => window.__wdioEvents__);
176
- for (const ev of events) {
150
+ for (const ev of (state.events || [])) {
177
151
  if ((ev.type === 'suite:start' || ev.type === 'suite:end') && ev.title === '') {
178
152
  continue;
179
153
  }
@@ -184,16 +158,13 @@ export default class BrowserFramework {
184
158
  cid: this._cid
185
159
  });
186
160
  }
161
+ return state.failures || 0;
187
162
  }
188
163
  async #processMessage(cmd) {
189
164
  if (cmd.command !== 'workerRequest' || !process.send) {
190
165
  return;
191
166
  }
192
167
  const { message, id } = cmd.args;
193
- if (message.type === MESSAGE_TYPES.switchDebugState) {
194
- this.#inDebugMode = message.value;
195
- return;
196
- }
197
168
  if (message.type === MESSAGE_TYPES.hookTriggerMessage) {
198
169
  return this.#handleHook(id, message.value);
199
170
  }
@@ -206,6 +177,9 @@ export default class BrowserFramework {
206
177
  if (message.type === MESSAGE_TYPES.expectRequestMessage) {
207
178
  return this.#handleExpectation(id, message.value);
208
179
  }
180
+ if (message.type === MESSAGE_TYPES.browserTestResult) {
181
+ return this.#handleTestFinish(message.value);
182
+ }
209
183
  }
210
184
  async #handleHook(id, payload) {
211
185
  const error = await executeHooksWithArgs(payload.name, this._config[payload.name], payload.args).then(() => undefined, (err) => err);
@@ -251,12 +225,6 @@ export default class BrowserFramework {
251
225
  const error = { message, stack, name: 'Error' };
252
226
  return this.#sendWorkerResponse(id, this.#commandResponse({ id: payload.id, error }));
253
227
  }
254
- /**
255
- * emit debug state to be enabled to runner so it can be propagated to the worker
256
- */
257
- if (payload.commandName === 'debug') {
258
- this.#inDebugMode = true;
259
- }
260
228
  try {
261
229
  /**
262
230
  * double check if function is registered
@@ -266,12 +234,6 @@ export default class BrowserFramework {
266
234
  }
267
235
  const result = await browser[payload.commandName](...payload.args);
268
236
  const resultMsg = this.#commandResponse({ id: payload.id, result });
269
- /**
270
- * emit debug state to be disabled to runner so it can be propagated to the worker
271
- */
272
- if (payload.commandName === 'debug') {
273
- this.#inDebugMode = false;
274
- }
275
237
  log.debug(`Return command result: ${resultMsg}`);
276
238
  return this.#sendWorkerResponse(id, resultMsg);
277
239
  }
@@ -335,6 +297,42 @@ export default class BrowserFramework {
335
297
  value
336
298
  };
337
299
  }
300
+ #handleTestFinish(payload) {
301
+ this.#resolveTestStatePromise({ failures: payload.failures, events: payload.events });
302
+ }
303
+ #onTestTimeout(message) {
304
+ return this.#resolveTestStatePromise?.({
305
+ events: [],
306
+ failures: 1,
307
+ errors: [{ message }]
308
+ });
309
+ }
310
+ async #checkForTestError() {
311
+ const testError = await browser.execute(function fetchExecutionState() {
312
+ let viteError;
313
+ const viteErrorElem = document.querySelector('vite-error-overlay');
314
+ if (viteErrorElem && viteErrorElem.shadowRoot) {
315
+ const errorElements = Array.from(viteErrorElem.shadowRoot.querySelectorAll('pre'));
316
+ if (errorElements.length) {
317
+ viteError = [{ message: errorElements.map((elem) => elem.innerText).join('\n') }];
318
+ }
319
+ }
320
+ const loadError = (typeof window.__wdioErrors__ === 'undefined' &&
321
+ document.title !== 'WebdriverIO Browser Test' &&
322
+ !document.querySelector('mocha-framework'))
323
+ ? [{ message: `Failed to load test page (title = "${document.title}", source: ${document.documentElement.innerHTML})` }]
324
+ : null;
325
+ const errors = viteError || window.__wdioErrors__ || loadError;
326
+ return { errors, hasViteError: Boolean(viteError) };
327
+ });
328
+ if ((testError.errors && testError.errors.length > 0) || testError.hasViteError) {
329
+ this.#resolveTestStatePromise?.({
330
+ events: [],
331
+ failures: 1,
332
+ ...testError
333
+ });
334
+ }
335
+ }
338
336
  static init(cid, config, specs, caps, reporter) {
339
337
  const framework = new BrowserFramework(cid, config, specs, caps, reporter);
340
338
  return framework;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/runner",
3
- "version": "8.28.4",
3
+ "version": "8.28.7",
4
4
  "description": "A WebdriverIO service that runs tests in arbitrary environments",
5
5
  "author": "Christian Bromann <mail@bromann.dev>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-runner",
@@ -30,19 +30,19 @@
30
30
  "typeScriptVersion": "3.8.3",
31
31
  "dependencies": {
32
32
  "@types/node": "^20.1.0",
33
- "@wdio/config": "8.28.0",
34
- "@wdio/globals": "8.28.4",
33
+ "@wdio/config": "8.28.6",
34
+ "@wdio/globals": "8.28.6",
35
35
  "@wdio/logger": "8.28.0",
36
- "@wdio/types": "8.28.0",
37
- "@wdio/utils": "8.28.0",
36
+ "@wdio/types": "8.28.6",
37
+ "@wdio/utils": "8.28.6",
38
38
  "deepmerge-ts": "^5.0.0",
39
39
  "expect-webdriverio": "^4.8.0",
40
40
  "gaze": "^1.1.2",
41
- "webdriver": "8.28.0",
42
- "webdriverio": "8.28.4"
41
+ "webdriver": "8.28.6",
42
+ "webdriverio": "8.28.6"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
- "gitHead": "fbb60e474d2565447f43016ebc7444b679f85ff1"
47
+ "gitHead": "17828852f2b687ee32eaa1a16dbd14d0fd9ec58b"
48
48
  }