@nx/cypress 24.0.0-beta.3 → 24.0.0-beta.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.
@@ -130,6 +130,19 @@ function nxE2EPreset(pathToConfig, options) {
130
130
  if (options?.bundler === 'vite') {
131
131
  on('file:preprocessor', (0, preprocessor_vite_1.default)(options?.viteConfigOverrides));
132
132
  }
133
+ // Set by Nx when the web server task already reported it is ready
134
+ const readyUrl = process.env.NX_READY_URL;
135
+ if (readyUrl && isBaseUrlOverridden(config, options)) {
136
+ console.log(`Testing against ${config.baseUrl} from --config or CYPRESS_BASE_URL, not the server Nx started on ${readyUrl}`);
137
+ await waitForServer(config.baseUrl, options?.webServerConfig, (ms) => `${config.baseUrl} did not respond within ${ms}ms. This can be configured in cypress.config.ts.`);
138
+ return;
139
+ }
140
+ if (readyUrl) {
141
+ config.baseUrl = (0, devkit_1.getReadyUrl)(config.baseUrl);
142
+ console.log(`Testing against the server Nx started on ${config.baseUrl}`);
143
+ // Cypress only applies config changes returned from setupNodeEvents.
144
+ return config;
145
+ }
133
146
  if (!options?.webServerCommands) {
134
147
  return;
135
148
  }
@@ -158,23 +171,54 @@ function nxE2EPreset(pathToConfig, options) {
158
171
  };
159
172
  return baseConfig;
160
173
  }
