@wdio/browser-runner 8.12.2 → 8.13.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.
@@ -9,7 +9,7 @@ declare global {
9
9
  __wdioEvents__: any[];
10
10
  __wdioSocket__: WebSocket;
11
11
  __wdioConnectPromise__: Promise<WebSocket>;
12
- __wdioMockFactories__: Record<string, any>;
12
+ __wdioMockCache__: Map<string, any>;
13
13
  }
14
14
  }
15
15
  export declare const socket: WebSocket;
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/browser/setup.ts"],"names":[],"mappings":"AAMA,OAAO,uBAAuB,CAAA;AAI9B,KAAK,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC,CAAA;AAC9D,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,KAAK,CAAC,EAAE,GAAG,CAAA;QACX,cAAc,EAAE,cAAc,EAAE,CAAA;QAChC,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,cAAc,EAAE,GAAG,EAAE,CAAA;QACrB,cAAc,EAAE,SAAS,CAAA;QACzB,sBAAsB,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;QAC1C,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAC7C;CACJ;AAWD,eAAO,MAAM,MAAM,WAA+C,CAAA;AAClE,eAAO,MAAM,cAAc,oBAGzB,CAAA"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/browser/setup.ts"],"names":[],"mappings":"AAMA,OAAO,uBAAuB,CAAA;AAI9B,KAAK,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC,CAAA;AAC9D,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,KAAK,CAAC,EAAE,GAAG,CAAA;QACX,cAAc,EAAE,cAAc,EAAE,CAAA;QAChC,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,cAAc,EAAE,GAAG,EAAE,CAAA;QACrB,cAAc,EAAE,SAAS,CAAA;QACzB,sBAAsB,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;QAC1C,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KACtC;CACJ;AAWD,eAAO,MAAM,MAAM,WAA+C,CAAA;AAClE,eAAO,MAAM,cAAc,oBAGzB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"spy.d.ts","sourceRoot":"","sources":["../../src/browser/spy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAGrD;;GAEG;AACH,cAAc,aAAa,CAAA;AAa3B,wBAAsB,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,oBA4BxE;AAGD,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,QAExC;AAeD;;GAEG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,kBAA0C"}
1
+ {"version":3,"file":"spy.d.ts","sourceRoot":"","sources":["../../src/browser/spy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAGrD;;GAEG;AACH,cAAc,aAAa,CAAA;AAY3B,wBAAsB,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,oBA4BxE;AAGD,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,QAExC;AAeD;;GAEG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,kBAA0C"}
@@ -12,7 +12,6 @@ const ERROR_MESSAGE = '[wdio] There was an error, when mocking a module. If you
12
12
  const socket = window.__wdioSocket__;
13
13
  const mockResolver = new Map();
14
14
  const origin = window.__wdioSpec__.split('/').slice(0, -1).join('/');
15
- window.__wdioMockFactories__ = [];
16
15
  export async function mock(path, factory) {
17
16
  /**
18
17
  * mock calls without factory parameter should get removed from the source code
@@ -31,7 +30,7 @@ export async function mock(path, factory) {
31
30
  type: MESSAGE_TYPES.mockRequest,
32
31
  value: { path: mockPath, origin, namedExports: Object.keys(resolvedMock) }
33
32
  }));
34
- window.__wdioMockFactories__[mockPath] = resolvedMock;
33
+ window.__wdioMockCache__.set(mockPath, resolvedMock);
35
34
  return new Promise((resolve) => mockResolver.set(mockPath, resolve));
36
35
  }
37
36
  catch (err) {
package/build/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export default class BrowserRunner extends LocalRunner {
13
13
  * nothing to initialise when running locally
14
14
  */
15
15
  initialise(): Promise<void>;
16
- run(runArgs: RunArgs): WorkerInstance;
16
+ run(runArgs: RunArgs): Promise<WorkerInstance>;
17
17
  /**
18
18
  * shutdown vite server
19
19
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAO5C,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAS/G,OAAO,KAAK,EAAE,oBAAoB,IAAI,0BAA0B,EAAmB,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAG5H,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;;IAU9C,OAAO,CAAC,OAAO;IACf,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU;IAJzC,OAAO,CAAC,aAAa,CAAoB;gBAG7B,OAAO,EAAE,0BAA0B,EACjC,OAAO,EAAE,OAAO,CAAC,UAAU;IAuBzC;;OAEG;IACG,UAAU;IAoBhB,GAAG,CAAE,OAAO,EAAE,OAAO,GAAG,cAAc;IAwBtC;;;;OAIG;IACG,QAAQ;YA8CA,wBAAwB;CA2DzC;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,oBAAqB,SAAQ,0BAA0B;SAAG;KACvE;CACJ;AAED;;GAEG;AACH,cAAc,aAAa,CAAA;AAE3B;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAEH,wBAAgB,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,QAAI;AAEvE;;;;GAIG;AAEH,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,QAAI;AAE7C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AACnE,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AACpE,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;CAChB,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;AACnB,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;CACd,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;AACvB,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC;CAChB,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC5B,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;CACd,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAO5C,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAS/G,OAAO,KAAK,EAAE,oBAAoB,IAAI,0BAA0B,EAAmB,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAK5H,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;;IAW9C,OAAO,CAAC,OAAO;IACf,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU;IAJzC,OAAO,CAAC,aAAa,CAAoB;gBAG7B,OAAO,EAAE,0BAA0B,EACjC,OAAO,EAAE,OAAO,CAAC,UAAU;IAuBzC;;OAEG;IACG,UAAU;IAaV,GAAG,CAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAgCrD;;;;OAIG;IACG,QAAQ;YAgDA,wBAAwB;CA2DzC;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,oBAAqB,SAAQ,0BAA0B;SAAG;KACvE;CACJ;AAED;;GAEG;AACH,cAAc,aAAa,CAAA;AAE3B;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAEH,wBAAgB,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,QAAI;AAEvE;;;;GAIG;AAEH,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,QAAI;AAE7C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AACnE,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AACpE,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;CAChB,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;AACnB,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;CACd,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;AACvB,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC;CAChB,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC5B,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;IACxC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;CACd,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAAA"}
package/build/index.js CHANGED
@@ -15,8 +15,9 @@ const log = logger('@wdio/browser-runner');
15
15
  export default class BrowserRunner extends LocalRunner {
16
16
  options;
17
17
  _config;
18
+ #options;
18
19
  #config;
19
- #server;
20
+ #servers = new Set();
20
21
  #coverageOptions;
21
22
  #reportsDirectory;
22
23
  #mapStore = libSourceMap.createSourceMapStore();
@@ -28,7 +29,7 @@ export default class BrowserRunner extends LocalRunner {
28
29
  if (_config.framework !== 'mocha') {
29
30
  throw new Error(FRAMEWORK_SUPPORT_ERROR);
30
31
  }
31
- this.#server = new ViteServer(options, _config);
32
+ this.#options = options;
32
33
  this.#config = _config;
33
34
  this.#coverageOptions = options.coverage || {};
34
35
  this.#reportsDirectory = this.#coverageOptions.reportsDirectory || path.join(this.#config.rootDir, DEFAULT_REPORTS_DIRECTORY);
@@ -46,13 +47,6 @@ export default class BrowserRunner extends LocalRunner {
46
47
  */
47
48
  async initialise() {
48
49
  log.info('Initiate browser environment');
49
- try {
50
- await this.#server.start();
51
- this._config.baseUrl = `http://localhost:${this.#server.config.server?.port}`;
52
- }
53
- catch (err) {
54
- throw new Error(`Vite server failed to start: ${err.stack}`);
55
- }
56
50
  if (typeof this.#coverageOptions.clean === 'undefined' || this.#coverageOptions.clean) {
57
51
  const reportsDirectoryExist = await fs.access(this.#reportsDirectory)
58
52
  .then(() => true, () => false);
@@ -62,24 +56,32 @@ export default class BrowserRunner extends LocalRunner {
62
56
  }
63
57
  await super.initialise();
64
58
  }
65
- run(runArgs) {
59
+ async run(runArgs) {
66
60
  runArgs.caps = makeHeadless(this.options, runArgs.caps);
67
- if (runArgs.command === 'run') {
61
+ const server = new ViteServer(this.#options, this.#config);
62
+ try {
63
+ await server.start();
64
+ runArgs.args.baseUrl = `http://localhost:${server.config.server?.port}`;
65
+ }
66
+ catch (err) {
67
+ throw new Error(`Vite server failed to start: ${err.stack}`);
68
+ }
69
+ if (!runArgs.args.baseUrl && runArgs.command === 'run') {
68
70
  runArgs.args.baseUrl = this._config.baseUrl;
69
71
  }
70
- const worker = super.run(runArgs);
71
- this.#server.on('debugState', (state) => worker.postMessage('switchDebugState', state, true));
72
- this.#server.on('workerHookExecution', (payload) => {
72
+ const worker = await super.run(runArgs);
73
+ server.on('debugState', (state) => worker.postMessage('switchDebugState', state, true));
74
+ server.on('workerHookExecution', (payload) => {
73
75
  if (worker.cid !== payload.cid) {
74
76
  return;
75
77
  }
76
78
  if (worker.isKilled) {
77
79
  log.debug(`Worker with cid ${payload.cid} was killed, skipping hook execution`);
78
- return process.nextTick(() => this.#server.resolveHook(payload));
80
+ return process.nextTick(() => server.resolveHook(payload));
79
81
  }
80
82
  return worker.postMessage('workerHookExecution', payload, true);
81
83
  });
82
- worker.on('message', this.#onWorkerMessage.bind(this));
84
+ worker.on('message', (payload) => this.#onWorkerMessage(payload, server));
83
85
  return worker;
84
86
  }
85
87
  /**
@@ -89,10 +91,12 @@ export default class BrowserRunner extends LocalRunner {
89
91
  */
90
92
  async shutdown() {
91
93
  await super.shutdown();
92
- await this.#server.close();
94
+ for (const server of this.#servers) {
95
+ await server.close();
96
+ }
93
97
  return this._generateCoverageReports();
94
98
  }
95
- async #onWorkerMessage(payload) {
99
+ async #onWorkerMessage(payload, workerServer) {
96
100
  if (payload.name === 'sessionStarted' && !SESSIONS.has(payload.cid)) {
97
101
  SESSIONS.set(payload.cid, {
98
102
  args: this.#config.mochaOpts || {},
@@ -119,7 +123,7 @@ export default class BrowserRunner extends LocalRunner {
119
123
  BROWSER_POOL.delete(payload.cid);
120
124
  }
121
125
  if (payload.name === 'workerHookResult') {
122
- this.#server.resolveHook(payload.args);
126
+ workerServer.resolveHook(payload.args);
123
127
  }
124
128
  if (payload.name === 'coverageMap') {
125
129
  const cmd = payload.content.coverageMap;
@@ -1 +1 @@
1
- {"version":3,"file":"mockHoisting.d.ts","sourceRoot":"","sources":["../../../src/vite/plugins/mockHoisting.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAM7C,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,EAAE,CAmN/D"}
1
+ {"version":3,"file":"mockHoisting.d.ts","sourceRoot":"","sources":["../../../src/vite/plugins/mockHoisting.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAU7C,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,EAAE,CA2T/D"}
@@ -6,10 +6,16 @@ import logger from '@wdio/logger';
6
6
  import { parse, print, visit, types } from 'recast';
7
7
  import typescriptParser from 'recast/parsers/typescript.js';
8
8
  const log = logger('@wdio/browser-runner:mockHoisting');
9
+ const INTERNALS_TO_IGNORE = [
10
+ '@vite/client', 'vite/dist/client', '/webdriverio/build/', '/@wdio/', '/webdriverio/node_modules/',
11
+ 'virtual:wdio', '?html-proxy', '/__fixtures__/', '/__mocks__/', '/.vite/deps/@testing-library_vue.js'
12
+ ];
9
13
  const b = types.builders;
10
14
  const MOCK_PREFIX = '/@mock';
11
15
  export function mockHoisting(mockHandler) {
12
16
  let spec = null;
17
+ let isTestDependency = false;
18
+ const sessionMocks = new Set();
13
19
  return [{
14
20
  name: 'wdio:mockHoisting:pre',
15
21
  enforce: 'pre',
@@ -44,12 +50,12 @@ export function mockHoisting(mockHandler) {
44
50
  if (mockedMod) {
45
51
  const newCode = mockedMod.namedExports.map((ne) => {
46
52
  if (ne === 'default') {
47
- return /*js*/ `export default window.__wdioMockFactories__['${mockedMod.path}'].default;`;
53
+ return /*js*/ `export default window.__wdioMockCache__.get('${mockedMod.path}').default;`;
48
54
  }
49
- return /*js*/ `export const ${ne} = window.__wdioMockFactories__['${mockedMod.path}']['${ne}'];`;
55
+ return /*js*/ `export const ${ne} = window.__wdioMockCache__.get('${mockedMod.path}')['${ne}'];`;
50
56
  });
51
57
  if (!mockedMod.namedExports.includes('default')) {
52
- newCode.push(/*js*/ `export default window.__wdioMockFactories__['${mockedMod.path}'];`);
58
+ newCode.push(/*js*/ `export default window.__wdioMockCache__.get('${mockedMod.path}');`);
53
59
  }
54
60
  log.debug(`Resolve mock for module "${mockedMod.path}"`);
55
61
  return newCode.join('\n');
@@ -59,17 +65,30 @@ export function mockHoisting(mockHandler) {
59
65
  name: 'wdio:mockHoisting',
60
66
  enforce: 'post',
61
67
  transform(code, id) {
68
+ const isSpecFile = id === spec;
69
+ if (isSpecFile) {
70
+ isTestDependency = true;
71
+ }
62
72
  /**
63
- * only transform when spec file is transformed
73
+ * only transform files that are loaded as part of the test and are not
74
+ * Vite or WebdriverIO internals
64
75
  */
65
- if (id !== spec) {
76
+ if (!isTestDependency || INTERNALS_TO_IGNORE.find((f) => id.includes(f))) {
66
77
  return { code };
67
78
  }
68
- const ast = parse(code, {
69
- parser: typescriptParser,
70
- sourceFileName: id,
71
- sourceRoot: path.dirname(id)
72
- });
79
+ let ast;
80
+ try {
81
+ ast = parse(code, {
82
+ parser: typescriptParser,
83
+ sourceFileName: id,
84
+ sourceRoot: path.dirname(id)
85
+ });
86
+ }
87
+ catch (err) {
88
+ return { code };
89
+ }
90
+ log.trace(`Transform file for mocking: ${id}`);
91
+ let importIndex = 0;
73
92
  let mockFunctionName;
74
93
  let unmockFunctionName;
75
94
  const mockCalls = [];
@@ -88,6 +107,9 @@ export function mockHoisting(mockHandler) {
88
107
  visitImportDeclaration: function (path) {
89
108
  const dec = path.value;
90
109
  const source = dec.source.value;
110
+ if (!dec.specifiers || dec.specifiers.length === 0) {
111
+ return this.traverse(path);
112
+ }
91
113
  /**
92
114
  * get name of mock function variable
93
115
  */
@@ -108,67 +130,130 @@ export function mockHoisting(mockHandler) {
108
130
  path.prune();
109
131
  return this.traverse(path);
110
132
  }
111
- const newNode = b.variableDeclaration('const', [
112
- b.variableDeclarator((dec.specifiers?.length === 1 && dec.specifiers[0].type === types.namedTypes.ImportNamespaceSpecifier.toString())
113
- /**
114
- * we deal with a ImportNamespaceSpecifier, e.g.:
115
- * import * as foo from 'bar'
116
- */
117
- ? dec.specifiers[0].local
118
- /**
119
- * we deal with default or named import, e.g.
120
- * import foo from 'bar'
121
- * or
122
- * import { foo } from 'bar'
123
- */
124
- : b.objectPattern(dec.specifiers.map((s) => {
125
- if (s.type === types.namedTypes.ImportDefaultSpecifier.toString()) {
126
- return b.property('init', b.identifier('default'), b.identifier(s.local.name));
127
- }
128
- return b.property('init', b.identifier(s.imported.name), b.identifier(s.local.name));
129
- })), b.awaitExpression(b.importExpression(b.literal(source))))
130
- ]);
131
- path.replace(newNode);
132
- this.traverse(path);
133
- },
134
- visitExpressionStatement: function (path) {
135
- const exp = path.value;
136
- if (exp.expression.type !== types.namedTypes.CallExpression.toString()) {
137
- return this.traverse(path);
138
- }
139
- const callExp = exp.expression;
140
- const isUnmockCall = unmockFunctionName && callExp.callee.name === unmockFunctionName;
141
- const isMockCall = mockFunctionName && callExp.callee.name === mockFunctionName;
142
- if (!isMockCall && !isUnmockCall) {
143
- return this.traverse(path);
144
- }
133
+ const newImportIdentifier = `__wdio_import${importIndex++}`;
145
134
  /**
146
- * hoist unmock calls
135
+ * assign imports outside of spec files into custom import identifier, e.g.
136
+ *
137
+ * from:
138
+ * import { foo } from 'bar'
139
+ *
140
+ * to:
141
+ * import * as __wdio_import0 from 'bar'
147
142
  */
148
- if (isUnmockCall && callExp.arguments[0] && typeof callExp.arguments[0].value === 'string') {
149
- mockHandler.unmock(callExp.arguments[0].value);
143
+ if (!isSpecFile) {
144
+ const newNode = b.importDeclaration([b.importNamespaceSpecifier(b.identifier(newImportIdentifier))], b.literal(source));
145
+ path.insertBefore(newNode);
150
146
  }
151
- else if (isMockCall) {
147
+ const isNamespaceImport = dec.specifiers.length === 1 && dec.specifiers[0].type === types.namedTypes.ImportNamespaceSpecifier.toString();
148
+ const mockImport = isSpecFile
152
149
  /**
153
- * if only one mock argument is set, we take the fixture from the automock directory
150
+ * within spec files we transform import declarations into import expresssions, e.g.
151
+ * from: import { foo } from 'bar'
152
+ * to: const { foo } = await wdioImport('bar', await import('bar'))
153
+ *
154
+ * in order to hoist `mock(...)` calls and have them run first
154
155
  */
155
- const mockCall = exp.expression;
156
- if (mockCall.arguments.length === 1) {
156
+ ? b.variableDeclaration('const', [
157
+ b.variableDeclarator(isNamespaceImport
158
+ /**
159
+ * we deal with a ImportNamespaceSpecifier, e.g.:
160
+ * import * as foo from 'bar'
161
+ */
162
+ ? dec.specifiers[0].local
163
+ /**
164
+ * we deal with default or named import, e.g.
165
+ * import foo from 'bar'
166
+ * or
167
+ * import { foo } from 'bar'
168
+ */
169
+ : b.objectPattern(dec.specifiers.map((s) => {
170
+ if (s.type === types.namedTypes.ImportDefaultSpecifier.toString()) {
171
+ return b.property('init', b.identifier('default'), b.identifier(s.local.name));
172
+ }
173
+ return b.property('init', b.identifier(s.imported.name), b.identifier(s.local.name));
174
+ })), b.callExpression(
157
175
  /**
158
- * enable manual mock
176
+ * wrap imports into a custom function that allows us to replace the actual
177
+ * module with the mocked module
159
178
  */
160
- mockHandler.manualMocks.push(mockCall.arguments[0].value);
179
+ b.identifier('wdioImport'), [
180
+ b.literal(source),
181
+ b.awaitExpression(b.importExpression(b.literal(source)))
182
+ ]))
183
+ ])
184
+ /**
185
+ * outside of spec files we transform import declarations so that the imported module gets
186
+ * wrapped within `wdioImport`, e.g.:
187
+ *
188
+ * from:
189
+ * import { foo } from 'bar'
190
+ *
191
+ * to:
192
+ * import { foo as __wdio_import0 } from 'bar'
193
+ * const { foo } = await wdioImport('bar', __wdio_import0)
194
+ */
195
+ : b.variableDeclaration('const', [
196
+ b.variableDeclarator(dec.specifiers.length === 1 && dec.specifiers[0].type === types.namedTypes.ImportNamespaceSpecifier.toString()
197
+ ? b.identifier(dec.specifiers[0].local.name)
198
+ : b.objectPattern(dec.specifiers.map((s) => {
199
+ if (s.type === types.namedTypes.ImportDefaultSpecifier.toString()) {
200
+ return b.property('init', b.identifier('default'), b.identifier(s.local.name));
201
+ }
202
+ return b.property('init', b.identifier(s.imported.name), b.identifier(s.local.name));
203
+ })), b.callExpression(b.identifier('wdioImport'), [
204
+ b.literal(source),
205
+ b.identifier(newImportIdentifier)
206
+ ]))
207
+ ]);
208
+ path.replace(mockImport);
209
+ this.traverse(path);
210
+ },
211
+ /**
212
+ * only run the following visitor if we deal with a spec file
213
+ */
214
+ ...(isSpecFile ? {
215
+ visitExpressionStatement: function (path) {
216
+ const exp = path.value;
217
+ if (exp.expression.type !== types.namedTypes.CallExpression.toString()) {
218
+ return this.traverse(path);
219
+ }
220
+ const callExp = exp.expression;
221
+ const isUnmockCall = unmockFunctionName && callExp.callee.name === unmockFunctionName;
222
+ const isMockCall = mockFunctionName && callExp.callee.name === mockFunctionName;
223
+ if (!isMockCall && !isUnmockCall) {
224
+ return this.traverse(path);
225
+ }
226
+ /**
227
+ * hoist unmock calls
228
+ */
229
+ if (isUnmockCall && callExp.arguments[0] && typeof callExp.arguments[0].value === 'string') {
230
+ mockHandler.unmock(callExp.arguments[0].value);
161
231
  }
162
- else {
232
+ else if (isMockCall) {
163
233
  /**
164
- * hoist mock calls
234
+ * if only one mock argument is set, we take the fixture from the automock directory
165
235
  */
166
- mockCalls.push(exp);
236
+ const mockCall = exp.expression;
237
+ if (mockCall.arguments.length === 1) {
238
+ /**
239
+ * enable manual mock
240
+ */
241
+ mockHandler.manualMocks.push(mockCall.arguments[0].value);
242
+ }
243
+ else {
244
+ if (exp.expression.arguments.length) {
245
+ sessionMocks.add(exp.expression.arguments[0].value);
246
+ }
247
+ /**
248
+ * hoist mock calls
249
+ */
250
+ mockCalls.push(exp);
251
+ }
167
252
  }
253
+ path.prune();
254
+ this.traverse(path);
168
255
  }
169
- path.prune();
170
- this.traverse(path);
171
- }
256
+ } : {})
172
257
  });
173
258
  ast.program.body.unshift(...mockCalls.map((mc) => {
174
259
  const exp = mc;
@@ -177,10 +262,15 @@ export function mockHoisting(mockHandler) {
177
262
  }
178
263
  return mc;
179
264
  }));
180
- const newCode = print(ast, {
181
- sourceMapName: id
182
- });
183
- return newCode;
265
+ try {
266
+ const newCode = print(ast, {
267
+ sourceMapName: id
268
+ });
269
+ return newCode;
270
+ }
271
+ catch (err) {
272
+ return { code };
273
+ }
184
274
  },
185
275
  configureServer(server) {
186
276
  return () => {
@@ -193,6 +283,7 @@ export function mockHoisting(mockHandler) {
193
283
  const specParam = urlParamString.get('spec');
194
284
  if (specParam) {
195
285
  mockHandler.resetMocks();
286
+ isTestDependency = false;
196
287
  spec = os.platform() === 'win32' ? specParam.slice(1) : specParam;
197
288
  }
198
289
  return next();
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/vite/utils.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAI/D,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,oBAAoB,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,iBAAU,mBAiGvH;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,MAAM,gBAa7E;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAY7D;AAED,wBAAsB,qBAAqB,CAAE,GAAG,EAAE,MAAM,qBAqBvD;AAGD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,+BAgBvD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,UAU9D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/vite/utils.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAI/D,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,oBAAoB,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,iBAAU,mBA0GvH;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,MAAM,gBAa7E;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAY7D;AAED,wBAAsB,qBAAqB,CAAE,GAAG,EAAE,MAAM,qBAqBvD;AAGD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,+BAgBvD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,UAU9D"}
@@ -49,6 +49,15 @@ export async function getTemplate(options, env, spec, p = process) {
49
49
  <head>
50
50
  <title>WebdriverIO Browser Test</title>
51
51
  <link rel="icon" type="image/x-icon" href="https://webdriver.io/img/favicon.png">
52
+ <script type="module">
53
+ window.__wdioMockCache__ = new Map()
54
+ window.wdioImport = function (modName, mod) {
55
+ if (window.__wdioMockCache__.get(modName)) {
56
+ return window.__wdioMockCache__.get(modName)
57
+ }
58
+ return mod
59
+ }
60
+ </script>
52
61
  <script type="module" src="/node_modules/mocha/mocha.js"></script>
53
62
  ${sourceMapScript}
54
63
  <script type="module">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/browser-runner",
3
- "version": "8.12.2",
3
+ "version": "8.13.0",
4
4
  "description": "A WebdriverIO runner to run unit tests tests in the browser.",
5
5
  "author": "Christian Bromann <mail@bromann.dev>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-browser-runner",
@@ -35,8 +35,8 @@
35
35
  "@types/istanbul-lib-source-maps": "^4.0.1",
36
36
  "@types/node": "^20.1.0",
37
37
  "@vitest/spy": "^0.33.0",
38
- "@wdio/globals": "8.12.1",
39
- "@wdio/local-runner": "8.12.1",
38
+ "@wdio/globals": "8.13.0",
39
+ "@wdio/local-runner": "8.13.0",
40
40
  "@wdio/logger": "8.11.0",
41
41
  "@wdio/mocha-framework": "8.12.1",
42
42
  "@wdio/protocols": "8.11.0",
@@ -59,8 +59,8 @@
59
59
  "vite": "~4.2.0",
60
60
  "vite-plugin-istanbul": "^4.0.1",
61
61
  "vite-plugin-top-level-await": "^1.3.0",
62
- "webdriver": "8.12.1",
63
- "webdriverio": "8.12.1",
62
+ "webdriver": "8.13.0",
63
+ "webdriverio": "8.13.0",
64
64
  "ws": "^8.13.0"
65
65
  },
66
66
  "scripts": {
@@ -71,7 +71,7 @@
71
71
  },
72
72
  "devDependencies": {
73
73
  "@types/ws": "^8.5.4",
74
- "@wdio/runner": "8.12.1"
74
+ "@wdio/runner": "8.13.0"
75
75
  },
76
- "gitHead": "a625a704f75cac182b0312d05f0b6f62cd719544"
76
+ "gitHead": "f16d03f0d7dc3beb55e3ab9b61d3ad50f90dccfd"
77
77
  }