@nx/cypress 23.2.0-beta.1 → 23.2.0-beta.10

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.
@@ -1,16 +1,20 @@
1
1
  import { GeneratorCallback, Tree } from '@nx/devkit';
2
- import { Linter, LinterType } from '@nx/eslint';
2
+ import { LinterType } from '@nx/js';
3
3
  export interface CypressE2EConfigSchema {
4
4
  project: string;
5
5
  baseUrl?: string;
6
6
  directory?: string;
7
7
  js?: boolean;
8
8
  skipFormat?: boolean;
9
+ enableTypedLinting?: boolean;
10
+ /**
11
+ * @deprecated Use `enableTypedLinting` instead. This option will be removed in Nx v24.
12
+ */
9
13
  setParserOptionsProject?: boolean;
10
14
  skipPackageJson?: boolean;
11
15
  bundler?: 'webpack' | 'vite' | 'none';
12
16
  devServerTarget?: string;
13
- linter?: Linter | LinterType;
17
+ linter?: LinterType;
14
18
  port?: number | 'cypress-auto';
15
19
  jsx?: boolean;
16
20
  rootProject?: boolean;
@@ -144,23 +144,23 @@ In this case you need to provide a devServerTarget,'<projectName>:<targetName>[:
144
144
  };
145
145
  }
