@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,82 +0,0 @@
1
- import libSourceMap from 'istanbul-lib-source-maps';
2
- import libCoverage from 'istanbul-lib-coverage';
3
- import logger from '@wdio/logger';
4
- import { MESSAGE_TYPES } from '@wdio/types';
5
- import { SESSIONS } from './constants.js';
6
- import { WDIO_EVENT_NAME } from './constants.js';
7
- const log = logger('@wdio/browser-runner');
8
- export class ServerWorkerCommunicator {
9
- #mapStore = libSourceMap.createSourceMapStore();
10
- #config;
11
- #msgId = 0;
12
- /**
13
- * keep track of custom commands per session
14
- */
15
- #customCommands = new Map();
16
- /**
17
- * keep track of request/response messages on browser/worker level
18
- */
19
- #pendingMessages = new Map();
20
- coverageMaps = [];
21
- constructor(config) {
22
- this.#config = config;
23
- }
24
- register(server, worker) {
25
- server.onBrowserEvent((data, client) => this.#onBrowserEvent(data, client, worker));
26
- worker.on('message', this.#onWorkerMessage.bind(this));
27
- }
28
- async #onWorkerMessage(payload) {
29
- if (payload.name === 'sessionStarted' && !SESSIONS.has(payload.cid)) {
30
- SESSIONS.set(payload.cid, {
31
- args: this.#config.mochaOpts || {},
32
- config: this.#config,
33
- capabilities: payload.content.capabilities,
34
- sessionId: payload.content.sessionId,
35
- injectGlobals: payload.content.injectGlobals
36
- });
37
- }
38
- if (payload.name === 'sessionEnded') {
39
- SESSIONS.delete(payload.cid);
40
- }
41
- if (payload.name === 'workerEvent' && payload.args.type === MESSAGE_TYPES.coverageMap) {
42
- const coverageMapData = payload.args.value;
43
- this.coverageMaps.push(await this.#mapStore.transformCoverage(libCoverage.createCoverageMap(coverageMapData)));
44
- }
45
- if (payload.name === 'workerEvent' && payload.args.type === MESSAGE_TYPES.customCommand) {
46
- const { commandName, cid } = payload.args.value;
47
- if (!this.#customCommands.has(cid)) {
48
- this.#customCommands.set(cid, new Set());
49
- }
50
- const customCommands = this.#customCommands.get(cid) || new Set();
51
- customCommands.add(commandName);
52
- return;
53
- }
54
- if (payload.name === 'workerResponse') {
55
- const msg = this.#pendingMessages.get(payload.args.id);
56
- if (!msg) {
57
- return log.error(`Couldn't find message with id ${payload.args.id} from type ${payload.args.message.type}`);
58
- }
59
- this.#pendingMessages.delete(payload.args.id);
60
- return msg.client.send(WDIO_EVENT_NAME, payload.args.message);
61
- }
62
- }
63
- #onBrowserEvent(message, client, worker) {
64
- /**
65
- * some browser events don't need to go through the worker process
66
- */
67
- if (message.type === MESSAGE_TYPES.initiateBrowserStateRequest) {
68
- const result = {
69
- type: MESSAGE_TYPES.initiateBrowserStateResponse,
70
- value: {
71
- customCommands: [...(this.#customCommands.get(message.value.cid) || [])]
72
- }
73
- };
74
- return client.send(WDIO_EVENT_NAME, result);
75
- }
76
- const id = this.#msgId++;
77
- const msg = { id, client };
78
- this.#pendingMessages.set(id, msg);
79
- const args = { id, message };
80
- return worker.postMessage('workerRequest', args, true);
81
- }
82
- }
@@ -1,89 +0,0 @@
1
- export const SESSIONS = new Map();
2
- export const WDIO_EVENT_NAME = 'wdio:workerMessage';
3
- export const EVENTS = {
4
- 'suite': 'suite:start',
5
- 'suite end': 'suite:end',
6
- 'test': 'test:start',
7
- 'test end': 'test:end',
8
- 'hook': 'hook:start',
9
- 'hook end': 'hook:end',
10
- 'pass': 'test:pass',
11
- 'fail': 'test:fail',
12
- 'retry': 'test:retry',
13
- 'pending': 'test:pending'
14
- };
15
- export const FRAMEWORK_SUPPORT_ERROR = 'Currently only "mocha" is supported as framework when using @wdio/browser-runner.';
16
- export const DEFAULT_INCLUDE = ['**'];
17
- export const DEFAULT_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs', '.ts', '.mts', '.cts', '.tsx', '.jsx', '.vue', '.svelte'];
18
- export const DEFAULT_REPORTS_DIRECTORY = 'coverage';
19
- export const DEFAULT_AUTOMOCK = true;
20
- export const DEFAULT_MOCK_DIRECTORY = '__mocks__';
21
- export const SUMMARY_REPORTER = 'json-summary';
22
- export const COVERAGE_FACTORS = ['lines', 'functions', 'branches', 'statements'];
23
- export const DEFAULT_COVERAGE_REPORTS = ['text', 'html', 'clover', SUMMARY_REPORTER];
24
- export const GLOBAL_TRESHOLD_REPORTING = 'ERROR: Coverage for %s (%s%) does not meet global threshold (%s%)';
25
- export const FILE_TRESHOLD_REPORTING = 'ERROR: Coverage for %s (%s%) does not meet threshold (%s%) for %s';
26
- export const MOCHA_VARIABELS = /*css*/ `:root {
27
- --mocha-color: #000;
28
- --mocha-bg-color: #fff;
29
- --mocha-pass-icon-color: #00d6b2;
30
- --mocha-pass-color: #fff;
31
- --mocha-pass-shadow-color: rgba(0, 0, 0, .2);
32
- --mocha-pass-mediump-color: #c09853;
33
- --mocha-pass-slow-color: #b94a48;
34
- --mocha-test-pending-color: #0b97c4;
35
- --mocha-test-pending-icon-color: #0b97c4;
36
- --mocha-test-fail-color: #c00;
37
- --mocha-test-fail-icon-color: #c00;
38
- --mocha-test-fail-pre-color: #000;
39
- --mocha-test-fail-pre-error-color: #c00;
40
- --mocha-test-html-error-color: #000;
41
- --mocha-box-shadow-color: #eee;
42
- --mocha-box-bottom-color: #ddd;
43
- --mocha-test-replay-color: #000;
44
- --mocha-test-replay-bg-color: #eee;
45
- --mocha-stats-color: #888;
46
- --mocha-stats-em-color: #000;
47
- --mocha-stats-hover-color: #eee;
48
- --mocha-error-color: #c00;
49
-
50
- --mocha-code-comment: #ddd;
51
- --mocha-code-init: #2f6fad;
52
- --mocha-code-string: #5890ad;
53
- --mocha-code-keyword: #8a6343;
54
- --mocha-code-number: #2f6fad;
55
- }
56
-
57
- @media (prefers-color-scheme: dark) {
58
- :root {
59
- --mocha-color: #fff;
60
- --mocha-bg-color: #222;
61
- --mocha-pass-icon-color: #00d6b2;
62
- --mocha-pass-color: #222;
63
- --mocha-pass-shadow-color: rgba(255, 255, 255, .2);
64
- --mocha-pass-mediump-color: #f1be67;
65
- --mocha-pass-slow-color: #f49896;
66
- --mocha-test-pending-color: #0b97c4;
67
- --mocha-test-pending-icon-color: #0b97c4;
68
- --mocha-test-fail-color: #f44;
69
- --mocha-test-fail-icon-color: #f44;
70
- --mocha-test-fail-pre-color: #fff;
71
- --mocha-test-fail-pre-error-color: #f44;
72
- --mocha-test-html-error-color: #fff;
73
- --mocha-box-shadow-color: #444;
74
- --mocha-box-bottom-color: #555;
75
- --mocha-test-replay-color: #fff;
76
- --mocha-test-replay-bg-color: #444;
77
- --mocha-stats-color: #aaa;
78
- --mocha-stats-em-color: #fff;
79
- --mocha-stats-hover-color: #444;
80
- --mocha-error-color: #f44;
81
-
82
- --mocha-code-comment: #ddd;
83
- --mocha-code-init: #9cc7f1;
84
- --mocha-code-string: #80d4ff;
85
- --mocha-code-keyword: #e3a470;
86
- --mocha-code-number: #4ca7ff;
87
- }
88
- }
89
- `;
package/build/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
package/build/utils.js DELETED
@@ -1,86 +0,0 @@
1
- import util from 'node:util';
2
- import { deepmerge } from 'deepmerge-ts';
3
- import logger from '@wdio/logger';
4
- import { COVERAGE_FACTORS, GLOBAL_TRESHOLD_REPORTING, FILE_TRESHOLD_REPORTING } from './constants.js';
5
- const log = logger('@wdio/browser-runner');
6
- export function makeHeadless(options, caps) {
7
- const capability = caps.alwaysMatch || caps;
8
- if (!capability.browserName) {
9
- throw new Error('No "browserName" defined in capability object. It seems you are trying to run tests ' +
10
- 'in a non web environment, however WebdriverIOs browser runner only supports web environments');
11
- }
12
- if (
13
- // either user sets headless option implicitly
14
- (typeof options.headless === 'boolean' && !options.headless) ||
15
- // or CI environment is set
16
- (typeof process.env.CI !== 'undefined' && !process.env.CI) ||
17
- // or non are set
18
- (typeof options.headless !== 'boolean' && typeof process.env.CI === 'undefined')) {
19
- return caps;
20
- }
21
- if (capability.browserName === 'chrome') {
22
- return deepmerge(capability, {
23
- 'goog:chromeOptions': {
24
- args: ['headless', 'disable-gpu']
25
- }
26
- });
27
- }
28
- else if (capability.browserName === 'firefox') {
29
- return deepmerge(capability, {
30
- 'moz:firefoxOptions': {
31
- args: ['-headless']
32
- }
33
- });
34
- }
35
- else if (capability.browserName === 'msedge' || capability.browserName === 'edge') {
36
- return deepmerge(capability, {
37
- 'ms:edgeOptions': {
38
- args: ['--headless']
39
- }
40
- });
41
- }
42
- log.error(`Headless mode not supported for browser "${capability.browserName}"`);
43
- return caps;
44
- }
45
- /**
46
- * Open with devtools open when in watch mode
47
- */
48
- export function adjustWindowInWatchMode(config, caps) {
49
- if (!config.watch) {
50
- return caps;
51
- }
52
- const capability = caps.alwaysMatch || caps;
53
- if (config.watch && capability.browserName === 'chrome') {
54
- return deepmerge(capability, {
55
- 'goog:chromeOptions': {
56
- args: ['auto-open-devtools-for-tabs', 'window-size=1600,1200'],
57
- prefs: {
58
- devtools: {
59
- preferences: {
60
- 'panel-selectedTab': '"console"'
61
- }
62
- }
63
- }
64
- }
65
- });
66
- }
67
- /**
68
- * TODO: add support for other browsers (if possible)
69
- * } else if (...) { }
70
- */
71
- return caps;
72
- }
73
- export function getCoverageByFactor(options, summary, fileName) {
74
- return COVERAGE_FACTORS.map((factor) => {
75
- const treshold = options[factor];
76
- if (!treshold) {
77
- return;
78
- }
79
- if (summary[factor].pct >= treshold) {
80
- return;
81
- }
82
- return fileName
83
- ? util.format(FILE_TRESHOLD_REPORTING, factor, summary[factor].pct, treshold, fileName)
84
- : util.format(GLOBAL_TRESHOLD_REPORTING, factor, summary[factor].pct, treshold);
85
- }).filter(Boolean);
86
- }
@@ -1,55 +0,0 @@
1
- import topLevelAwait from 'vite-plugin-top-level-await';
2
- import { esbuildCommonjs } from '@originjs/vite-plugin-commonjs';
3
- import { codeFrameFix } from './plugins/esbuild.js';
4
- export const PRESET_DEPENDENCIES = {
5
- react: ['@vitejs/plugin-react', 'default', {
6
- babel: {
7
- assumptions: {
8
- setPublicClassFields: true
9
- },
10
- parserOpts: {
11
- plugins: ['decorators-legacy', 'classProperties']
12
- }
13
- }
14
- }],
15
- preact: ['@preact/preset-vite', 'default', undefined],
16
- vue: ['@vitejs/plugin-vue', 'default', undefined],
17
- svelte: ['@sveltejs/vite-plugin-svelte', 'svelte', undefined],
18
- solid: ['vite-plugin-solid', 'default', undefined],
19
- stencil: undefined,
20
- lit: undefined
21
- };
22
- export const DEFAULT_VITE_CONFIG = {
23
- configFile: false,
24
- server: { host: 'localhost' },
25
- logLevel: 'silent',
26
- plugins: [topLevelAwait()],
27
- build: {
28
- sourcemap: 'inline',
29
- commonjsOptions: {
30
- include: [/node_modules/],
31
- }
32
- },
33
- optimizeDeps: {
34
- /**
35
- * the following deps are CJS packages and need to be optimized (compiled to ESM) by Vite
36
- */
37
- include: [
38
- 'expect', 'minimatch', 'css-shorthand-properties', 'lodash.merge', 'lodash.zip', 'ws',
39
- 'lodash.clonedeep', 'lodash.pickby', 'lodash.flattendeep', 'aria-query', 'grapheme-splitter',
40
- 'css-value', 'rgb2hex', 'p-iteration', 'deepmerge-ts', 'jest-util', 'jest-matcher-utils', 'split2'
41
- ],
42
- esbuildOptions: {
43
- logLevel: 'silent',
44
- // Node.js global to browser globalThis
45
- define: {
46
- global: 'globalThis',
47
- },
48
- // Enable esbuild polyfill plugins
49
- plugins: [
50
- esbuildCommonjs(['@testing-library/vue']),
51
- codeFrameFix()
52
- ],
53
- },
54
- }
55
- };
@@ -1,19 +0,0 @@
1
- import { isNuxtFramework, optimizeForNuxt } from './nuxt.js';
2
- import { isUsingTailwindCSS, optimizeForTailwindCSS } from './tailwindcss.js';
3
- import { isUsingStencilJS, optimizeForStencil } from './stencil.js';
4
- export default async function updateViteConfig(options, config) {
5
- const optimizations = {};
6
- const rootDir = options.rootDir || config.rootDir || process.cwd();
7
- const isNuxt = await isNuxtFramework(rootDir);
8
- if (isNuxt) {
9
- Object.assign(optimizations, await optimizeForNuxt(options, config));
10
- }
11
- const isTailwind = await isUsingTailwindCSS(rootDir);
12
- if (isTailwind) {
13
- Object.assign(optimizations, await optimizeForTailwindCSS(rootDir));
14
- }
15
- if (await isUsingStencilJS(rootDir, options)) {
16
- Object.assign(optimizations, await optimizeForStencil(rootDir));
17
- }
18
- return optimizations;
19
- }
@@ -1,61 +0,0 @@
1
- import url from 'node:url';
2
- import path from 'node:path';
3
- import logger from '@wdio/logger';
4
- import { resolve } from 'import-meta-resolve';
5
- import { hasFileByExtensions, hasDir } from '../utils.js';
6
- const log = logger('@wdio/browser-runner:NuxtOptimization');
7
- export async function isNuxtFramework(rootDir) {
8
- return (await Promise.all([
9
- hasFileByExtensions(path.join(rootDir, 'nuxt.config')),
10
- hasDir(path.join(rootDir, '.nuxt'))
11
- ])).filter(Boolean).length > 0;
12
- }
13
- export async function optimizeForNuxt(options, config) {
14
- const Unimport = (await import('unimport/unplugin')).default;
15
- const { scanDirExports, scanExports } = await import('unimport');
16
- const { loadNuxtConfig } = await import('@nuxt/kit');
17
- const rootDir = config.rootDir || process.cwd();
18
- const nuxtOptions = await loadNuxtConfig({ rootDir });
19
- if (nuxtOptions.imports?.autoImport === false) {
20
- return {};
21
- }
22
- const nuxtDepPath = await resolve('nuxt', import.meta.url);
23
- const composablesDirs = [];
24
- for (const layer of nuxtOptions._layers) {
25
- composablesDirs.push(path.resolve(layer.config.srcDir, 'composables'));
26
- composablesDirs.push(path.resolve(layer.config.srcDir, 'utils'));
27
- for (const dir of (layer.config.imports?.dirs ?? [])) {
28
- if (!dir) {
29
- continue;
30
- }
31
- composablesDirs.push(path.resolve(layer.config.srcDir, dir));
32
- }
33
- }
34
- const composableImports = await Promise.all([
35
- scanDirExports([
36
- ...composablesDirs,
37
- path.resolve(path.dirname(url.fileURLToPath(nuxtDepPath)), 'app', 'components')
38
- ]),
39
- scanExports(path.resolve(path.dirname(url.fileURLToPath(nuxtDepPath)), 'app', 'composables', 'index.js'))
40
- ]).then((scannedExports) => scannedExports.flat().map((ci) => {
41
- /**
42
- * auto mock nuxt composables as they can't be loaded within the browser
43
- */
44
- if (ci.from.includes('/nuxt/dist/app/composables')) {
45
- ci.from = 'virtual:wdio';
46
- ci.name = 'wrappedFn';
47
- }
48
- return ci;
49
- }));
50
- const viteConfig = {
51
- resolve: {
52
- alias: nuxtOptions.alias || {}
53
- },
54
- plugins: [Unimport.vite({
55
- presets: ['vue'],
56
- imports: composableImports
57
- })]
58
- };
59
- log.info(`Optimized Vite config for Nuxt project at ${rootDir}`);
60
- return viteConfig;
61
- }
@@ -1,165 +0,0 @@
1
- import path from 'node:path';
2
- import url from 'node:url';
3
- import { findStaticImports, parseStaticImport } from 'mlly';
4
- import { hasFileByExtensions } from '../utils.js';
5
- const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
6
- const STENCIL_IMPORT = '@stencil/core';
7
- export async function isUsingStencilJS(rootDir, options) {
8
- return Boolean(options.preset === 'stencil' || await hasFileByExtensions(path.join(rootDir, 'stencil.config')));
9
- }
10
- export async function optimizeForStencil(rootDir) {
11
- const stencilConfig = await importStencilConfig(rootDir);
12
- const stencilPlugins = stencilConfig.config.plugins;
13
- const stencilOptimizations = {
14
- plugins: [await stencilVitePlugin(rootDir)],
15
- optimizeDeps: { include: [] }
16
- };
17
- if (stencilPlugins) {
18
- const esbuildPlugin = stencilPlugins.find((plugin) => plugin.name === 'esbuild-plugin');
19
- if (esbuildPlugin) {
20
- stencilOptimizations.optimizeDeps?.include?.push(...esbuildPlugin.options.include);
21
- }
22
- }
23
- /**
24
- * testing helper from the stencil core package is unfortunately exported as CJS
25
- * module, in order to be able to use it in the browser we have to optimize it
26
- * it to compile it to ESM
27
- */
28
- stencilOptimizations.optimizeDeps?.include?.push('@wdio/browser-runner/stencil > @stencil/core/internal/testing/index.js');
29
- return stencilOptimizations;
30
- }
31
- async function stencilVitePlugin(rootDir) {
32
- const { transpileSync, ts } = await import('@stencil/core/compiler/stencil.js');
33
- const stencilHelperPath = path.resolve(__dirname, '..', '..', 'browser', 'integrations', 'stencil.js');
34
- return {
35
- name: 'wdio-stencil',
36
- enforce: 'pre',
37
- resolveId(source) {
38
- if (source === '@wdio/browser-runner/stencil') {
39
- return stencilHelperPath;
40
- }
41
- },
42
- transform: function (code, id) {
43
- const staticImports = findStaticImports(code);
44
- const stencilImports = staticImports
45
- .filter((imp) => imp.specifier === STENCIL_IMPORT)
46
- .map((imp) => parseStaticImport(imp));
47
- const isStencilComponent = stencilImports.some((imp) => 'Component' in (imp.namedImports || {}));
48
- /**
49
- * if file doesn't define a Stencil component
50
- */
51
- if (!isStencilComponent) {
52
- /**
53
- * if a test imports the `@wdio/browser-runner/stencil` package we want to automatically
54
- * import `h` and `Fragment` from the `@stencil/core` package
55
- */
56
- const stencilHelperImport = staticImports.find((imp) => imp.specifier === '@wdio/browser-runner/stencil');
57
- if (stencilHelperImport) {
58
- const imports = parseStaticImport(stencilHelperImport);
59
- if ('render' in (imports.namedImports || {})) {
60
- code = injectStencilImports(code, stencilImports);
61
- }
62
- }
63
- return { code };
64
- }
65
- const tsCompilerOptions = getCompilerOptions(ts, rootDir);
66
- const opts = {
67
- componentExport: 'module',
68
- componentMetadata: 'compilerstatic',
69
- coreImportPath: '@stencil/core/internal/client',
70
- currentDirectory: rootDir,
71
- file: path.basename(id),
72
- module: 'esm',
73
- sourceMap: 'inline',
74
- style: 'static',
75
- proxy: 'defineproperty',
76
- styleImportData: 'queryparams',
77
- transformAliasedImportPaths: process.env.__STENCIL_TRANSPILE_PATHS__ === 'true',
78
- target: tsCompilerOptions?.target || 'es2018',
79
- paths: tsCompilerOptions?.paths,
80
- baseUrl: tsCompilerOptions?.baseUrl,
81
- };
82
- const transpiledCode = transpileSync(code, opts);
83
- /**
84
- * StencilJS applies only a getter to the component without having a setter defined.
85
- * This causes issue in the browser as there is a check that the setter is defined
86
- * if the getter is defined. We can work around this by defining a setter.
87
- */
88
- let transformedCode = transpiledCode.code.replace('static get style()', 'static set style(_) {}\n static get style()');
89
- /**
90
- * StencilJS does not import the `h` or `Fragment` function by default. We need to add it so the user
91
- * doesn't need to.
92
- */
93
- transformedCode = injectStencilImports(transformedCode, stencilImports);
94
- /**
95
- * Ensure that CSS imports by Stencil have an `&inline` query parameter
96
- */
97
- findStaticImports(transformedCode)
98
- .filter((imp) => imp.specifier.includes('&encapsulation=shadow'))
99
- .forEach((imp) => {
100
- const cssPath = path.resolve(path.dirname(id), imp.specifier);
101
- transformedCode = transformedCode.replace(imp.code, `import ${imp.imports.trim()} from '/@fs/${cssPath}&inline';\n`);
102
- });
103
- return {
104
- ...transpiledCode,
105
- code: transformedCode,
106
- inputFilePath: id
107
- };
108
- }
109
- };
110
- }
111
- /**
112
- * StencilJS does not import the `h` or `Fragment` function by default. We need to add it so the user
113
- * doesn't need to.
114
- */
115
- function injectStencilImports(code, imports) {
116
- const hasRenderFunctionImport = imports.some((imp) => 'h' in (imp.namedImports || {}));
117
- if (!hasRenderFunctionImport) {
118
- code = `import { h } from '@stencil/core/internal/client';\n${code}`;
119
- }
120
- const hasFragmentImport = imports.some((imp) => 'Fragment' in (imp.namedImports || {}));
121
- if (!hasFragmentImport) {
122
- code = `import { Fragment } from '@stencil/core/internal/client';\n${code}`;
123
- }
124
- return code;
125
- }
126
- let _tsCompilerOptions = null;
127
- /**
128
- * Read the TypeScript compiler configuration file from disk
129
- * @param rootDir the location to search for the config file
130
- * @returns the configuration, or `null` if the file cannot be found
131
- */
132
- function getCompilerOptions(ts, rootDir) {
133
- if (_tsCompilerOptions) {
134
- return _tsCompilerOptions;
135
- }
136
- if (typeof rootDir !== 'string') {
137
- return null;
138
- }
139
- const tsconfigFilePath = ts.findConfigFile(rootDir, ts.sys.fileExists);
140
- if (!tsconfigFilePath) {
141
- return null;
142
- }
143
- const tsconfigResults = ts.readConfigFile(tsconfigFilePath, ts.sys.readFile);
144
- if (tsconfigResults.error) {
145
- throw new Error(tsconfigResults.error);
146
- }
147
- const parseResult = ts.parseJsonConfigFileContent(tsconfigResults.config, ts.sys, rootDir, undefined, tsconfigFilePath);
148
- _tsCompilerOptions = parseResult.options;
149
- return _tsCompilerOptions;
150
- }
151
- /**
152
- * helper method to import a Stencil config file
153
- */
154
- export async function importStencilConfig(rootDir) {
155
- const configPath = path.join(rootDir, 'stencil.config.ts');
156
- const config = await import(configPath).catch(() => ({ config: {} }));
157
- /**
158
- * if we import the config within a CJS environment we need to
159
- * access the default property even though there is a named export
160
- */
161
- if ('default' in config) {
162
- return config.default;
163
- }
164
- return config;
165
- }
@@ -1,28 +0,0 @@
1
- import url from 'node:url';
2
- import path from 'node:path';
3
- import { resolve } from 'import-meta-resolve';
4
- import { hasFileByExtensions } from '../utils.js';
5
- /**
6
- * returns `true` if TailwindCSS config exist but no postcss.config
7
- * (if a `postcss.config` exists it will be automatically picked up by Vite)
8
- */
9
- export function isUsingTailwindCSS(rootDir) {
10
- return Promise.all([
11
- hasFileByExtensions(path.join(rootDir, 'tailwind.config')),
12
- hasFileByExtensions(path.join(rootDir, 'postcss.config'))
13
- ]).then(([hasTailwindConfig, hasPostCSSConfig]) => {
14
- return hasTailwindConfig && !hasPostCSSConfig;
15
- });
16
- }
17
- /**
18
- * add tailwind plugin if installed as dependency
19
- */
20
- export async function optimizeForTailwindCSS(rootDir) {
21
- const viteConfig = {};
22
- const tailwindcssPath = await resolve('tailwindcss', url.pathToFileURL(path.resolve(rootDir, 'index.js')).href);
23
- const tailwindcss = (await import(tailwindcssPath)).default;
24
- viteConfig.css = {
25
- postcss: { plugins: [tailwindcss] }
26
- };
27
- return viteConfig;
28
- }
@@ -1,50 +0,0 @@
1
- import path from 'node:path';
2
- import { getManualMocks } from './utils.js';
3
- import { DEFAULT_MOCK_DIRECTORY, DEFAULT_AUTOMOCK } from '../constants.js';
4
- const FIXTURE_PREFIX = '/@fixture/';
5
- export class MockHandler {
6
- #automock;
7
- #automockDir;
8
- #manualMocksList;
9
- #mocks = new Map();
10
- #unmocked = [];
11
- manualMocks = [];
12
- constructor(options, config) {
13
- this.#automock = typeof options.automock === 'boolean' ? options.automock : DEFAULT_AUTOMOCK;
14
- this.#automockDir = path.resolve(config.rootDir, options.automockDir || DEFAULT_MOCK_DIRECTORY);
15
- this.#manualMocksList = getManualMocks(this.#automockDir);
16
- }
17
- get mocks() {
18
- return this.#mocks;
19
- }
20
- unmock(moduleName) {
21
- this.#unmocked.push(moduleName);
22
- }
23
- async resolveId(id) {
24
- const manualMocksList = await this.#manualMocksList;
25
- const mockPath = manualMocksList.find((m) => (
26
- // e.g. someModule
27
- id === m[1].replace(path.sep, '/') ||
28
- // e.g. @some/module
29
- id.slice(1) === m[1].replace(path.sep, '/')));
30
- /**
31
- * return manual mock if `automock` is enabled or a manual mock was set via `mock('module')`
32
- */
33
- if ((this.manualMocks.includes(id) || this.#automock) && mockPath && !this.#unmocked.includes(id)) {
34
- return mockPath[0];
35
- }
36
- /**
37
- * return fixture
38
- */
39
- if (id.startsWith(FIXTURE_PREFIX)) {
40
- return path.resolve(this.#automockDir, id.slice(FIXTURE_PREFIX.length));
41
- }
42
- }
43
- /**
44
- * reset manual mocks between tests
45
- */
46
- resetMocks() {
47
- this.manualMocks = [];
48
- this.#unmocked = [];
49
- }
50
- }
@@ -1,25 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- export function codeFrameFix() {
3
- return {
4
- name: 'wdio:codeFrameFix',
5
- setup(build) {
6
- build.onLoad({ filter: /@babel\/code-frame/, namespace: 'file' },
7
- /**
8
- * mock @babel/code-frame as it fails in Safari due
9
- * to usage of chalk
10
- */
11
- async ({ path: id }) => {
12
- const code = await fs.readFile(id).then((buf) => buf.toString(), () => undefined);
13
- if (!code) {
14
- return;
15
- }
16
- return {
17
- contents: code.replace('require("@babel/highlight");', /*js*/ `{
18
- shouldHighlight: false,
19
- reset: () => {}
20
- }`)
21
- };
22
- });
23
- }
24
- };
25
- }