@nx/angular 23.3.0-canary.20260915-071d621 → 23.3.0-canary.20260917-ea5c01d

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.
@@ -27,8 +27,7 @@ async function componentTestGenerator(tree, options) {
27
27
  });
28
28
  }
29
29
  const tasks = [];
30
- if (!options.skipPackageJson) {
31
- // Cypress CT still requires @angular/platform-browser-dynamic
30
+ if (!options.skipPackageJson && usesPlatformBrowserDynamic(tree)) {
32
31
  tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
33
32
  '@angular/platform-browser-dynamic': (0, version_utils_1.versions)(tree).angularVersion,
34
33
  }, undefined, true));
@@ -38,4 +37,11 @@ async function componentTestGenerator(tree, options) {
38
37
  }
39
38
  return (0, devkit_1.runTasksInSerial)(...tasks);
40
39
  }
40
+ // The Cypress 16 harness bootstraps through @angular/platform-browser/testing;
41
+ // earlier harnesses need @angular/platform-browser-dynamic/testing.
42
+ function usesPlatformBrowserDynamic(tree) {
43
+ const { getInstalledCypressMajorVersion, } = require('@nx/cypress/internal');
44
+ const cypressMajorVersion = getInstalledCypressMajorVersion(tree);
45
+ return cypressMajorVersion !== null && cypressMajorVersion < 16;
46
+ }
41
47
  exports.default = componentTestGenerator;
@@ -43,15 +43,21 @@ async function cypressComponentConfiguration(tree, options) {
43
43
  // For libraries, check if zone.js is installed in the workspace
44
44
  isZoneless = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, 'zone.js') === null;
45
45
  }
46
+ // Cypress 16 dropped `cypress/angular-zoneless`; `cypress/angular` is zoneless there.
47
+ let mountModule = 'cypress/angular';
46
48
  if (isZoneless) {
47
49
  const { getInstalledCypressVersion, } = require('@nx/cypress/internal');
48
50
  const installedCypressVersion = getInstalledCypressVersion(tree);
49
- // Zoneless support was introduced in Cypress 15.8.0
50
51
  // If Cypress is not yet installed, we'll install the latest version, which will have zoneless support
51
- if (installedCypressVersion && (0, semver_1.lt)(installedCypressVersion, '15.8.0')) {
52
- throw new Error(`Cypress Component Testing doesn't support Zoneless Angular projects for your installed Cypress version (${installedCypressVersion}). ` +
53
- `The project "${options.project}" is configured without Zone.js. ` +
54
- `Please upgrade Cypress to version 15.8.0 or higher.`);
52
+ if (installedCypressVersion && (0, semver_1.major)(installedCypressVersion) < 16) {
53
+ // Zoneless support was introduced in Cypress 15.8.0
54
+ const unsupportedCypressVersion = (0, assert_cypress_component_testing_support_1.findCypressBelow)(tree, '15.8.0');
55
+ if (unsupportedCypressVersion) {
56
+ throw new Error(`Cypress Component Testing doesn't support Zoneless Angular projects for your Cypress version (${unsupportedCypressVersion}). ` +
57
+ `The project "${options.project}" is configured without Zone.js. ` +
58
+ `Please upgrade Cypress to version 15.8.0 or higher.`);
59
+ }
60
+ mountModule = 'cypress/angular-zoneless';
55
61
  }
56
62
  }
57
63
  const tasks = [];
@@ -63,7 +69,7 @@ async function cypressComponentConfiguration(tree, options) {
63
69
  skipPackageJson: options.skipPackageJson,
64
70
  }));
65
71
  await configureCypressCT(tree, options);
66
- tasks.push(await addFiles(tree, projectConfig, options, isZoneless));
72
+ tasks.push(await addFiles(tree, projectConfig, options, mountModule));
67
73
  if (projectConfig.projectType === 'application') {
68
74
  (0, update_app_editor_tsconfig_excluded_files_1.updateAppEditorTsConfigExcludedFiles)(tree, projectConfig);
69
75
  }
@@ -72,11 +78,11 @@ async function cypressComponentConfiguration(tree, options) {
72
78
  }
73
79
  return (0, devkit_1.runTasksInSerial)(...tasks);
74
80
  }
