@nx/cypress 0.0.0-pr-32490-e4fdfa9 → 0.0.0-pr-32868-a65a4a2

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/README.md CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # Nx: Smart Repos · Fast Builds
24
24
 
25
- An AI-first build platform that connects everything from your editor to CI. Helping you deliver fast, without breaking things.
25
+ Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.
26
26
 
27
27
  This package is a [Cypress plugin for Nx](https://nx.dev/cypress/overview).
28
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/cypress",
3
- "version": "0.0.0-pr-32490-e4fdfa9",
3
+ "version": "0.0.0-pr-32868-a65a4a2",
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": "0.0.0-pr-32490-e4fdfa9",
40
- "@nx/eslint": "0.0.0-pr-32490-e4fdfa9",
41
- "@nx/js": "0.0.0-pr-32490-e4fdfa9",
39
+ "@nx/devkit": "0.0.0-pr-32868-a65a4a2",
40
+ "@nx/eslint": "0.0.0-pr-32868-a65a4a2",
41
+ "@nx/js": "0.0.0-pr-32868-a65a4a2",
42
42
  "@phenomnomnominal/tsquery": "~5.0.1",
43
43
  "detect-port": "^1.5.1",
44
44
  "semver": "^7.6.3",
@@ -46,7 +46,7 @@
46
46
  "tslib": "^2.3.0"
47
47
  },
