@nx/cypress 17.2.0-beta.2 → 17.2.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.
package/migrations.json CHANGED
@@ -87,6 +87,15 @@
87
87
  "alwaysAddToPackageJson": false
88
88
  }
89
89
  }
90
+ },
91
+ "17.2.0-beta.2": {
92
+ "version": "17.2.0-beta.2",
93
+ "packages": {
94
+ "vite": {
95
+ "version": "^5.0.0",
96
+ "alwaysAddToPackageJson": false
97
+ }
98
+ }
90
99
  }
91
100
  }
92
101
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/cypress",
3
- "version": "17.2.0-beta.2",
3
+ "version": "17.2.0-beta.4",
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": {
@@ -34,14 +34,15 @@
34
34
  "migrations": "./migrations.json"
35
35
  },
36
36
  "dependencies": {
37
- "@nx/devkit": "17.2.0-beta.2",
38
- "@nx/eslint": "17.2.0-beta.2",
39
- "@nx/js": "17.2.0-beta.2",
37
+ "@nx/devkit": "17.2.0-beta.4",
38
+ "@nx/eslint": "17.2.0-beta.4",
39
+ "@nx/js": "17.2.0-beta.4",
40
40
  "@phenomnomnominal/tsquery": "~5.0.1",
41
41
  "detect-port": "^1.5.1",
42
+ "string-argv": "^0.3.2",
42
43
  "semver": "7.5.3",
43
44
  "tslib": "^2.3.0",
44
- "@nrwl/cypress": "17.2.0-beta.2"
45
+ "@nrwl/cypress": "17.2.0-beta.4"
45
46
  },
