@wdio/browser-runner 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.
Files changed (47) hide show
  1. package/build/browser/driver.js +249 -234
  2. package/build/browser/expect.js +107 -148
  3. package/build/browser/frameworks/mocha.d.ts.map +1 -1
  4. package/build/browser/integrations/stencil.js +370 -407
  5. package/build/browser/mock.d.ts +3 -2
  6. package/build/browser/mock.d.ts.map +1 -1
  7. package/build/browser/mock.js +78 -34
  8. package/build/browser/setup.js +313 -37
  9. package/build/browser/spy.d.ts.map +1 -1
  10. package/build/browser/spy.js +29 -40
  11. package/build/browser/utils.d.ts +7 -0
  12. package/build/browser/utils.d.ts.map +1 -1
  13. package/build/index.d.ts.map +1 -1
  14. package/build/index.js +1465 -171
  15. package/build/types.d.ts +19 -2
  16. package/build/types.d.ts.map +1 -1
  17. package/build/utils.d.ts +3 -3
  18. package/build/utils.d.ts.map +1 -1
  19. package/build/vite/constants.d.ts +3 -0
  20. package/build/vite/constants.d.ts.map +1 -1
  21. package/build/vite/plugins/esbuild.d.ts.map +1 -1
  22. package/build/vite/plugins/testrunner.d.ts.map +1 -1
  23. package/build/vite/server.d.ts +0 -1
  24. package/build/vite/server.d.ts.map +1 -1
  25. package/build/vite/utils.d.ts.map +1 -1
  26. package/package.json +57 -26
  27. package/build/browser/commands/debug.js +0 -6
  28. package/build/browser/frameworks/mocha.js +0 -320
  29. package/build/browser/utils.js +0 -61
  30. package/build/communicator.js +0 -82
  31. package/build/constants.js +0 -89
  32. package/build/types.js +0 -1
  33. package/build/utils.js +0 -86
  34. package/build/vite/constants.js +0 -55
  35. package/build/vite/frameworks/index.js +0 -19
  36. package/build/vite/frameworks/nuxt.js +0 -61
  37. package/build/vite/frameworks/stencil.js +0 -165
  38. package/build/vite/frameworks/tailwindcss.js +0 -28
  39. package/build/vite/mock.js +0 -50
  40. package/build/vite/plugins/esbuild.js +0 -25
  41. package/build/vite/plugins/mockHoisting.js +0 -312
  42. package/build/vite/plugins/testrunner.js +0 -152
  43. package/build/vite/plugins/worker.js +0 -12
  44. package/build/vite/server.js +0 -104
  45. package/build/vite/types.js +0 -1
  46. package/build/vite/utils.js +0 -223
  47. /package/{LICENSE-MIT → LICENSE} +0 -0