48
48
  "devDependencies": {
49
- "nx": "0.0.0-pr-32490-e4fdfa9"
49
+ "nx": "0.0.0-pr-32868-a65a4a2"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "cypress": ">= 3 < 15"
@@ -1,9 +1,10 @@
1
- import { CreateNodes, CreateNodesV2 } from '@nx/devkit';
1
+ import { type CreateNodes, type CreateNodesV2 } from '@nx/devkit';
2
2
  export interface CypressPluginOptions {
3
3
  ciTargetName?: string;
4
4
  targetName?: string;
5
5
  openTargetName?: string;
6
6
  componentTestingTargetName?: string;
7
+ ciComponentTestingTargetName?: string;
7
8
  }
8
9
  export declare const createNodesV2: CreateNodesV2<CypressPluginOptions>;
9
10
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/cypress/src/plugins/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAGX,aAAa,EAWd,MAAM,YAAY,CAAC;AAepB,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAoBD,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,oBAAoB,CAqB7D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,oBAAoB,CAQzD,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/cypress/src/plugins/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAGhB,KAAK,aAAa,EAWnB,MAAM,YAAY,CAAC;AAYpB,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,4BAA4B,CAAC,EAAE,MAAM,CAAC;CACvC;AA8BD,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,oBAAoB,CAqB7D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,oBAAoB,CAQzD,CAAC"}
@@ -2,16 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createNodes = exports.createNodesV2 = void 0;
4
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
5
  const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
10
- const cache_directory_1 = require("nx/src/utils/cache-directory");
11
- const constants_1 = require("../utils/constants");
12
6
  const config_utils_1 = require("@nx/devkit/src/utils/config-utils");
7
+ const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
8
+ const js_1 = require("@nx/js");
9
+ const fs_1 = require("fs");
13
10
  const devkit_internals_1 = require("nx/src/devkit-internals");
11
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
14
12
  const workspace_context_1 = require("nx/src/utils/workspace-context");
13
+ const path_1 = require("path");
14
+ const constants_1 = require("../utils/constants");
15
15
  function readTargetsCache(cachePath) {
16
16
  try {
17
17
  return process.env.NX_CACHE_PROJECT_GRAPH !== 'false'
@@ -26,6 +26,16 @@ function writeTargetsToCache(cachePath, results) {
26
26
  (0, devkit_1.writeJsonFile)(cachePath, results);
27
27
  }
28
28
  const cypressConfigGlob = '**/cypress.config.{js,ts,mjs,cjs}';
29
+ const defaultPatterns = {
30
+ e2e: {
31
+ specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
32
+ excludeSpecPattern: '*.hot-update.js',
33
+ },
34
+ component: {
35
+ specPattern: '**/*.cy.{js,jsx,ts,tsx}',
36
+ excludeSpecPattern: ['/snapshots/*', '/image_snapshots/*'],
37
+ },
38
+ };
29
39
  const pmc = (0, devkit_1.getPackageManagerCommand)();
30
40
  exports.createNodesV2 = [
31
41
  cypressConfigGlob,
@@ -214,16 +224,7 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
214
224
  }
215
225
  const ciWebServerCommand = pluginPresetOptions?.ciWebServerCommand;
216
226
  if (ciWebServerCommand) {
217
- const specPatterns = Array.isArray(cypressConfig.e2e.specPattern)
218
- ? cypressConfig.e2e.specPattern.map((p) => (0, path_1.join)(projectRoot, p))
219
- : [(0, path_1.join)(projectRoot, cypressConfig.e2e.specPattern)];
220
- const excludeSpecPatterns = !cypressConfig.e2e
221
- .excludeSpecPattern
222
- ? cypressConfig.e2e.excludeSpecPattern
223
- : Array.isArray(cypressConfig.e2e.excludeSpecPattern)
224
- ? cypressConfig.e2e.excludeSpecPattern.map((p) => (0, path_1.join)(projectRoot, p))
225
- : [(0, path_1.join)(projectRoot, cypressConfig.e2e.excludeSpecPattern)];
226
- const specFiles = await (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, specPatterns, excludeSpecPatterns);
227
+ const { specFiles, specPatterns, excludeSpecPatterns } = await getSpecFilesAndPatternsForTestType(cypressConfig, 'e2e', context.workspaceRoot, projectRoot);
227
228
  const ciBaseUrl = pluginPresetOptions?.ciBaseUrl;
228
229
  const dependsOn = [];
229
230
  const outputs = getOutputs(projectRoot, cypressConfig, 'e2e');
@@ -276,6 +277,7 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
276
277
  target: targetName,
277
278
  projects: 'self',
278
279
  params: 'forward',
280
+ options: 'forward',
279
281
  });
280
282
  if (ciWebServerCommandTask) {
281
283
  targets[targetName].dependsOn = [
@@ -314,6 +316,8 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
314
316
  }
315
317
  }
316
318
  if ('component' in cypressConfig) {
319
+ const inputs = getInputs(namedInputs);
320
+ const outputs = getOutputs(projectRoot, cypressConfig, 'component');
317
321
  // This will not override the e2e target if it is the same
318
322
  targets[options.componentTestingTargetName] ??= {
319
323
  command: `cypress run --component`,
@@ -322,8 +326,8 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
322
326
  env: { TS_NODE_COMPILER_OPTIONS: tsNodeCompilerOptions },
323
327
  },
324
328
  cache: true,
325
- inputs: getInputs(namedInputs),
326
- outputs: getOutputs(projectRoot, cypressConfig, 'component'),
329
+ inputs,
330
+ outputs,
327
331
  metadata: {
328
332
  technologies: ['cypress'],
329
333
  description: 'Runs Cypress Component Tests',
@@ -335,6 +339,83 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
335
339
  },
336
340
  },
337
341
  };
342
+ if (options.ciComponentTestingTargetName) {
343
+ const { specFiles, specPatterns, excludeSpecPatterns } = await getSpecFilesAndPatternsForTestType(cypressConfig, 'component', context.workspaceRoot, projectRoot);
344
+ const dependsOn = [];
345
+ const groupName = 'Component Testing (CI)';
346
+ metadata ??= {};
347
+ metadata.targetGroups ??= {};
348
+ metadata.targetGroups[groupName] ??= [];
349
+ const ctCiTargetGroup = metadata.targetGroups[groupName];
350
+ for (const file of specFiles) {
351
+ const relativeSpecFilePath = (0, devkit_1.normalizePath)((0, path_1.relative)(projectRoot, file));
352
+ if (relativeSpecFilePath.includes('../')) {
353
+ throw new Error('@nx/cypress/plugin attempted to run tests outside of the project root. This is not supported and should not happen. Please open an issue at https://github.com/nrwl/nx/issues/new/choose with the following information:\n\n' +
354
+ `\n\n${JSON.stringify({
355
+ projectRoot,
356
+ relativeSpecFilePath,
357
+ specFiles,
358
+ context,
359
+ excludeSpecPatterns,
360
+ specPatterns,
361
+ }, null, 2)}`);
362
+ }
363
+ const targetName = options.ciComponentTestingTargetName + '--' + relativeSpecFilePath;
364
+ const outputSubfolder = relativeSpecFilePath
365
+ .replace(/[\/\\]/g, '-')
366
+ .replace(/\./g, '-');
367
+ ctCiTargetGroup.push(targetName);
368
+ targets[targetName] = {
369
+ outputs: getTargetOutputs(outputs, outputSubfolder),
370
+ inputs,
371
+ cache: true,
372
+ command: `cypress run --component --spec ${relativeSpecFilePath} --config=${getTargetConfig(cypressConfig, outputSubfolder)}`,
373
+ options: {
374
+ cwd: projectRoot,
375
+ env: { TS_NODE_COMPILER_OPTIONS: tsNodeCompilerOptions },
376
+ },
377
+ // Cypress handles starting the server, there's no separate server
378
+ // target we can use as continuous, so we need to disable parallelism
379
+ // to avoid port conflicts
380
+ parallelism: false,
381
+ metadata: {
382
+ technologies: ['cypress'],
383
+ description: `Runs Cypress Component Tests for ${relativeSpecFilePath} in CI`,
384
+ help: {
385
+ command: `${pmc.exec} cypress run --help`,
386
+ example: {
387
+ args: ['--dev', '--headed'],
388
+ },
389
+ },
390
+ },
391
+ };
392
+ dependsOn.push({
393
+ target: targetName,
394
+ projects: 'self',
395
+ params: 'forward',
396
+ options: 'forward',
397
+ });
398
+ }
399
+ targets[options.ciComponentTestingTargetName] = {
400
+ executor: 'nx:noop',
401
+ cache: true,
402
+ inputs,
403
+ outputs,
404
+ dependsOn,
405
+ metadata: {
406
+ technologies: ['cypress'],
407
+ description: 'Runs Cypress Component Tests in CI',
408
+ nonAtomizedTarget: options.componentTestingTargetName,
409
+ help: {
410
+ command: `${pmc.exec} cypress run --help`,
411
+ example: {
412
+ args: ['--dev', '--headed'],
413
+ },
414
+ },
415
+ },
416
+ };
417
+ ctCiTargetGroup.push(options.ciComponentTestingTargetName);
418
+ }
338
419
  }