46
47
  "peerDependencies": {
47
48
  "cypress": ">= 3 < 14"
@@ -32,6 +32,17 @@ export declare function nxBaseCypressPreset(pathToConfig: string, options?: {
32
32
  *
33
33
  */
34
34
  export declare function nxE2EPreset(pathToConfig: string, options?: NxCypressE2EPresetOptions): any;
35
+ export interface WebServerConfig {
36
+ /**
37
+ * Timeout to wait for the webserver to start listening
38
+ */
39
+ timeout?: number;
40
+ /**
41
+ * Reuse an existing web server if it exists
42
+ * If this is false, an error will be thrown if the server is already running
43
+ */
44
+ reuseExistingServer?: boolean;
45
+ }
35
46
  export type NxCypressE2EPresetOptions = {
36
47
  bundler?: string;
37
48
  /**
@@ -40,7 +51,8 @@ export type NxCypressE2EPresetOptions = {
40
51
  * default is 'src'
41
52
  **/
42
53
  cypressDir?: string;
43
- devServerTargets?: Record<string, string>;
44
- ciDevServerTarget?: string;
54
+ webServerCommands?: Record<string, string>;
55
+ ciWebServerCommand?: string;
56
+ webServerConfig?: WebServerConfig;
45
57
  };
46
58
  export {};
@@ -5,8 +5,9 @@ const devkit_1 = require("@nx/devkit");
5
5
  const path_1 = require("path");
6
6
  const fs_1 = require("fs");
7
7
  const preprocessor_vite_1 = require("../src/plugins/preprocessor-vite");
8
- const ct_helpers_1 = require("../src/utils/ct-helpers");
9
- const start_dev_server_1 = require("../src/utils/start-dev-server");
8
+ const child_process_1 = require("child_process");
9
+ const http_1 = require("http");
10
+ const https_1 = require("https");
10
11
  function nxBaseCypressPreset(pathToConfig, options) {
11
12
  // used to set babel settings for react CT.
12
13
  process.env.NX_CYPRESS_COMPONENT_TEST =
@@ -27,6 +28,16 @@ function nxBaseCypressPreset(pathToConfig, options) {
27
28
  };
28
29
  }
29
30
  exports.nxBaseCypressPreset = nxBaseCypressPreset;
31
+ function startWebServer(webServerCommand) {
32
+ const serverProcess = (0, child_process_1.exec)(webServerCommand, {
33
+ cwd: devkit_1.workspaceRoot,
34
+ });
35
+ serverProcess.stdout.pipe(process.stdout);
36
+ serverProcess.stderr.pipe(process.stderr);
37
+ return () => {
38
+ serverProcess.kill();
39
+ };
40
+ }
30
41
  /**
31
42
  * nx E2E Preset for Cypress
32
43
  * @description
@@ -51,40 +62,78 @@ function nxE2EPreset(pathToConfig, options) {
51
62
  specPattern: `${basePath}/**/*.cy.{js,jsx,ts,tsx}`,
52
63
  fixturesFolder: `${basePath}/fixtures`,
53
64
  env: {
54
- devServerTargets: options?.devServerTargets,
55
- devServerTargetOptions: {},
56
- ciDevServerTarget: options?.ciDevServerTarget,
65
+ webServerCommands: options?.webServerCommands,
66
+ ciWebServerCommand: options?.ciWebServerCommand,
57
67
  },
58
68
  async setupNodeEvents(on, config) {
59
69
  if (options?.bundler === 'vite') {
60
70
  on('file:preprocessor', (0, preprocessor_vite_1.default)());
61
71
  }
62
- if (!config.env.devServerTargets) {
72
+ if (!config.env.webServerCommands) {
63
73
  return;
64
74
  }
65
- const devServerTarget = config.env.devServerTarget ?? config.env.devServerTargets['default'];
66
- if (!devServerTarget) {
75
+ const webServerCommand = config.env.webServerCommand ?? config.env.webServerCommands.default;
76
+ if (!webServerCommand) {
67
77
  return;
68
78
  }
69
- if (!config.baseUrl && devServerTarget) {
70
- const graph = await (0, devkit_1.createProjectGraphAsync)();
71
- const target = (0, devkit_1.parseTargetString)(devServerTarget, graph);
72
- const context = (0, ct_helpers_1.createExecutorContext)(graph, graph.nodes[target.project].data?.targets, target.project, target.target, target.configuration);
73
- const devServer = (0, start_dev_server_1.startDevServer)({
74
- devServerTarget,
75
- ...config.env.devServerTargetOptions,
76
- }, context);
79
+ if (config.baseUrl && webServerCommand) {
80
+ if (await isServerUp(config.baseUrl)) {
81
+ if (options.webServerConfig.reuseExistingServer === undefined
82
+ ? true
83
+ : options.webServerConfig.reuseExistingServer) {
84
+ console.log(`Reusing the server already running on ${config.baseUrl}`);
85
+ return;
86
+ }
87
+ else {
88
+ throw new Error(`Web server is already running at ${config.baseUrl}`);
89
+ }
90
+ }
91
+ const killWebServer = startWebServer(webServerCommand);
77
92
  on('after:run', () => {
78
- devServer.return();
93
+ killWebServer();
79
94
  });
80
- const devServerValue = (await devServer.next()).value;
81
- if (!devServerValue) {
82
- return;
83
- }
84
- return { ...config, baseUrl: devServerValue.baseUrl };
95
+ await waitForServer(config.baseUrl, options.webServerConfig);
85
96
  }
86
97
  },
87
98
  };
88
99
  return baseConfig;
89
100
  }
90
101
  exports.nxE2EPreset = nxE2EPreset;
102
+ function waitForServer(url, webServerConfig) {
103
+ return new Promise((resolve, reject) => {
104
+ let pollTimeout;
105
+ const { protocol } = new URL(url);
106
+ const timeoutDuration = webServerConfig?.timeout ?? 5 * 1000;
107
+ const timeout = setTimeout(() => {
108
+ clearTimeout(pollTimeout);
109
+ reject(new Error(`Web server failed to start in ${timeoutDuration}ms. This can be configured in cypress.config.ts.`));
110
+ }, timeoutDuration);
111
+ const makeRequest = protocol === 'https:' ? https_1.request : http_1.request;
112
+ function pollForServer() {
113
+ const request = makeRequest(url, () => {
114
+ clearTimeout(timeout);
115
+ resolve();
116
+ });
117
+ request.on('error', () => {
118
+ pollTimeout = setTimeout(pollForServer, 100);
119
+ });
120
+ // Don't forget to end the request
121
+ request.end();
122
+ }
123
+ pollForServer();
124
+ });
125
+ }
126
+ function isServerUp(url) {
127
+ const { protocol } = new URL(url);
128
+ const makeRequest = protocol === 'https:' ? https_1.request : http_1.request;
129
+ return new Promise((resolve) => {
130
+ const request = makeRequest(url, () => {
131
+ resolve(true);
132
+ });
133
+ request.on('error', () => {
134
+ resolve(false);
135
+ });
136
+ // Don't forget to end the request
137
+ request.end();
138
+ });
139
+ }
@@ -109,9 +109,6 @@ async function runCypress(baseUrl, opts) {
109
109
  if (opts.browser) {
110
110
  options.browser = opts.browser;
111
111
  }
112
- options.env = {
113
- devServerTarget: opts.devServerTarget,
114
- };
115
112
  if (opts.env) {
116
113
  options.env = {
117
114
  ...options.env,
@@ -95,28 +95,28 @@ async function addFiles(tree, options, projectGraph, hasPlugin) {
95
95
  jsx: options.jsx,
96
96
  });
97
97
  const cyFile = (0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress.config.ts');
98
- let devServerTargets;
98
+ let webServerCommands;
99
99
  let ciDevServerTarget;
100
100
  if (hasPlugin && !options.baseUrl && options.devServerTarget) {
101
- devServerTargets = {};
102
- devServerTargets.default = options.devServerTarget;
101
+ webServerCommands = {};
102
+ webServerCommands.default = 'nx run ' + options.devServerTarget;
103
103
  const parsedTarget = (0, devkit_1.parseTargetString)(options.devServerTarget, projectGraph);
104
104
  const devServerProjectConfig = (0, devkit_1.readProjectConfiguration)(tree, parsedTarget.project);
105
105
  // Add production e2e target if serve target is found
106
106
  if (parsedTarget.configuration !== 'production' &&
107
107
  devServerProjectConfig.targets[parsedTarget.target]?.configurations?.['production']) {
108
- devServerTargets.production = `${parsedTarget.project}:${parsedTarget.target}:production`;
108
+ webServerCommands.production = `nx run ${parsedTarget.project}:${parsedTarget.target}:production`;
109
109
  }
110
110
  // Add ci/static e2e target if serve target is found
111
111
  if (devServerProjectConfig.targets?.['serve-static']) {
112
- ciDevServerTarget = `${parsedTarget.project}:serve-static`;
112
+ ciDevServerTarget = `nx run ${parsedTarget.project}:serve-static`;
113
113
  }
114
114
  }
115
115
  const updatedCyConfig = await (0, config_1.addDefaultE2EConfig)(tree.read(cyFile, 'utf-8'), {
116
116
  cypressDir: options.directory,
117
117
  bundler: options.bundler === 'vite' ? 'vite' : undefined,
118
- devServerTargets,
119
- ciDevServerTarget: ciDevServerTarget,
118
+ webServerCommands,
119
+ ciWebServerCommand: ciDevServerTarget,
120
120
  }, options.baseUrl);
121
121
  tree.write(cyFile, updatedCyConfig);
122
122
  }
@@ -124,12 +124,12 @@ function buildCypressTargets(configFilePath, projectRoot, options, context) {
124
124
  targets[options.targetName].configurations ??= {};
125
125
  for (const [configuration, devServerTarget] of Object.entries(devServerTargets ?? {})) {
126
126
  targets[options.targetName].configurations[configuration] = {
127
- command: `cypress run --config-file ${relativeConfigPath} --e2e --env.devServerTarget ${devServerTarget}`,
127
+ command: `cypress run --config-file ${relativeConfigPath} --e2e --env.webServerCommand "nx run ${devServerTarget}"`,
128
128
  };
129
129
  }
130
130
  }
131
- const ciDevServerTarget = cypressEnv?.ciDevServerTarget;
132
- if (ciDevServerTarget) {
131
+ const ciWebServerCommand = cypressEnv?.ciWebServerCommand;
132
+ if (ciWebServerCommand) {
133
133
  const specPatterns = Array.isArray(cypressConfig.e2e.specPattern)
134
134
  ? cypressConfig.e2e.specPattern.map((p) => (0, path_1.join)(projectRoot, p))
135
135
  : [(0, path_1.join)(projectRoot, cypressConfig.e2e.specPattern)];
@@ -150,7 +150,10 @@ function buildCypressTargets(configFilePath, projectRoot, options, context) {
150
150
  outputs,
151
151
  inputs,
152
152
  cache: true,
153
- command: `cypress run --config-file ${relativeConfigPath} --e2e --env.devServerTarget ${ciDevServerTarget} --spec ${relativeSpecFilePath}`,
153
+ command: `cypress run --config-file ${relativeConfigPath} --e2e --env=${JSON.stringify({ webServerCommand: ciWebServerCommand })} --spec ${relativeSpecFilePath}`,
154
+ options: {
155
+ cwd: projectRoot,
156
+ },
154
157
  };
155
158
  dependsOn.push({
156
159
  target: targetName,
@@ -5,5 +5,5 @@ export declare const cypressViteDevServerVersion = "^2.2.1";
5
5
  export declare const cypressVersion = "^13.0.0";
6
6
  export declare const cypressWebpackVersion = "^2.0.0";
7
7
  export declare const webpackHttpPluginVersion = "^5.5.0";
8
- export declare const viteVersion = "~4.3.9";
8
+ export declare const viteVersion = "^5.0.0";
9
9
  export declare const htmlWebpackPluginVersion = "^5.5.0";
@@ -8,5 +8,5 @@ exports.cypressViteDevServerVersion = '^2.2.1';
8
8
  exports.cypressVersion = '^13.0.0';
9
9
  exports.cypressWebpackVersion = '^2.0.0';
10
10
  exports.webpackHttpPluginVersion = '^5.5.0';
11
- exports.viteVersion = '~4.3.9';
11
+ exports.viteVersion = '^5.0.0';
12
12
  exports.htmlWebpackPluginVersion = '^5.5.0';