146
146
  async function promptForMissingServeData(projectName) {
147
- const { devServerTarget, port } = await (0, internal_1.promptWhenInteractive)([
148
- {
149
- type: 'input',
150
- name: 'devServerTarget',
151
- message: 'What is the name of the target used to serve the application locally?',
152
- initial: `${projectName}:serve`,
153
- },
154
- {
155
- type: 'numeral',
156
- name: 'port',
157
- message: 'What port will the application be served on?',
158
- initial: 3000,
159
- },
160
- ], {
161
- devServerTarget: `${projectName}:serve`,
162
- port: 3000,
147
+ if (!(0, internal_1.isInteractive)()) {
148
+ return {
149
+ devServerTarget: `${projectName}:serve`,
150
+ baseUrl: 'http://localhost:3000',
151
+ };
152
+ }
153
+ const devServerTarget = await (0, internal_1.textPrompt)({
154
+ message: 'What is the name of the target used to serve the application locally?',
155
+ initialValue: `${projectName}:serve`,
163
156
  });
157
+ const port = Number(await (0, internal_1.textPrompt)({
158
+ message: 'What port will the application be served on?',
159
+ initialValue: '3000',
160
+ validate: (value) => value !== '' && !Number.isNaN(Number(value))
161
+ ? undefined
162
+ : 'Please enter a number',
163
+ }));
164
164
  return {
165
165
  devServerTarget,
166
166
  baseUrl: `http://localhost:${port}`,
@@ -44,9 +44,9 @@
44
44
  "default": "cypress"
45
45
  },
46
46
  "linter": {
47
- "description": "The tool to use for running lint checks.",
47
+ "description": "The tool to use for running lint checks. Defaults to the linter the workspace already uses.",
48
48
  "type": "string",
49
- "enum": ["none", "eslint"],
49
+ "enum": ["none", "eslint", "oxlint"],
50
50
  "x-priority": "important"
51
51
  },
52
52
  "js": {
@@ -60,11 +60,17 @@
60
60
  "default": false,
61
61
  "x-priority": "internal"
62
62
  },
63
- "setParserOptionsProject": {
63
+ "enableTypedLinting": {
64
64
  "type": "boolean",
65
- "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
65
+ "description": "Whether to enable typed linting. For flat configs, this configures the recommended `parserOptions.projectService` and `tsconfigRootDir`. For legacy `.eslintrc` configs, this configures `parserOptions.project`. We do not enable this by default for lint performance reasons.",
66
66
  "default": false
67
67
  },
68
+ "setParserOptionsProject": {
69
+ "type": "boolean",
70
+ "description": "Deprecated alias for `enableTypedLinting`.",
71
+ "default": false,
72
+ "x-deprecated": "Use `enableTypedLinting` instead. This option will be removed in Nx v24."
73
+ },
68
74
  "skipPackageJson": {
69
75
  "type": "boolean",
70
76
  "default": false,
@@ -5,10 +5,6 @@ const internal_1 = require("@nx/devkit/internal");
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const js_1 = require("@nx/js");
7
7
  const fs_1 = require("fs");
8
- const devkit_internals_1 = require("nx/src/devkit-internals");
9
- const cache_directory_1 = require("nx/src/utils/cache-directory");
10
- const plugin_cache_utils_1 = require("nx/src/utils/plugin-cache-utils");
11
- const workspace_context_1 = require("nx/src/utils/workspace-context");
12
8
  const path_1 = require("path");
13
9
  const constants_1 = require("../utils/constants");
14
10
  const cypressConfigGlob = '**/cypress.config.{js,ts,mjs,cjs}';
@@ -25,9 +21,9 @@ const defaultPatterns = {
25
21
  exports.createNodes = [
26
22
  cypressConfigGlob,
27
23
  async (configFiles, options, context) => {
28
- const optionsHash = (0, devkit_internals_1.hashObject)(options);
29
- const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `cypress-${optionsHash}.hash`);
30
- const pluginCache = new plugin_cache_utils_1.PluginCache(cachePath);
24
+ const optionsHash = (0, internal_1.hashObject)(options);
25
+ const cachePath = (0, path_1.join)(internal_1.workspaceDataDirectory, `cypress-${optionsHash}.hash`);
26
+ const pluginCache = new internal_1.PluginCache(cachePath);
31
27
  const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
32
28
  const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
33
29
  const lockFileName = (0, js_1.getLockFileName)(packageManager);
@@ -490,7 +486,7 @@ async function getSpecFilesAndPatternsForTestType(cypressConfig, testType, works
490
486
  const excludeSpecPatterns = Array.isArray(excludeSpecPattern)
491
487
  ? excludeSpecPattern.map((p) => (0, path_1.join)(projectRoot, p))
492
488
  : [(0, path_1.join)(projectRoot, excludeSpecPattern)];
493
- const specFiles = await (0, workspace_context_1.globWithWorkspaceContext)(workspaceRoot, specPatterns, excludeSpecPatterns);
489
+ const specFiles = await (0, internal_1.globWithWorkspaceContext)(workspaceRoot, specPatterns, excludeSpecPatterns);
494
490
  return { specFiles, specPatterns, excludeSpecPatterns };
495
491
  }
496
492
  async function filterCypressConfigs(configFiles, context) {
@@ -1,8 +1,12 @@
1
1
  import { GeneratorCallback, Tree } from '@nx/devkit';
2
- import { Linter, LinterType } from '@nx/eslint';
2
+ import { type LinterType } from '@nx/js';
3
3
  export interface CyLinterOptions {
4
4
  project: string;
5
- linter: Linter | LinterType;
5
+ linter: LinterType;
6
+ enableTypedLinting?: boolean;
7
+ /**
8
+ * @deprecated Use `enableTypedLinting` instead. This option will be removed in Nx v24.
9
+ */
6
10
  setParserOptionsProject?: boolean;
7
11
  skipPackageJson?: boolean;
8
12
  rootProject?: boolean;
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addLinterToCyProject = addLinterToCyProject;
4
4
  const devkit_1 = require("@nx/devkit");
5
- const eslint_1 = require("@nx/eslint");
6
5
  const internal_1 = require("@nx/eslint/internal");
7
6
  const versions_1 = require("./versions");
7
+ const internal_2 = require("@nx/js/internal");
8
8
  async function addLinterToCyProject(tree, options) {
9
9
  if (options.linter === 'none') {
10
10
  return () => { };
@@ -12,19 +12,24 @@ async function addLinterToCyProject(tree, options) {
12
12
  const tasks = [];
13
13
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
14
14
  const eslintFile = (0, internal_1.findEslintFile)(tree, projectConfig.root);
15
- if (!eslintFile) {
16
- tasks.push(await (0, eslint_1.lintProjectGenerator)(tree, {
15
+ const enableTypedLinting = (0, internal_1.isTypedLintingEnabled)(options);
16
+ // Register whichever linter was asked for. An existing ESLint config means
17
+ // the project is already registered, so skip straight to the Cypress-specific
18
+ // shaping below.
19
+ if (options.linter !== 'eslint' || !eslintFile) {
20
+ tasks.push(await (0, internal_2.addLintingToProject)(tree, {
17
21
  project: options.project,
18
22
  linter: options.linter,
19
- skipFormat: true,
20
23
  tsConfigPaths: [(0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json')],
21
- setParserOptionsProject: options.setParserOptionsProject,
24
+ enableTypedLinting,
22
25
  skipPackageJson: options.skipPackageJson,
23
26
  rootProject: options.rootProject,
24
27
  addPlugin: options.addPlugin,
25
28
  }));
26
29
  }
27
- if (!options.linter || options.linter !== 'eslint') {
30
+ // Everything below configures ESLint — predefined configs, `extends`, ignore
31
+ // entries — which have no equivalent in other linters.
32
+ if (options.linter !== 'eslint') {
28
33
  return (0, devkit_1.runTasksInSerial)(...tasks);
29
34
  }
30
35
  options.overwriteExisting = options.overwriteExisting || !eslintFile;
@@ -35,7 +40,8 @@ async function addLinterToCyProject(tree, options) {
35
40
  if ((0, internal_1.isEslintConfigSupported)(tree, projectConfig.root) ||
36
41
  (0, internal_1.isEslintConfigSupported)(tree)) {
37
42
  const overrides = [];
38
- if ((0, internal_1.useFlatConfig)(tree)) {
43
+ const isFlatConfig = (0, internal_1.useFlatConfig)(tree);
44
+ if (isFlatConfig) {
39
45
  (0, internal_1.addPredefinedConfigToFlatLintConfig)(tree, projectConfig.root, 'recommended', {
40
46
  moduleName: 'cypress',
41
47
  moduleImportPath: 'eslint-plugin-cypress/flat',
@@ -67,39 +73,44 @@ async function addLinterToCyProject(tree, options) {
67
73
  'no-undef': 'off',
68
74
  },
69
75
  };
76
+ // For flat configs typed linting is handled by `lintProjectGenerator` via
77
+ // `parserOptions.projectService`, so we don't emit `parserOptions.project`
78
+ // here. Legacy `.eslintrc` configs are JSON, which can't express the
79
+ // `__dirname` that `tsconfigRootDir` needs, so they keep `project`.
80
+ const legacyParserOptions = !isFlatConfig && enableTypedLinting
81
+ ? { project: `${projectConfig.root}/tsconfig.*?.json` }
82
+ : undefined;
70
83
  if (options.overwriteExisting) {
71
84
  overrides.unshift({
72
- files: (0, internal_1.useFlatConfig)(tree)
85
+ files: isFlatConfig
73
86
  ? // For flat configs we don't need to specify the files
74
87
  undefined
75
88
  : ['*.ts', '*.tsx', '*.js', '*.jsx'],
76
- parserOptions: !options.setParserOptionsProject
77
- ? undefined
78
- : {
79
- project: `${projectConfig.root}/tsconfig.*?.json`,
80
- },
89
+ parserOptions: legacyParserOptions,
81
90
  rules: {},
82
91
  });
83
92
  (0, internal_1.replaceOverridesInLintConfig)(tree, projectConfig.root, overrides);
84
93
  }
85
94
  else {
86
95
  overrides.unshift({
87
- files: (0, internal_1.useFlatConfig)(tree)
96
+ files: isFlatConfig
88
97
  ? // For flat configs we don't need to specify the files
89
98
  undefined
90
99
  : [
91
100
  '*.cy.{ts,js,tsx,jsx}',
92
101
  `${options.cypressDir}/**/*.{ts,js,tsx,jsx}`,
93
102
  ],
94
- parserOptions: !options.setParserOptionsProject
95
- ? undefined
96
- : {
97
- project: `${projectConfig.root}/tsconfig.*?.json`,
98
- },
103
+ parserOptions: legacyParserOptions,
99
104
  rules: {},
100
105
  });
101
106
  overrides.forEach((override) => (0, internal_1.addOverrideToLintConfig)(tree, projectConfig.root, override));
102
107
  }
108
+ // `lintProjectGenerator` only sets up the projectService block when it
109
+ // creates the config, and `replaceOverridesInLintConfig` strips it. For a
110
+ // flat config, re-add it here when typed linting is enabled.
111
+ if (isFlatConfig && enableTypedLinting) {
112
+ (0, internal_1.addTypedLintingToFlatConfig)(tree, projectConfig.root);
113
+ }
103
114
  }
104
115
  return (0, devkit_1.runTasksInSerial)(...tasks);
105
116
  }
@@ -131,7 +131,10 @@ ${jitComment}
131
131
  }`;
132
132
  });
133
133
  }
134
- if (presetImportPath) {
134
+ // Re-running the generator must not prepend a second declaration - Cypress
135
+ // loads TS configs through esbuild, which rejects duplicate bindings.
136
+ const isPresetAlreadyDeclared = tsquery.query(updatedConfigContents, ':matches(ImportSpecifier, BindingElement) Identifier[name="nxComponentTestingPreset"]').length > 0;
137
+ if (presetImportPath && !isPresetAlreadyDeclared) {
135
138
  // Use the path verbatim - callers pass the public exported subpath. Don't
136
139
  // append `.js`: @nx/react and @nx/angular's package exports only declare
137
140
  // the bare `./plugins/component-testing` subpath, so a `.js` suffix
@@ -8,9 +8,7 @@ exports.createExecutorContext = createExecutorContext;
8
8
  const devkit_1 = require("@nx/devkit");
9
9
  const path_1 = require("path");
10
10
  const fs_1 = require("fs");
11
- const find_project_for_path_1 = require("nx/src/project-graph/utils/find-project-for-path");
12
- const project_graph_1 = require("nx/src/project-graph/project-graph");
13
- const configuration_1 = require("nx/src/config/configuration");
11
+ const internal_1 = require("@nx/devkit/internal");
14
12
  exports.CY_FILE_MATCHER = new RegExp(/\.cy\.[tj]sx?$/);
15
13
  /**
16
14
  * return a path to a temp css file
@@ -55,8 +53,8 @@ function getProjectConfigByPath(graph, configPath) {
55
53
  const normalizedPathFromWorkspaceRoot = (0, devkit_1.normalizePath)((0, fs_1.lstatSync)(configPath).isFile()
56
54
  ? configFileFromWorkspaceRoot.replace((0, path_1.extname)(configPath), '')
57
55
  : configFileFromWorkspaceRoot);
58
- const projectRootMappings = (0, find_project_for_path_1.createProjectRootMappings)(graph.nodes);
59
- const componentTestingProjectName = (0, find_project_for_path_1.findProjectForPath)(normalizedPathFromWorkspaceRoot, projectRootMappings);
56
+ const projectRootMappings = (0, internal_1.createProjectRootMappings)(graph.nodes);
57
+ const componentTestingProjectName = (0, internal_1.findProjectForPath)(normalizedPathFromWorkspaceRoot, projectRootMappings);
60
58
  if (!componentTestingProjectName ||
61
59
  !graph.nodes[componentTestingProjectName]?.data) {
62
60
  throw new Error((0, devkit_1.stripIndents) `Unable to find the project configuration that includes ${normalizedPathFromWorkspaceRoot}.
@@ -69,8 +67,8 @@ function getProjectConfigByPath(graph, configPath) {
69
67
  return graph.nodes[componentTestingProjectName].data;
70
68
  }
71
69
  function createExecutorContext(graph, targets, projectName, targetName, configurationName) {
72
- const projectsConfigurations = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(graph);
73
- const nxJsonConfiguration = (0, configuration_1.readNxJson)();
70
+ const projectsConfigurations = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(graph);
71
+ const nxJsonConfiguration = (0, internal_1.readNxJsonFromDisk)();
74
72
  return {
75
73
  cwd: process.cwd(),
76
74
  projectGraph: graph,
@@ -2,8 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findBuildConfig = findBuildConfig;
4
4
  const devkit_1 = require("@nx/devkit");
5
- const configuration_1 = require("nx/src/config/configuration");
6
- const project_graph_1 = require("nx/src/project-graph/project-graph");
5
+ const internal_1 = require("@nx/devkit/internal");
7
6
  async function findBuildConfig(tree, options) {
8
7
  try {
9
8
  // attempt to use the provided target
@@ -118,8 +117,8 @@ function findTargetOptionsInProject(tree, graph, projectName, options) {
118
117
  }
119
118
  }
120
119
  function createExecutorContext(graph, targets, projectName, targetName, configurationName) {
121
- const nxJsonConfiguration = (0, configuration_1.readNxJson)();
122
- const projectsConfigurations = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(graph);
120
+ const nxJsonConfiguration = (0, internal_1.readNxJsonFromDisk)();
121
+ const projectsConfigurations = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(graph);
123
122
  return {
124
123
  cwd: process.cwd(),
125
124
  projectGraph: graph,
@@ -5,9 +5,9 @@ const tslib_1 = require("tslib");
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const path_1 = require("path");
7
7
  const detect_port_1 = tslib_1.__importDefault(require("detect-port"));
8
- const executor_utils_1 = require("nx/src/command-line/run/executor-utils");
9
8
  const fs_1 = require("fs");
10
9
  const os_1 = require("os");
10
+ const internal_1 = require("@nx/devkit/internal");
11
11
  const PORT_LOCK_DIR = (0, path_1.join)((0, os_1.tmpdir)(), 'nx-cypress-port-locks');
12
12
  async function* startDevServer(opts, context) {
13
13
  // no dev server, return the provisioned base url
@@ -136,8 +136,8 @@ ${e.message || e}`);
136
136
  // so we double check the schema if readTargetOptions didn't return a value for the property
137
137
  const projectConfig = context.projectsConfigurations?.projects?.[target.project];
138
138
  const targetConfig = projectConfig.targets[target.target];
139
- const [collection, executor] = (0, executor_utils_1.parseExecutor)(targetConfig.executor);
140
- const { schema } = (0, executor_utils_1.getExecutorInformation)(collection, executor, context.root, context.projectsConfigurations.projects);
139
+ const [collection, executor] = (0, internal_1.parseExecutor)(targetConfig.executor);
140
+ const { schema } = (0, internal_1.getExecutorInformation)(collection, executor, context.root, context.projectsConfigurations.projects);
141
141
  // NOTE: schema won't have a default since readTargetOptions would have
142
142
  // already set that and this check wouldn't need to be made
143
143
  targetHasOpt = Object.keys(schema.properties).includes(property);
@@ -4,7 +4,7 @@ export declare const minSupportedCypressVersion = "13.0.0";
4
4
  export declare const eslintPluginCypressVersion = "^3.5.0";
5
5
  export declare const typesNodeVersion = "^22.0.0";
6
6
  export declare const cypressViteDevServerVersion = "^7.3.1";
7
- export declare const cypressVersion = "^15.17.0";
7
+ export declare const cypressVersion = "^15.20.1";
8
8
  export declare const cypressWebpackVersion = "^5.4.1";
9
9
  export declare const viteVersion = "^6.0.0";
10
10
  export declare const htmlWebpackPluginVersion = "^5.5.0";
@@ -13,7 +13,7 @@ exports.minSupportedCypressVersion = '13.0.0';
13
13
  exports.eslintPluginCypressVersion = '^3.5.0';
14
14
  exports.typesNodeVersion = '^22.0.0';
15
15
  exports.cypressViteDevServerVersion = '^7.3.1';
16
- exports.cypressVersion = '^15.17.0';
16
+ exports.cypressVersion = '^15.20.1';
17
17
  exports.cypressWebpackVersion = '^5.4.1';
18
18
  exports.viteVersion = '^6.0.0';
19
19
  exports.htmlWebpackPluginVersion = '^5.5.0';
package/migrations.json CHANGED
@@ -148,6 +148,18 @@
148
148
  "alwaysAddToPackageJson": false
149
149
  }
150
150
  }
151
+ },
152
+ "23.2.0-cypress-15.20.1": {
153
+ "version": "23.2.0-beta.6",
154
+ "requires": {
155
+ "cypress": ">=15.0.0 <15.20.1"
156
+ },
157
+ "packages": {
158
+ "cypress": {
159
+ "version": "^15.20.1",
160
+ "alwaysAddToPackageJson": false
161
+ }
162
+ }
151
163
  }
152
164
  }
153
165
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/cypress",
3
- "version": "23.2.0-beta.1",
3
+ "version": "23.2.0-beta.10",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -89,12 +89,12 @@
89
89
  "semver": "^7.6.3",
90
90
  "tree-kill": "^1.2.2",
91
91
  "tslib": "^2.3.0",
92
- "@nx/devkit": "23.2.0-beta.1",
93
- "@nx/js": "23.2.0-beta.1",
94
- "@nx/eslint": "23.2.0-beta.1"
92
+ "@nx/devkit": "23.2.0-beta.10",
93
+ "@nx/eslint": "23.2.0-beta.10",
94
+ "@nx/js": "23.2.0-beta.10"
95
95
  },
96
96
  "devDependencies": {
97
- "nx": "23.2.0-beta.1"
97
+ "nx": "23.2.0-beta.10"
98
98
  },
99
99
  "peerDependencies": {
100
100
  "cypress": ">= 13 < 16"