@nx/cypress 17.0.2 → 17.0.4

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 (57) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -4
  3. package/generators.json +3 -3
  4. package/index.d.ts +2 -2
  5. package/index.js +4 -4
  6. package/migrations.json +24 -0
  7. package/package.json +6 -6
  8. package/plugin.d.ts +1 -0
  9. package/plugin.js +6 -0
  10. package/plugins/cypress-preset.d.ts +27 -19
  11. package/plugins/cypress-preset.js +102 -11
  12. package/src/executors/cypress/cypress.impl.d.ts +1 -1
  13. package/src/executors/cypress/cypress.impl.js +6 -152
  14. package/src/executors/cypress/schema.json +11 -1
  15. package/src/generators/base-setup/base-setup.d.ts +1 -0
  16. package/src/generators/base-setup/base-setup.js +26 -3
  17. package/src/generators/base-setup/files/config-js-cjs/__directory__/support/commands.js__ext__ +35 -0
  18. package/src/generators/base-setup/files/config-js-cjs/cypress.config.js__ext__ +3 -0
  19. package/src/generators/base-setup/files/config-js-esm/__directory__/support/commands.js__ext__ +35 -0
  20. package/src/generators/base-setup/files/config-ts/__directory__/support/commands.ts__ext__ +35 -0
  21. package/src/generators/base-setup/files/config-ts/cypress.config.ts__ext__ +3 -0
  22. package/src/generators/component-configuration/component-configuration.d.ts +3 -2
  23. package/src/generators/component-configuration/component-configuration.js +50 -27
  24. package/src/generators/component-configuration/files/__directory__/support/component-index.html +4 -1
  25. package/src/generators/component-configuration/schema.d.ts +7 -0
  26. package/src/generators/component-configuration/schema.json +1 -1
  27. package/src/generators/configuration/configuration.d.ts +5 -0
  28. package/src/generators/configuration/configuration.js +91 -27
  29. package/src/generators/configuration/schema.json +1 -1
  30. package/src/generators/cypress-project/cypress-project.js +25 -5
  31. package/src/generators/cypress-project/schema.d.ts +1 -0
  32. package/src/generators/cypress-project/schema.json +1 -1
  33. package/src/generators/init/init.d.ts +2 -0
  34. package/src/generators/init/init.js +71 -15
  35. package/src/generators/init/schema.d.ts +4 -2
  36. package/src/generators/init/schema.json +19 -1
  37. package/src/generators/migrate-to-cypress-11/schema.json +1 -1
  38. package/src/migrations/update-18-1-0/update-cypress-version-13-6-6.d.ts +2 -0
  39. package/src/migrations/update-18-1-0/update-cypress-version-13-6-6.js +12 -0
  40. package/src/plugins/plugin.d.ts +9 -0
  41. package/src/plugins/plugin.js +215 -0
  42. package/src/utils/add-linter.d.ts +1 -0
  43. package/src/utils/add-linter.js +4 -4
  44. package/src/utils/config.d.ts +6 -7
  45. package/src/utils/config.js +39 -12
  46. package/src/utils/constants.d.ts +4 -0
  47. package/src/utils/constants.js +7 -0
  48. package/src/utils/ct-helpers.d.ts +1 -1
  49. package/src/utils/ct-helpers.js +6 -2
  50. package/src/utils/start-dev-server.d.ts +9 -0
  51. package/src/utils/start-dev-server.js +157 -0
  52. package/src/utils/versions.d.ts +3 -3
  53. package/src/utils/versions.js +3 -3
  54. /package/src/generators/base-setup/files/{__directory__ → common/__directory__}/fixtures/example.json +0 -0
  55. /package/src/generators/base-setup/files/{__directory__ → common/__directory__}/support/commands.ts__ext__ +0 -0
  56. /package/src/generators/base-setup/files/{__directory__ → common/__directory__}/tsconfig.json__ext__ +0 -0
  57. /package/src/generators/base-setup/files/{cypress.config.ts__ext__ → config-js-esm/cypress.config.js__ext__} +0 -0
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cypressInitGenerator = void 0;
3
+ exports.cypressInitGeneratorInternal = exports.cypressInitGenerator = exports.addPlugin = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ const update_package_scripts_1 = require("@nx/devkit/src/utils/update-package-scripts");
6
+ const plugin_1 = require("../../plugins/plugin");
5
7
  const versions_1 = require("../../utils/versions");
