@nx/cypress 20.0.7 → 20.1.0-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/cypress",
3
- "version": "20.0.7",
3
+ "version": "20.1.0-beta.0",
4
4
  "private": false,
5
5
  "description": "The Nx Plugin for Cypress contains executors and generators allowing your workspace to use the powerful Cypress integration testing capabilities.",
6
6
  "repository": {
@@ -36,9 +36,9 @@
36
36
  "migrations": "./migrations.json"
37
37
  },
38
38
  "dependencies": {
39
- "@nx/devkit": "20.0.7",
40
- "@nx/eslint": "20.0.7",
41
- "@nx/js": "20.0.7",
39
+ "@nx/devkit": "20.1.0-beta.0",
40
+ "@nx/eslint": "20.1.0-beta.0",
41
+ "@nx/js": "20.1.0-beta.0",
42
42
  "@phenomnomnominal/tsquery": "~5.0.1",
43
43
  "detect-port": "^1.5.1",
44
44
  "tslib": "^2.3.0"
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nxBaseCypressPreset = nxBaseCypressPreset;
4
4
  exports.nxE2EPreset = nxE2EPreset;
5
5
  const devkit_1 = require("@nx/devkit");
6
- const path_1 = require("path");
7
- const fs_1 = require("fs");
8
- const preprocessor_vite_1 = require("../src/plugins/preprocessor-vite");
9
- const constants_1 = require("../src/utils/constants");
6
+ const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
10
7
  const child_process_1 = require("child_process");
8
+ const fs_1 = require("fs");
11
9
  const http_1 = require("http");
12
10
  const https_1 = require("https");
11
+ const path_1 = require("path");
12
+ const preprocessor_vite_1 = require("../src/plugins/preprocessor-vite");
13
+ const constants_1 = require("../src/utils/constants");
13
14
  function nxBaseCypressPreset(pathToConfig, options) {
14
15
  // used to set babel settings for react CT.
15
16
  process.env.NX_CYPRESS_COMPONENT_TEST =
@@ -21,8 +22,13 @@ function nxBaseCypressPreset(pathToConfig, options) {
21
22
  : (0, path_1.dirname)(pathToConfig);
22
23
  const projectPath = (0, path_1.relative)(devkit_1.workspaceRoot, normalizedPath);
23
24
  const offset = (0, path_1.relative)(normalizedPath, devkit_1.workspaceRoot);
24
- const videosFolder = (0, path_1.join)(offset, 'dist', 'cypress', projectPath, 'videos');
25
- const screenshotsFolder = (0, path_1.join)(offset, 'dist', 'cypress', projectPath, 'screenshots');
25
+ const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)();
26
+ const videosFolder = isTsSolutionSetup
27
+ ? (0, path_1.join)('test-output', 'cypress', 'videos')
28
+ : (0, path_1.join)(offset, 'dist', 'cypress', projectPath, 'videos');
29
+ const screenshotsFolder = isTsSolutionSetup
30
+ ? (0, path_1.join)('test-output', 'cypress', 'screenshots')
31
+ : (0, path_1.join)(offset, 'dist', 'cypress', projectPath, 'screenshots');
26
32
  return {
27
33
  videosFolder,
28
34
  screenshotsFolder,
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addBaseCypressSetup = addBaseCypressSetup;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const js_1 = require("@nx/js");
6
+ const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
6
7
  const path_1 = require("path");
7
8
  function addBaseCypressSetup(tree, options) {
8
9
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
@@ -19,9 +20,13 @@ function addBaseCypressSetup(tree, options) {
19
20
  tsConfigPath: opts.hasTsConfig
20
21
  ? `${opts.offsetFromProjectRoot}tsconfig.json`
21
22
  : (0, js_1.getRelativePathToRootTsConfig)(tree, projectConfig.root),
23
+ linter: isEslintInstalled(tree) ? 'eslint' : 'none',
22
24
  ext: '',
23
25
  };
24
26
  (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files/common'), projectConfig.root, templateVars);
27
+ (0, devkit_1.generateFiles)(tree, (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree)
28
+ ? (0, path_1.join)(__dirname, 'files/tsconfig/ts-solution')
29
+ : (0, path_1.join)(__dirname, 'files/tsconfig/non-ts-solution'), projectConfig.root, templateVars);
25
30
  if (options.js) {
26
31
  if (isEsmProject(tree, projectConfig.root)) {
27
32
  (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files/config-js-esm'), projectConfig.root, templateVars);
@@ -77,3 +82,7 @@ function isEsmProject(tree, projectRoot) {
77
82
  }
78
83
  return packageJson.type === 'module';
79
84
  }
85
+ function isEslintInstalled(tree) {
86
+ const { dependencies, devDependencies } = (0, devkit_1.readJson)(tree, 'package.json');
87
+ return !!(dependencies?.eslint || devDependencies?.eslint);
88
+ }
@@ -10,11 +10,13 @@
10
10
  // https://on.cypress.io/custom-commands
11
11
  // ***********************************************
12
12
 
13
- // eslint-disable-next-line @typescript-eslint/no-namespace
14
- declare namespace Cypress {
15
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
- interface Chainable<Subject> {
17
- login(email: string, password: string): void;
13
+ declare global {<% if (linter === 'eslint') { %>
14
+ // eslint-disable-next-line @typescript-eslint/no-namespace<% } %>
15
+ namespace Cypress {<% if (linter === 'eslint') { %>
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars<% } %>
17
+ interface Chainable<Subject> {
18
+ login(email: string, password: string): void;
19
+ }
18
20
  }
19
21
  }
20
22
 
@@ -10,11 +10,13 @@
10
10
  // https://on.cypress.io/custom-commands
11
11
  // ***********************************************
12
12
 
13
- // eslint-disable-next-line @typescript-eslint/no-namespace
14
- declare namespace Cypress {
15
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
- interface Chainable<Subject> {
17
- login(email: string, password: string): void;
13
+ declare global {<% if (linter === 'eslint') { %>
14
+ // eslint-disable-next-line @typescript-eslint/no-namespace<% } %>
15
+ namespace Cypress {<% if (linter === 'eslint') { %>
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars<% } %>
17
+ interface Chainable<Subject> {
18
+ login(email: string, password: string): void;
19
+ }
18
20
  }
19
21
  }
20
22
 
@@ -10,11 +10,13 @@
10
10
  // https://on.cypress.io/custom-commands
11
11
  // ***********************************************
12
12
 
13
- // eslint-disable-next-line @typescript-eslint/no-namespace
14
- declare namespace Cypress {
15
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
- interface Chainable<Subject> {
17
- login(email: string, password: string): void;
13
+ declare global {<% if (linter === 'eslint') { %>
14
+ // eslint-disable-next-line @typescript-eslint/no-namespace<% } %>
15
+ namespace Cypress {<% if (linter === 'eslint') { %>
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars<% } %>
17
+ interface Chainable<Subject> {
18
+ login(email: string, password: string): void;
19
+ }
18
20
  }
19
21
  }
20
22
 
@@ -10,11 +10,13 @@
10
10
  // https://on.cypress.io/custom-commands
11
11
  // ***********************************************
12
12
 
13
- // eslint-disable-next-line @typescript-eslint/no-namespace
14
- declare namespace Cypress {
15
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
- interface Chainable<Subject> {
17
- login(email: string, password: string): void;
13
+ declare global {<% if (linter === 'eslint') { %>
14
+ // eslint-disable-next-line @typescript-eslint/no-namespace<% } %>
15
+ namespace Cypress {<% if (linter === 'eslint') { %>
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars<% } %>
17
+ interface Chainable<Subject> {
18
+ login(email: string, password: string): void;
19
+ }
18
20
  }
19
21
  }
20
22
 
@@ -12,9 +12,9 @@
12
12
  "**/*.js",
13
13
  "<%= offsetFromProjectRoot %>cypress.config.ts",
14
14
  "<%= offsetFromProjectRoot %>**/*.cy.ts",
15
- <% if (jsx) { %> "<%= offsetFromProjectRoot %>**/*.cy.tsx",<% } %>
15
+ <%_ if (jsx) { _%>"<%= offsetFromProjectRoot %>**/*.cy.tsx",<%_ } _%>
16
16
  "<%= offsetFromProjectRoot %>**/*.cy.js",
17
- <% if (jsx) { %>"<%= offsetFromProjectRoot %>**/*.cy.jsx",<% } %>
17
+ <%_ if (jsx) { _%>"<%= offsetFromProjectRoot %>**/*.cy.jsx",<%_ } _%>
18
18
  "<%= offsetFromProjectRoot %>**/*.d.ts"
19
19
  ]
20
20
  }
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "<%= tsConfigPath %>",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
6
+ "allowJs": true,
7
+ "types": ["cypress", "node"],
8
+ "sourceMap": false
9
+ },
10
+ "include": [
11
+ "**/*.ts",
12
+ "**/*.js",
13
+ "<%= offsetFromProjectRoot %>cypress.config.ts",
14
+ "<%= offsetFromProjectRoot %>**/*.cy.ts",
15
+ <%_ if (jsx) { _%>"<%= offsetFromProjectRoot %>**/*.cy.tsx",<%_ } _%>
16
+ "<%= offsetFromProjectRoot %>**/*.cy.js",
17
+ <%_ if (jsx) { _%>"<%= offsetFromProjectRoot %>**/*.cy.jsx",<%_ } _%>
18
+ "<%= offsetFromProjectRoot %>**/*.d.ts"
19
+ ]
20
+ }
@@ -78,6 +78,7 @@ function addProjectFiles(tree, projectConfig, opts) {
78
78
  ...opts,
79
79
  projectRoot: projectConfig.root,
80
80
  offsetFromRoot: (0, devkit_1.offsetFromRoot)(projectConfig.root),
81
+ linter: isEslintInstalled(tree) ? 'eslint' : 'none',
81
82
  ext: '',
82
83
  });
83
84
  }
@@ -163,4 +164,8 @@ function updateTsConfigForComponentTesting(tree, projectConfig) {
163
164
  });
164
165
  }
165
166
  }
167
+ function isEslintInstalled(tree) {
168
+ const { dependencies, devDependencies } = (0, devkit_1.readJson)(tree, 'package.json');
169
+ return !!(dependencies?.eslint || devDependencies?.eslint);
170
+ }
166
171
  exports.default = componentConfigurationGenerator;
@@ -17,11 +17,10 @@
17
17
  import './commands';
18
18
 
19
19
  // add component testing only related command here, such as mount
20
- declare global {
21
- // eslint-disable-next-line @typescript-eslint/no-namespace
22
- namespace Cypress {
23
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
- interface Chainable<Subject> {
25
- }
20
+ declare global {<% if (linter === 'eslint') { %>
21
+ // eslint-disable-next-line @typescript-eslint/no-namespace<% } %>
22
+ namespace Cypress {<% if (linter === 'eslint') { %>
23
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars<% } %>
24
+ interface Chainable<Subject> {}
26
25
  }
27
26
  }
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.configurationGenerator = configurationGenerator;
4
4
  exports.configurationGeneratorInternal = configurationGeneratorInternal;
5
5
  const devkit_1 = require("@nx/devkit");
6
- const eslint_1 = require("@nx/eslint");
6
+ const project_name_and_root_utils_1 = require("@nx/devkit/src/generators/project-name-and-root-utils");
7
+ const prompt_1 = require("@nx/devkit/src/generators/prompt");
7
8
  const js_1 = require("@nx/js");
9
+ const package_manager_workspaces_1 = require("@nx/js/src/utils/package-manager-workspaces");
8
10
  const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
9
11
  const path_1 = require("path");
10
12
  const add_linter_1 = require("../../utils/add-linter");
@@ -20,9 +22,7 @@ function configurationGenerator(tree, options) {
20
22
  });
21
23
  }
22
24
  async function configurationGeneratorInternal(tree, options) {
23
- (0, ts_solution_setup_1.assertNotUsingTsSolutionSetup)(tree, 'cypress', 'configuration');
24
- const opts = normalizeOptions(tree, options);
25
- opts.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
25
+ const opts = await normalizeOptions(tree, options);
26
26
  const tasks = [];
27
27
  const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
28
28
  if (!(0, cypress_version_1.installedCypressVersion)()) {
@@ -43,6 +43,20 @@ async function configurationGeneratorInternal(tree, options) {
43
43
  if (!hasPlugin) {
44
44
  addTarget(tree, opts, projectGraph);
45
45
  }
46
+ const { root: projectRoot } = (0, devkit_1.readProjectConfiguration)(tree, options.project);
47
+ const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
48
+ if (isTsSolutionSetup) {
49
+ createPackageJson(tree, opts);
50
+ ignoreTestOutput(tree);
51
+ if (!options.rootProject) {
52
+ // add the project tsconfig to the workspace root tsconfig.json references
53
+ (0, devkit_1.updateJson)(tree, 'tsconfig.json', (json) => {
54
+ json.references ??= [];
55
+ json.references.push({ path: './' + projectRoot });
56
+ return json;
57
+ });
58
+ }
59
+ }
46
60
  const linterTask = await (0, add_linter_1.addLinterToCyProject)(tree, {
47
61
  ...opts,
48
62
  cypressDir: opts.directory,
@@ -54,6 +68,12 @@ async function configurationGeneratorInternal(tree, options) {
54
68
  if (!opts.skipFormat) {
55
69
  await (0, devkit_1.formatFiles)(tree);
56
70
  }
71
+ if (isTsSolutionSetup) {
72
+ const projectPackageManagerWorkspaceState = (0, package_manager_workspaces_1.getProjectPackageManagerWorkspaceState)(tree, projectRoot);
73
+ if (projectPackageManagerWorkspaceState !== 'included') {
74
+ tasks.push((0, package_manager_workspaces_1.getProjectPackageManagerWorkspaceStateWarningTask)(projectPackageManagerWorkspaceState, tree.root));
75
+ }
76
+ }
57
77
  return (0, devkit_1.runTasksInSerial)(...tasks);
58
78
  }
59
79
  function ensureDependencies(tree, options) {
@@ -65,7 +85,22 @@ function ensureDependencies(tree, options) {
65
85
  }
66
86
  return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, devDependencies);
67
87
  }
68
- function normalizeOptions(tree, options) {
88
+ async function normalizeOptions(tree, options) {
89
+ const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
90
+ let linter = options.linter;
91
+ if (!linter) {
92
+ const choices = isTsSolutionSetup
93
+ ? [{ name: 'none' }, { name: 'eslint' }]
94
+ : [{ name: 'eslint' }, { name: 'none' }];
95
+ const defaultValue = isTsSolutionSetup ? 'none' : 'eslint';
96
+ linter = await (0, prompt_1.promptWhenInteractive)({
97
+ type: 'select',
98
+ name: 'linter',
99
+ message: `Which linter would you like to use?`,
100
+ choices,
101
+ initial: 0,
102
+ }, { linter: defaultValue }).then(({ linter }) => linter);
103
+ }
69
104
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
70
105
  if (projectConfig?.targets?.e2e) {
71
106
  throw new Error(`Project ${options.project} already has an e2e target.
@@ -91,7 +126,7 @@ In this case you need to provide a devServerTarget,'<projectName>:<targetName>[:
91
126
  ...options,
92
127
  bundler: options.bundler ?? 'webpack',
93
128
  rootProject: options.rootProject ?? projectConfig.root === '.',
94
- linter: options.linter ?? eslint_1.Linter.EsLint,
129
+ linter,
95
130
  devServerTarget,
96
131
  };
97
132
  }
@@ -221,4 +256,29 @@ function addTarget(tree, opts, projectGraph) {
221
256
  }
222
257
  (0, devkit_1.updateProjectConfiguration)(tree, opts.project, projectConfig);
223
258
  }
259
+ function createPackageJson(tree, options) {
260
+ const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
261
+ const packageJsonPath = (0, devkit_1.joinPathFragments)(projectConfig.root, 'package.json');
262
+ if (tree.exists(packageJsonPath)) {
263
+ return;
264
+ }
265
+ const importPath = (0, project_name_and_root_utils_1.resolveImportPath)(tree, projectConfig.name, projectConfig.root);
266
+ const packageJson = {
267
+ name: importPath,
268
+ version: '0.0.1',
269
+ private: true,
270
+ };
271
+ (0, devkit_1.writeJson)(tree, packageJsonPath, packageJson);
272
+ }
273
+ function ignoreTestOutput(tree) {
274
+ if (!tree.exists('.gitignore')) {
275
+ devkit_1.logger.warn(`Couldn't find a root .gitignore file to update.`);
276
+ }
277
+ let content = tree.read('.gitignore', 'utf-8');
278
+ if (/^test-output$/gm.test(content)) {
279
+ return;
280
+ }
281
+ content = `${content}\ntest-output\n`;
282
+ tree.write('.gitignore', content);
283
+ }
224
284
  exports.default = configurationGenerator;
@@ -46,8 +46,8 @@
46
46
  "linter": {
47
47
  "description": "The tool to use for running lint checks.",
48
48
  "type": "string",
49
- "enum": ["eslint", "none"],
50
- "default": "eslint"
49
+ "enum": ["none", "eslint"],
50
+ "x-priority": "important"
51
51
  },
52
52
  "js": {
53
53
  "description": "Generate JavaScript files rather than TypeScript files.",
@@ -5,7 +5,6 @@ exports.cypressInitGenerator = cypressInitGenerator;
5
5
  exports.cypressInitGeneratorInternal = cypressInitGeneratorInternal;
6
6
  const devkit_1 = require("@nx/devkit");
7
7
  const add_plugin_1 = require("@nx/devkit/src/utils/add-plugin");
8
- const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
9
8
  const plugin_1 = require("../../plugins/plugin");
10
9
  const versions_1 = require("../../utils/versions");
11
10
  function setupE2ETargetDefaults(tree) {
@@ -62,7 +61,6 @@ async function cypressInitGenerator(tree, options) {
62
61
  return cypressInitGeneratorInternal(tree, { addPlugin: false, ...options });
63
62
  }
64
63
  async function cypressInitGeneratorInternal(tree, options) {
65
- (0, ts_solution_setup_1.assertNotUsingTsSolutionSetup)(tree, 'cypress', 'init');
66
64
  updateProductionFileset(tree);
67
65
  const nxJson = (0, devkit_1.readNxJson)(tree);
68
66
  options.addPlugin ??=
@@ -68,6 +68,42 @@ async function createNodesInternal(configFilePath, options, context, targetsCach
68
68
  },
69
69
  };
70
70
  }
71
+ function getTargetOutputs(outputs, subfolder) {
72
+ return outputs.map((output) => subfolder ? (0, path_1.join)(output, subfolder) : output);
73
+ }
74
+ function getTargetConfig(cypressConfig, outputSubfolder, ciBaseUrl) {
75
+ const config = {};
76
+ if (ciBaseUrl) {
77
+ config['baseUrl'] = ciBaseUrl;
78
+ }
79
+ const { screenshotsFolder, videosFolder, e2e, component } = cypressConfig;
80
+ if (videosFolder) {
81
+ config['videosFolder'] = (0, path_1.join)(videosFolder, outputSubfolder);
82
+ }
83
+ if (screenshotsFolder) {
84
+ config['screenshotsFolder'] = (0, path_1.join)(screenshotsFolder, outputSubfolder);
85
+ }
86
+ if (e2e) {
87
+ config['e2e'] = {};
88
+ if (e2e.videosFolder) {
89
+ config['e2e']['videosFolder'] = (0, path_1.join)(e2e.videosFolder, outputSubfolder);
90
+ }
91
+ if (e2e.screenshotsFolder) {
92
+ config['e2e']['screenshotsFolder'] = (0, path_1.join)(e2e.screenshotsFolder, outputSubfolder);
93
+ }
94
+ }
95
+ if (component) {
96
+ config['component'] = {};
97
+ if (component.videosFolder) {
98
+ config['component']['videosFolder'] = (0, path_1.join)(component.videosFolder, outputSubfolder);
99
+ }
100
+ if (component.screenshotsFolder) {
101
+ config['component']['screenshotsFolder'] = (0, path_1.join)(component.screenshotsFolder, outputSubfolder);
102
+ }
103
+ }
104
+ // Stringify twice to escape the quotes.
105
+ return JSON.stringify(JSON.stringify(config));
106
+ }
71
107
  function getOutputs(projectRoot, cypressConfig, testingType) {
72
108
  function getOutput(path) {
73
109
  if (path.startsWith('..')) {
@@ -170,12 +206,15 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
170
206
  for (const file of specFiles) {
171
207
  const relativeSpecFilePath = (0, devkit_1.normalizePath)((0, path_1.relative)(projectRoot, file));
172
208
  const targetName = options.ciTargetName + '--' + relativeSpecFilePath;
209
+ const outputSubfolder = relativeSpecFilePath
210
+ .replace(/[\/\\]/g, '-')
211
+ .replace(/\./g, '-');
173
212
  ciTargetGroup.push(targetName);
174
213
  targets[targetName] = {
175
- outputs,
214
+ outputs: getTargetOutputs(outputs, outputSubfolder),
176
215
  inputs,
177
216
  cache: true,
178
- command: `cypress run --env webServerCommand="${ciWebServerCommand}" --spec ${relativeSpecFilePath}${ciBaseUrl ? ` --config='{"baseUrl": "${ciBaseUrl}"}'` : ''}`,
217
+ command: `cypress run --env webServerCommand="${ciWebServerCommand}" --spec ${relativeSpecFilePath} --config=${getTargetConfig(cypressConfig, outputSubfolder, ciBaseUrl)}`,
179
218
  options: {
180
219
  cwd: projectRoot,
181
220
  },