mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-28 11:21:21 +00:00
233 lines
10 KiB
JavaScript
233 lines
10 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.nxComponentTestingPreset = nxComponentTestingPreset;
|
|
const cypress_preset_1 = require("@nx/cypress/plugins/cypress-preset");
|
|
const ct_helpers_1 = require("@nx/cypress/src/utils/ct-helpers");
|
|
const devkit_1 = require("@nx/devkit");
|
|
const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
|
|
const fs_1 = require("fs");
|
|
const path_1 = require("path");
|
|
/**
|
|
* React nx preset for Cypress Component Testing
|
|
*
|
|
* This preset contains the base configuration
|
|
* for your component tests that nx recommends.
|
|
* including a devServer that supports nx workspaces.
|
|
* you can easily extend this within your cypress config via spreading the preset
|
|
* @example
|
|
* export default defineConfig({
|
|
* component: {
|
|
* ...nxComponentTestingPreset(__dirname)
|
|
* // add your own config here
|
|
* }
|
|
* })
|
|
*
|
|
* @param pathToConfig will be used for loading project options and to construct the output paths for videos and screenshots
|
|
* @param options override options
|
|
*/
|
|
function nxComponentTestingPreset(pathToConfig, options) {
|
|
const basePresetSettings = (0, cypress_preset_1.nxBaseCypressPreset)(pathToConfig, {
|
|
testingType: 'component',
|
|
});
|
|
if (global.NX_GRAPH_CREATION) {
|
|
// this is only used by plugins, so we don't need the component testing
|
|
// options, cast to any to avoid type errors
|
|
return basePresetSettings;
|
|
}
|
|
const normalizedProjectRootPath = ['.ts', '.js'].some((ext) => pathToConfig.endsWith(ext))
|
|
? pathToConfig
|
|
: (0, path_1.dirname)(pathToConfig);
|
|
if (options?.bundler === 'vite') {
|
|
return {
|
|
...basePresetSettings,
|
|
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
|
|
devServer: {
|
|
...{ framework: 'react', bundler: 'vite' },
|
|
viteConfig: async () => {
|
|
const viteConfigPath = findViteConfig(normalizedProjectRootPath);
|
|
// TODO(jack): Remove this cast when @nx/react switches to
|
|
// moduleResolution: "nodenext". Vite 8 ships ESM-only type
|
|
// declarations (.d.mts) not resolvable under moduleResolution: "node".
|
|
const { mergeConfig, loadConfigFromFile, searchForWorkspaceRoot } = await Function('return import("vite")')();
|
|
const resolved = await loadConfigFromFile({
|
|
mode: 'watch',
|
|
command: 'serve',
|
|
}, viteConfigPath);
|
|
return mergeConfig(resolved.config, {
|
|
server: {
|
|
fs: {
|
|
allow: [
|
|
searchForWorkspaceRoot(normalizedProjectRootPath),
|
|
devkit_1.workspaceRoot,
|
|
(0, devkit_1.joinPathFragments)(devkit_1.workspaceRoot, 'node_modules/vite'),
|
|
],
|
|
},
|
|
},
|
|
});
|
|
},
|
|
},
|
|
};
|
|
}
|
|
let webpackConfig = null;
|
|
try {
|
|
const graph = (0, devkit_1.readCachedProjectGraph)();
|
|
const { targets: ctTargets, name: ctProjectName } = (0, ct_helpers_1.getProjectConfigByPath)(graph, pathToConfig);
|
|
const ctTargetName = options?.ctTargetName || 'component-test';
|
|
const ctConfigurationName = process.env.NX_CYPRESS_TARGET_CONFIGURATION;
|
|
const ctExecutorContext = (0, ct_helpers_1.createExecutorContext)(graph, ctTargets, ctProjectName, ctTargetName, ctConfigurationName);
|
|
let buildTarget = options?.buildTarget;
|
|
if (!buildTarget) {
|
|
const ctExecutorOptions = (0, devkit_1.readTargetOptions)({
|
|
project: ctProjectName,
|
|
target: ctTargetName,
|
|
configuration: ctConfigurationName,
|
|
}, ctExecutorContext);
|
|
buildTarget = ctExecutorOptions.devServerTarget;
|
|
}
|
|
if (!buildTarget) {
|
|
throw new Error(`Unable to find the 'devServerTarget' executor option in the '${ctTargetName}' target of the '${ctProjectName}' project`);
|
|
}
|
|
webpackConfig = buildTargetWebpack(ctExecutorContext, buildTarget, ctProjectName);
|
|
}
|
|
catch (e) {
|
|
if (e instanceof InvalidExecutorError) {
|
|
throw e;
|
|
}
|
|
devkit_1.logger.warn((0, devkit_1.stripIndents) `Unable to build a webpack config with the project graph.
|
|
Falling back to default webpack config.`);
|
|
devkit_1.logger.warn(e);
|
|
}
|
|
// Fallback config
|
|
if (!webpackConfig) {
|
|
const { buildBaseWebpackConfig } = require('./webpack-fallback');
|
|
webpackConfig = buildBaseWebpackConfig({
|
|
tsConfigPath: findTsConfig(normalizedProjectRootPath),
|
|
compiler: options?.compiler || 'babel',
|
|
});
|
|
}
|
|
return {
|
|
...basePresetSettings,
|
|
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
|
|
devServer: {
|
|
// cypress uses string union type,
|
|
// need to use const to prevent typing to string
|
|
// but don't want to use as const on webpackConfig
|
|
// so it is still user modifiable
|
|
...{ framework: 'react', bundler: 'webpack' },
|
|
webpackConfig,
|
|
},
|
|
};
|
|
}
|
|
/**
|
|
* apply the schema.json defaults from the @nx/web:webpack executor to the target options
|
|
*/
|
|
function withSchemaDefaults(target, context) {
|
|
const options = (0, devkit_1.readTargetOptions)(target, context);
|
|
options.compiler ??= 'babel';
|
|
options.deleteOutputPath ??= true;
|
|
options.vendorChunk ??= true;
|
|
options.commonChunk ??= true;
|
|
options.runtimeChunk ??= true;
|
|
options.sourceMap ??= true;
|
|
options.assets ??= [];
|
|
options.scripts ??= [];
|
|
options.styles ??= [];
|
|
options.budgets ??= [];
|
|
options.namedChunks ??= true;
|
|
options.outputHashing ??= 'none';
|
|
options.extractCss ??= true;
|
|
options.memoryLimit ??= 2048;
|
|
options.maxWorkers ??= 2;
|
|
options.fileReplacements ??= [];
|
|
options.buildLibsFromSource ??= true;
|
|
return options;
|
|
}
|
|
function buildTargetWebpack(ctx, buildTarget, componentTestingProjectName) {
|
|
const graph = ctx.projectGraph;
|
|
const parsed = (0, devkit_1.parseTargetString)(buildTarget, graph);
|
|
const buildableProjectConfig = graph.nodes[parsed.project]?.data;
|
|
const ctProjectConfig = graph.nodes[componentTestingProjectName]?.data;
|
|
if (!buildableProjectConfig || !ctProjectConfig) {
|
|
throw new Error((0, devkit_1.stripIndents) `Unable to load project configs from graph.
|
|
Using build target '${buildTarget}'
|
|
Has build config? ${!!buildableProjectConfig}
|
|
Has component config? ${!!ctProjectConfig}
|
|
`);
|
|
}
|
|
if (buildableProjectConfig.targets[parsed.target].executor !==
|
|
'@nx/webpack:webpack' &&
|
|
buildableProjectConfig.targets[parsed.target].executor !==
|
|
'@nx/rspack:rspack') {
|
|
throw new InvalidExecutorError(`The '${parsed.target}' target of the '${parsed.project}' project is not using the '@nx/webpack:webpack' or '@nx/rspack:rspack' executor. ` +
|
|
`Please make sure to use '@nx/webpack:webpack' or '@nx/rspack:rspack' executor in that target to use Cypress Component Testing.`);
|
|
}
|
|
const context = (0, ct_helpers_1.createExecutorContext)(graph, buildableProjectConfig.targets, parsed.project, parsed.target, parsed.target);
|
|
const { normalizeOptions, } = require('@nx/webpack/src/executors/webpack/lib/normalize-options');
|
|
const { resolveUserDefinedWebpackConfig, } = require('@nx/webpack/src/utils/webpack/resolve-user-defined-webpack-config');
|
|
const { composePluginsSync } = require('@nx/webpack/src/utils/config');
|
|
const { withNx } = require('@nx/webpack/src/utils/with-nx');
|
|
const { withWeb } = require('@nx/webpack/src/utils/with-web');
|
|
const options = normalizeOptions(withSchemaDefaults(parsed, context), devkit_1.workspaceRoot, buildableProjectConfig.root, (0, ts_solution_setup_1.getProjectSourceRoot)(buildableProjectConfig));
|
|
let customWebpack;
|
|
if (options.webpackConfig) {
|
|
customWebpack = resolveUserDefinedWebpackConfig(options.webpackConfig, options.tsConfig.startsWith(context.root)
|
|
? options.tsConfig
|
|
: (0, path_1.join)(context.root, options.tsConfig));
|
|
}
|
|
return async () => {
|
|
customWebpack = await customWebpack;
|
|
// For legacy `composePlugins(...)` setup, we need change some options to make Cypress CT work properly.
|
|
if (customWebpack &&
|
|
require('@nx/webpack').isNxWebpackComposablePlugin(customWebpack) // using inline since @nx/webpack may not be installed when using vite so top-level import would error
|
|
) {
|
|
return await customWebpack({}, {
|
|
options: {
|
|
...options,
|
|
// cypress will generate its own index.html from component-index.html
|
|
generateIndexHtml: false,
|
|
// causes issues with buildable libraries with ENOENT: no such file or directory, scandir error
|
|
extractLicenses: false,
|
|
root: devkit_1.workspaceRoot,
|
|
projectRoot: ctProjectConfig.root,
|
|
sourceRoot: (0, ts_solution_setup_1.getProjectSourceRoot)(ctProjectConfig),
|
|
},
|
|
context,
|
|
configuration: parsed.configuration,
|
|
});
|
|
}
|
|
else if (typeof customWebpack === 'object' ||
|
|
typeof customWebpack === 'function') {
|
|
// If this is a standard webpack config object or function, just return. it
|
|
return customWebpack;
|
|
}
|
|
return null; // return null to use fallback config
|
|
};
|
|
}
|
|
function findViteConfig(projectRootFullPath) {
|
|
const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
|
|
for (const ext of allowsExt) {
|
|
if ((0, fs_1.existsSync)((0, path_1.join)(projectRootFullPath, `vite.config.${ext}`))) {
|
|
return (0, path_1.join)(projectRootFullPath, `vite.config.${ext}`);
|
|
}
|
|
}
|
|
}
|
|
function findTsConfig(projectRoot) {
|
|
const potentialConfigs = [
|
|
'cypress/tsconfig.json',
|
|
'cypress/tsconfig.cy.json',
|
|
'tsconfig.cy.json',
|
|
];
|
|
for (const config of potentialConfigs) {
|
|
if ((0, fs_1.existsSync)((0, path_1.join)(projectRoot, config))) {
|
|
return config;
|
|
}
|
|
}
|
|
}
|
|
class InvalidExecutorError extends Error {
|
|
constructor(message) {
|
|
super(message);
|
|
this.message = message;
|
|
this.name = 'InvalidExecutorError';
|
|
}
|
|
}
|