6
- const js_1 = require("@nx/js");
7
8
  function setupE2ETargetDefaults(tree) {
8
9
  const nxJson = (0, devkit_1.readNxJson)(tree);
9
10
  if (!nxJson.namedInputs) {
@@ -13,31 +14,86 @@ function setupE2ETargetDefaults(tree) {
13
14
  nxJson.targetDefaults ??= {};
14
15
  const productionFileSet = !!nxJson.namedInputs?.production;
15
16
  nxJson.targetDefaults.e2e ??= {};
17
+ nxJson.targetDefaults.e2e.cache ??= true;
16
18
  nxJson.targetDefaults.e2e.inputs ??= [
17
19
  'default',
18
20
  productionFileSet ? '^production' : '^default',
19
21
  ];
20
22
  (0, devkit_1.updateNxJson)(tree, nxJson);
21
23
  }
22
- function updateDependencies(tree) {
23
- (0, devkit_1.removeDependenciesFromPackageJson)(tree, ['@nx/cypress'], []);
24
- return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
24
+ function updateDependencies(tree, options) {
25
+ const tasks = [];
26
+ tasks.push((0, devkit_1.removeDependenciesFromPackageJson)(tree, ['@nx/cypress'], []));
27
+ tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
25
28
  ['@nx/cypress']: versions_1.nxVersion,
26
29
  cypress: versions_1.cypressVersion,
27
- '@types/node': versions_1.typesNodeVersion,
30
+ }, undefined, options.keepExistingVersions));
31
+ return (0, devkit_1.runTasksInSerial)(...tasks);
32
+ }
33
+ function addPlugin(tree) {
34
+ const nxJson = (0, devkit_1.readNxJson)(tree);
35
+ nxJson.plugins ??= [];
36
+ for (const plugin of nxJson.plugins) {
37
+ if (typeof plugin === 'string'
38
+ ? plugin === '@nx/cypress/plugin'
39
+ : plugin.plugin === '@nx/cypress/plugin') {
40
+ return;
41
+ }
42
+ }
43
+ nxJson.plugins.push({
44
+ plugin: '@nx/cypress/plugin',
45
+ options: {
46
+ targetName: 'e2e',
47
+ componentTestingTargetName: 'component-test',
48
+ ciTargetName: 'e2e-ci',
49
+ openTargetName: 'open-cypress',
50
+ },
28
51
  });
52
+ (0, devkit_1.updateNxJson)(tree, nxJson);
53
+ }
54
+ exports.addPlugin = addPlugin;
55
+ function updateProductionFileset(tree) {
56
+ const nxJson = (0, devkit_1.readNxJson)(tree);
57
+ const productionFileset = nxJson.namedInputs?.production;
58
+ if (productionFileset) {
59
+ nxJson.namedInputs.production = Array.from(new Set([
60
+ ...productionFileset,
61
+ '!{projectRoot}/cypress/**/*',
62
+ '!{projectRoot}/**/*.cy.[jt]s?(x)',
63
+ '!{projectRoot}/cypress.config.[jt]s',
64
+ ]));
65
+ }
66
+ (0, devkit_1.updateNxJson)(tree, nxJson);
29
67
  }
30
68
  async function cypressInitGenerator(tree, options) {
31
- setupE2ETargetDefaults(tree);
32
- const tasks = [];
33
- tasks.push(await (0, js_1.initGenerator)(tree, {
34
- ...options,
35
- skipFormat: true,
36
- }));
69
+ return cypressInitGeneratorInternal(tree, { addPlugin: false, ...options });
70
+ }
71
+ exports.cypressInitGenerator = cypressInitGenerator;
72
+ async function cypressInitGeneratorInternal(tree, options) {
73
+ updateProductionFileset(tree);
74
+ const nxJson = (0, devkit_1.readNxJson)(tree);
75
+ options.addPlugin ??=
76
+ process.env.NX_ADD_PLUGINS !== 'false' &&
77
+ nxJson.useInferencePlugins !== false;
78
+ if (options.addPlugin) {
79
+ addPlugin(tree);
80
+ }
81
+ else {
82
+ setupE2ETargetDefaults(tree);
83
+ }
84
+ let installTask = () => { };
37
85
  if (!options.skipPackageJson) {
38
- tasks.push(updateDependencies(tree));
86
+ installTask = updateDependencies(tree, options);
39
87
  }
40
- return (0, devkit_1.runTasksInSerial)(...tasks);
88
+ if (options.updatePackageScripts) {
89
+ global.NX_CYPRESS_INIT_GENERATOR_RUNNING = true;
90
+ await (0, update_package_scripts_1.updatePackageScripts)(tree, plugin_1.createNodes);
91
+ global.NX_CYPRESS_INIT_GENERATOR_RUNNING = false;
92
+ }
93
+ if (!options.skipFormat) {
94
+ await (0, devkit_1.formatFiles)(tree);
95
+ }
96
+ return installTask;
41
97
  }
