@nx/cypress 16.8.0-beta.5 → 16.8.0-beta.6

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
@@ -59,6 +59,12 @@
59
59
  "version": "16.4.0-beta.10",
60
60
  "description": "Remove tsconfig.e2e.json and add settings to project tsconfig.json. tsConfigs executor option is now deprecated. The project level tsconfig.json file should be used instead.",
61
61
  "implementation": "./src/migrations/update-16-4-0/tsconfig-sourcemaps"
62
+ },
63
+ "update-16-8-0-cypress-13": {
64
+ "cli": "nx",
65
+ "version": "16.8.0-beta.4",
66
+ "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",
67
+ "implementation": "./src/migrations/update-16-8-0/cypress-13"
62
68
  }
63
69
  },
64
70
  "packageJsonUpdates": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/cypress",
3
- "version": "16.8.0-beta.5",
3
+ "version": "16.8.0-beta.6",
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,17 +34,17 @@
34
34
  "migrations": "./migrations.json"
35
35
  },
36
36
  "dependencies": {
37
- "@nrwl/cypress": "16.8.0-beta.5",
38
- "@nx/devkit": "16.8.0-beta.5",
39
- "@nx/js": "16.8.0-beta.5",
40
- "@nx/linter": "16.8.0-beta.5",
37
+ "@nrwl/cypress": "16.8.0-beta.6",
38
+ "@nx/devkit": "16.8.0-beta.6",
39
+ "@nx/js": "16.8.0-beta.6",
40
+ "@nx/linter": "16.8.0-beta.6",
41
41
  "@phenomnomnominal/tsquery": "~5.0.1",
42
42
  "detect-port": "^1.5.1",
43
43
  "semver": "7.5.3",
44
44
  "tslib": "^2.3.0"
45
45
  },
46
46
  "peerDependencies": {
47
- "cypress": ">= 3 < 13"
47
+ "cypress": ">= 3 < 14"
48
48
  },
49
49
  "peerDependenciesMeta": {
50
50
  "cypress": {
@@ -55,5 +55,5 @@
55
55
  "access": "public"
56
56
  },
57
57
  "type": "commonjs",
58
- "gitHead": "ad2d1e8a55b2d1b358bb5e7483343d9757ff2c53"
58
+ "gitHead": "0cc6ba996f2ef09f00b932c8eacf42de642457f3"
59
59
  }
@@ -1,7 +1,6 @@
1
1
  interface BaseCypressPreset {
2
2
  videosFolder: string;
3
3
  screenshotsFolder: string;
4
- video: boolean;
5
4
  chromeWebSecurity: boolean;
6
5
  }