339
420
  targets[options.openTargetName] = {
340
421
  command: `cypress open`,
@@ -361,6 +442,8 @@ function normalizeOptions(options) {
361
442
  options.openTargetName ??= 'open-cypress';
362
443
  options.componentTestingTargetName ??= 'component-test';
363
444
  options.ciTargetName ??= 'e2e-ci';
445
+ // must be explicitly provided to opt-in to atomized component testing
446
+ options.ciComponentTestingTargetName;
364
447
  return options;
365
448
  }
366
449
  function getInputs(namedInputs) {
@@ -388,3 +471,17 @@ function parseTaskFromCommand(command) {
388
471
  }
389
472
  return null;
390
473
  }
474
+ async function getSpecFilesAndPatternsForTestType(cypressConfig, testType, workspaceRoot, projectRoot) {
475
+ const specPattern = cypressConfig[testType].specPattern ??
476
+ defaultPatterns[testType].specPattern;
477
+ const specPatterns = Array.isArray(specPattern)
478
+ ? specPattern.map((p) => (0, path_1.join)(projectRoot, p))
479
+ : [(0, path_1.join)(projectRoot, specPattern)];
480
+ const excludeSpecPattern = cypressConfig[testType].excludeSpecPattern ??
481
+ defaultPatterns[testType].excludeSpecPattern;
482
+ const excludeSpecPatterns = Array.isArray(excludeSpecPattern)
483
+ ? excludeSpecPattern.map((p) => (0, path_1.join)(projectRoot, p))
484
+ : [(0, path_1.join)(projectRoot, excludeSpecPattern)];
485
+ const specFiles = await (0, workspace_context_1.globWithWorkspaceContext)(workspaceRoot, specPatterns, excludeSpecPatterns);
486
+ return { specFiles, specPatterns, excludeSpecPatterns };
487
+ }
@@ -7,7 +7,7 @@ export declare const cypressVersion = "^14.2.1";
7
7
  export declare const cypressWebpackVersion = "^4.0.2";
8
8
  export declare const viteVersion = "^6.0.0";
9
9
  export declare const htmlWebpackPluginVersion = "^5.5.0";
10
- export declare function versions(tree: Tree, cypressMajorVersion?: number): Omit<typeof import("./versions"), "versions" | "getInstalledCypressMajorVersion" | "assertMinimumCypressVersion"> | {
10
+ export declare function versions(tree: Tree): Omit<typeof import("./versions"), "versions" | "getInstalledCypressVersion" | "getInstalledCypressMajorVersion" | "assertMinimumCypressVersion"> | {
11
11
  nxVersion: any;
12
12
  eslintPluginCypressVersion: string;
13
13
  typesNodeVersion: string;
@@ -17,6 +17,7 @@ export declare function versions(tree: Tree, cypressMajorVersion?: number): Omit
17
17
  viteVersion: string;
18
18
  htmlWebpackPluginVersion: string;
19
19
  };
20
+ export declare function getInstalledCypressVersion(tree?: Tree): string | null;
20
21
  export declare function getInstalledCypressMajorVersion(tree?: Tree): number | null;
21
22
  export declare function assertMinimumCypressVersion(minVersion: number, tree?: Tree): void;
22
23
  //# sourceMappingURL=versions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../../../packages/cypress/src/utils/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAIjD,eAAO,MAAM,SAAS,KAAwC,CAAC;AAC/D,eAAO,MAAM,0BAA0B,WAAW,CAAC;AACnD,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,2BAA2B,WAAW,CAAC;AACpD,eAAO,MAAM,cAAc,YAAY,CAAC;AACxC,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,eAAO,MAAM,WAAW,WAAW,CAAC;AACpC,eAAO,MAAM,wBAAwB,WAAW,CAAC;AAgBjD,wBAAgB,QAAQ,CACtB,IAAI,EAAE,IAAI,EACV,mBAAmB,SAAwC;;;;;;;;;EAwB5D;AAED,wBAAgB,+BAA+B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAc1E;AAED,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,IAAI,GACV,IAAI,CAON"}
1
+ {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../../../packages/cypress/src/utils/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAIjD,eAAO,MAAM,SAAS,KAAwC,CAAC;AAC/D,eAAO,MAAM,0BAA0B,WAAW,CAAC;AACnD,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,2BAA2B,WAAW,CAAC;AACpD,eAAO,MAAM,cAAc,YAAY,CAAC;AACxC,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,eAAO,MAAM,WAAW,WAAW,CAAC;AACpC,eAAO,MAAM,wBAAwB,WAAW,CAAC;AAmBjD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI;;;;;;;;;EA2BlC;AAED,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAcrE;AAED,wBAAgB,+BAA+B,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAI1E;AAED,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,IAAI,GACV,IAAI,CAON"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.htmlWebpackPluginVersion = exports.viteVersion = exports.cypressWebpackVersion = exports.cypressVersion = exports.cypressViteDevServerVersion = exports.typesNodeVersion = exports.eslintPluginCypressVersion = exports.nxVersion = void 0;
4
4
  exports.versions = versions;
5
+ exports.getInstalledCypressVersion = getInstalledCypressVersion;
5
6
  exports.getInstalledCypressMajorVersion = getInstalledCypressMajorVersion;
6
7
  exports.assertMinimumCypressVersion = assertMinimumCypressVersion;
7
8
  const devkit_1 = require("@nx/devkit");
@@ -24,16 +25,18 @@ const latestVersions = {
24
25
  viteVersion: exports.viteVersion,
25
26
  htmlWebpackPluginVersion: exports.htmlWebpackPluginVersion,
26
27
  };
27
- function versions(tree, cypressMajorVersion = getInstalledCypressMajorVersion(tree)) {
28
- if (!cypressMajorVersion) {
28
+ function versions(tree) {
29
+ const installedCypressVersion = getInstalledCypressVersion(tree);
30
+ if (!installedCypressVersion) {
29
31
  return latestVersions;
30
32
  }
31
- if (cypressMajorVersion > 14) {
32
- throw new Error(`Unsupported Cypress version: ${exports.cypressVersion}`);
33
- }
33
+ const cypressMajorVersion = (0, semver_1.major)(installedCypressVersion);
34
34
  if (cypressMajorVersion === 14) {
35
35
  return latestVersions;
36
36
  }
37
+ if (cypressMajorVersion > 14) {
38
+ throw new Error(`You're currently using an unsupported Cypress version: ${installedCypressVersion}. Supported versions are v13 and v14.`);
39
+ }
37
40
  return {
38
41
  nxVersion: exports.nxVersion,
39
42
  eslintPluginCypressVersion: '^3.5.0',
@@ -45,7 +48,7 @@ function versions(tree, cypressMajorVersion = getInstalledCypressMajorVersion(tr
45
48
  htmlWebpackPluginVersion: '^5.5.0',
46
49
  };
47
50
  }
48
- function getInstalledCypressMajorVersion(tree) {
51
+ function getInstalledCypressVersion(tree) {
49
52
  try {
50
53
  let version;
51
54
  if (tree) {
@@ -54,12 +57,16 @@ function getInstalledCypressMajorVersion(tree) {
54
57
  else {
55
58
  version = getCypressVersionFromFileSystem();
56
59
  }
57
- return version ? (0, semver_1.major)(version) : null;
60
+ return version;
58
61
  }
59
62
  catch {
60
63
  return null;
61
64
  }
62
65
  }
66
+ function getInstalledCypressMajorVersion(tree) {
67
+ const installedCypressVersion = getInstalledCypressVersion(tree);
68
+ return installedCypressVersion ? (0, semver_1.major)(installedCypressVersion) : null;
69
+ }
63
70
  function assertMinimumCypressVersion(minVersion, tree) {
64
71
  const version = getInstalledCypressMajorVersion(tree);
65
72
  if (version && version < minVersion) {