@@ -1,312 +0,0 @@
1
- import os from 'node:os';
2
- import url from 'node:url';
3
- import path from 'node:path';
4
- import fs from 'node:fs/promises';
5
- import logger from '@wdio/logger';
6
- import { parse, print, visit, types } from 'recast';
7
- import typescriptParser from 'recast/parsers/typescript.js';
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
- ];
13
- const b = types.builders;
14
- const MOCK_PREFIX = '/@mock';
15
- export function mockHoisting(mockHandler) {
16
- let spec = null;
17
- let isTestDependency = false;
18
- const sessionMocks = new Set();
19
- const importMap = new Map();
20
- return [{
21
- name: 'wdio:mockHoisting:pre',
22
- enforce: 'pre',
23
- resolveId: mockHandler.resolveId.bind(mockHandler),
24
- load: async function (id) {
25
- if (id.startsWith(MOCK_PREFIX)) {
26
- try {
27
- const orig = await fs.readFile(id.slice(MOCK_PREFIX.length + (os.platform() === 'win32' ? 1 : 0)));
28
- return orig.toString();
29
- }
30
- catch (err) {
31
- log.error(`Failed to read file (${id}) for mocking: ${err.message}`);
32
- return '';
33
- }
34
- }
35
- }
36
- }, {
37
- name: 'wdio:mockHoisting',
38
- enforce: 'post',
39
- transform(code, id) {
40
- const isSpecFile = id === spec;
41
- if (isSpecFile) {
42
- isTestDependency = true;
43
- }
44
- /**
45
- * only transform files:
46
- */
47
- if (
48
- // where loading was inititated through the test file
49
- (!isTestDependency && (
50
- // however when files are inlined they will be loaded when parsing file under test
51
- // in this case we want to transform them, but make sure we exclude these paths
52
- id.includes('/node_modules/') || id.includes('/?cid=') || id.startsWith('virtual:'))) ||
53
- // are not Vite or WebdriverIO internals
54
- INTERNALS_TO_IGNORE.find((f) => id.includes(f)) ||
55
- // when the spec file is actually mocking any dependencies
56
- (!isSpecFile && sessionMocks.size === 0)) {
57
- return { code };
58
- }
59
- let ast;
60
- const start = Date.now();
61
- try {
62
- ast = parse(code, {
63
- parser: typescriptParser,
64
- sourceFileName: id,
65
- sourceRoot: path.dirname(id)
66
- });
67
- log.trace(`Parsed file for mocking: ${id} in ${Date.now() - start}ms`);
68
- }
69
- catch (err) {
70
- return { code };
71
- }
72
- let importIndex = 0;
73
- let mockFunctionName;
74
- let unmockFunctionName;
75
- const mockCalls = [];
76
- visit(ast, {
77
- /**
78
- * find function name for mock and unmock calls
79
- */
80
- visitImportDeclaration: function (path) {
81
- const dec = path.value;
82
- const source = dec.source.value;
83
- if (!dec.specifiers || dec.specifiers.length === 0 || source !== '@wdio/browser-runner') {
84
- return this.traverse(path);
85
- }
86
- /**
87
- * get name of mock function variable
88
- */
89
- const mockSpecifier = dec.specifiers
90
- .filter((s) => s.type === types.namedTypes.ImportSpecifier.toString())
91
- .find((s) => s.imported.name === 'mock');
92
- if (mockSpecifier && mockSpecifier.local) {
93
- mockFunctionName = mockSpecifier.local.name;
94
- }
95
- const unmockSpecifier = dec.specifiers
96
- .filter((s) => s.type === types.namedTypes.ImportSpecifier.toString())
97
- .find((s) => s.imported.name === 'unmock');
98
- if (unmockSpecifier && unmockSpecifier.local) {
99
- unmockFunctionName = unmockSpecifier.local.name;
100
- }
101
- mockCalls.push(dec);
102
- path.prune();
103
- return this.traverse(path);
104
- },
105
- /**
106
- * detect which modules are supposed to be mocked
107
- */
108
- ...(isSpecFile ? {
109
- visitExpressionStatement: function (path) {
110
- const exp = path.value;
111
- if (exp.expression.type !== types.namedTypes.CallExpression.toString()) {
112
- return this.traverse(path);
113
- }
114
- const callExp = exp.expression;
115
- const isUnmockCall = unmockFunctionName && callExp.callee.name === unmockFunctionName;
116
- const isMockCall = mockFunctionName && callExp.callee.name === mockFunctionName;
117
- if (!isMockCall && !isUnmockCall) {
118
- return this.traverse(path);
119
- }
120
- /**
121
- * hoist unmock calls
122
- */
123
- if (isUnmockCall && callExp.arguments[0] && typeof callExp.arguments[0].value === 'string') {
124
- mockHandler.unmock(callExp.arguments[0].value);
125
- }
126
- else if (isMockCall) {
127
- /**
128
- * if only one mock argument is set, we take the fixture from the automock directory
129
- */
130
- const mockCall = exp.expression;
131
- if (mockCall.arguments.length === 1) {
132
- /**
133
- * enable manual mock
134
- */
135
- mockHandler.manualMocks.push(mockCall.arguments[0].value);
136
- }
137
- else {
138
- if (exp.expression.arguments.length) {
139
- sessionMocks.add(exp.expression.arguments[0].value);
140
- }
141
- /**
142
- * hoist mock calls
143
- */
144
- mockCalls.push(exp);
145
- }
146
- }
147
- path.prune();
148
- this.traverse(path);
149
- }
150
- } : {})
151
- });
152
- visit(ast, {
153
- /**
154
- * rewrite import statements
155
- */
156
- visitImportDeclaration: function (nodePath) {
157
- const dec = nodePath.value;
158
- const source = dec.source.value;
159
- if (!dec.specifiers || dec.specifiers.length === 0) {
160
- return this.traverse(nodePath);
161
- }
162
- const newImportIdentifier = `__wdio_import${importIndex++}`;
163
- const isMockedModule = Boolean(
164
- // matches if a dependency is mocked
165
- sessionMocks.has(source) ||
166
- // matches if a relative file is mocked
167
- (source.startsWith('.') &&
168
- [...sessionMocks.values()].find((m) => {
169
- const fileImportPath = path.resolve(path.dirname(id), source);
170
- const fileImportPathSliced = fileImportPath.slice(0, path.extname(fileImportPath).length * -1);
171
- const testMockPath = path.resolve(path.dirname(spec || '/'), m);
172
- const testMockPathSliced = testMockPath.slice(0, path.extname(testMockPath).length * -1);
173
- return fileImportPathSliced === testMockPathSliced && fileImportPathSliced.length > 0;
174
- })));
175
- /**
176
- * add to import map if module is mocked and imported in the test file
177
- */
178
- if (isMockedModule && isSpecFile) {
179
- importMap.set(source, newImportIdentifier);
180
- }
181
- /**
182
- * Assign imports outside of spec files or when module gets mocked
183
- * into custom import identifier, e.g.
184
- *
185
- * from:
186
- * import { foo } from 'bar'
187
- *
188
- * to:
189
- * import * as __wdio_import0 from 'bar'
190
- */
191
- if (!isSpecFile || isMockedModule) {
192
- const newNode = b.importDeclaration([b.importNamespaceSpecifier(b.identifier(newImportIdentifier))], b.literal(source));
193
- mockCalls.unshift(newNode);
194
- }
195
- // determine file extension length so we can cut it out, fall back to infinity if no extension is set
196
- const mockExtensionLengh = (path.extname(source).length * -1) || Infinity;
197
- const wdioImportModuleIdentifier = source.startsWith('.') || source.startsWith('/')
198
- ? url.pathToFileURL(path.resolve(path.dirname(id), source).slice(0, mockExtensionLengh)).pathname
199
- : source;
200
- const isNamespaceImport = dec.specifiers.length === 1 && dec.specifiers[0].type === types.namedTypes.ImportNamespaceSpecifier.toString();
201
- const mockImport = isSpecFile && !isMockedModule
202
- /**
203
- * within spec files we transform import declarations into import expresssions, e.g.
204
- * from: import { foo } from 'bar'
205
- * to: const { foo } = await wdioImport('bar', await import('bar'))
206
- *
207
- * in order to hoist `mock(...)` calls and have them run first
208
- */
209
- ? b.variableDeclaration('const', [
210
- b.variableDeclarator(isNamespaceImport
211
- /**
212
- * we deal with a ImportNamespaceSpecifier, e.g.:
213
- * import * as foo from 'bar'
214
- */
215
- ? dec.specifiers[0].local
216
- /**
217
- * we deal with default or named import, e.g.
218
- * import foo from 'bar'
219
- * or
220
- * import { foo } from 'bar'
221
- */
222
- : b.objectPattern(dec.specifiers.map((s) => {
223
- if (s.type === types.namedTypes.ImportDefaultSpecifier.toString()) {
224
- return b.property('init', b.identifier('default'), b.identifier(s.local.name));
225
- }
226
- return b.property('init', b.identifier(s.imported.name), b.identifier(s.local.name));
227
- })), b.awaitExpression(b.importExpression(b.literal(source))))
228
- ])
229
- /**
230
- * outside of spec files we transform import declarations so that the imported module gets
231
- * wrapped within `wdioImport`, e.g.:
232
- *
233
- * from:
234
- * import { foo } from 'bar'
235
- *
236
- * to:
237
- * import { foo as __wdio_import0 } from 'bar'
238
- * const { foo } = await wdioImport('bar', __wdio_import0)
239
- */
240
- : b.variableDeclaration('const', [
241
- b.variableDeclarator(dec.specifiers.length === 1 && dec.specifiers[0].type === types.namedTypes.ImportNamespaceSpecifier.toString()
242
- ? b.identifier(dec.specifiers[0].local.name)
243
- : b.objectPattern(dec.specifiers.map((s) => {
244
- if (s.type === types.namedTypes.ImportDefaultSpecifier.toString()) {
245
- return b.property('init', b.identifier('default'), b.identifier(s.local.name));
246
- }
247
- return b.property('init', b.identifier(s.imported.name), b.identifier(s.local.name));
248
- })), b.callExpression(b.identifier('wdioImport'), [
249
- b.literal(wdioImportModuleIdentifier),
250
- b.identifier(newImportIdentifier)
251
- ]))
252
- ]);
253
- nodePath.replace(mockImport);
254
- this.traverse(nodePath);
255
- }
256
- });
257
- ast.program.body.unshift(...mockCalls.map((mc) => {
258
- const exp = mc;
259
- if (exp.expression && exp.expression.type === types.namedTypes.CallExpression.toString()) {
260
- const mockCallExpression = exp.expression;
261
- const mockedModule = mockCallExpression.arguments[0].value;
262
- const mockFactory = mockCallExpression.arguments[1];
263
- /**
264
- * add actual module as 3rd parameter to the mock call if imported in the same test file
265
- */
266
- if (importMap.has(mockedModule)) {
267
- mockCallExpression.arguments.push(b.identifier(importMap.get(mockedModule)));
268
- }
269
- else if (mockFactory.params.length > 0) {
270
- /**
271
- * `importMap` only has an entry if the module is imported in the same test file.
272
- * However if the user mocks a dependency of a different dependency we need to add
273
- * the import manually if the users wants to access the original module.
274
- */
275
- const newImportIdentifier = `__wdio_import${importIndex++}`;
276
- ast.program.body.unshift(b.importDeclaration([b.importNamespaceSpecifier(b.identifier(newImportIdentifier))], b.literal(mockedModule)));
277
- mockCallExpression.arguments.push(b.identifier(newImportIdentifier));
278
- }
279
- return b.expressionStatement(b.awaitExpression(mockCallExpression));
280
- }
281
- return mc;
282
- }));
283
- try {
284
- const newCode = print(ast, { sourceMapName: id });
285
- log.trace(`Transformed file for mocking: ${id} in ${Date.now() - start}ms`);
286
- return newCode;
287
- }
288
- catch (err) {
289
- log.trace(`Failed to transformed file (${id}) for mocking: ${err.stack}`);
290
- return { code };
291
- }
292
- },
293
- configureServer(server) {
294
- return () => {
295
- server.middlewares.use('/', async (req, res, next) => {
296
- if (!req.originalUrl) {
297
- return next();
298
- }
299
- const urlParsed = url.parse(req.originalUrl);
300
- const urlParamString = new URLSearchParams(urlParsed.query || '');
301
- const specParam = urlParamString.get('spec');
302
- if (specParam) {
303
- mockHandler.resetMocks();
304
- isTestDependency = false;
305
- spec = os.platform() === 'win32' ? specParam.slice(1) : specParam;
306
- }
307
- return next();
308
- });
309
- };
310
- }
311
- }];
312
- }
@@ -1,152 +0,0 @@
1
- import url from 'node:url';
2
- import path from 'node:path';
3
- import { builtinModules } from 'node:module';
4
- import logger from '@wdio/logger';
5
- import { polyfillPath } from 'modern-node-polyfills';
6
- import { deepmerge } from 'deepmerge-ts';
7
- import { resolve } from 'import-meta-resolve';
8
- import { WebDriverProtocol, MJsonWProtocol, AppiumProtocol, ChromiumProtocol, SauceLabsProtocol, SeleniumProtocol, GeckoProtocol } from '@wdio/protocols';
9
- import { SESSIONS } from '../../constants.js';
10
- import { getTemplate, getErrorTemplate, normalizeId } from '../utils.js';
11
- const log = logger('@wdio/browser-runner:plugin');
12
- const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
13
- const commands = deepmerge(WebDriverProtocol, MJsonWProtocol, AppiumProtocol, ChromiumProtocol, SauceLabsProtocol, SeleniumProtocol, GeckoProtocol);
14
- const protocolCommandList = Object.values(commands).map((endpoint) => Object.values(endpoint).map(({ command }) => command)).flat();
15
- const WDIO_PACKAGES = ['webdriverio', 'expect-webdriverio'];
16
- const virtualModuleId = 'virtual:wdio';
17
- const resolvedVirtualModuleId = '\0' + virtualModuleId;
18
- /**
19
- * these modules are used in Node.js environments only and
20
- * don't need to be compiled, we just have them point to a
21
- * mocked module that returns a matching interface without
22
- * functionality
23
- */
24
- const MODULES_TO_MOCK = [
25
- 'import-meta-resolve', 'puppeteer-core', 'archiver', 'glob', 'ws', 'decamelize',
26
- 'geckodriver', 'safaridriver', 'edgedriver', '@puppeteer/browsers', 'locate-app', 'wait-port',
27
- 'lodash.isequal', '@wdio/repl'
28
- ];
29
- const POLYFILLS = [
30
- ...builtinModules,
31
- ...builtinModules.map((m) => `node:${m}`)
32
- ];
33
- export function testrunner(options) {
34
- const browserModules = path.resolve(__dirname, '..', '..', 'browser');
35
- const automationProtocolPath = `/@fs${url.pathToFileURL(path.resolve(browserModules, 'driver.js')).pathname}`;
36
- const mockModulePath = path.resolve(browserModules, 'mock.js');
37
- const setupModulePath = path.resolve(browserModules, 'setup.js');
38
- const spyModulePath = path.resolve(browserModules, 'spy.js');
39
- const wdioExpectModulePath = path.resolve(browserModules, 'expect.js');
40
- return [{
41
- name: 'wdio:testrunner',
42
- enforce: 'pre',
43
- resolveId: async (id) => {
44
- if (id === virtualModuleId) {
45
- return resolvedVirtualModuleId;
46
- }
47
- if (POLYFILLS.includes(id)) {
48
- return polyfillPath(normalizeId(id.replace('/promises', '')));
49
- }
50
- /**
51
- * fake the content of this package and load the implementation of the mock
52
- * features from the browser module directory
53
- */
54
- if (id === '@wdio/browser-runner') {
55
- return spyModulePath;
56
- }
57
- /**
58
- * allow to load the setup script from a script tag
59
- */
60
- if (id.endsWith('@wdio/browser-runner/setup')) {
61
- return setupModulePath;
62
- }
63
- /**
64
- * run WebdriverIO assertions within the Node.js context so we can do things like
65
- * visual assertions or snapshot testing
66
- */
67
- if (id === 'expect-webdriverio') {
68
- return wdioExpectModulePath;
69
- }
70
- /**
71
- * make sure WDIO imports are resolved properly as ESM module
72
- */
73
- if (id.startsWith('@wdio') || WDIO_PACKAGES.includes(id)) {
74
- return url.fileURLToPath(await resolve(id, import.meta.url));
75
- }
76
- /**
77
- * mock out imports that we can't transpile into browser land
78
- */
79
- if (MODULES_TO_MOCK.includes(id)) {
80
- return mockModulePath;
81
- }
82
- },
83
- load(id) {
84
- /**
85
- * provide a list of protocol commands to generate the prototype in the browser
86
- */
87
- if (id === resolvedVirtualModuleId) {
88
- return /*js*/ `
89
- import { fn } from '@wdio/browser-runner'
90
- export const commands = ${JSON.stringify(protocolCommandList)}
91
- export const automationProtocolPath = ${JSON.stringify(automationProtocolPath)}
92
- export const wrappedFn = (...args) => fn()(...args)
93
- `;
94
- }
95
- },
96
- transform(code, id) {
97
- if (id.includes('.vite/deps/expect.js')) {
98
- return {
99
- code: code.replace('var fs = _interopRequireWildcard(require_graceful_fs());', 'var fs = {};').replace('var expect_default = require_build11();', 'var expect_default = require_build11();\nwindow.expect = expect_default.default;').replace('process.stdout.isTTY', 'false')
100
- };
101
- }
102
- return { code };
103
- },
104
- configureServer(server) {
105
- return () => {
106
- server.middlewares.use(async (req, res, next) => {
107
- log.info(`Received request for: ${req.originalUrl}`);
108
- /**
109
- * don't return test page when sourcemaps are requested
110
- */
111
- if (!req.originalUrl || req.url?.endsWith('.map') || req.url?.endsWith('.wasm')) {
112
- return next();
113
- }
114
- const cookies = ((req.headers.cookie && req.headers.cookie.split(';')) || []).map((c) => c.trim());
115
- const urlParsed = url.parse(req.originalUrl);
116
- const urlParamString = new URLSearchParams(urlParsed.query || '');
117
- const cid = urlParamString.get('cid') || cookies.find((c) => c.includes('WDIO_CID'))?.split('=').pop();
118
- const spec = urlParamString.get('spec') || cookies.find((c) => c.includes('WDIO_SPEC'))?.split('=').pop();
119
- if (!cid || !SESSIONS.has(cid)) {
120
- log.error(`No environment found for ${cid || 'non determined environment'}`);
121
- return next();
122
- }
123
- if (!spec) {
124
- log.error('No spec file was defined to run for this environment');
125
- return next();
126
- }
127
- const env = SESSIONS.get(cid);
128
- try {
129
- const template = await getTemplate(options, env, spec);
130
- log.debug(`Render template for ${req.originalUrl}`);
131
- res.end(await server.transformIndexHtml(`${req.originalUrl}`, template));
132
- }
133
- catch (err) {
134
- const template = getErrorTemplate(req.originalUrl, err);
135
- log.error(`Failed to render template: ${err.message}`);
136
- res.end(await server.transformIndexHtml(`${req.originalUrl}`, template));
137
- }
138
- return next();
139
- });
140
- };
141
- }
142
- }, {
143
- name: 'modern-node-polyfills',
144
- async resolveId(id, _, ctx) {
145
- if (ctx.ssr || !builtinModules.includes(id)) {
146
- return;
147
- }
148
- id = normalizeId(id);
149
- return { id: await polyfillPath(id), moduleSideEffects: false };
150
- },
151
- }];
152
- }
@@ -1,12 +0,0 @@
1
- import { WDIO_EVENT_NAME } from '../../constants.js';
2
- /**
3
- * a Vite plugin to help communicate with the worker process
4
- */
5
- export function workerPlugin(onSocketEvent) {
6
- return {
7
- name: 'wdio:worker',
8
- configureServer({ ws }) {
9
- ws.on(WDIO_EVENT_NAME, onSocketEvent);
10
- }
11
- };
12
- }
@@ -1,104 +0,0 @@
1
- import path from 'node:path';
2
- import { EventEmitter } from 'node:events';
3
- import getPort from 'get-port';
4
- import logger from '@wdio/logger';
5
- import istanbulPlugin from 'vite-plugin-istanbul';
6
- import { deepmerge } from 'deepmerge-ts';
7
- import { createServer } from 'vite';
8
- import { testrunner } from './plugins/testrunner.js';
9
- import { mockHoisting } from './plugins/mockHoisting.js';
10
- import { workerPlugin } from './plugins/worker.js';
11
- import { userfriendlyImport } from './utils.js';
12
- import { MockHandler } from './mock.js';
13
- import { PRESET_DEPENDENCIES, DEFAULT_VITE_CONFIG } from './constants.js';
14
- import { DEFAULT_INCLUDE, DEFAULT_FILE_EXTENSIONS } from '../constants.js';
15
- const log = logger('@wdio/browser-runner:ViteServer');
16
- const DEFAULT_CONFIG_ENV = {
17
- command: 'serve',
18
- mode: process.env.NODE_ENV === 'production' ? 'production' : 'development'
19
- };
20
- /**
21
- * Class that sets up the Vite server with correct configuration based on given WebdriverIO options.
22
- */
23
- export class ViteServer extends EventEmitter {
24
- #options;
25
- #config;
26
- #viteConfig;
27
- #server;
28
- #mockHandler;
29
- #socketEventHandler = [];
30
- get config() {
31
- return this.#viteConfig;
32
- }
33
- constructor(options, config, optimizations) {
34
- super();
35
- this.#options = options;
36
- this.#config = config;
37
- this.#mockHandler = new MockHandler(options, config);
38
- const root = options.rootDir || config.rootDir || process.cwd();
39
- this.#viteConfig = deepmerge(DEFAULT_VITE_CONFIG, optimizations, {
40
- root,
41
- plugins: [
42
- testrunner(options),
43
- mockHoisting(this.#mockHandler),
44
- workerPlugin((payload, client) => (this.#socketEventHandler.forEach((handler) => handler(payload, client))))
45
- ]
46
- });
47
- if (options.coverage && options.coverage.enabled) {
48
- log.info('Capturing test coverage enabled');
49
- // @ts-expect-error istanbul plugin seems to incorrectly export
50
- // its type for our setup
51
- const plugin = istanbulPlugin;
52
- this.#viteConfig.plugins?.push(plugin({
53
- cwd: config.rootDir,
54
- include: DEFAULT_INCLUDE,
55
- extension: DEFAULT_FILE_EXTENSIONS,
56
- forceBuildInstrument: true,
57
- ...options.coverage
58
- }));
59
- }
60
- }
61
- onBrowserEvent(handler) {
62
- this.#socketEventHandler.push(handler);
63
- }
64
- async start() {
65
- const vitePort = await getPort();
66
- this.#viteConfig = deepmerge(this.#viteConfig, {
67
- server: {
68
- host: '0.0.0.0',
69
- port: vitePort
70
- }
71
- });
72
- /**
73
- * load additional Vite plugins for framework
74
- */
75
- if (this.#options.preset) {
76
- const [pkg, importProp, opts] = PRESET_DEPENDENCIES[this.#options.preset] || [];
77
- const plugin = (await userfriendlyImport(this.#options.preset, pkg))[importProp || 'default'];
78
- if (plugin) {
79
- this.#viteConfig.plugins.push(plugin(opts));
80
- }
81
- }
82
- /**
83
- * merge custom `viteConfig` last into the object
84
- */
85
- if (this.#options.viteConfig) {
86
- const { plugins, ...configToMerge } = typeof this.#options.viteConfig === 'string'
87
- ? (await import(path.resolve(this.#config.rootDir || process.cwd(), this.#options.viteConfig))).default
88
- : typeof this.#options.viteConfig === 'function'
89
- ? await this.#options.viteConfig(DEFAULT_CONFIG_ENV)
90
- : this.#options.viteConfig;
91
- this.#viteConfig = deepmerge(this.#viteConfig, configToMerge);
92
- this.#viteConfig.plugins = [...(plugins || []), ...this.#viteConfig.plugins];
93
- }
94
- /**
95
- * initialize Vite
96
- */
97
- this.#server = await createServer(this.#viteConfig);
98
- await this.#server.listen();
99
- log.info(`Vite server started successfully on port ${vitePort}, root directory: ${this.#viteConfig.root}`);
100
- }
101
- async close() {
102
- await this.#server?.close();
103
- }
104
- }
@@ -1 +0,0 @@
1
- export {};