@nx/cypress 17.0.3 → 17.0.5
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/LICENSE +1 -1
- package/README.md +9 -4
- package/generators.json +3 -3
- package/index.d.ts +2 -2
- package/index.js +4 -4
- package/migrations.json +24 -0
- package/package.json +6 -6
- package/plugin.d.ts +1 -0
- package/plugin.js +6 -0
- package/plugins/cypress-preset.d.ts +27 -19
- package/plugins/cypress-preset.js +102 -11
- package/src/executors/cypress/cypress.impl.d.ts +1 -1
- package/src/executors/cypress/cypress.impl.js +6 -152
- package/src/executors/cypress/schema.json +11 -1
- package/src/generators/base-setup/base-setup.d.ts +1 -0
- package/src/generators/base-setup/base-setup.js +26 -3
- package/src/generators/base-setup/files/config-js-cjs/__directory__/support/commands.js__ext__ +35 -0
- package/src/generators/base-setup/files/config-js-cjs/cypress.config.js__ext__ +3 -0
- package/src/generators/base-setup/files/config-js-esm/__directory__/support/commands.js__ext__ +35 -0
- package/src/generators/base-setup/files/config-ts/__directory__/support/commands.ts__ext__ +35 -0
- package/src/generators/base-setup/files/config-ts/cypress.config.ts__ext__ +3 -0
- package/src/generators/component-configuration/component-configuration.d.ts +3 -2
- package/src/generators/component-configuration/component-configuration.js +50 -27
- package/src/generators/component-configuration/files/__directory__/support/component-index.html +4 -1
- package/src/generators/component-configuration/schema.d.ts +7 -0
- package/src/generators/component-configuration/schema.json +1 -1
- package/src/generators/configuration/configuration.d.ts +4 -0
- package/src/generators/configuration/configuration.js +90 -26
- package/src/generators/configuration/schema.json +1 -1
- package/src/generators/cypress-project/cypress-project.js +25 -5
- package/src/generators/cypress-project/schema.d.ts +1 -0
- package/src/generators/cypress-project/schema.json +1 -1
- package/src/generators/init/init.d.ts +2 -0
- package/src/generators/init/init.js +71 -15
- package/src/generators/init/schema.d.ts +4 -2
- package/src/generators/init/schema.json +19 -1
- package/src/generators/migrate-to-cypress-11/schema.json +1 -1
- package/src/migrations/update-18-1-0/update-cypress-version-13-6-6.d.ts +2 -0
- package/src/migrations/update-18-1-0/update-cypress-version-13-6-6.js +12 -0
- package/src/plugins/plugin.d.ts +9 -0
- package/src/plugins/plugin.js +227 -0
- package/src/utils/add-linter.d.ts +1 -0
- package/src/utils/add-linter.js +4 -4
- package/src/utils/config.d.ts +6 -7
- package/src/utils/config.js +39 -12
- package/src/utils/constants.d.ts +4 -0
- package/src/utils/constants.js +7 -0
- package/src/utils/ct-helpers.d.ts +1 -1
- package/src/utils/ct-helpers.js +6 -2
- package/src/utils/start-dev-server.d.ts +9 -0
- package/src/utils/start-dev-server.js +157 -0
- package/src/utils/versions.d.ts +3 -3
- package/src/utils/versions.js +3 -3
- /package/src/generators/base-setup/files/{__directory__ → common/__directory__}/fixtures/example.json +0 -0
- /package/src/generators/base-setup/files/{__directory__ → common/__directory__}/support/commands.ts__ext__ +0 -0
- /package/src/generators/base-setup/files/{__directory__ → common/__directory__}/tsconfig.json__ext__ +0 -0
- /package/src/generators/base-setup/files/{cypress.config.ts__ext__ → config-js-esm/cypress.config.js__ext__} +0 -0
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
<p style="text-align: center;"
|
|
1
|
+
<p style="text-align: center;">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
|
|
4
|
+
<img alt="Nx - Smart Monorepos · Fast CI" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
2
7
|
|
|
3
8
|
<div style="text-align: center;">
|
|
4
9
|
|
|
@@ -15,9 +20,9 @@
|
|
|
15
20
|
|
|
16
21
|
<hr>
|
|
17
22
|
|
|
18
|
-
# Nx: Smart
|
|
23
|
+
# Nx: Smart Monorepos · Fast CI
|
|
19
24
|
|
|
20
|
-
Nx is a
|
|
25
|
+
Nx is a build system with built-in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, both locally and on CI.
|
|
21
26
|
|
|
22
27
|
This package is a [Cypress plugin for Nx](https://nx.dev/cypress/overview).
|
|
23
28
|
|
|
@@ -59,5 +64,5 @@ npx nx@latest init
|
|
|
59
64
|
- [Blog Posts About Nx](https://blog.nrwl.io/nx/home)
|
|
60
65
|
|
|
61
66
|
<p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-courses-and-videos.svg"
|
|
62
|
-
width="100%" alt="Nx - Smart
|
|
67
|
+
width="100%" alt="Nx - Smart Monorepos · Fast CI"></a></p>
|
|
63
68
|
|
package/generators.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"version": "0.1",
|
|
4
4
|
"generators": {
|
|
5
5
|
"init": {
|
|
6
|
-
"factory": "./src/generators/init/init#
|
|
6
|
+
"factory": "./src/generators/init/init#cypressInitGeneratorInternal",
|
|
7
7
|
"schema": "./src/generators/init/schema.json",
|
|
8
8
|
"description": "Initialize the `@nrwl/cypress` plugin.",
|
|
9
9
|
"aliases": ["ng-add"],
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
},
|
|
18
18
|
"configuration": {
|
|
19
19
|
"aliases": ["cypress-e2e-configuration", "e2e", "e2e-config"],
|
|
20
|
-
"factory": "./src/generators/configuration/configuration",
|
|
20
|
+
"factory": "./src/generators/configuration/configuration#configurationGeneratorInternal",
|
|
21
21
|
"schema": "./src/generators/configuration/schema.json",
|
|
22
22
|
"description": "Add a Cypress E2E Configuration to an existing project."
|
|
23
23
|
},
|
|
24
24
|
"component-configuration": {
|
|
25
25
|
"aliases": ["cypress-component-configuration"],
|
|
26
|
-
"factory": "./src/generators/component-configuration/component-configuration",
|
|
26
|
+
"factory": "./src/generators/component-configuration/component-configuration#componentConfigurationGeneratorInternal",
|
|
27
27
|
"schema": "./src/generators/component-configuration/schema.json",
|
|
28
28
|
"description": "Set up Cypress Component Test for a project",
|
|
29
29
|
"hidden": true
|
package/index.d.ts
CHANGED
|
@@ -2,10 +2,10 @@ import { configurationGenerator } from './src/generators/configuration/configura
|
|
|
2
2
|
import { componentConfigurationGenerator } from './src/generators/component-configuration/component-configuration';
|
|
3
3
|
import { cypressProjectGenerator as _cypressProjectGenerator } from './src/generators/cypress-project/cypress-project';
|
|
4
4
|
export { configurationGenerator, componentConfigurationGenerator };
|
|
5
|
-
/** @deprecated Use `configurationGenerator` instead. It will be removed in Nx
|
|
5
|
+
/** @deprecated Use `configurationGenerator` instead. It will be removed in Nx 19. */
|
|
6
6
|
export declare const cypressComponentConfiguration: typeof componentConfigurationGenerator;
|
|
7
7
|
export { configurationGenerator as cypressE2EConfigurationGenerator };
|
|
8
|
-
/** @deprecated Add a new project and call `configurationGenerator` instead. It will be removed in Nx
|
|
8
|
+
/** @deprecated Add a new project and call `configurationGenerator` instead. It will be removed in Nx 19. */
|
|
9
9
|
export declare const cypressProjectGenerator: typeof _cypressProjectGenerator;
|
|
10
10
|
export { cypressInitGenerator } from './src/generators/init/init';
|
|
11
11
|
export { migrateCypressProject } from './src/generators/migrate-to-cypress-11/migrate-to-cypress-11';
|
package/index.js
CHANGED
|
@@ -8,11 +8,11 @@ const component_configuration_1 = require("./src/generators/component-configurat
|
|
|
8
8
|
Object.defineProperty(exports, "componentConfigurationGenerator", { enumerable: true, get: function () { return component_configuration_1.componentConfigurationGenerator; } });
|
|
9
9
|
const cypress_project_1 = require("./src/generators/cypress-project/cypress-project");
|
|
10
10
|
// Maintain backwards compatibility with the old names in case community plugins used them.
|
|
11
|
-
// TODO(
|
|
12
|
-
/** @deprecated Use `configurationGenerator` instead. It will be removed in Nx
|
|
11
|
+
// TODO(v19): Remove old name
|
|
12
|
+
/** @deprecated Use `configurationGenerator` instead. It will be removed in Nx 19. */
|
|
13
13
|
exports.cypressComponentConfiguration = component_configuration_1.componentConfigurationGenerator;
|
|
14
|
-
// TODO(
|
|
15
|
-
/** @deprecated Add a new project and call `configurationGenerator` instead. It will be removed in Nx
|
|
14
|
+
// TODO(v19): Remove project generator
|
|
15
|
+
/** @deprecated Add a new project and call `configurationGenerator` instead. It will be removed in Nx 19. */
|
|
16
16
|
exports.cypressProjectGenerator = cypress_project_1.cypressProjectGenerator;
|
|
17
17
|
var init_1 = require("./src/generators/init/init");
|
|
18
18
|
Object.defineProperty(exports, "cypressInitGenerator", { enumerable: true, get: function () { return init_1.cypressInitGenerator; } });
|
package/migrations.json
CHANGED
|
@@ -47,6 +47,12 @@
|
|
|
47
47
|
"version": "16.8.0-beta.4",
|
|
48
48
|
"description": "Update to Cypress v13. Most noteable change is video recording is off by default. This migration will only update if the workspace is already on Cypress v12. https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-130",
|
|
49
49
|
"implementation": "./src/migrations/update-16-8-0/cypress-13"
|
|
50
|
+
},
|
|
51
|
+
"update-cypress-version-13-6-6": {
|
|
52
|
+
"cli": "nx",
|
|
53
|
+
"version": "18.1.0-beta.3",
|
|
54
|
+
"description": "Update to Cypress ^13.6.6 if the workspace is using Cypress v13 to ensure workspaces don't use v13.6.5 which has an issue when verifying Cypress.",
|
|
55
|
+
"implementation": "./src/migrations/update-18-1-0/update-cypress-version-13-6-6"
|
|
50
56
|
}
|
|
51
57
|
},
|
|
52
58
|
"packageJsonUpdates": {
|
|
@@ -82,6 +88,24 @@
|
|
|
82
88
|
"alwaysAddToPackageJson": false
|
|
83
89
|
}
|
|
84
90
|
}
|
|
91
|
+
},
|
|
92
|
+
"17.2.0-beta.2": {
|
|
93
|
+
"version": "17.2.0-beta.2",
|
|
94
|
+
"packages": {
|
|
95
|
+
"vite": {
|
|
96
|
+
"version": "^5.0.0",
|
|
97
|
+
"alwaysAddToPackageJson": false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"17.3.0": {
|
|
102
|
+
"version": "17.3.0-beta.3",
|
|
103
|
+
"packages": {
|
|
104
|
+
"@types/node": {
|
|
105
|
+
"version": "18.16.9",
|
|
106
|
+
"alwaysAddToPackageJson": false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
85
109
|
}
|
|
86
110
|
}
|
|
87
111
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/cypress",
|
|
3
|
-
"version": "17.0.
|
|
3
|
+
"version": "17.0.5",
|
|
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,14 @@
|
|
|
34
34
|
"migrations": "./migrations.json"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@nx/devkit": "17.0.5",
|
|
38
|
+
"@nx/eslint": "17.0.5",
|
|
39
|
+
"@nx/js": "17.0.5",
|
|
37
40
|
"@phenomnomnominal/tsquery": "~5.0.1",
|
|
38
41
|
"detect-port": "^1.5.1",
|
|
39
|
-
"semver": "7.5.3",
|
|
42
|
+
"semver": "^7.5.3",
|
|
40
43
|
"tslib": "^2.3.0",
|
|
41
|
-
"@
|
|
42
|
-
"@nx/js": "17.0.3",
|
|
43
|
-
"@nx/eslint": "17.0.3",
|
|
44
|
-
"@nrwl/cypress": "17.0.3"
|
|
44
|
+
"@nrwl/cypress": "17.0.5"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"cypress": ">= 3 < 14"
|
package/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createNodes, createDependencies } from './src/plugins/plugin';
|
package/plugin.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDependencies = exports.createNodes = void 0;
|
|
4
|
+
var plugin_1 = require("./src/plugins/plugin");
|
|
5
|
+
Object.defineProperty(exports, "createNodes", { enumerable: true, get: function () { return plugin_1.createNodes; } });
|
|
6
|
+
Object.defineProperty(exports, "createDependencies", { enumerable: true, get: function () { return plugin_1.createDependencies; } });
|
|
@@ -10,7 +10,9 @@ export interface NxComponentTestingOptions {
|
|
|
10
10
|
* @example 'component-test'
|
|
11
11
|
*/
|
|
12
12
|
ctTargetName?: string;
|
|
13
|
+
buildTarget?: string;
|
|
13
14
|
bundler?: 'vite' | 'webpack';
|
|
15
|
+
compiler?: 'swc' | 'babel';
|
|
14
16
|
}
|
|
15
17
|
export declare function nxBaseCypressPreset(pathToConfig: string, options?: {
|
|
16
18
|
testingType: 'component' | 'e2e';
|
|
@@ -29,26 +31,19 @@ export declare function nxBaseCypressPreset(pathToConfig: string, options?: {
|
|
|
29
31
|
* }
|
|
30
32
|
* })
|
|
31
33
|
*
|
|
32
|
-
* @param pathToConfig will be used to construct the output paths for videos and screenshots
|
|
33
34
|
*/
|
|
34
|
-
export declare function nxE2EPreset(pathToConfig: string, options?: NxCypressE2EPresetOptions):
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
specPattern: string;
|
|
47
|
-
fixturesFolder: string;
|
|
48
|
-
videosFolder: string;
|
|
49
|
-
screenshotsFolder: string;
|
|
50
|
-
chromeWebSecurity: boolean;
|
|
51
|
-
};
|
|
35
|
+
export declare function nxE2EPreset(pathToConfig: string, options?: NxCypressE2EPresetOptions): any;
|
|
36
|
+
export interface WebServerConfig {
|
|
37
|
+
/**
|
|
38
|
+
* Timeout to wait for the webserver to start listening
|
|
39
|
+
*/
|
|
40
|
+
timeout?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Reuse an existing web server if it exists
|
|
43
|
+
* If this is false, an error will be thrown if the server is already running
|
|
44
|
+
*/
|
|
45
|
+
reuseExistingServer?: boolean;
|
|
46
|
+
}
|
|
52
47
|
export type NxCypressE2EPresetOptions = {
|
|
53
48
|
bundler?: string;
|
|
54
49
|
/**
|
|
@@ -57,5 +52,18 @@ export type NxCypressE2EPresetOptions = {
|
|
|
57
52
|
* default is 'src'
|
|
58
53
|
**/
|
|
59
54
|
cypressDir?: string;
|
|
55
|
+
/**
|
|
56
|
+
* A map of commandName -> command to start the web server for testing.
|
|
57
|
+
* Currently only default is read.
|
|
58
|
+
*/
|
|
59
|
+
webServerCommands?: Record<string, string>;
|
|
60
|
+
/**
|
|
61
|
+
* A command to start the web server - used for e2e tests distributed by Nx.
|
|
62
|
+
*/
|
|
63
|
+
ciWebServerCommand?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Configures how the web server command is started and monitored.
|
|
66
|
+
*/
|
|
67
|
+
webServerConfig?: WebServerConfig;
|
|
60
68
|
};
|
|
61
69
|
export {};
|
|
@@ -5,6 +5,10 @@ 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 constants_1 = require("../src/utils/constants");
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const http_1 = require("http");
|
|
11
|
+
const https_1 = require("https");
|
|
8
12
|
function nxBaseCypressPreset(pathToConfig, options) {
|
|
9
13
|
// used to set babel settings for react CT.
|
|
10
14
|
process.env.NX_CYPRESS_COMPONENT_TEST =
|
|
@@ -25,6 +29,26 @@ function nxBaseCypressPreset(pathToConfig, options) {
|
|
|
25
29
|
};
|
|
26
30
|
}
|
|
27
31
|
exports.nxBaseCypressPreset = nxBaseCypressPreset;
|
|
32
|
+
function startWebServer(webServerCommand) {
|
|
33
|
+
const serverProcess = (0, child_process_1.spawn)(webServerCommand, {
|
|
34
|
+
cwd: devkit_1.workspaceRoot,
|
|
35
|
+
shell: true,
|
|
36
|
+
// Detaching the process on unix will create a process group, allowing us to kill it later
|
|
37
|
+
// Windows is fine so we leave it attached to this process
|
|
38
|
+
detached: process.platform !== 'win32',
|
|
39
|
+
stdio: 'inherit',
|
|
40
|
+
});
|
|
41
|
+
return () => {
|
|
42
|
+
if (process.platform === 'win32') {
|
|
43
|
+
serverProcess.kill();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// child.kill() does not work on linux
|
|
47
|
+
// process.kill will kill the whole process group on unix
|
|
48
|
+
process.kill(-serverProcess.pid, 'SIGKILL');
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
28
52
|
/**
|
|
29
53
|
* nx E2E Preset for Cypress
|
|
30
54
|
* @description
|
|
@@ -39,25 +63,92 @@ exports.nxBaseCypressPreset = nxBaseCypressPreset;
|
|
|
39
63
|
* }
|
|
40
64
|
* })
|
|
41
65
|
*
|
|
42
|
-
* @param pathToConfig will be used to construct the output paths for videos and screenshots
|
|
43
66
|
*/
|
|
44
67
|
function nxE2EPreset(pathToConfig, options) {
|
|
45
68
|
const basePath = options?.cypressDir || 'src';
|
|
46
|
-
const baseConfig
|
|
69
|
+
const baseConfig /*Cypress.EndToEndConfigOptions & {
|
|
70
|
+
[NX_PLUGIN_OPTIONS]: unknown;
|
|
71
|
+
}*/ = {
|
|
47
72
|
...nxBaseCypressPreset(pathToConfig),
|
|
48
73
|
fileServerFolder: '.',
|
|
49
|
-
supportFile: `${basePath}/support/e2e.ts`,
|
|
74
|
+
supportFile: `${basePath}/support/e2e.{js,ts}`,
|
|
50
75
|
specPattern: `${basePath}/**/*.cy.{js,jsx,ts,tsx}`,
|
|
51
76
|
fixturesFolder: `${basePath}/fixtures`,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
77
|
+
[constants_1.NX_PLUGIN_OPTIONS]: {
|
|
78
|
+
webServerCommand: options?.webServerCommands?.default,
|
|
79
|
+
webServerCommands: options?.webServerCommands,
|
|
80
|
+
ciWebServerCommand: options?.ciWebServerCommand,
|
|
81
|
+
},
|
|
82
|
+
async setupNodeEvents(on, config) {
|
|
83
|
+
const webServerCommands = config.env?.webServerCommands ?? options?.webServerCommands;
|
|
84
|
+
const webServerCommand = config.env?.webServerCommand ?? webServerCommands?.default;
|
|
85
|
+
if (options?.bundler === 'vite') {
|
|
57
86
|
on('file:preprocessor', (0, preprocessor_vite_1.default)());
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
87
|
+
}
|
|
88
|
+
if (!options?.webServerCommands) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!webServerCommand) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (config.baseUrl && webServerCommand) {
|
|
95
|
+
if (await isServerUp(config.baseUrl)) {
|
|
96
|
+
if (options?.webServerConfig?.reuseExistingServer === undefined
|
|
97
|
+
? true
|
|
98
|
+
: options.webServerConfig.reuseExistingServer) {
|
|
99
|
+
console.log(`Reusing the server already running on ${config.baseUrl}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw new Error(`Web server is already running at ${config.baseUrl}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const killWebServer = startWebServer(webServerCommand);
|
|
107
|
+
on('after:run', () => {
|
|
108
|
+
killWebServer();
|
|
109
|
+
});
|
|
110
|
+
await waitForServer(config.baseUrl, options.webServerConfig);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
};
|
|
61
114
|
return baseConfig;
|
|
62
115
|
}
|
|
63
116
|
exports.nxE2EPreset = nxE2EPreset;
|
|
117
|
+
function waitForServer(url, webServerConfig) {
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
let pollTimeout;
|
|
120
|
+
const { protocol } = new URL(url);
|
|
121
|
+
const timeoutDuration = webServerConfig?.timeout ?? 60 * 1000;
|
|
122
|
+
const timeout = setTimeout(() => {
|
|
123
|
+
clearTimeout(pollTimeout);
|
|
124
|
+
reject(new Error(`Web server failed to start in ${timeoutDuration}ms. This can be configured in cypress.config.ts.`));
|
|
125
|
+
}, timeoutDuration);
|
|
126
|
+
const makeRequest = protocol === 'https:' ? https_1.request : http_1.request;
|
|
127
|
+
function pollForServer() {
|
|
128
|
+
const request = makeRequest(url, () => {
|
|
129
|
+
clearTimeout(timeout);
|
|
130
|
+
resolve();
|
|
131
|
+
});
|
|
132
|
+
request.on('error', () => {
|
|
133
|
+
pollTimeout = setTimeout(pollForServer, 100);
|
|
134
|
+
});
|
|
135
|
+
// Don't forget to end the request
|
|
136
|
+
request.end();
|
|
137
|
+
}
|
|
138
|
+
pollForServer();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function isServerUp(url) {
|
|
142
|
+
const { protocol } = new URL(url);
|
|
143
|
+
const makeRequest = protocol === 'https:' ? https_1.request : http_1.request;
|
|
144
|
+
return new Promise((resolve) => {
|
|
145
|
+
const request = makeRequest(url, () => {
|
|
146
|
+
resolve(true);
|
|
147
|
+
});
|
|
148
|
+
request.on('error', () => {
|
|
149
|
+
resolve(false);
|
|
150
|
+
});
|
|
151
|
+
// Don't forget to end the request
|
|
152
|
+
request.end();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
@@ -25,7 +25,7 @@ export interface CypressExecutorOptions extends Json {
|
|
|
25
25
|
copyFiles?: string;
|
|
26
26
|
ciBuildId?: string | number;
|
|
27
27
|
group?: string;
|
|
28
|
-
ignoreTestFiles?: string;
|
|
28
|
+
ignoreTestFiles?: string | string[];
|
|
29
29
|
reporter?: string;
|
|
30
30
|
reporterOptions?: string | Json;
|
|
31
31
|
skipServe?: boolean;
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const devkit_1 = require("@nx/devkit");
|
|
4
|
-
const executor_utils_1 = require("nx/src/command-line/run/executor-utils");
|
|
5
4
|
const fs_1 = require("fs");
|
|
6
5
|
const path_1 = require("path");
|
|
7
6
|
const ct_helpers_1 = require("../../utils/ct-helpers");
|
|
8
7
|
const cypress_version_1 = require("../../utils/cypress-version");
|
|
9
|
-
const
|
|
8
|
+
const start_dev_server_1 = require("../../utils/start-dev-server");
|
|
10
9
|
const Cypress = require('cypress'); // @NOTE: Importing via ES6 messes the whole test dependencies.
|
|
11
10
|
async function cypressExecutor(options, context) {
|
|
12
11
|
options = normalizeOptions(options, context);
|
|
13
12
|
// this is used by cypress component testing presets to build the executor contexts with the correct configuration options.
|
|
14
13
|
process.env.NX_CYPRESS_TARGET_CONFIGURATION = context.configurationName;
|
|
15
14
|
let success;
|
|
16
|
-
for await (const devServerValues of startDevServer(options, context)) {
|
|
15
|
+
for await (const devServerValues of (0, start_dev_server_1.startDevServer)(options, context)) {
|
|
17
16
|
try {
|
|
18
17
|
success = await runCypress(devServerValues.baseUrl, {
|
|
19
18
|
...options,
|
|
@@ -90,50 +89,6 @@ A generator to migrate from v8 to v10 is provided. See https://nx.dev/cypress/v1
|
|
|
90
89
|
`);
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
|
-
async function* startDevServer(opts, context) {
|
|
94
|
-
// no dev server, return the provisioned base url
|
|
95
|
-
if (!opts.devServerTarget || opts.skipServe) {
|
|
96
|
-
yield { baseUrl: opts.baseUrl };
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const parsedDevServerTarget = (0, devkit_1.parseTargetString)(opts.devServerTarget, context);
|
|
100
|
-
const [targetSupportsWatchOpt] = getValueFromSchema(context, parsedDevServerTarget, 'watch');
|
|
101
|
-
const overrides = {
|
|
102
|
-
// @NOTE: Do not forward watch option if not supported by the target dev server,
|
|
103
|
-
// this is relevant for running Cypress against dev server target that does not support this option,
|
|
104
|
-
// for instance @nguniversal/builders:ssr-dev-server.
|
|
105
|
-
...(targetSupportsWatchOpt ? { watch: opts.watch } : {}),
|
|
106
|
-
};
|
|
107
|
-
if (opts.port === 'cypress-auto') {
|
|
108
|
-
const freePort = await getPortForProject(context, parsedDevServerTarget);
|
|
109
|
-
overrides['port'] = freePort;
|
|
110
|
-
}
|
|
111
|
-
else if (opts.port !== undefined) {
|
|
112
|
-
overrides['port'] = opts.port;
|
|
113
|
-
// zero is a special case that means any valid port so there is no reason to try to 'lock it'
|
|
114
|
-
if (opts.port !== 0) {
|
|
115
|
-
const didLock = attemptToLockPort(opts.port);
|
|
116
|
-
if (!didLock) {
|
|
117
|
-
devkit_1.logger.warn((0, devkit_1.stripIndents) `${opts.port} is potentially already in use by another cypress run.
|
|
118
|
-
If the port is in use, try using a different port value or passing --port='cypress-auto' to find a free port.`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
for await (const output of await (0, devkit_1.runExecutor)(parsedDevServerTarget, overrides, context)) {
|
|
123
|
-
if (!output.success && !opts.watch)
|
|
124
|
-
throw new Error('Could not compile application files');
|
|
125
|
-
if (!opts.baseUrl &&
|
|
126
|
-
!output.baseUrl &&
|
|
127
|
-
!output.info?.baseUrl &&
|
|
128
|
-
output.info?.port) {
|
|
129
|
-
output.baseUrl = `http://localhost:${output.info.port}`;
|
|
130
|
-
}
|
|
131
|
-
yield {
|
|
132
|
-
baseUrl: opts.baseUrl || output.baseUrl || output.info?.baseUrl,
|
|
133
|
-
portLockFilePath: overrides.port && (0, path_1.join)(__dirname, `${overrides.port}.txt`),
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
92
|
/**
|
|
138
93
|
* @whatItDoes Initialize the Cypress test runner with the provided project configuration.
|
|
139
94
|
* By default, Cypress will run tests from the CLI without the GUI and provide directly the results in the console output.
|
|
@@ -155,7 +110,10 @@ async function runCypress(baseUrl, opts) {
|
|
|
155
110
|
options.browser = opts.browser;
|
|
156
111
|
}
|
|
157
112
|
if (opts.env) {
|
|
158
|
-
options.env =
|
|
113
|
+
options.env = {
|
|
114
|
+
...options.env,
|
|
115
|
+
...opts.env,
|
|
116
|
+
};
|
|
159
117
|
}
|
|
160
118
|
if (opts.spec) {
|
|
161
119
|
options.spec = opts.spec;
|
|
@@ -211,110 +169,6 @@ async function runCypress(baseUrl, opts) {
|
|
|
211
169
|
*/
|
|
212
170
|
return !result.totalFailed && !result.failures;
|
|
213
171
|
}
|
|
214
|
-
/**
|
|
215
|
-
* try to find a free port for the project to run on
|
|
216
|
-
* will return undefined if no port is found or the project doesn't have a port option
|
|
217
|
-
**/
|
|
218
|
-
async function getPortForProject(context, target, defaultPort = 4200) {
|
|
219
|
-
const fmtTarget = (0, devkit_1.targetToTargetString)(target);
|
|
220
|
-
const [hasPortOpt, schemaPortValue] = getValueFromSchema(context, target, 'port');
|
|
221
|
-
let freePort;
|
|
222
|
-
if (hasPortOpt) {
|
|
223
|
-
let normalizedPortValue;
|
|
224
|
-
if (!schemaPortValue) {
|
|
225
|
-
devkit_1.logger.info(`NX ${fmtTarget} did not have a defined port value, checking for free port with the default value of ${defaultPort}`);
|
|
226
|
-
normalizedPortValue = defaultPort;
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
normalizedPortValue = Number(schemaPortValue);
|
|
230
|
-
}
|
|
231
|
-
if (isNaN(normalizedPortValue)) {
|
|
232
|
-
devkit_1.output.warn({
|
|
233
|
-
title: `Port Not a Number`,
|
|
234
|
-
bodyLines: [
|
|
235
|
-
`The port value found was not a number or can't be parsed to a number`,
|
|
236
|
-
`When reading the devServerTarget (${fmtTarget}) schema, expected ${schemaPortValue} to be a number but got NaN.`,
|
|
237
|
-
`Nx will use the default value of ${defaultPort} instead.`,
|
|
238
|
-
`You can manually specify a port by setting the 'port' option`,
|
|
239
|
-
],
|
|
240
|
-
});
|
|
241
|
-
normalizedPortValue = defaultPort;
|
|
242
|
-
}
|
|
243
|
-
try {
|
|
244
|
-
let attempts = 0;
|
|
245
|
-
// make sure when this check happens in parallel,
|
|
246
|
-
// we don't let the same port be used by multiple projects
|
|
247
|
-
do {
|
|
248
|
-
freePort = await detectPort(freePort || normalizedPortValue);
|
|
249
|
-
if (attemptToLockPort(freePort)) {
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
attempts++;
|
|
253
|
-
// increment port in case the lock file isn't cleaned up
|
|
254
|
-
freePort++;
|
|
255
|
-
} while (attempts < 20);
|
|
256
|
-
devkit_1.logger.info(`NX Using port ${freePort} for ${fmtTarget}`);
|
|
257
|
-
}
|
|
258
|
-
catch (err) {
|
|
259
|
-
throw new Error((0, devkit_1.stripIndents) `Unable to find a free port for the dev server, ${fmtTarget}.
|
|
260
|
-
You can disable auto port detection by specifing a port or not passing a value to --port`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
devkit_1.output.warn({
|
|
265
|
-
title: `No Port Option Found`,
|
|
266
|
-
bodyLines: [
|
|
267
|
-
`The 'port' option is set to 'cypress-auto', but the devServerTarget (${fmtTarget}) does not have a port option.`,
|
|
268
|
-
`Because of this, Nx is unable to verify the port is free before starting the dev server.`,
|
|
269
|
-
`This might cause issues if the devServerTarget is trying to use a port that is already in use.`,
|
|
270
|
-
],
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
return freePort;
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Check if the given target has the given property in it's options.
|
|
277
|
-
* if the property is does not have a default value or is not in the actual executor options,
|
|
278
|
-
* the value will be undefined even if it's in the executor schema.
|
|
279
|
-
**/
|
|
280
|
-
function getValueFromSchema(context, target, property) {
|
|
281
|
-
let targetOpts;
|
|
282
|
-
try {
|
|
283
|
-
targetOpts = (0, devkit_1.readTargetOptions)(target, context);
|
|
284
|
-
}
|
|
285
|
-
catch (e) {
|
|
286
|
-
throw new Error(`Unable to read the target options for ${(0, devkit_1.targetToTargetString)(target)}.
|
|
287
|
-
Are you sure this is a valid target?
|
|
288
|
-
Was trying to read the target for the property: '${property}', but got the following error:
|
|
289
|
-
${e.message || e}`);
|
|
290
|
-
}
|
|
291
|
-
let targetHasOpt = Object.keys(targetOpts).includes(property);
|
|
292
|
-
if (!targetHasOpt) {
|
|
293
|
-
// NOTE: readTargetOptions doesn't apply non defaulted values, i.e. @nx/vite has a port options but is optional
|
|
294
|
-
// so we double check the schema if readTargetOptions didn't return a value for the property
|
|
295
|
-
const projectConfig = context.projectsConfigurations?.projects?.[target.project];
|
|
296
|
-
const targetConfig = projectConfig.targets[target.target];
|
|
297
|
-
const [collection, executor] = targetConfig.executor.split(':');
|
|
298
|
-
const { schema } = (0, executor_utils_1.getExecutorInformation)(collection, executor, context.root);
|
|
299
|
-
// NOTE: schema won't have a default since readTargetOptions would have
|
|
300
|
-
// already set that and this check wouldn't need to be made
|
|
301
|
-
targetHasOpt = Object.keys(schema.properties).includes(property);
|
|
302
|
-
}
|
|
303
|
-
return [targetHasOpt, targetOpts[property]];
|
|
304
|
-
}
|
|
305
|
-
function attemptToLockPort(port) {
|
|
306
|
-
const portLockFilePath = (0, path_1.join)(__dirname, `${port}.txt`);
|
|
307
|
-
try {
|
|
308
|
-
if ((0, fs_1.existsSync)(portLockFilePath)) {
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
(0, fs_1.writeFileSync)(portLockFilePath, 'locked');
|
|
312
|
-
return true;
|
|
313
|
-
}
|
|
314
|
-
catch (err) {
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
172
|
function cleanupTmpFile(path) {
|
|
319
173
|
try {
|
|
320
174
|
if (path && (0, fs_1.existsSync)(path)) {
|
|
@@ -113,7 +113,17 @@
|
|
|
113
113
|
},
|
|
114
114
|
"ignoreTestFiles": {
|
|
115
115
|
"aliases": ["excludeSpecPattern"],
|
|
116
|
-
"
|
|
116
|
+
"oneOf": [
|
|
117
|
+
{
|
|
118
|
+
"type": "string"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {
|
|
123
|
+
"type": "string"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
],
|
|
117
127
|
"description": "A String or Array of glob patterns used to ignore test files that would otherwise be shown in your list of tests. Cypress uses minimatch with the options: `{dot: true, matchBase: true}`. We suggest using https://globster.xyz to test what files would match."
|
|
118
128
|
},
|
|
119
129
|
"reporter": {
|