diff --git a/docs/generated/manifests/nx-api.json b/docs/generated/manifests/nx-api.json index 7d688d4516..c6aa899dce 100644 --- a/docs/generated/manifests/nx-api.json +++ b/docs/generated/manifests/nx-api.json @@ -1312,6 +1312,16 @@ } }, "migrations": { + "/nx-api/cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor": { + "description": "Removes the `tsConfig` and `copyFiles` options from the `@nx/cypress:cypress` executor.", + "file": "generated/packages/cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor.json", + "hidden": false, + "name": "remove-tsconfig-and-copy-files-options-from-cypress-executor", + "version": "21.0.0-beta.10", + "originalFilePath": "/packages/cypress", + "path": "/nx-api/cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor", + "type": "migration" + }, "/nx-api/cypress/migrations/set-inject-document-domain": { "description": "Replaces the `experimentalSkipDomainInjection` configuration option with the new `injectDocumentDomain` configuration option.", "file": "generated/packages/cypress/migrations/set-inject-document-domain.json", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index b2010a5f30..f1b95406f6 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -1304,6 +1304,16 @@ } ], "migrations": [ + { + "description": "Removes the `tsConfig` and `copyFiles` options from the `@nx/cypress:cypress` executor.", + "file": "generated/packages/cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor.json", + "hidden": false, + "name": "remove-tsconfig-and-copy-files-options-from-cypress-executor", + "version": "21.0.0-beta.10", + "originalFilePath": "/packages/cypress", + "path": "cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor", + "type": "migration" + }, { "description": "Replaces the `experimentalSkipDomainInjection` configuration option with the new `injectDocumentDomain` configuration option.", "file": "generated/packages/cypress/migrations/set-inject-document-domain.json", diff --git a/docs/generated/packages/cypress/executors/cypress.json b/docs/generated/packages/cypress/executors/cypress.json index 8bc1894951..06b56cf06b 100644 --- a/docs/generated/packages/cypress/executors/cypress.json +++ b/docs/generated/packages/cypress/executors/cypress.json @@ -31,13 +31,6 @@ "description": "Recompile and run tests when files change.", "default": false }, - "tsConfig": { - "x-deprecated": "This option no longer has any effect. Cypress supports typescript out of the box. Add any options directly to /tsconfig.json or /cypress/tsconfig.json", - "type": "string", - "description": "The path of the Cypress tsconfig configuration json file.", - "x-completion-type": "file", - "x-completion-glob": "tsconfig.*.json" - }, "devServerTarget": { "type": "string", "description": "Dev server target to run tests against." @@ -51,7 +44,7 @@ "type": "boolean", "description": "Hide the browser instead of running headed.", "default": false, - "x-deprecated": "Cypress runs headless by default. Use the --watch flag to control head/headless behavior instead." + "x-deprecated": "Cypress runs headless by default. Use the --watch flag to control head/headless behavior instead. It will be removed in Nx v22." }, "exit": { "type": "boolean", @@ -90,12 +83,6 @@ "type": "string", "description": "A comma delimited glob string that is provided to the Cypress runner to specify which spec files to run. i.e. `**examples/**,**actions.spec**`." }, - "copyFiles": { - "type": "string", - "description": "A regex string that is used to choose what additional integration files to copy to the dist folder.", - "x-deprecated": "No longer used since cypress supports typescript out of the box. If specified, it will be ignored.", - "x-priority": "internal" - }, "ciBuildId": { "oneOf": [{ "type": "string" }, { "type": "number" }], "description": "A unique identifier for a run to enable grouping or parallelization." diff --git a/docs/generated/packages/cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor.json b/docs/generated/packages/cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor.json new file mode 100644 index 0000000000..10b725389e --- /dev/null +++ b/docs/generated/packages/cypress/migrations/remove-tsconfig-and-copy-files-options-from-cypress-executor.json @@ -0,0 +1,12 @@ +{ + "name": "remove-tsconfig-and-copy-files-options-from-cypress-executor", + "version": "21.0.0-beta.10", + "description": "Removes the `tsConfig` and `copyFiles` options from the `@nx/cypress:cypress` executor.", + "implementation": "/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.ts", + "aliases": [], + "hidden": false, + "path": "/packages/cypress", + "schema": null, + "type": "migration", + "examplesFile": "#### Remove `tsConfig` and `copyFiles` Options from Cypress Executor\n\nRemoves the previously deprecated and unused `tsConfig` and `copyFiles` options from the `@nx/cypress:cypress` executor configuration in all projects.\n\n#### Examples\n\nRemove the options from the project configuration:\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"apps/app1-e2e/project.json\" highlightLines=[7,8] %}\n{\n \"targets\": {\n \"e2e\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app1-e2e/cypress.config.ts\",\n \"tsConfig\": \"apps/app1-e2e/tsconfig.json\",\n \"copyFiles\": \"**/*.spec.ts\",\n \"devServerTarget\": \"app1:serve\"\n }\n }\n }\n}\n```\n\n{% /tab %}\n\n{% tab label=\"After\" %}\n\n```json {% fileName=\"apps/app1-e2e/project.json\" %}\n{\n \"targets\": {\n \"e2e\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app1-e2e/cypress.config.ts\",\n \"devServerTarget\": \"app1:serve\"\n }\n }\n }\n}\n```\n\n{% /tab %}\n{% /tabs %}\n\nRemove the options from a target default using the `@nx/cypress:cypress` executor:\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" highlightLines=[7,8] %}\n{\n \"targetDefaults\": {\n \"e2e\": {\n \"cache\": true,\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"tsConfig\": \"{projectRoot}/tsconfig.json\",\n \"copyFiles\": \"**/*.spec.ts\"\n }\n }\n }\n}\n```\n\n{% /tab %}\n\n{% tab label=\"After\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"targetDefaults\": {\n \"e2e\": {\n \"cache\": true,\n \"executor\": \"@nx/cypress:cypress\"\n }\n }\n}\n```\n\n{% /tab %}\n{% /tabs %}\n\nRemove the options from a target default using the `@nx/cypress:cypress` executor as the key:\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" highlightLines=[6,7] %}\n{\n \"targetDefaults\": {\n \"@nx/cypress:cypress\": {\n \"cache\": true,\n \"options\": {\n \"tsConfig\": \"{projectRoot}/tsconfig.json\",\n \"copyFiles\": \"**/*.spec.ts\"\n }\n }\n }\n}\n```\n\n{% /tab %}\n\n{% tab label=\"After\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"targetDefaults\": {\n \"@nx/cypress:cypress\": {\n \"cache\": true\n }\n }\n}\n```\n\n{% /tab %}\n{% /tabs %}\n" +} diff --git a/packages/cypress/migrations.json b/packages/cypress/migrations.json index 3cbde522ea..7af5ed282e 100644 --- a/packages/cypress/migrations.json +++ b/packages/cypress/migrations.json @@ -41,6 +41,11 @@ }, "description": "Updates the module specifier for the Component Testing `mount` function.", "implementation": "./src/migrations/update-20-8-0/update-component-testing-mount-imports" + }, + "remove-tsconfig-and-copy-files-options-from-cypress-executor": { + "version": "21.0.0-beta.10", + "description": "Removes the `tsConfig` and `copyFiles` options from the `@nx/cypress:cypress` executor.", + "implementation": "./src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor" } }, "packageJsonUpdates": { diff --git a/packages/cypress/src/executors/cypress/cypress.impl.spec.ts b/packages/cypress/src/executors/cypress/cypress.impl.spec.ts index a76f092fa9..6f9a40ca66 100644 --- a/packages/cypress/src/executors/cypress/cypress.impl.spec.ts +++ b/packages/cypress/src/executors/cypress/cypress.impl.spec.ts @@ -22,7 +22,6 @@ describe('Cypress builder', () => { const cypressOptions: CypressExecutorOptions = { cypressConfig: 'apps/my-app-e2e/cypress.json', parallel: false, - tsConfig: 'apps/my-app-e2e/tsconfig.json', devServerTarget: 'my-app:serve', exit: true, record: false, @@ -270,7 +269,6 @@ A generator to migrate from v8 to v10 is provided. See https://nx.dev/cypress/v1 const { success } = await cypressExecutor( { cypressConfig: 'apps/my-app-e2e/cypress.json', - tsConfig: 'apps/my-app-e2e/tsconfig.json', devServerTarget: undefined, headless: true, exit: true, diff --git a/packages/cypress/src/executors/cypress/cypress.impl.ts b/packages/cypress/src/executors/cypress/cypress.impl.ts index c9bf9ab086..7a37361d8b 100644 --- a/packages/cypress/src/executors/cypress/cypress.impl.ts +++ b/packages/cypress/src/executors/cypress/cypress.impl.ts @@ -15,7 +15,8 @@ export interface CypressExecutorOptions extends Json { devServerTarget?: string; headed?: boolean; /** - * @deprecated use watch instead + * @deprecated Cypress runs headless by default. Use the --watch flag to + * control head/headless behavior instead. It will be removed in Nx v22. **/ headless?: boolean; exit?: boolean; @@ -26,10 +27,6 @@ export interface CypressExecutorOptions extends Json { browser?: string; env?: Record; spec?: string; - /** - * @deprecated no longer used since cypress supports typescript out of the box - **/ - copyFiles?: string; ciBuildId?: string | number; group?: string; ignoreTestFiles?: string | string[]; diff --git a/packages/cypress/src/executors/cypress/schema.json b/packages/cypress/src/executors/cypress/schema.json index c0e11b179a..d8c8fb9d4d 100644 --- a/packages/cypress/src/executors/cypress/schema.json +++ b/packages/cypress/src/executors/cypress/schema.json @@ -31,13 +31,6 @@ "description": "Recompile and run tests when files change.", "default": false }, - "tsConfig": { - "x-deprecated": "This option no longer has any effect. Cypress supports typescript out of the box. Add any options directly to /tsconfig.json or /cypress/tsconfig.json", - "type": "string", - "description": "The path of the Cypress tsconfig configuration json file.", - "x-completion-type": "file", - "x-completion-glob": "tsconfig.*.json" - }, "devServerTarget": { "type": "string", "description": "Dev server target to run tests against." @@ -51,7 +44,7 @@ "type": "boolean", "description": "Hide the browser instead of running headed.", "default": false, - "x-deprecated": "Cypress runs headless by default. Use the --watch flag to control head/headless behavior instead." + "x-deprecated": "Cypress runs headless by default. Use the --watch flag to control head/headless behavior instead. It will be removed in Nx v22." }, "exit": { "type": "boolean", @@ -90,12 +83,6 @@ "type": "string", "description": "A comma delimited glob string that is provided to the Cypress runner to specify which spec files to run. i.e. `**examples/**,**actions.spec**`." }, - "copyFiles": { - "type": "string", - "description": "A regex string that is used to choose what additional integration files to copy to the dist folder.", - "x-deprecated": "No longer used since cypress supports typescript out of the box. If specified, it will be ignored.", - "x-priority": "internal" - }, "ciBuildId": { "oneOf": [ { diff --git a/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.md b/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.md new file mode 100644 index 0000000000..8453ce90a4 --- /dev/null +++ b/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.md @@ -0,0 +1,121 @@ +#### Remove `tsConfig` and `copyFiles` Options from Cypress Executor + +Removes the previously deprecated and unused `tsConfig` and `copyFiles` options from the `@nx/cypress:cypress` executor configuration in all projects. + +#### Examples + +Remove the options from the project configuration: + +{% tabs %} +{% tab label="Before" %} + +```json {% fileName="apps/app1-e2e/project.json" highlightLines=[7,8] %} +{ + "targets": { + "e2e": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/app1-e2e/cypress.config.ts", + "tsConfig": "apps/app1-e2e/tsconfig.json", + "copyFiles": "**/*.spec.ts", + "devServerTarget": "app1:serve" + } + } + } +} +``` + +{% /tab %} + +{% tab label="After" %} + +```json {% fileName="apps/app1-e2e/project.json" %} +{ + "targets": { + "e2e": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/app1-e2e/cypress.config.ts", + "devServerTarget": "app1:serve" + } + } + } +} +``` + +{% /tab %} +{% /tabs %} + +Remove the options from a target default using the `@nx/cypress:cypress` executor: + +{% tabs %} +{% tab label="Before" %} + +```json {% fileName="nx.json" highlightLines=[7,8] %} +{ + "targetDefaults": { + "e2e": { + "cache": true, + "executor": "@nx/cypress:cypress", + "options": { + "tsConfig": "{projectRoot}/tsconfig.json", + "copyFiles": "**/*.spec.ts" + } + } + } +} +``` + +{% /tab %} + +{% tab label="After" %} + +```json {% fileName="nx.json" %} +{ + "targetDefaults": { + "e2e": { + "cache": true, + "executor": "@nx/cypress:cypress" + } + } +} +``` + +{% /tab %} +{% /tabs %} + +Remove the options from a target default using the `@nx/cypress:cypress` executor as the key: + +{% tabs %} +{% tab label="Before" %} + +```json {% fileName="nx.json" highlightLines=[6,7] %} +{ + "targetDefaults": { + "@nx/cypress:cypress": { + "cache": true, + "options": { + "tsConfig": "{projectRoot}/tsconfig.json", + "copyFiles": "**/*.spec.ts" + } + } + } +} +``` + +{% /tab %} + +{% tab label="After" %} + +```json {% fileName="nx.json" %} +{ + "targetDefaults": { + "@nx/cypress:cypress": { + "cache": true + } + } +} +``` + +{% /tab %} +{% /tabs %} diff --git a/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.spec.ts b/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.spec.ts new file mode 100644 index 0000000000..5c7f18fd77 --- /dev/null +++ b/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.spec.ts @@ -0,0 +1,326 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + +import { + addProjectConfiguration, + readJson, + readProjectConfiguration, + updateJson, + type NxJsonConfiguration, + type ProjectConfiguration, + type Tree, +} from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import migration from './remove-tsconfig-and-copy-files-options-from-cypress-executor'; + +describe('remove-tsconfig-and-copy-files-options-from-cypress-executor', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + }); + + it('should remove tsConfig and copyFiles from default options', async () => { + const projectConfig: ProjectConfiguration = { + root: 'apps/app1-e2e', + sourceRoot: 'apps/app1-e2e/src', + projectType: 'application', + targets: { + e2e: { + executor: '@nx/cypress:cypress', + options: { + cypressConfig: 'apps/app1-e2e/cypress.config.ts', + tsConfig: 'apps/app1-e2e/tsconfig.json', + copyFiles: '**/*.spec.ts', + devServerTarget: 'app1:serve', + }, + }, + }, + }; + addProjectConfiguration(tree, 'app1-e2e', projectConfig); + + await migration(tree); + + const updatedConfig = readProjectConfiguration(tree, 'app1-e2e'); + expect(updatedConfig.targets.e2e.options).toEqual({ + cypressConfig: 'apps/app1-e2e/cypress.config.ts', + devServerTarget: 'app1:serve', + }); + expect('tsConfig' in updatedConfig.targets.e2e.options).toEqual(false); + expect('copyFiles' in updatedConfig.targets.e2e.options).toEqual(false); + }); + + it('should remove tsConfig and copyFiles from configurations', async () => { + const projectConfig: ProjectConfiguration = { + root: 'apps/app1-e2e', + sourceRoot: 'apps/app1-e2e/src', + projectType: 'application', + targets: { + e2e: { + executor: '@nx/cypress:cypress', + options: { + cypressConfig: 'apps/app1-e2e/cypress.config.ts', + devServerTarget: 'app1:serve', + }, + configurations: { + production: { + devServerTarget: 'app1:serve:production', + tsConfig: 'apps/app1-e2e/tsconfig.prod.json', + copyFiles: '**/*.prod.spec.ts', + }, + }, + }, + }, + }; + addProjectConfiguration(tree, 'app1-e2e', projectConfig); + + await migration(tree); + + const updatedConfig = readProjectConfiguration(tree, 'app1-e2e'); + expect(updatedConfig.targets.e2e.configurations.production).toEqual({ + devServerTarget: 'app1:serve:production', + }); + expect( + 'tsConfig' in updatedConfig.targets.e2e.configurations.production + ).toEqual(false); + expect( + 'copyFiles' in updatedConfig.targets.e2e.configurations.production + ).toEqual(false); + }); + + it('should handle projects without the deprecated options', async () => { + const projectConfig: ProjectConfiguration = { + root: 'apps/app2-e2e', + sourceRoot: 'apps/app2-e2e/src', + projectType: 'application', + targets: { + e2e: { + executor: '@nx/cypress:cypress', + options: { + cypressConfig: 'apps/app2-e2e/cypress.config.ts', + devServerTarget: 'app2:serve', + }, + }, + }, + }; + addProjectConfiguration(tree, 'app2-e2e', projectConfig); + + await migration(tree); + + const updatedConfig = readProjectConfiguration(tree, 'app2-e2e'); + expect(updatedConfig.targets.e2e.options).toEqual({ + cypressConfig: 'apps/app2-e2e/cypress.config.ts', + devServerTarget: 'app2:serve', + }); + }); + + it('should handle projects with multiple targets using cypress executor', async () => { + const projectConfig: ProjectConfiguration = { + root: 'apps/app3-e2e', + sourceRoot: 'apps/app3-e2e/src', + projectType: 'application', + targets: { + e2e: { + executor: '@nx/cypress:cypress', + options: { + cypressConfig: 'apps/app3-e2e/cypress.config.ts', + tsConfig: 'apps/app3-e2e/tsconfig.json', + devServerTarget: 'app3:serve', + }, + }, + ct: { + executor: '@nx/cypress:cypress', + options: { + cypressConfig: 'apps/app3-e2e/cypress.config.ts', + copyFiles: '**/*.ct.spec.ts', + devServerTarget: 'app3:serve-ct', + testingType: 'component', + }, + }, + }, + }; + addProjectConfiguration(tree, 'app3-e2e', projectConfig); + + await migration(tree); + + const updatedConfig = readProjectConfiguration(tree, 'app3-e2e'); + expect(updatedConfig.targets.e2e.options).toEqual({ + cypressConfig: 'apps/app3-e2e/cypress.config.ts', + devServerTarget: 'app3:serve', + }); + expect(updatedConfig.targets.ct.options).toEqual({ + cypressConfig: 'apps/app3-e2e/cypress.config.ts', + devServerTarget: 'app3:serve-ct', + testingType: 'component', + }); + }); + + it('should remove tsConfig and copyFiles options in nx.json target defaults for a target with the cypress executor', async () => { + updateJson(tree, 'nx.json', (json) => { + json.targetDefaults ??= {}; + json.targetDefaults.e2e = { + executor: '@nx/cypress:cypress', + options: { + cypressConfig: '{projectRoot}/cypress.config.ts', + tsConfig: '{projectRoot}/tsconfig.json', + copyFiles: '**/*.spec.ts', + devServerTarget: '{projectName}:serve', + }, + configurations: { + production: { + devServerTarget: '{projectName}:serve:production', + tsConfig: '{projectRoot}/tsconfig.prod.json', + copyFiles: '**/*.prod.spec.ts', + }, + }, + }; + return json; + }); + + await migration(tree); + + const nxJson = readJson(tree, 'nx.json'); + expect(nxJson.targetDefaults.e2e.options).toStrictEqual({ + cypressConfig: '{projectRoot}/cypress.config.ts', + devServerTarget: '{projectName}:serve', + }); + expect(nxJson.targetDefaults.e2e.options.tsConfig).toBeUndefined(); + expect(nxJson.targetDefaults.e2e.options.copyFiles).toBeUndefined(); + expect(nxJson.targetDefaults.e2e.configurations.production).toStrictEqual({ + devServerTarget: '{projectName}:serve:production', + }); + expect( + nxJson.targetDefaults.e2e.configurations.production.tsConfig + ).toBeUndefined(); + expect( + nxJson.targetDefaults.e2e.configurations.production.copyFiles + ).toBeUndefined(); + }); + + it('should remove tsConfig and copyFiles options in nx.json target defaults for the cypress executor', async () => { + updateJson(tree, 'nx.json', (json) => { + json.targetDefaults ??= {}; + json.targetDefaults['@nx/cypress:cypress'] = { + options: { + cypressConfig: '{projectRoot}/cypress.config.ts', + tsConfig: '{projectRoot}/tsconfig.json', + copyFiles: '**/*.spec.ts', + devServerTarget: '{projectName}:serve', + }, + configurations: { + production: { + devServerTarget: '{projectName}:serve:production', + tsConfig: '{projectRoot}/tsconfig.prod.json', + copyFiles: '**/*.prod.spec.ts', + }, + }, + }; + return json; + }); + + await migration(tree); + + const nxJson = readJson(tree, 'nx.json'); + expect(nxJson.targetDefaults['@nx/cypress:cypress'].options).toStrictEqual({ + cypressConfig: '{projectRoot}/cypress.config.ts', + devServerTarget: '{projectName}:serve', + }); + expect( + nxJson.targetDefaults['@nx/cypress:cypress'].options.tsConfig + ).toBeUndefined(); + expect( + nxJson.targetDefaults['@nx/cypress:cypress'].options.copyFiles + ).toBeUndefined(); + expect( + nxJson.targetDefaults['@nx/cypress:cypress'].configurations.production + ).toStrictEqual({ + devServerTarget: '{projectName}:serve:production', + }); + expect( + nxJson.targetDefaults['@nx/cypress:cypress'].configurations.production + .tsConfig + ).toBeUndefined(); + expect( + nxJson.targetDefaults['@nx/cypress:cypress'].configurations.production + .copyFiles + ).toBeUndefined(); + }); + + it('should remove empty options and configurations objects from project configuration', async () => { + const projectConfig: ProjectConfiguration = { + root: 'apps/app4-e2e', + sourceRoot: 'apps/app4-e2e/src', + projectType: 'application', + targets: { + e2e: { + executor: '@nx/cypress:cypress', + options: { + tsConfig: 'apps/app4-e2e/tsconfig.json', + copyFiles: '**/*.spec.ts', + }, + configurations: { + production: { + tsConfig: 'apps/app4-e2e/tsconfig.prod.json', + copyFiles: '**/*.prod.spec.ts', + }, + }, + }, + }, + }; + addProjectConfiguration(tree, 'app4-e2e', projectConfig); + + await migration(tree); + + const updatedConfig = readProjectConfiguration(tree, 'app4-e2e'); + expect(updatedConfig.targets.e2e.options).toBeUndefined(); + expect(updatedConfig.targets.e2e.configurations).toBeUndefined(); + }); + + it('should remove empty targetDefault object from nx.json when using a target name as the key', async () => { + updateJson(tree, 'nx.json', (json) => { + json.targetDefaults = {}; + json.targetDefaults.e2e = { + executor: '@nx/cypress:cypress', + options: { + tsConfig: '{projectRoot}/tsconfig.json', + copyFiles: '**/*.spec.ts', + }, + configurations: { + production: { + tsConfig: '{projectRoot}/tsconfig.prod.json', + copyFiles: '**/*.prod.spec.ts', + }, + }, + }; + return json; + }); + + await migration(tree); + + const nxJson = readJson(tree, 'nx.json'); + expect(nxJson.targetDefaults).toBeUndefined(); + }); + + it('should remove empty targetDefault object from nx.json when using the cypress executor as the key', async () => { + updateJson(tree, 'nx.json', (json) => { + json.targetDefaults = {}; + json.targetDefaults['@nx/cypress:cypress'] = { + options: { + tsConfig: '{projectRoot}/tsconfig.json', + copyFiles: '**/*.spec.ts', + }, + configurations: { + production: { + tsConfig: '{projectRoot}/tsconfig.prod.json', + copyFiles: '**/*.prod.spec.ts', + }, + }, + }; + return json; + }); + + await migration(tree); + + const nxJson = readJson(tree, 'nx.json'); + expect(nxJson.targetDefaults).toBeUndefined(); + }); +}); diff --git a/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.ts b/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.ts new file mode 100644 index 0000000000..a48e2454cf --- /dev/null +++ b/packages/cypress/src/migrations/update-21-0-0/remove-tsconfig-and-copy-files-options-from-cypress-executor.ts @@ -0,0 +1,105 @@ +import { + formatFiles, + type ProjectConfiguration, + readNxJson, + readProjectConfiguration, + type TargetConfiguration, + type Tree, + updateNxJson, + updateProjectConfiguration, +} from '@nx/devkit'; +import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; +import type { CypressExecutorOptions } from '../../executors/cypress/cypress.impl'; + +const EXECUTOR_TO_MIGRATE = '@nx/cypress:cypress'; + +export default async function (tree: Tree) { + // update options from project configs + forEachExecutorOptions( + tree, + EXECUTOR_TO_MIGRATE, + (options, project, target, configuration) => { + if (options.tsConfig === undefined && options.copyFiles === undefined) { + return; + } + + const projectConfiguration = readProjectConfiguration(tree, project); + if (configuration) { + updateConfiguration( + projectConfiguration.targets[target], + configuration + ); + } else { + updateOptions(projectConfiguration.targets[target]); + } + + updateProjectConfiguration(tree, project, projectConfiguration); + } + ); + + // update options from nx.json target defaults + const nxJson = readNxJson(tree); + if (nxJson.targetDefaults) { + for (const [targetOrExecutor, targetConfig] of Object.entries( + nxJson.targetDefaults + )) { + if ( + targetOrExecutor !== EXECUTOR_TO_MIGRATE && + targetConfig.executor !== EXECUTOR_TO_MIGRATE + ) { + continue; + } + + if (targetConfig.options) { + updateOptions(targetConfig); + } + + Object.keys(targetConfig.configurations ?? {}).forEach((config) => { + updateConfiguration(targetConfig, config); + }); + + if ( + !Object.keys(targetConfig).length || + (Object.keys(targetConfig).length === 1 && + Object.keys(targetConfig)[0] === 'executor') + ) { + delete nxJson.targetDefaults[targetOrExecutor]; + } + + if (!Object.keys(nxJson.targetDefaults).length) { + delete nxJson.targetDefaults; + } + } + + updateNxJson(tree, nxJson); + } + + await formatFiles(tree); +} + +function updateOptions(target: TargetConfiguration) { + delete target.options.tsConfig; + delete target.options.copyFiles; + + if (!Object.keys(target.options).length) { + delete target.options; + } +} + +function updateConfiguration( + target: TargetConfiguration, + configuration: string +) { + delete target.configurations[configuration].tsConfig; + delete target.configurations[configuration].copyFiles; + if ( + !Object.keys(target.configurations[configuration]).length && + (!target.defaultConfiguration || + target.defaultConfiguration !== configuration) + ) { + delete target.configurations[configuration]; + } + if (!Object.keys(target.configurations).length) { + delete target.configurations; + } +}