42
- exports.cypressInitGenerator = cypressInitGenerator;
98
+ exports.cypressInitGeneratorInternal = cypressInitGeneratorInternal;
43
99
  exports.default = cypressInitGenerator;
@@ -1,5 +1,7 @@
1
1
  export interface Schema {
2
- skipPackageJson?: boolean;
3
-
4
2
  skipFormat?: boolean;
3
+ skipPackageJson?: boolean;
4
+ keepExistingVersions?: boolean;
5
+ updatePackageScripts?: boolean;
6
+ addPlugin?: boolean;
5
7
  }
@@ -1,16 +1,34 @@
1
1
  {
2
- "$schema": "http://json-schema.org/schema",
2
+ "$schema": "https://json-schema.org/schema",
3
3
  "$id": "NxCypressInit",
4
4
  "cli": "nx",
5
5
  "title": "Add Cypress Configuration to the workspace",
6
6
  "description": "Add Cypress Configuration to the workspace.",
7
7
  "type": "object",
8
8
  "properties": {
9
+ "skipFormat": {
10
+ "description": "Skip formatting files.",
11
+ "type": "boolean",
12
+ "default": false,
13
+ "x-priority": "internal"
14
+ },
9
15
  "skipPackageJson": {
10
16
  "type": "boolean",
11
17
  "default": false,
12
18
  "description": "Do not add dependencies to `package.json`.",
13
19
  "x-priority": "internal"
20
+ },
21
+ "keepExistingVersions": {
22
+ "type": "boolean",
23
+ "x-priority": "internal",
24
+ "description": "Keep existing dependencies versions",
25
+ "default": false
26
+ },
27
+ "updatePackageScripts": {
28
+ "type": "boolean",
29
+ "x-priority": "internal",
30
+ "description": "Update `package.json` scripts with inferred targets",
31
+ "default": false
14
32
  }
15
33
  }
16
34
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "http://json-schema.org/schema",
2
+ "$schema": "https://json-schema.org/schema",
3
3
  "$id": "NxCypressMigrateTo11",
4
4
  "cli": "nx",
5
5
  "title": "Migrate e2e project to Cypress 11",
@@ -0,0 +1,2 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export default function (tree: Tree): Promise<void>;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const devkit_1 = require("@nx/devkit");
4
+ const cypress_version_1 = require("../../utils/cypress-version");
5
+ async function default_1(tree) {
6
+ if ((0, cypress_version_1.installedCypressVersion)() < 13) {
7
+ return;
8
+ }
9
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { cypress: '^13.6.6' });
10
+ await (0, devkit_1.formatFiles)(tree);
11
+ }
12
+ exports.default = default_1;
@@ -0,0 +1,9 @@
1
+ import { CreateDependencies, CreateNodes } from '@nx/devkit';
2
+ export interface CypressPluginOptions {
3
+ ciTargetName?: string;
4
+ targetName?: string;
5
+ openTargetName?: string;
6
+ componentTestingTargetName?: string;
7
+ }
8
+ export declare const createDependencies: CreateDependencies;
9
+ export declare const createNodes: CreateNodes<CypressPluginOptions>;
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNodes = exports.createDependencies = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const path_1 = require("path");
6
+ const js_1 = require("@nx/js");
7
+ const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
8
+ const fs_1 = require("fs");
9
+ const workspace_context_1 = require("nx/src/utils/workspace-context");
10
+ const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
11
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
12
+ const constants_1 = require("../utils/constants");
13
+ const config_utils_1 = require("@nx/devkit/src/utils/config-utils");
14
+ const cachePath = (0, path_1.join)(cache_directory_1.projectGraphCacheDirectory, 'cypress.hash');
15
+ const targetsCache = (0, fs_1.existsSync)(cachePath) ? readTargetsCache() : {};
16
+ const calculatedTargets = {};
17
+ function readTargetsCache() {
18
+ return (0, devkit_1.readJsonFile)(cachePath);
19
+ }
20
+ function writeTargetsToCache(targets) {
21
+ (0, devkit_1.writeJsonFile)(cachePath, targets);
22
+ }
23
+ const createDependencies = () => {
24
+ writeTargetsToCache(calculatedTargets);
25
+ return [];
26
+ };
27
+ exports.createDependencies = createDependencies;
28
+ exports.createNodes = [
29
+ '**/cypress.config.{js,ts,mjs,cjs}',
30
+ async (configFilePath, options, context) => {
31
+ options = normalizeOptions(options);
32
+ const projectRoot = (0, path_1.dirname)(configFilePath);
33
+ // Do not create a project if package.json and project.json isn't there.
34
+ const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot));
35
+ if (!siblingFiles.includes('package.json') &&
36
+ !siblingFiles.includes('project.json')) {
37
+ return {};
38
+ }
39
+ const hash = (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, options, context, [
40
+ (0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot)),
41
+ ]);
42
+ const { targets, targetGroups } = targetsCache[hash]
43
+ ? targetsCache[hash]
44
+ : await buildCypressTargets(configFilePath, projectRoot, options, context);
45
+ calculatedTargets[hash] = { targets, targetGroups };
46
+ const project = {
47
+ projectType: 'application',
48
+ targets,
49
+ metadata: {
50
+ technologies: ['cypress'],
51
+ },
52
+ };
53
+ if (targetGroups) {
54
+ project.metadata.targetGroups = targetGroups;
55
+ }
56
+ return {
57
+ projects: {
58
+ [projectRoot]: project,
59
+ },
60
+ };
61
+ },
62
+ ];
63
+ function getOutputs(projectRoot, cypressConfig, testingType) {
64
+ function getOutput(path) {
65
+ if (path.startsWith('..')) {
66
+ return (0, devkit_1.joinPathFragments)('{workspaceRoot}', projectRoot, path);
67
+ }
68
+ else {
69
+ return (0, devkit_1.joinPathFragments)('{projectRoot}', path);
70
+ }
71
+ }
72
+ const { screenshotsFolder, videosFolder, e2e, component } = cypressConfig;
73
+ const outputs = [];
74
+ if (videosFolder) {
75
+ outputs.push(getOutput(videosFolder));
76
+ }
77
+ if (screenshotsFolder) {
78
+ outputs.push(getOutput(screenshotsFolder));
79
+ }
80
+ switch (testingType) {
81
+ case 'e2e': {
82
+ if (e2e.videosFolder) {
83
+ outputs.push(getOutput(e2e.videosFolder));
84
+ }
85
+ if (e2e.screenshotsFolder) {
86
+ outputs.push(getOutput(e2e.screenshotsFolder));
87
+ }
88
+ break;
89
+ }
90
+ case 'component': {
91
+ if (component.videosFolder) {
92
+ outputs.push(getOutput(component.videosFolder));
93
+ }
94
+ if (component.screenshotsFolder) {
95
+ outputs.push(getOutput(component.screenshotsFolder));
96
+ }
97
+ break;
98
+ }
99
+ }
100
+ return outputs;
101
+ }
102
+ async function buildCypressTargets(configFilePath, projectRoot, options, context) {
103
+ const cypressConfig = await (0, config_utils_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFilePath));
104
+ const pluginPresetOptions = {
105
+ ...cypressConfig.e2e?.[constants_1.NX_PLUGIN_OPTIONS],
106
+ ...cypressConfig.env,
107
+ ...cypressConfig.e2e?.env,
108
+ };
109
+ const webServerCommands = pluginPresetOptions?.webServerCommands;
110
+ const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
111
+ const targets = {};
112
+ let targetGroups;
113
+ if ('e2e' in cypressConfig) {
114
+ targets[options.targetName] = {
115
+ command: `cypress run`,
116
+ options: { cwd: projectRoot },
117
+ cache: true,
118
+ inputs: getInputs(namedInputs),
119
+ outputs: getOutputs(projectRoot, cypressConfig, 'e2e'),
120
+ };
121
+ if (webServerCommands?.default) {
122
+ delete webServerCommands.default;
123
+ }
124
+ if (Object.keys(webServerCommands ?? {}).length > 0) {
125
+ targets[options.targetName].configurations ??= {};
126
+ for (const [configuration, webServerCommand] of Object.entries(webServerCommands ?? {})) {
127
+ targets[options.targetName].configurations[configuration] = {
128
+ command: `cypress run --env webServerCommand="${webServerCommand}"`,
129
+ };
130
+ }
131
+ }
132
+ const ciWebServerCommand = pluginPresetOptions?.ciWebServerCommand;
133
+ if (ciWebServerCommand) {
134
+ const specPatterns = Array.isArray(cypressConfig.e2e.specPattern)
135
+ ? cypressConfig.e2e.specPattern.map((p) => (0, path_1.join)(projectRoot, p))
136
+ : [(0, path_1.join)(projectRoot, cypressConfig.e2e.specPattern)];
137
+ const excludeSpecPatterns = !cypressConfig.e2e
138
+ .excludeSpecPattern
139
+ ? cypressConfig.e2e.excludeSpecPattern
140
+ : Array.isArray(cypressConfig.e2e.excludeSpecPattern)
141
+ ? cypressConfig.e2e.excludeSpecPattern.map((p) => (0, path_1.join)(projectRoot, p))
142
+ : [(0, path_1.join)(projectRoot, cypressConfig.e2e.excludeSpecPattern)];
143
+ const specFiles = (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, specPatterns, excludeSpecPatterns);
144
+ const dependsOn = [];
145
+ const outputs = getOutputs(projectRoot, cypressConfig, 'e2e');
146
+ const inputs = getInputs(namedInputs);
147
+ const groupName = 'E2E (CI)';
148
+ targetGroups = { [groupName]: [] };
149
+ const ciTargetGroup = targetGroups[groupName];
150
+ for (const file of specFiles) {
151
+ const relativeSpecFilePath = (0, devkit_1.normalizePath)((0, path_1.relative)(projectRoot, file));
152
+ const targetName = options.ciTargetName + '--' + relativeSpecFilePath;
153
+ ciTargetGroup.push(targetName);
154
+ targets[targetName] = {
155
+ outputs,
156
+ inputs,
157
+ cache: true,
158
+ command: `cypress run --env webServerCommand="${ciWebServerCommand}" --spec ${relativeSpecFilePath}`,
159
+ options: {
160
+ cwd: projectRoot,
161
+ },
162
+ };
163
+ dependsOn.push({
164
+ target: targetName,
165
+ projects: 'self',
166
+ params: 'forward',
167
+ });
168
+ }
169
+ targets[options.ciTargetName] = {
170
+ executor: 'nx:noop',
171
+ cache: true,
172
+ inputs,
173
+ outputs,
174
+ dependsOn,
175
+ };
176
+ ciTargetGroup.push(options.ciTargetName);
177
+ }
178
+ else {
179
+ targetGroups = null;
180
+ }
181
+ }
182
+ if ('component' in cypressConfig) {
183
+ // This will not override the e2e target if it is the same
184
+ targets[options.componentTestingTargetName] ??= {
185
+ command: `cypress run --component`,
186
+ options: { cwd: projectRoot },
187
+ cache: true,
188
+ inputs: getInputs(namedInputs),
189
+ outputs: getOutputs(projectRoot, cypressConfig, 'component'),
190
+ };
191
+ }
192
+ targets[options.openTargetName] = {
193
+ command: `cypress open`,
194
+ options: { cwd: projectRoot },
195
+ };
196
+ return { targets, targetGroups };
197
+ }
198
+ function normalizeOptions(options) {
199
+ options ??= {};
200
+ options.targetName ??= 'e2e';
201
+ options.openTargetName ??= 'open-cypress';
202
+ options.componentTestingTargetName ??= 'component-test';
203
+ options.ciTargetName ??= 'e2e-ci';
204
+ return options;
205
+ }
206
+ function getInputs(namedInputs) {
207
+ return [
208
+ ...('production' in namedInputs
209
+ ? ['default', '^production']
210
+ : ['default', '^default']),
211
+ {
212
+ externalDependencies: ['cypress'],
213
+ },
214
+ ];
215
+ }
@@ -17,5 +17,6 @@ export interface CyLinterOptions {
17
17
  * This is useful when adding linting to a brand new project vs an existing one
18
18
  **/
19
19
  overwriteExisting?: boolean;
20
+ addPlugin?: boolean;
20
21
  }