7
6
  export interface NxComponentTestingOptions {
@@ -39,7 +38,6 @@ export declare function nxE2EPreset(pathToConfig: string, options?: NxCypressE2E
39
38
  fixturesFolder: string;
40
39
  videosFolder: string;
41
40
  screenshotsFolder: string;
42
- video: boolean;
43
41
  chromeWebSecurity: boolean;
44
42
  } | {
45
43
  setupNodeEvents(on: any): void;
@@ -49,7 +47,6 @@ export declare function nxE2EPreset(pathToConfig: string, options?: NxCypressE2E
49
47
  fixturesFolder: string;
50
48
  videosFolder: string;
51
49
  screenshotsFolder: string;
52
- video: boolean;
53
50
  chromeWebSecurity: boolean;
54
51
  };
55
52
  export type NxCypressE2EPresetOptions = {
@@ -21,7 +21,6 @@ function nxBaseCypressPreset(pathToConfig, options) {
21
21
  return {
22
22
  videosFolder,
23
23
  screenshotsFolder,
24
- video: true,
25
24
  chromeWebSecurity: false,
26
25
  };
27
26
  }
@@ -33,6 +33,7 @@ export interface CypressExecutorOptions extends Json {
33
33
  tag?: string;
34
34
  port?: number | 'cypress-auto';
35
35
  quiet?: boolean;
36
+ runnerUi?: boolean;
36
37
  }
37
38
  export default function cypressExecutor(options: CypressExecutorOptions, context: ExecutorContext): Promise<{
38
39
  success: any;
@@ -163,6 +163,7 @@ async function runCypress(baseUrl, opts) {
163
163
  options.tag = opts.tag;
164
164
  options.exit = opts.exit;
165
165
  options.headed = opts.headed;
166
+ options.runnerUi = opts.runnerUi;
166
167
  if (opts.headless) {
167
168
  options.headless = opts.headless;
168
169
  }
@@ -164,6 +164,10 @@
164
164
  "type": "boolean",
165
165
  "description": "If passed, Cypress output will not be printed to stdout. Only output from the configured Mocha reporter will print.",
166
166
  "default": false
167
+ },
168
+ "runnerUi": {
169
+ "type": "boolean",
170
+ "description": "Displays the Cypress Runner UI. Useful for when Test Replay is enabled and you would still like the Cypress Runner UI to be displayed for screenshots and video."
167
171
  }
168
172
  },
169
173
  "additionalProperties": true,
@@ -0,0 +1,7 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export declare function updateToCypress13(tree: Tree): Promise<void>;
3
+ /**
4
+ * leave a comment on all usages of overriding built-ins that are now banned
5
+ **/
6
+ export declare function shouldNotOverrideReadFile(tree: Tree, filePath: string): void;
7
+ export default updateToCypress13;
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shouldNotOverrideReadFile = exports.updateToCypress13 = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const cypress_version_1 = require("../../utils/cypress-version");
6
+ const typescript_1 = require("typescript");
7
+ const tsquery_1 = require("@phenomnomnominal/tsquery");
8
+ const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
9
+ const JS_TS_FILE_MATCHER = /\.[jt]sx?$/;
10
+ async function updateToCypress13(tree) {
11
+ if ((0, cypress_version_1.installedCypressVersion)() < 12) {
12
+ return;
13
+ }
14
+ const projects = (0, devkit_1.getProjects)(tree);
15
+ (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/cypress:cypress', (options, projectName) => {
16
+ if (!options.cypressConfig || !tree.exists(options.cypressConfig)) {
17
+ return;
18
+ }
19
+ const projectConfig = projects.get(projectName);
20
+ removeNodeVersionOption(tree, options.cypressConfig);
21
+ removeVideoUploadOnPassesOption(tree, options.cypressConfig);
22
+ (0, devkit_1.visitNotIgnoredFiles)(tree, projectConfig.root, (filePath) => {
23
+ if (!JS_TS_FILE_MATCHER.test(filePath)) {
24
+ return;
25
+ }
26
+ shouldNotOverrideReadFile(tree, filePath);
27
+ });
28
+ });
29
+ (0, devkit_1.updateJson)(tree, 'package.json', (json) => {
30
+ json.devDependencies ??= {};
31
+ json.devDependencies.cypress = '^13.0.0';
32
+ return json;
33
+ });
34
+ await (0, devkit_1.formatFiles)(tree);
35
+ }
36
+ exports.updateToCypress13 = updateToCypress13;
37
+ function removeVideoUploadOnPassesOption(tree, configPath) {
38
+ const config = tree.read(configPath, 'utf-8');
39
+ const isUsingDeprecatedOption = tsquery_1.tsquery.query(config, getPropertyQuery('videoUploadOnPasses'))?.length > 0;
40
+ if (!isUsingDeprecatedOption) {
41
+ return;
42
+ }
43
+ const importStatement = configPath.endsWith('.ts')
44
+ ? "import fs from 'fs';"
45
+ : "const fs = require('fs');";
46
+ const replacementFunction = `/**
47
+ * Delete videos for specs that do not contain failing or retried tests.
48
+ * This function is to be used in the 'setupNodeEvents' configuration option as a replacement to
49
+ * 'videoUploadOnPasses' which has been removed.
50
+ *
51
+ * https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests
52
+ **/
53
+ function removePassedSpecs(on) {
54
+ on('after:spec', (spec, results) => {
55
+ if(results && results.vide) {
56
+ const hasFailures = results.tests.some(t => t.attempts.some(a => a.state === 'failed'));
57
+
58
+ if(!hasFailures) {
59
+ fs.unlinkSync(results.video);
60
+ }
61
+ }
62
+ })
63
+ }`;
64
+ const withReplacementFn = `${importStatement}\n${config}\n${replacementFunction}`;
65
+ // setupNodeEvents can be a property or method.
66
+ const setupNodeEventsQuery = 'ExportAssignment ObjectLiteralExpression > :matches(PropertyAssignment:has(Identifier[name="setupNodeEvents"]), MethodDeclaration:has(Identifier[name="setupNodeEvents"]))';
67
+ const hasSetupNodeEvents = tsquery_1.tsquery.query(withReplacementFn, setupNodeEventsQuery)?.length > 0;
68
+ let updatedWithSetupNodeEvents = withReplacementFn;
69
+ if (hasSetupNodeEvents) {
70
+ // if have setupNodeEvents, update existing fn to use removePassedSpecs helper and remove videoUploadOnPasses
71
+ const noVideoUploadOption = tsquery_1.tsquery.replace(withReplacementFn, getPropertyQuery('videoUploadOnPasses'), (node) => {
72
+ if ((0, typescript_1.isObjectLiteralExpression)(node.initializer)) {
73
+ // is a nested config object
74
+ const key = node.name.getText().trim();
75
+ const listOfProperties = node.initializer.properties
76
+ .map((j) => j.getText())
77
+ .filter((j) => !j.includes('videoUploadOnPasses'))
78
+ .join(',\n');
79
+ return `${key}: {
80
+ ${listOfProperties}
81
+ }
82
+ `;
83
+ }
84
+ else {
85
+ if (isPropertyTopLevel(node)) {
86
+ return `// ${node.getText()} `;
87
+ }
88
+ }
89
+ });
90
+ updatedWithSetupNodeEvents = tsquery_1.tsquery.replace(noVideoUploadOption, `${setupNodeEventsQuery} Block`, (node) => {
91
+ const blockWithoutBraces = node
92
+ .getFullText()
93
+ .trim()
94
+ .slice(1, -1)
95
+ .trim();
96
+ return `{
97
+ ${blockWithoutBraces}
98
+ removePassedSpecs(on);
99
+ }
100
+ `;
101
+ }, { visitAllChildren: false });
102
+ }
103
+ else {
104
+ // if don't have setupNodeEvents, replace videoUploadOnPasses with setupNodeEvents method
105
+ updatedWithSetupNodeEvents = tsquery_1.tsquery.replace(withReplacementFn, getPropertyQuery('videoUploadOnPasses'), () => {
106
+ return `setupNodeEvents(on, config) {
107
+ removePassedSpecs(on);
108
+ }`;
109
+ });
110
+ }
111
+ tree.write(configPath, updatedWithSetupNodeEvents);
112
+ }
113
+ /**
114
+ * remove the nodeVersion option from the config file
115
+ **/
116
+ function removeNodeVersionOption(tree, configPath) {
117
+ const config = tree.read(configPath, 'utf-8');
118
+ const updated = tsquery_1.tsquery.replace(config, getPropertyQuery('nodeVersion'), (node) => {
119
+ if ((0, typescript_1.isObjectLiteralExpression)(node.initializer)) {
120
+ // is a nested config object
121
+ const key = node.name.getText().trim();
122
+ const listOfProperties = node.initializer.properties
123
+ .map((j) => j.getFullText())
124
+ .filter((j) => !j.includes('nodeVersion'))
125
+ .join(', ');
126
+ return `${key}: {
127
+ ${listOfProperties}
128
+ }`;
129
+ }
130
+ else {
131
+ if (isPropertyTopLevel(node)) {
132
+ return `// ${node.getText()}`;
133
+ }
134
+ }
135
+ });
136
+ if (updated !== config) {
137
+ tree.write(configPath, updated);
138
+ }
139
+ }
140
+ /**
141
+ * leave a comment on all usages of overriding built-ins that are now banned
142
+ **/
143
+ function shouldNotOverrideReadFile(tree, filePath) {
144
+ const content = tree.read(filePath, 'utf-8');
145
+ const markedOverrideUsage = tsquery_1.tsquery.replace(content, 'PropertyAccessExpression:has(Identifier[name="overwrite"]):has(Identifier[name="Cypress"])', (node) => {
146
+ if (isAlreadyCommented(node)) {
147
+ return;
148
+ }
149
+ const expression = node.expression.getText().trim();
150
+ // prevent grabbing other Cypress.<something>.defaults
151
+ if (expression === 'Cypress.Commands') {
152
+ // get value.
153
+ const overwriteExpression = node.parent;
154
+ const command = overwriteExpression.arguments?.[0]?.text; // need string without quotes
155
+ if (command === 'readFile') {
156
+ // overwrite
157
+ return `/**
158
+ * TODO(@nx/cypress): This command can no longer be overridden
159
+ * Consider using a different name like 'custom_${command}'
160
+ * More info: https://docs.cypress.io/guides/references/migration-guide#readFile-can-no-longer-be-overwritten-with-CypressCommandsoverwrite
161
+ **/
162
+ ${node.getText()}`;
163
+ }
164
+ }
165
+ });
166
+ tree.write(filePath, markedOverrideUsage);
167
+ }
168
+ exports.shouldNotOverrideReadFile = shouldNotOverrideReadFile;
169
+ function isAlreadyCommented(node) {
170
+ return node.getFullText().includes('TODO(@nx/cypress)');
171
+ }
172
+ function isPropertyTopLevel(node) {
173
+ return (node.parent &&
174
+ (0, typescript_1.isObjectLiteralExpression)(node.parent) &&
175
+ node.parent.parent &&
176
+ (0, typescript_1.isCallExpression)(node.parent.parent));
177
+ }
178
+ const getPropertyQuery = (propertyName) => `ExportAssignment ObjectLiteralExpression > PropertyAssignment:has(Identifier[name="${propertyName}"])`;
179
+ exports.default = updateToCypress13;
@@ -2,7 +2,7 @@ export declare const nxVersion: any;
2
2
  export declare const eslintPluginCypressVersion = "^2.13.4";
3
3
  export declare const typesNodeVersion = "16.11.7";
4
4
  export declare const cypressViteDevServerVersion = "^2.2.1";
5
- export declare const cypressVersion = "^12.16.0";
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
8
  export declare const viteVersion = "~4.3.9";
@@ -5,7 +5,7 @@ exports.nxVersion = require('../../package.json').version;
5
5
  exports.eslintPluginCypressVersion = '^2.13.4';
6
6
  exports.typesNodeVersion = '16.11.7';
7
7
  exports.cypressViteDevServerVersion = '^2.2.1';
8
- exports.cypressVersion = '^12.16.0';
8
+ exports.cypressVersion = '^13.0.0';
9
9
  exports.cypressWebpackVersion = '^2.0.0';
10
10
  exports.webpackHttpPluginVersion = '^5.5.0';
11
11
  exports.viteVersion = '~4.3.9';