Skip to content

Commit 9096d41

Browse files
fix(testing): cypress 10 migration supports more configuration setups (#12036)
1 parent cc55cff commit 9096d41

File tree

6 files changed

+284
-28
lines changed

6 files changed

+284
-28
lines changed

docs/generated/packages/cypress.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"name": "v10 Migration Guide",
2424
"id": "v10-migration-guide",
2525
"file": "shared/guides/cypress/cypress-v10-migration",
26-
"content": "# Migrating to Cypress V10\n\nCypress v10 introduce new features, like component testing, along with some breaking changes.\n\nBefore continuing, make sure you have all your changes committed and have a clean working tree.\n\nYou can migrate an E2E project to v10 by running the following command:\n\n```shell\nnx g @nrwl/cypress:migrate-to-cypress-10\n```\n\nIn general, these are the steps taken to migrate your project:\n\n1. Migrates your existing `cypress.json` configuration to a new `cypress.config.ts` configuration file.\n - The `pluginsFile` option has been replaced for `setupNodeEvents`. We will import the file and add it to\n the `setupNodeEvents` config option. Double-check your plugins are working correctly.\n2. Rename all test files from `.spec.ts` to `.cy.ts`\n3. Rename the `support/index.ts` to `support/e2e.ts` and update any associated imports\n4. Rename the `integrations` folder to the `e2e` folder\n\nWe take the best effort to make this migration seamless, but there can be edge cases we didn't anticipate. So feel free to [open an issue](https://github.com/nrwl/nx/issues/new?assignees=&labels=type%3A+bug&template=1-bug.md) if you come across any problems.\n\nYou can also consult the [official Cypress migration guide](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-version-10-0) if you get stuck and want to manually migrate your projects.\n"
26+
"content": "# Migrating to Cypress V10\n\nCypress v10 introduce new features, like component testing, along with some breaking changes.\n\nBefore continuing, make sure you have all your changes committed and have a clean working tree.\n\nYou can migrate an E2E project to v10 by running the following command:\n\n```shell\nnx g @nrwl/cypress:migrate-to-cypress-10\n```\n\nIn general, these are the steps taken to migrate your project:\n\n1. Migrates your existing `cypress.json` configuration to a new `cypress.config.ts` configuration file.\n - The `pluginsFile` option has been replaced for `setupNodeEvents`. We will import the file and add it to\n the `setupNodeEvents` config option. Double-check your plugins are working correctly.\n2. Rename all test files from `.spec.ts` to `.cy.ts`\n3. Rename the `support/index.ts` to `support/e2e.ts` and update any associated imports\n4. Rename the `integrations` folder to the `e2e` folder\n\n{% callout type=\"caution\" title=\"Root cypress.json\" %}\nKeeping a root `cypress.json` file, will cause issues with [Cypress trying to load the project](https://github.com/nrwl/nx/issues/11512).\nInstead, you can create a [root ts file and import it into each project's cypress config file](https://github.com/nrwl/nx/issues/11512#issuecomment-1213420638) to share values across projects.\n{% /callout %}\n\nWe take the best effort to make this migration seamless, but there can be edge cases we didn't anticipate. So feel free to [open an issue](https://github.com/nrwl/nx/issues/new?assignees=&labels=type%3A+bug&template=1-bug.md) if you come across any problems.\n\nYou can also consult the [official Cypress migration guide](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-version-10-0) if you get stuck and want to manually migrate your projects.\n"
2727
}
2828
],
2929
"generators": [

docs/shared/guides/cypress/cypress-v10-migration.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ In general, these are the steps taken to migrate your project:
1919
3. Rename the `support/index.ts` to `support/e2e.ts` and update any associated imports
2020
4. Rename the `integrations` folder to the `e2e` folder
2121

22+
{% callout type="caution" title="Root cypress.json" %}
23+
Keeping a root `cypress.json` file, will cause issues with [Cypress trying to load the project](https://github.com/nrwl/nx/issues/11512).
24+
Instead, you can create a [root ts file and import it into each project's cypress config file](https://github.com/nrwl/nx/issues/11512#issuecomment-1213420638) to share values across projects.
25+
{% /callout %}
26+
2227
We take the best effort to make this migration seamless, but there can be edge cases we didn't anticipate. So feel free to [open an issue](https://github.com/nrwl/nx/issues/new?assignees=&labels=type%3A+bug&template=1-bug.md) if you come across any problems.
2328

2429
You can also consult the [official Cypress migration guide](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-version-10-0) if you get stuck and want to manually migrate your projects.

packages/cypress/src/generators/migrate-to-cypress-ten/__snapshots__/migrate-to-cypress-ten.spec.ts.snap

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,72 @@ Object {
6767
}
6868
`;
6969

70+
exports[`convertToCypressTen convertCypressProject should handle multiple configurations with no default cypressConfig option 1`] = `
71+
"import { defineConfig } from 'cypress'
72+
import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
73+
74+
75+
const cypressJsonConfig = {
76+
\\"fileServerFolder\\": \\".\\",
77+
\\"fixturesFolder\\": \\"./src/fixtures\\",
78+
\\"video\\": true,
79+
\\"videosFolder\\": \\"../../dist/cypress/apps/app-e2e/videos\\",
80+
\\"screenshotsFolder\\": \\"../../dist/cypress/apps/app-e2e/screenshots\\",
81+
\\"chromeWebSecurity\\": false,
82+
\\"specPattern\\": \\"src/e2e/**/*.cy.{js,jsx,ts,tsx}\\",
83+
\\"supportFile\\": \\"src/support/e2e.ts\\"
84+
}
85+
export default defineConfig({
86+
e2e: {
87+
...nxE2EPreset(__dirname),
88+
...cypressJsonConfig,
89+
90+
}
91+
})"
92+
`;
93+
94+
exports[`convertToCypressTen convertCypressProject should handle multiple configurations with no default cypressConfig option 2`] = `
95+
Object {
96+
"configurations": Object {
97+
"production": Object {
98+
"cypressConfig": "apps/app-e2e/cypress.production.config.ts",
99+
"devServerTarget": "target:serve:production",
100+
},
101+
"static": Object {
102+
"baseUrl": "http://localhost:3000",
103+
"cypressConfig": "apps/app-e2e/cypress.config.ts",
104+
},
105+
},
106+
"executor": "@nrwl/cypress:cypress",
107+
"options": Object {
108+
"baseUrl": "http://localhost:4200",
109+
"testingType": "e2e",
110+
},
111+
}
112+
`;
113+
114+
exports[`convertToCypressTen convertCypressProject should handle sharing the same config across projects 1`] = `
115+
"import { defineConfig } from 'cypress'
116+
import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
117+
118+
119+
const cypressJsonConfig = {
120+
\\"fileServerFolder\\": \\".\\",
121+
\\"fixturesFolder\\": \\"./src/fixtures\\",
122+
\\"video\\": true,
123+
\\"chromeWebSecurity\\": false,
124+
\\"specPattern\\": \\"src/e2e/**/*.cy.{js,jsx,ts,tsx}\\",
125+
\\"supportFile\\": \\"src/support/e2e.ts\\"
126+
}
127+
export default defineConfig({
128+
e2e: {
129+
...nxE2EPreset(__dirname),
130+
...cypressJsonConfig,
131+
132+
}
133+
})"
134+
`;
135+
70136
exports[`convertToCypressTen convertCypressProject should infer targets with --all flag 1`] = `
71137
"import { defineConfig } from 'cypress'
72138
import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';

packages/cypress/src/generators/migrate-to-cypress-ten/conversion.util.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Tree,
77
updateJson,
88
visitNotIgnoredFiles,
9+
normalizePath,
910
} from '@nrwl/devkit';
1011
import { tsquery } from '@phenomnomnominal/tsquery';
1112
import { basename, dirname, extname, relative } from 'path';
@@ -36,15 +37,20 @@ export function findCypressConfigs(
3637
} {
3738
const cypressConfigPathJson =
3839
projectConfig.targets[target]?.configurations?.[config]?.cypressConfig ||
39-
// make sure it's a json file, since it could have been updated to ts file from previous configuration migration
40-
(projectConfig.targets[target]?.options?.cypressConfig.endsWith('json')
41-
? projectConfig.targets[target]?.options?.cypressConfig
42-
: joinPathFragments(projectConfig.root, 'cypress.json'));
40+
projectConfig.targets[target]?.options?.cypressConfig;
41+
42+
// make sure it's a json file, since it could have been updated to ts file from previous configuration migration
43+
if (!cypressConfigPathJson || extname(cypressConfigPathJson) !== '.json') {
44+
return {
45+
cypressConfigPathJson: null,
46+
cypressConfigPathTs: null,
47+
};
48+
}
4349

4450
const cypressConfigPathTs = joinPathFragments(
45-
projectConfig.root,
51+
dirname(cypressConfigPathJson),
4652
// create matching ts config for custom cypress config if present
47-
cypressConfigPathJson.endsWith('cypress.json')
53+
cypressConfigPathJson?.endsWith('cypress.json')
4854
? 'cypress.config.ts' //default
4955
: `${basename(
5056
cypressConfigPathJson,
@@ -230,17 +236,21 @@ export function updateProjectPaths(
230236
// tree.rename doesn't work on directories must update each file within
231237
// the directory to the new directory
232238
visitNotIgnoredFiles(tree, projectConfig.sourceRoot, (path) => {
233-
if (!path.includes(oldIntegrationFolder)) {
239+
const normalizedPath = normalizePath(path);
240+
if (!normalizedPath.includes(oldIntegrationFolder)) {
234241
return;
235242
}
236-
const fileName = basename(path);
237-
let newPath = path.replace(oldIntegrationFolder, newIntegrationFolder);
243+
const fileName = basename(normalizedPath);
244+
let newPath = normalizedPath.replace(
245+
oldIntegrationFolder,
246+
newIntegrationFolder
247+
);
238248

239249
if (fileName.includes('.spec.')) {
240250
newPath = newPath.replace('.spec.', '.cy.');
241251
}
242-
if (newPath !== path && tree.exists(path)) {
243-
tree.rename(path, newPath);
252+
if (newPath !== normalizedPath && tree.exists(normalizedPath)) {
253+
tree.rename(normalizedPath, newPath);
244254
}
245255
// if they weren't using the supportFile then there is no need to update the imports.
246256
if (

packages/cypress/src/generators/migrate-to-cypress-ten/migrate-to-cypress-ten.spec.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,149 @@ describe('convertToCypressTen', () => {
233233
readProjectConfiguration(tree, 'app-e2e').targets['e2e']
234234
).toMatchSnapshot();
235235
});
236+
237+
it('should handle multiple configurations with no default cypressConfig option', async () => {
238+
expect(tree.exists('apps/app-e2e/cypress.json')).toBeTruthy();
239+
tree.write(
240+
'apps/app-e2e/cypress.production.json',
241+
JSON.stringify({
242+
fileServerFolder: '.',
243+
fixturesFolder: './src/fixtures',
244+
integrationFolder: './src/release-integration',
245+
modifyObstructiveCode: false,
246+
pluginsFile: './src/plugins/index',
247+
supportFile: './src/support/index.ts',
248+
video: true,
249+
videosFolder: '../../dist/cypress/apps/client-e2e/videos',
250+
screenshotsFolder: '../../dist/cypress/apps/client-e2e/screenshots',
251+
chromeWebSecurity: false,
252+
})
253+
);
254+
const pc = readProjectConfiguration(tree, 'app-e2e');
255+
pc.targets = {
256+
...pc.targets,
257+
e2e: {
258+
executor: '@nrwl/cypress:cypress',
259+
options: {
260+
baseUrl: 'http://localhost:4200',
261+
},
262+
configurations: {
263+
production: {
264+
cypressConfig: 'apps/app-e2e/cypress.production.json',
265+
devServerTarget: 'target:serve:production',
266+
},
267+
static: {
268+
baseUrl: 'http://localhost:3000',
269+
cypressConfig: 'apps/app-e2e/cypress.json',
270+
},
271+
},
272+
},
273+
};
274+
275+
updateProjectConfiguration(tree, 'app-e2e', pc);
276+
277+
await migrateCypressProject(tree);
278+
279+
expect(tree.exists('apps/app-e2e/cypress.config.ts')).toBeTruthy();
280+
expect(
281+
tree.read('apps/app-e2e/cypress.config.ts', 'utf-8')
282+
).toMatchSnapshot();
283+
expect(readJson(tree, 'apps/app-e2e/tsconfig.json').include).toEqual([
284+
'src/**/*.ts',
285+
'src/**/*.js',
286+
'cypress.production.config.ts',
287+
'cypress.config.ts',
288+
]);
289+
expect(tree.exists('apps/app-e2e/src/e2e/app.cy.ts')).toBeTruthy();
290+
expect(tree.exists('apps/app-e2e/src/support/e2e.ts')).toBeTruthy();
291+
expect(
292+
readProjectConfiguration(tree, 'app-e2e').targets['e2e']
293+
).toMatchSnapshot();
294+
});
295+
296+
it('should handle sharing the same config across projects', async () => {
297+
mockedInstalledCypressVersion.mockReturnValue(9);
298+
addProjectConfiguration(tree, 'app-two', {
299+
root: 'apps/app-two',
300+
sourceRoot: 'apps/app-two/src',
301+
targets: {
302+
serve: {
303+
executor: '@nrwl/web:file-server',
304+
options: {},
305+
},
306+
},
307+
});
308+
309+
await cypressProjectGenerator(tree, {
310+
name: 'app-two-e2e',
311+
skipFormat: true,
312+
project: 'app-two',
313+
});
314+
const appOneProjectConfig = readProjectConfiguration(tree, 'app-e2e');
315+
appOneProjectConfig.targets['e2e'].options.cypressConfig = 'cypress.json';
316+
updateProjectConfiguration(tree, 'app-e2e', appOneProjectConfig);
317+
const appTwoProjectConfig = readProjectConfiguration(tree, 'app-two-e2e');
318+
appTwoProjectConfig.targets['e2e'].options.cypressConfig = 'cypress.json';
319+
updateProjectConfiguration(tree, 'app-two-e2e', appTwoProjectConfig);
320+
321+
tree.write(
322+
'cypress.json',
323+
JSON.stringify({
324+
fileServerFolder: '.',
325+
fixturesFolder: './src/fixtures',
326+
integrationFolder: './src/integration',
327+
modifyObstructiveCode: false,
328+
video: true,
329+
chromeWebSecurity: false,
330+
})
331+
);
332+
333+
await migrateCypressProject(tree);
334+
335+
expect(tree.read('cypress.config.ts', 'utf-8')).toMatchSnapshot();
336+
expect(readJson(tree, 'apps/app-e2e/tsconfig.json').include).toEqual([
337+
'src/**/*.ts',
338+
'src/**/*.js',
339+
'../../cypress.config.ts',
340+
]);
341+
expect(tree.exists('apps/app-e2e/src/e2e/app.cy.ts')).toBeTruthy();
342+
expect(tree.exists('apps/app-e2e/src/support/e2e.ts')).toBeTruthy();
343+
expect(readProjectConfiguration(tree, 'app-e2e').targets['e2e']).toEqual({
344+
executor: '@nrwl/cypress:cypress',
345+
options: {
346+
cypressConfig: 'cypress.config.ts',
347+
devServerTarget: 'app:serve',
348+
testingType: 'e2e',
349+
},
350+
configurations: {
351+
production: {
352+
devServerTarget: 'app:serve:production',
353+
},
354+
},
355+
});
356+
expect(readJson(tree, 'apps/app-two-e2e/tsconfig.json').include).toEqual([
357+
'src/**/*.ts',
358+
'src/**/*.js',
359+
'../../cypress.config.ts',
360+
]);
361+
expect(tree.exists('apps/app-two-e2e/src/e2e/app.cy.ts')).toBeTruthy();
362+
expect(tree.exists('apps/app-two-e2e/src/support/e2e.ts')).toBeTruthy();
363+
expect(
364+
readProjectConfiguration(tree, 'app-two-e2e').targets['e2e']
365+
).toEqual({
366+
executor: '@nrwl/cypress:cypress',
367+
options: {
368+
cypressConfig: 'cypress.config.ts',
369+
devServerTarget: 'app-two:serve',
370+
testingType: 'e2e',
371+
},
372+
configurations: {
373+
production: {
374+
devServerTarget: 'app-two:serve:production',
375+
},
376+
},
377+
});
378+
});
236379
});
237380

238381
describe('updateProjectPaths', () => {

0 commit comments

Comments
 (0)