21
22
  export declare function addLinterToCyProject(tree: Tree, options: CyLinterOptions): Promise<() => void>;
@@ -20,17 +20,16 @@ async function addLinterToCyProject(tree, options) {
20
20
  linter: options.linter,
21
21
  skipFormat: true,
22
22
  tsConfigPaths: [(0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json')],
23
- eslintFilePatterns: [
24
- `${projectConfig.root}/**/*.${options.js ? 'js' : '{js,ts}'}`,
25
- ],
26
23
  setParserOptionsProject: options.setParserOptionsProject,
27
24
  skipPackageJson: options.skipPackageJson,
28
25
  rootProject: options.rootProject,
26
+ addPlugin: options.addPlugin,
29
27
  }));
30
28
  }
31
29
  if (!options.linter || options.linter !== eslint_1.Linter.EsLint) {
32
30
  return (0, devkit_1.runTasksInSerial)(...tasks);
33
31
  }
32
+ options.overwriteExisting = options.overwriteExisting || !eslintFile;
34
33
  tasks.push(!options.skipPackageJson
35
34
  ? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { 'eslint-plugin-cypress': versions_1.eslintPluginCypressVersion })
36
35
  : () => { });
@@ -38,6 +37,7 @@ async function addLinterToCyProject(tree, options) {
38
37
  const overrides = [];
39
38
  if (options.rootProject) {
40
39
  (0, eslint_file_1.addPluginsToLintConfig)(tree, projectConfig.root, '@nx');
40
+ overrides.push(global_eslint_config_1.typeScriptOverride);
41
41
  overrides.push(global_eslint_config_1.javaScriptOverride);
42
42
  }
43
43
  (0, eslint_file_1.addExtendsToLintConfig)(tree, projectConfig.root, 'plugin:cypress/recommended');
@@ -55,7 +55,7 @@ async function addLinterToCyProject(tree, options) {
55
55
  };
56
56
  const addCy6Override = cyVersion && cyVersion < 7;
57
57
  if (options.overwriteExisting) {
58
- overrides.push({
58
+ overrides.unshift({
59
59
  files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
60
60
  parserOptions: !options.setParserOptionsProject
61
61
  ? undefined
@@ -1,18 +1,17 @@
1
- export declare function addDefaultE2EConfig(cyConfigContents: string, options: {
2
- directory: string;
3
- bundler?: string;
4
- }): Promise<string>;
1
+ import { type Tree } from '@nx/devkit';
2
+ import type { NxComponentTestingOptions, NxCypressE2EPresetOptions } from '../../plugins/cypress-preset';
3
+ export declare const CYPRESS_CONFIG_FILE_NAME_PATTERN = "cypress.config.{js,ts,mjs,cjs}";
4
+ export declare function addDefaultE2EConfig(cyConfigContents: string, options: NxCypressE2EPresetOptions, baseUrl: string): Promise<string>;
5
5
  /**
6
6
  * Adds the nxComponentTestingPreset to the cypress config file
7
7
  * Make sure after calling this the correct import statement is addeda
8
8
  * to bring in the nxComponentTestingPreset function
9
9
  **/
10
- export declare function addDefaultCTConfig(cyConfigContents: string, options?: {
11
- bundler?: string;
12
- }): Promise<string>;
10
+ export declare function addDefaultCTConfig(cyConfigContents: string, options?: NxComponentTestingOptions): Promise<string>;
13
11
  /**
14
12
  * Adds the mount command for Cypress
15
13
  * Make sure after calling this the correct import statement is added
16
14
  * to bring in the correct mount from cypress.
17
15
  **/
18
16
  export declare function addMountDefinition(cmpCommandFileContents: string): Promise<string>;
17
+ export declare function getProjectCypressConfigPath(tree: Tree, projectRoot: string): string;
@@ -1,30 +1,40 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addMountDefinition = exports.addDefaultCTConfig = exports.addDefaultE2EConfig = void 0;
4
- const TS_QUERY_EXPORT_CONFIG_PREFIX = ':matches(ExportAssignment, BinaryExpression:has(Identifier[name="module"]):has(Identifier[name="exports"]))';
5
- async function addDefaultE2EConfig(cyConfigContents, options) {
3
+ exports.getProjectCypressConfigPath = exports.addMountDefinition = exports.addDefaultCTConfig = exports.addDefaultE2EConfig = exports.CYPRESS_CONFIG_FILE_NAME_PATTERN = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ exports.CYPRESS_CONFIG_FILE_NAME_PATTERN = 'cypress.config.{js,ts,mjs,cjs}';
6
+ const TS_QUERY_COMMON_JS_EXPORT_SELECTOR = 'BinaryExpression:has(Identifier[name="module"]):has(Identifier[name="exports"])';
7
+ const TS_QUERY_EXPORT_CONFIG_PREFIX = `:matches(ExportAssignment, ${TS_QUERY_COMMON_JS_EXPORT_SELECTOR}) `;
8
+ async function addDefaultE2EConfig(cyConfigContents, options, baseUrl) {
6
9
  if (!cyConfigContents) {
7
10
  throw new Error('The passed in cypress config file is empty!');
8
11
  }
9
12
  const { tsquery } = await Promise.resolve().then(() => require('@phenomnomnominal/tsquery'));
13
+ const isCommonJS = tsquery.query(cyConfigContents, TS_QUERY_COMMON_JS_EXPORT_SELECTOR).length >
14
+ 0;
10
15
  const testingTypeConfig = tsquery.query(cyConfigContents, `${TS_QUERY_EXPORT_CONFIG_PREFIX} PropertyAssignment:has(Identifier[name="e2e"])`);
11
16
  let updatedConfigContents = cyConfigContents;
12
17
  if (testingTypeConfig.length === 0) {
13
- const configValue = options.bundler === 'vite'
14
- ? `nxE2EPreset(__filename, { cypressDir: '${options.directory}', bundler: 'vite' })`
15
- : `nxE2EPreset(__filename, { cypressDir: '${options.directory}' })`;
18
+ const configValue = `nxE2EPreset(__filename, ${JSON.stringify(options)})`;
16
19
  updatedConfigContents = tsquery.replace(cyConfigContents, `${TS_QUERY_EXPORT_CONFIG_PREFIX} ObjectLiteralExpression:first-child`, (node) => {
20
+ let baseUrlContents = baseUrl ? `,\nbaseUrl: '${baseUrl}'` : '';
17
21
  if (node.properties.length > 0) {
18
22
  return `{
19
23
  ${node.properties.map((p) => p.getText()).join(',\n')},
20
- e2e: ${configValue}
24
+ e2e: { ...${configValue}${baseUrlContents} }
21
25
  }`;
22
26
  }
23
27
  return `{
24
- e2e: ${configValue}
28
+ e2e: { ...${configValue}${baseUrlContents} }
25
29
  }`;
26
30
  });
27
- updatedConfigContents = `import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';\n${updatedConfigContents}`;
31
+ return isCommonJS
32
+ ? `const { nxE2EPreset } = require('@nx/cypress/plugins/cypress-preset');
33
+
34
+ ${updatedConfigContents}`
35
+ : `import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
36
+
37
+ ${updatedConfigContents}`;
28
38
  }
29
39
  return updatedConfigContents;
30
40
  }
@@ -42,9 +52,16 @@ async function addDefaultCTConfig(cyConfigContents, options = {}) {
42
52
  const testingTypeConfig = tsquery.query(cyConfigContents, `${TS_QUERY_EXPORT_CONFIG_PREFIX} PropertyAssignment:has(Identifier[name="component"])`);
43
53
  let updatedConfigContents = cyConfigContents;
44
54
  if (testingTypeConfig.length === 0) {
45
- const configValue = options?.bundler === 'vite'
46
- ? "nxComponentTestingPreset(__filename, { bundler: 'vite' })"
47
- : 'nxComponentTestingPreset(__filename)';
55
+ let configValue = 'nxComponentTestingPreset(__filename)';
56
+ if (options) {
57
+ if (options.bundler !== 'vite') {
58
+ // vite is the default bundler, so we don't need to set it
59
+ delete options.bundler;
60
+ }
61
+ if (Object.keys(options).length) {
62
+ configValue = `nxComponentTestingPreset(__filename, ${JSON.stringify(options)})`;
63
+ }
64
+ }
48
65
  updatedConfigContents = tsquery.replace(cyConfigContents, `${TS_QUERY_EXPORT_CONFIG_PREFIX} ObjectLiteralExpression:first-child`, (node) => {
49
66
  if (node.properties.length > 0) {
50
67
  return `{
@@ -86,3 +103,13 @@ async function addMountDefinition(cmpCommandFileContents) {
86
103
  return `${updatedInterface}\n${mountCommand}`;
87
104
  }
88
105
  exports.addMountDefinition = addMountDefinition;
106
+ function getProjectCypressConfigPath(tree, projectRoot) {
107
+ const cypressConfigPaths = (0, devkit_1.glob)(tree, [
108
+ (0, devkit_1.joinPathFragments)(projectRoot, exports.CYPRESS_CONFIG_FILE_NAME_PATTERN),
109
+ ]);
110
+ if (cypressConfigPaths.length === 0) {
111
+ throw new Error(`Could not find a cypress config file in ${projectRoot}.`);
112
+ }
113
+ return cypressConfigPaths[0];
114
+ }
115
+ exports.getProjectCypressConfigPath = getProjectCypressConfigPath;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Key used to store options used by the nx plugin for @nx/cypress.
3
+ */
4
+ export declare const NX_PLUGIN_OPTIONS = "__NxPluginOptions__";
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NX_PLUGIN_OPTIONS = void 0;
4
+ /**
5
+ * Key used to store options used by the nx plugin for @nx/cypress.
6
+ */
7
+ exports.NX_PLUGIN_OPTIONS = '__NxPluginOptions__';
@@ -11,6 +11,6 @@ export declare function getTempTailwindPath(context: ExecutorContext): string;
11
11
  * Checks if the childProjectName is a descendent of the parentProjectName
12
12
  * in the project graph
13
13
  **/
14
- export declare function isCtProjectUsingBuildProject(graph: ProjectGraph, parentProjectName: string, childProjectName: string): boolean;
14
+ export declare function isCtProjectUsingBuildProject(graph: ProjectGraph, parentProjectName: string, childProjectName: string, seen?: Set<string>): boolean;
15
15
  export declare function getProjectConfigByPath(graph: ProjectGraph, configPath: string): ProjectConfiguration;
16
16
  export declare function createExecutorContext(graph: ProjectGraph, targets: Record<string, TargetConfiguration>, projectName: string, targetName: string, configurationName: string): ExecutorContext;
@@ -30,14 +30,18 @@ exports.getTempTailwindPath = getTempTailwindPath;
30
30
  * Checks if the childProjectName is a descendent of the parentProjectName
31
31
  * in the project graph
32
32
  **/
33
- function isCtProjectUsingBuildProject(graph, parentProjectName, childProjectName) {
33
+ function isCtProjectUsingBuildProject(graph, parentProjectName, childProjectName, seen = new Set()) {
34
+ if (seen.has(parentProjectName)) {
35
+ return false;
36
+ }
37
+ seen.add(parentProjectName);
34
38
  const isProjectDirectDep = graph.dependencies[parentProjectName].some((p) => p.target === childProjectName);
35
39
  if (isProjectDirectDep) {
36
40
  return true;
37
41
  }
38
42
  const maybeIntermediateProjects = graph.dependencies[parentProjectName].filter((p) => !graph.externalNodes[p.target]);
39
43
  for (const maybeIntermediateProject of maybeIntermediateProjects) {
40
- if (isCtProjectUsingBuildProject(graph, maybeIntermediateProject.target, childProjectName)) {
44
+ if (isCtProjectUsingBuildProject(graph, maybeIntermediateProject.target, childProjectName, seen)) {
41
45
  return true;
42
46
  }
43
47
  }
@@ -0,0 +1,9 @@
1
+ import { ExecutorContext } from '@nx/devkit';
2
+ import { CypressExecutorOptions } from '../executors/cypress/cypress.impl';
3
+ export declare function startDevServer(opts: Omit<CypressExecutorOptions, 'cypressConfig'>, context: ExecutorContext): AsyncGenerator<{
4
+ baseUrl: any;
5
+ portLockFilePath?: undefined;
6
+ } | {
7
+ baseUrl: any;
8
+ portLockFilePath: string;
9
+ }, void, unknown>;