161
- function waitForServer(url, webServerConfig) {
174
+ // Cypress keeps the config file's values in rawJson, without --config, and
175
+ // reports CYPRESS_BASE_URL as from 'env'. A config file that reads
176
+ // CYPRESS_BASE_URL has it in rawJson too. Inferred CI targets pass ciBaseUrl.
177
+ function isBaseUrlOverridden(config, options) {
178
+ if (!config.baseUrl) {
179
+ return false;
180
+ }
181
+ if (config.resolved?.baseUrl?.from === 'env') {
182
+ return true;
183
+ }
184
+ const isInferredCiTarget = !!options?.ciWebServerCommand &&
185
+ config.env?.webServerCommand === options.ciWebServerCommand;
186
+ return (!isSameUrl(config.baseUrl, config.rawJson?.e2e?.baseUrl) &&
187
+ !(isInferredCiTarget && isSameUrl(config.baseUrl, options.ciBaseUrl)));
188
+ }
189
+ function isSameUrl(url, other) {
190
+ if (typeof other !== 'string') {
191
+ return false;
192
+ }
193
+ try {
194
+ return new URL(url).href === new URL(other).href;
195
+ }
196
+ catch {
197
+ return url === other;
198
+ }
199
+ }
200
+ function waitForServer(url, webServerConfig, timeoutMessage = (ms) => `Web server failed to start in ${ms}ms. This can be configured in cypress.config.ts.`) {
162
201
  return new Promise((resolve, reject) => {
163
202
  let pollTimeout;
164
203
  const { protocol } = new URL(url);
204
+ let settled = false;
165
205
  const timeoutDuration = webServerConfig?.timeout ?? 60 * 1000;
166
206
  const timeout = setTimeout(() => {
207
+ settled = true;
167
208
  clearTimeout(pollTimeout);
168
- reject(new Error(`Web server failed to start in ${timeoutDuration}ms. This can be configured in cypress.config.ts.`));
209
+ reject(new Error(timeoutMessage(timeoutDuration)));
169
210
  }, timeoutDuration);
170
211
  const makeRequest = protocol === 'https:' ? https_1.request : http_1.request;
171
212
  function pollForServer() {
172
213
  const request = makeRequest(url, () => {
214
+ settled = true;
173
215
  clearTimeout(timeout);
174
216
  resolve();
175
217
  });
176
218
  request.on('error', () => {
177
- pollTimeout = setTimeout(pollForServer, 100);
219
+ if (!settled) {
220
+ pollTimeout = setTimeout(pollForServer, 100);
221
+ }
178
222
  });
179
223
  // Don't forget to end the request
180
224
  request.end();
@@ -29,8 +29,9 @@ const NX_WEBPACK_CT_PRESETS = [
29
29
  '@nx/react/plugins/component-testing',
30
30
  ];
31
31
  // Re-collects the Cypress 16 migrations: below their version, above every
32
- // 23.2.x. `--from` is exclusive.
33
- const REPLAN_COMMAND = `npx nx migrate @nx/cypress@${versions_1.nxVersion} --from=@nx/cypress@23.3.0-beta.0`;
32
+ // 23.2.x. `--from` is exclusive. `--include=all` overrides nx.json and the
33
+ // prompt: `required` skips the upgrade and `optional` rejects `--from`.
34
+ const REPLAN_COMMAND = `npx nx migrate @nx/cypress@${versions_1.nxVersion} --from=@nx/cypress@23.3.0-beta.0 --include=all`;
34
35
  const RERUN_COMMAND = `${REPLAN_COMMAND} && npx nx migrate --run-migration=@nx/cypress:upgrade-to-cypress-16`;
35
36
  let ts;
36
37
  async function upgradeToCypress16(tree) {
@@ -0,0 +1,4 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export default function update(tree: Tree): Promise<{
3
+ skipAgentic: boolean;
4
+ }>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = update;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const pluginName = '@nx/cypress/plugin';
6
+ async function update(tree) {
7
+ const nxJson = (0, devkit_1.readNxJson)(tree);
8
+ if (!nxJson?.plugins) {
9
+ return { skipAgentic: true };
10
+ }
11
+ let changed = false;
12
+ nxJson.plugins = nxJson.plugins.map((plugin) => {
13
+ if (typeof plugin === 'string') {
14
+ if (plugin !== pluginName) {
15
+ return plugin;
16
+ }
17
+ changed = true;
18
+ return { plugin, options: { waitForServerReady: false } };
19
+ }
20
+ if (plugin.plugin !== pluginName) {
21
+ return plugin;
22
+ }
23
+ const options = (plugin.options ?? {});
24
+ if (options.waitForServerReady !== undefined) {
25
+ return plugin;
26
+ }
27
+ changed = true;
28
+ return { ...plugin, options: { ...options, waitForServerReady: false } };
29
+ });
30
+ if (!changed) {
31
+ return { skipAgentic: true };
32
+ }
33
+ (0, devkit_1.updateNxJson)(tree, nxJson);
34
+ await (0, devkit_1.formatFiles)(tree);
35
+ }
@@ -0,0 +1,33 @@
1
+ #### Keep the Cypress e2e tasks from waiting for the dev server to be ready
2
+
3
+ The `@nx/cypress/plugin` option `waitForServerReady` now defaults to `true`.
4
+ With it on, the inferred e2e tasks wait for the dev server task's `readyWhen` check, and `nxE2EPreset` tests against the address the server reported instead of `baseUrl`.
5
+
6
+ This migration sets `waitForServerReady` to `false` on every `@nx/cypress/plugin` entry in `nx.json`, so existing workspaces keep the old behavior.
7
+ It expands a string entry into an object entry, keeps `include`, `exclude`, and other options, and leaves an entry alone when it already sets `waitForServerReady`.
8
+ To opt in later, set the option to `true`.
9
+
10
+ #### Sample code changes
11
+
12
+ ##### Before
13
+
14
+ ```json title="nx.json"
15
+ {
16
+ "plugins": ["@nx/cypress/plugin"]
17
+ }
18
+ ```
19
+
20
+ ##### After
21
+
22
+ ```json title="nx.json"
23
+ {
24
+ "plugins": [
25
+ {
26
+ "plugin": "@nx/cypress/plugin",
27
+ "options": {
28
+ "waitForServerReady": false
29
+ }
30
+ }
31
+ ]
32
+ }
33
+ ```
@@ -5,6 +5,11 @@ export interface CypressPluginOptions {
5
5
  openTargetName?: string;
6
6
  componentTestingTargetName?: string;
7
7
  ciComponentTestingTargetName?: string;
8
+ /**
9
+ * Wait for the web server task's `readyWhen` and test against the URL it
10
+ * reports. Defaults to `true`.
11
+ */
12
+ waitForServerReady?: boolean;
8
13
  }
9
14
  export declare const createNodes: CreateNodes<CypressPluginOptions>;
10
15
  export declare const createNodesV2: CreateNodes<CypressPluginOptions>;
@@ -177,6 +177,7 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
177
177
  };
178
178
  const webServerCommands = pluginPresetOptions?.webServerCommands;
179
179
  const shouldReuseExistingServer = pluginPresetOptions?.reuseExistingServer ?? true;
180
+ const waitForServer = options.waitForServerReady === false ? {} : { waitFor: 'ready' };
180
181
  const namedInputs = (0, internal_1.getNamedInputs)(projectRoot, context);
181
182
  const targets = {};
182
183
  let metadata;
@@ -211,6 +212,7 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
211
212
  {
212
213
  projects: [webServerCommandTask.project],
213
214
  target: webServerCommandTask.target,
215
+ ...waitForServer,
214
216
  },
215
217
  ];
216
218
  }
@@ -291,6 +293,7 @@ async function buildCypressTargets(configFilePath, projectRoot, options, context
291
293
  {
292
294
  target: ciWebServerCommandTask.target,
293
295
  projects: [ciWebServerCommandTask.project],
296
+ ...waitForServer,
294
297
  },
295
298
  ];
296
299
  }
@@ -42,7 +42,6 @@ ${Array.from(options.validExecutorNames)
42
42
  .map((ve) => ` - ${ve}`)
43
43
  .join('\n')}
44
44
 
45
- ${frameworkHelperMessage(Array.from(options.buildTarget), executorName)}
46
45
  This is most likely because the provided --build-target is not a build target for an application or framework.
47
46
  For example, the provide build target, '${options.buildTarget}' is:
48
47
  - the build target for a buildable/publishable library instead of an app.
@@ -55,29 +54,6 @@ If you do not have an app in the workspace to you can make a new app with 'nx g
55
54
  const foundConfig = configuration || projectConfig?.targets?.[target]?.defaultConfiguration;
56
55
  return (0, devkit_1.readTargetOptions)({ project, target, configuration: foundConfig }, createExecutorContext(graph, projectConfig.targets, project, target, foundConfig));
57
56
  }
58
- function frameworkHelperMessage(validExecutorNames, executorName) {
59
- const executorsToFramework = {
60
- '@nx/webpack:webpack': 'react',
61
- '@nx/vite:build': 'react',
62
- '@nrwl/webpack:webpack': 'react',
63
- '@nrwl/vite:build': 'react',
64
- '@nx/angular:webpack-browser': 'angular',
65
- '@nrwl/angular:webpack-browser': 'angular',
66
- '@angular-devkit/build-angular:browser': 'angular',
67
- '@nx/next:build': 'next',
68
- '@nrwl/next:build': 'next',
69
- };
70
- const buildTargetFramework = executorsToFramework[executorName];
71
- const invokedGeneratorFramework = validExecutorNames.find((e) => !!executorsToFramework[e]);
72
- if (buildTargetFramework &&
73
- invokedGeneratorFramework &&
74
- buildTargetFramework !== invokedGeneratorFramework) {
75
- return `It looks like you're using a different plugin generator than the --build-target framework is set up for.
76
- The provided build target is configured for ${buildTargetFramework} instead of ${invokedGeneratorFramework}.
77
- Try using @nx/${buildTargetFramework} instead.`;
78
- }
79
- return '';
80
- }
81
57
  async function findInGraph(tree, graph, options) {
82
58
  const parents = findParentsOfProject(graph, options.project);
83
59
  const potentialTargets = [];
package/migrations.json CHANGED
@@ -104,6 +104,7 @@
104
104
  "requires": {
105
105
  "cypress": ">=15.0.0 <16.0.0"
106
106
  },
107
+ "optionalUpdate": true,
107
108
  "description": "Moves a Cypress 15 workspace to Cypress 16: bumps `cypress` and the declared `@cypress/*-dev-server` packages unless a Vite component testing config, or a config whose bundler cannot be determined statically, resolves a Vite below 8, applies the Cypress 16 config option, `overwriteQuery` and `cypress/angular` rewrites, and hands the remaining source changes to an AI prompt.",
108
109
  "implementation": "./dist/src/migrations/update-23-3-0/upgrade-to-cypress-16",
109
110
  "prompt": "./dist/src/migrations/update-23-3-0/ai-instructions-for-cypress-16.md",
@@ -115,6 +116,12 @@
115
116
  "implementation": "./dist/src/migrations/update-24-0-0/remove-deprecated-executors",
116
117
  "prompt": "./dist/src/migrations/update-24-0-0/finish-inferred-conversion.md",
117
118
  "documentation": "./dist/src/migrations/update-24-0-0/remove-deprecated-executors.md"
119
+ },
120
+ "disable-wait-for-server-ready": {
121
+ "version": "24.0.0-beta.4",
122
+ "description": "Sets `waitForServerReady: false` on `@nx/cypress/plugin` entries in `nx.json` so existing Cypress e2e tasks keep starting without waiting for the dev server to report it is ready.",
123
+ "implementation": "./dist/src/migrations/update-24-0-0/disable-wait-for-server-ready",
124
+ "documentation": "./dist/src/migrations/update-24-0-0/disable-wait-for-server-ready.md"
118
125
  }
119
126
  },
120
127
  "packageJsonUpdates": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/cypress",
3
- "version": "24.0.0-beta.3",
3
+ "version": "24.0.0-beta.4",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -84,16 +84,16 @@
84
84
  "supportsOptionalMigrations": true
85
85
  },
86
86
  "dependencies": {
87
- "@nx/devkit": "24.0.0-beta.3",
88
- "@nx/eslint": "24.0.0-beta.3",
89
- "@nx/js": "24.0.0-beta.3",
87
+ "@nx/devkit": "24.0.0-beta.4",
88
+ "@nx/eslint": "24.0.0-beta.4",
89
+ "@nx/js": "24.0.0-beta.4",
90
90
  "@phenomnomnominal/tsquery": "~6.2.0",
91
91
  "semver": "^7.6.3",
92
92
  "tree-kill": "^1.2.2",
93
93
  "tslib": "^2.3.0"
94
94
  },
95
95
  "devDependencies": {
96
- "nx": "24.0.0-beta.3"
96
+ "nx": "24.0.0-beta.4"
97
97
  },
98
98
  "peerDependencies": {
99
99
  "cypress": ">= 13 < 17"