75
- async function addFiles(tree, projectConfig, options, isZoneless) {
81
+ async function addFiles(tree, projectConfig, options, mountModule) {
76
82
  const componentFile = (0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress', 'support', 'component.ts');
77
83
  const { addMountDefinition } = (require('@nx/cypress/internal'));
78
84
  const updatedCmpContents = await addMountDefinition(tree.read(componentFile, 'utf-8'));
79
- tree.write(componentFile, `import { mount } from '${isZoneless ? 'cypress/angular-zoneless' : 'cypress/angular'}';\n${updatedCmpContents}`);
85
+ tree.write(componentFile, `import { mount } from '${mountModule}';\n${updatedCmpContents}`);
80
86
  if (!options.generateTests) {
81
87
  return () => { };
82
88
  }
@@ -4,3 +4,14 @@ import { type Tree } from '@nx/devkit';
4
4
  * Angular version. Must be called after `@nx/cypress` has been ensured.
5
5
  */
6
6
  export declare function assertCypressComponentTestingSupport(tree: Tree): void;
7
+ /**
8
+ * Returns the installed Cypress version, or the declared range when nothing
9
+ * satisfying is installed, if it cannot reach `floor`; `null` otherwise.
10
+ *
11
+ * A satisfying install decides. Without one, only a range capped below the
12
+ * floor fails: `^15.17.0` installs 15.20.1+, so its lower bound cannot be
13
+ * compared. Declarations that are not ranges (`latest`, `file:`) are not
14
+ * gated.
15
+ * When Cypress is not declared, the generators install `cypressVersion`.
16
+ */
17
+ export declare function findCypressBelow(tree: Tree, floor: string): string | null;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertCypressComponentTestingSupport = assertCypressComponentTestingSupport;
4
+ exports.findCypressBelow = findCypressBelow;
4
5
  const devkit_1 = require("@nx/devkit");
5
6
  const internal_1 = require("@nx/devkit/internal");
6
7
  const semver_1 = require("semver");
@@ -10,22 +11,46 @@ const minCypressVersion = '15.20.1';
10
11
  * Angular version. Must be called after `@nx/cypress` has been ensured.
11
12
  */
12
13
  function assertCypressComponentTestingSupport(tree) {
13
- const angularVersion = (0, internal_1.getDeclaredPackageVersion)(tree, '@angular/core');
14
- if (!angularVersion || (0, semver_1.lt)(angularVersion, '22.1.0')) {
14
+ const angularVersion = (0, internal_1.getResolvedPackageVersion)(tree, '@angular/core');
15
+ if (!angularVersion) {
15
16
  return;
16
17
  }
17
- const { cypressVersion, } = require('@nx/cypress/internal');
18
- // When Cypress is not installed, the generators install `cypressVersion`
19
- const declaredCypressVersion = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, 'cypress') ?? cypressVersion;
20
- // Gate only ranges capped below the floor. `^15.17.0` installs 15.20.1+, so
21
- // comparing its lower bound would reject workspaces that work. Dist tags
22
- // (`latest`, `next`) aren't ranges and aren't gated.
23
- if (!(0, semver_1.validRange)(declaredCypressVersion) ||
24
- !(0, semver_1.subset)(declaredCypressVersion, `<${minCypressVersion}`)) {
18
+ // A prerelease of 22.1 counts as 22.1.
19
+ const angularRelease = (0, semver_1.coerce)(angularVersion)?.version ?? angularVersion;
20
+ if ((0, semver_1.lt)(angularRelease, '22.1.0')) {
25
21
  return;
26
22
  }
23
+ const found = findCypressBelow(tree, minCypressVersion);
24
+ if (found) {
25
+ throwForUnsupportedCypress(found);
26
+ }
27
+ }
28
+ /**
29
+ * Returns the installed Cypress version, or the declared range when nothing
30
+ * satisfying is installed, if it cannot reach `floor`; `null` otherwise.
31
+ *
32
+ * A satisfying install decides. Without one, only a range capped below the
33
+ * floor fails: `^15.17.0` installs 15.20.1+, so its lower bound cannot be
34
+ * compared. Declarations that are not ranges (`latest`, `file:`) are not
35
+ * gated.
36
+ * When Cypress is not declared, the generators install `cypressVersion`.
37
+ */
38
+ function findCypressBelow(tree, floor) {
39
+ const { cypressVersion, } = require('@nx/cypress/internal');
40
+ const declaredCypressVersion = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, 'cypress');
41
+ const installedCypressVersion = declaredCypressVersion
42
+ ? (0, internal_1.getSatisfyingInstalledPackageVersion)(tree, 'cypress', declaredCypressVersion)
43
+ : null;
44
+ if (installedCypressVersion) {
45
+ const release = (0, semver_1.coerce)(installedCypressVersion)?.version ?? installedCypressVersion;
46
+ return (0, semver_1.lt)(release, floor) ? installedCypressVersion : null;
47
+ }
48
+ const range = declaredCypressVersion ?? cypressVersion;
49
+ return (0, semver_1.validRange)(range) && (0, semver_1.subset)(range, `<${floor}`) ? range : null;
50
+ }
51
+ function throwForUnsupportedCypress(found) {
27
52
  throw new Error(`Cypress Component Testing with Angular 22.1 and higher requires Cypress ${minCypressVersion} or higher. ` +
28
- `Found Cypress ${declaredCypressVersion}. Earlier Cypress versions can't load Angular's Babel 8 dependencies. ` +
53
+ `Found Cypress ${found}. Earlier Cypress versions can't load Angular's Babel 8 dependencies. ` +
29
54
  `Please upgrade Cypress. ` +
30
55
  `See https://github.com/cypress-io/cypress/issues/34461.`);
31
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/angular",
3
- "version": "23.3.0-canary.20260915-071d621",
3
+ "version": "23.3.0-canary.20260917-ea5c01d",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "description": "The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications and libraries within an Nx workspace. It provides: \n\n- Integration with libraries such as Storybook, Jest, ESLint, Playwright and Cypress. \n\n- Generators to help scaffold code quickly (like: Micro Frontends, Libraries, both internal to your codebase and publishable to npm) \n\n- Single Component Application Modules (SCAMs) \n\n- NgRx helpers. \n\n- Utilities for automatic workspace refactoring.",
@@ -79,15 +79,15 @@
79
79
  "picomatch": "4.0.4",
80
80
  "semver": "^7.6.3",
81
81
  "tslib": "^2.3.0",
82
- "@nx/devkit": "23.3.0-canary.20260915-071d621",
83
- "@nx/js": "23.3.0-canary.20260915-071d621",
84
- "@nx/eslint": "23.3.0-canary.20260915-071d621",
85
- "@nx/web": "23.3.0-canary.20260915-071d621"
82
+ "@nx/js": "23.3.0-canary.20260917-ea5c01d",
83
+ "@nx/web": "23.3.0-canary.20260917-ea5c01d",
84
+ "@nx/eslint": "23.3.0-canary.20260917-ea5c01d",
85
+ "@nx/devkit": "23.3.0-canary.20260917-ea5c01d"
86
86
  },
87
87
  "devDependencies": {
88
- "@nx/storybook": "23.3.0-canary.20260915-071d621",
89
- "@nx/vitest": "23.3.0-canary.20260915-071d621",
90
- "nx": "23.3.0-canary.20260915-071d621"
88
+ "@nx/storybook": "23.3.0-canary.20260917-ea5c01d",
89
+ "@nx/vitest": "23.3.0-canary.20260917-ea5c01d",
90
+ "nx": "23.3.0-canary.20260917-ea5c01d"
91
91
  },
92
92
  "peerDependencies": {
93
93
  "@angular/build": ">= 20.0.0 < 23.0.0",
@@ -98,11 +98,11 @@
98
98
  "ng-packagr": ">= 20.0.0 < 23.0.0",
99
99
  "rxjs": "^6.5.3 || ^7.5.0",
100
100
  "webpack-merge": "^5.8.0",
101
- "@nx/cypress": "23.3.0-canary.20260915-071d621",
102
- "@nx/playwright": "23.3.0-canary.20260915-071d621",
103
- "@nx/module-federation": "23.3.0-canary.20260915-071d621",
104
- "@nx/webpack": "23.3.0-canary.20260915-071d621",
105
- "@nx/rspack": "23.3.0-canary.20260915-071d621"
101
+ "@nx/cypress": "23.3.0-canary.20260917-ea5c01d",
102
+ "@nx/playwright": "23.3.0-canary.20260917-ea5c01d",
103
+ "@nx/module-federation": "23.3.0-canary.20260917-ea5c01d",
104
+ "@nx/rspack": "23.3.0-canary.20260917-ea5c01d",
105
+ "@nx/webpack": "23.3.0-canary.20260917-ea5c01d"
106
106
  },
107
107
  "peerDependenciesMeta": {
108
108
  "@angular/build": {