diff --git a/docs/generated/packages/cypress/generators/component-configuration.json b/docs/generated/packages/cypress/generators/component-configuration.json index 6fc62deecec01..2beddcaacbc1f 100644 --- a/docs/generated/packages/cypress/generators/component-configuration.json +++ b/docs/generated/packages/cypress/generators/component-configuration.json @@ -33,6 +33,11 @@ "type": "string", "description": "A directory where the project is placed relative from the project root", "default": "cypress" + }, + "jsx": { + "description": "Whether or not this project uses JSX.", + "type": "boolean", + "default": true } }, "required": ["project"], diff --git a/docs/generated/packages/cypress/generators/configuration.json b/docs/generated/packages/cypress/generators/configuration.json index d9b209b8a9398..b9ae6fbe475ba 100644 --- a/docs/generated/packages/cypress/generators/configuration.json +++ b/docs/generated/packages/cypress/generators/configuration.json @@ -81,6 +81,11 @@ "enum": ["vite", "webpack", "none"], "x-prompt": "Which Cypress bundler do you want to use?", "default": "webpack" + }, + "jsx": { + "description": "Whether or not this project uses JSX.", + "type": "boolean", + "default": true } }, "required": ["project"], diff --git a/docs/generated/packages/cypress/generators/cypress-project.json b/docs/generated/packages/cypress/generators/cypress-project.json index f242c0f036ef4..e5ae6e71b9724 100644 --- a/docs/generated/packages/cypress/generators/cypress-project.json +++ b/docs/generated/packages/cypress/generators/cypress-project.json @@ -57,12 +57,6 @@ "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.", "default": false }, - "standaloneConfig": { - "description": "Split the project configuration into `/project.json` rather than including it inside workspace.json.", - "type": "boolean", - "default": true, - "x-deprecated": "Nx only supports standaloneConfig" - }, "skipPackageJson": { "type": "boolean", "default": false, diff --git a/docs/generated/packages/storybook/generators/cypress-project.json b/docs/generated/packages/storybook/generators/cypress-project.json index 11cebcf71df2e..9235f914e044c 100644 --- a/docs/generated/packages/storybook/generators/cypress-project.json +++ b/docs/generated/packages/storybook/generators/cypress-project.json @@ -33,12 +33,6 @@ "enum": ["eslint", "none"], "default": "eslint" }, - "standaloneConfig": { - "description": "Split the project configuration into `/project.json` rather than including it inside `workspace.json`.", - "type": "boolean", - "default": true, - "x-deprecated": "Nx only supports standaloneConfig" - }, "ciTargetName": { "type": "string", "description": "The name of the devServerTarget to use for the Cypress CI configuration. Used to control if using :static-storybook:ci or :storybook:ci", @@ -49,6 +43,11 @@ "type": "boolean", "default": false, "x-priority": "internal" + }, + "projectNameAndRootFormat": { + "description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).", + "type": "string", + "enum": ["as-provided", "derived"] } }, "required": ["name"], diff --git a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap index f0bf73bb2bbb0..ca8234587f71e 100644 --- a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap +++ b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap @@ -369,6 +369,7 @@ exports[`app --project-name-and-root-format=derived should generate correctly wh "compilerOptions": { "allowJs": true, "forceConsistentCasingInFileNames": true, + "module": "commonjs", "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, @@ -383,9 +384,12 @@ exports[`app --project-name-and-root-format=derived should generate correctly wh }, "extends": "../../../tsconfig.base.json", "include": [ - "src/**/*.ts", - "src/**/*.js", + "**/*.ts", + "**/*.js", "cypress.config.ts", + "**/*.cy.ts", + "**/*.cy.js", + "**/*.d.ts", ], } `; @@ -609,6 +613,7 @@ exports[`app --project-name-and-root-format=derived should generate correctly wh "compilerOptions": { "allowJs": true, "forceConsistentCasingInFileNames": true, + "module": "commonjs", "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, @@ -623,9 +628,12 @@ exports[`app --project-name-and-root-format=derived should generate correctly wh }, "extends": "../../tsconfig.base.json", "include": [ - "src/**/*.ts", - "src/**/*.js", + "**/*.ts", + "**/*.js", "cypress.config.ts", + "**/*.cy.ts", + "**/*.cy.js", + "**/*.d.ts", ], } `; @@ -874,6 +882,7 @@ exports[`app --strict should enable strict type checking: e2e tsconfig.json 1`] "compilerOptions": { "allowJs": true, "forceConsistentCasingInFileNames": true, + "module": "commonjs", "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, @@ -888,9 +897,12 @@ exports[`app --strict should enable strict type checking: e2e tsconfig.json 1`] }, "extends": "../tsconfig.base.json", "include": [ - "src/**/*.ts", - "src/**/*.js", + "**/*.ts", + "**/*.js", "cypress.config.ts", + "**/*.cy.ts", + "**/*.cy.js", + "**/*.d.ts", ], } `; @@ -1218,6 +1230,7 @@ exports[`app not nested should generate files: e2e tsconfig.json 1`] = ` "compilerOptions": { "allowJs": true, "forceConsistentCasingInFileNames": true, + "module": "commonjs", "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, @@ -1232,9 +1245,12 @@ exports[`app not nested should generate files: e2e tsconfig.json 1`] = ` }, "extends": "../tsconfig.base.json", "include": [ - "src/**/*.ts", - "src/**/*.js", + "**/*.ts", + "**/*.js", "cypress.config.ts", + "**/*.cy.ts", + "**/*.cy.js", + "**/*.d.ts", ], } `; diff --git a/packages/angular/src/generators/application/lib/add-e2e.ts b/packages/angular/src/generators/application/lib/add-e2e.ts index d8ddb27a991ad..545158e80ad89 100644 --- a/packages/angular/src/generators/application/lib/add-e2e.ts +++ b/packages/angular/src/generators/application/lib/add-e2e.ts @@ -10,23 +10,27 @@ import { } from '@nx/devkit'; import { nxVersion } from '../../../utils/versions'; import type { NormalizedSchema } from './normalized-schema'; -import { cypressProjectGenerator } from '@nx/cypress'; +import { configurationGenerator } from '@nx/cypress'; export async function addE2e(tree: Tree, options: NormalizedSchema) { if (options.e2eTestRunner === 'cypress') { // TODO: This can call `@nx/web:static-config` generator when ready addFileServerTarget(tree, options, 'serve-static'); - - await cypressProjectGenerator(tree, { - name: options.e2eProjectName, - directory: options.e2eProjectRoot, - // the name and root are already normalized, instruct the generator to use them as is - projectNameAndRootFormat: 'as-provided', - project: options.name, + addProjectConfiguration(tree, options.e2eProjectName, { + projectType: 'application', + root: options.e2eProjectRoot, + sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), + targets: {}, + tags: [], + implicitDependencies: [options.name], + }); + await configurationGenerator(tree, { + project: options.e2eProjectName, + directory: 'src', linter: options.linter, - standaloneConfig: options.standaloneConfig, skipPackageJson: options.skipPackageJson, skipFormat: true, + devServerTarget: `${options.name}:serve:development`, }); } else if (options.e2eTestRunner === 'playwright') { const { configurationGenerator: playwrightConfigurationGenerator } = @@ -35,6 +39,7 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) { nxVersion ); addProjectConfiguration(tree, options.e2eProjectName, { + projectType: 'application', root: options.e2eProjectRoot, sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), targets: {}, diff --git a/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts b/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts index 050cebf1e423f..8ab0c77dc39b5 100644 --- a/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts +++ b/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts @@ -13,7 +13,7 @@ import { librarySecondaryEntryPointGenerator } from '../library-secondary-entry- import { generateTestApplication, generateTestLibrary } from '../utils/testing'; import { cypressComponentConfiguration } from './cypress-component-configuration'; -let projectGraph: ProjectGraph; +let projectGraph: ProjectGraph = { nodes: {}, dependencies: {} }; jest.mock('@nx/cypress/src/utils/cypress-version'); jest.mock('@nx/devkit', () => ({ ...jest.requireActual('@nx/devkit'), diff --git a/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts b/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts index c180bb46dab47..6ad2306ab514c 100644 --- a/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts +++ b/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts @@ -337,11 +337,11 @@ export class E2eMigrator extends ProjectMigrator { private async migrateCypressE2eProject(): Promise { const oldCypressConfigFilePath = this.getOldCypressConfigFilePath(); + // TODO(v18): This needs to be removed before v18 since the generator is going away. await cypressProjectGenerator(this.tree, { name: this.project.name, project: this.appName, linter: this.isProjectUsingEsLint ? Linter.EsLint : Linter.None, - standaloneConfig: true, skipFormat: true, }); diff --git a/packages/cypress/index.ts b/packages/cypress/index.ts index b24b600a846f1..25e308c012ada 100644 --- a/packages/cypress/index.ts +++ b/packages/cypress/index.ts @@ -1,12 +1,17 @@ import { configurationGenerator } from './src/generators/configuration/configuration'; import { componentConfigurationGenerator } from './src/generators/component-configuration/component-configuration'; +import { cypressProjectGenerator as _cypressProjectGenerator } from './src/generators/cypress-project/cypress-project'; + export { configurationGenerator, componentConfigurationGenerator }; // Maintain backwards compatibility with the old names in case community plugins used them. -/** @deprecated Use `configurationGenerator` instead. */ +// TODO(v18): Remove old name +/** @deprecated Use `configurationGenerator` instead. It will be removed in Nx 18. */ export const cypressComponentConfiguration = componentConfigurationGenerator; export { configurationGenerator as cypressE2EConfigurationGenerator }; -export { cypressProjectGenerator } from './src/generators/cypress-project/cypress-project'; +// TODO(v18): Remove project generator +/** @deprecated Add a new project and call `configurationGenerator` instead. It will be removed in Nx 18. */ +export const cypressProjectGenerator = _cypressProjectGenerator; export { cypressInitGenerator } from './src/generators/init/init'; export { migrateCypressProject } from './src/generators/migrate-to-cypress-11/migrate-to-cypress-11'; diff --git a/packages/cypress/src/generators/base-setup/base-setup.ts b/packages/cypress/src/generators/base-setup/base-setup.ts index bd0b95f70ec5a..545844875365c 100644 --- a/packages/cypress/src/generators/base-setup/base-setup.ts +++ b/packages/cypress/src/generators/base-setup/base-setup.ts @@ -17,6 +17,7 @@ export interface CypressBaseSetupSchema { * default is `cypress` * */ directory?: string; + jsx?: boolean; } export function addBaseCypressSetup( @@ -33,6 +34,7 @@ export function addBaseCypressSetup( generateFiles(tree, join(__dirname, 'files'), projectConfig.root, { ...opts, + jsx: !!opts.jsx, offsetFromRoot: offsetFromRoot(projectConfig.root), offsetFromProjectRoot: opts.hasTsConfig ? opts.offsetFromProjectRoot : '', tsConfigPath: opts.hasTsConfig diff --git a/packages/cypress/src/generators/base-setup/files/__directory__/tsconfig.json b/packages/cypress/src/generators/base-setup/files/__directory__/tsconfig.json__ext__ similarity index 76% rename from packages/cypress/src/generators/base-setup/files/__directory__/tsconfig.json rename to packages/cypress/src/generators/base-setup/files/__directory__/tsconfig.json__ext__ index c07c6593913bc..eb50c8dd4140a 100644 --- a/packages/cypress/src/generators/base-setup/files/__directory__/tsconfig.json +++ b/packages/cypress/src/generators/base-setup/files/__directory__/tsconfig.json__ext__ @@ -12,9 +12,9 @@ "**/*.js", "<%= offsetFromProjectRoot %>cypress.config.ts", "<%= offsetFromProjectRoot %>**/*.cy.ts", - "<%= offsetFromProjectRoot %>**/*.cy.tsx", + <% if (jsx) { %> "<%= offsetFromProjectRoot %>**/*.cy.tsx",<% } %> "<%= offsetFromProjectRoot %>**/*.cy.js", - "<%= offsetFromProjectRoot %>**/*.cy.jsx", + <% if (jsx) { %>"<%= offsetFromProjectRoot %>**/*.cy.jsx",<% } %> "<%= offsetFromProjectRoot %>**/*.d.ts" ] } diff --git a/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts b/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts index 1934a657d7bb6..da062d1dd58a4 100644 --- a/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts +++ b/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts @@ -100,6 +100,7 @@ describe('Cypress Component Configuration', () => { await componentConfigurationGenerator(tree, { project: 'cool-lib', skipFormat: false, + jsx: true, }); const projectConfig = readProjectConfiguration(tree, 'cool-lib'); expect(tree.exists('libs/cool-lib/cypress.config.ts')).toEqual(true); diff --git a/packages/cypress/src/generators/component-configuration/component-configuration.ts b/packages/cypress/src/generators/component-configuration/component-configuration.ts index b8187b649c2e0..ad1a65da4fb8e 100644 --- a/packages/cypress/src/generators/component-configuration/component-configuration.ts +++ b/packages/cypress/src/generators/component-configuration/component-configuration.ts @@ -85,6 +85,7 @@ function addProjectFiles( addBaseCypressSetup(tree, { project: opts.project, directory: opts.directory, + jsx: opts.jsx, }); generateFiles( diff --git a/packages/cypress/src/generators/component-configuration/schema.d.ts b/packages/cypress/src/generators/component-configuration/schema.d.ts index bd8ea6198ade7..4b2e26ce4275e 100644 --- a/packages/cypress/src/generators/component-configuration/schema.d.ts +++ b/packages/cypress/src/generators/component-configuration/schema.d.ts @@ -3,4 +3,5 @@ export interface CypressComponentConfigurationSchema { skipFormat: boolean; directory?: string; bundler?: 'webpack' | 'vite'; + jsx?: boolean; } diff --git a/packages/cypress/src/generators/component-configuration/schema.json b/packages/cypress/src/generators/component-configuration/schema.json index a34fbc9d8cbd0..d7ac0b043ed81 100644 --- a/packages/cypress/src/generators/component-configuration/schema.json +++ b/packages/cypress/src/generators/component-configuration/schema.json @@ -31,6 +31,11 @@ "type": "string", "description": "A directory where the project is placed relative from the project root", "default": "cypress" + }, + "jsx": { + "description": "Whether or not this project uses JSX.", + "type": "boolean", + "default": true } }, "required": ["project"], diff --git a/packages/cypress/src/generators/configuration/configuration.spec.ts b/packages/cypress/src/generators/configuration/configuration.spec.ts index 68c0ed93813eb..8d9ce68233730 100644 --- a/packages/cypress/src/generators/configuration/configuration.spec.ts +++ b/packages/cypress/src/generators/configuration/configuration.spec.ts @@ -52,11 +52,6 @@ describe('Cypress e2e configuration', () => { expect(readProjectConfiguration(tree, 'my-app').targets.e2e) .toMatchInlineSnapshot(` { - "configurations": { - "production": { - "devServerTarget": "my-app:serve:production", - }, - }, "executor": "@nx/cypress:cypress", "options": { "cypressConfig": "apps/my-app/cypress.config.ts", @@ -85,9 +80,7 @@ describe('Cypress e2e configuration', () => { "**/*.js", "cypress.config.ts", "**/*.cy.ts", - "**/*.cy.tsx", "**/*.cy.js", - "**/*.cy.jsx", "**/*.d.ts", ], } @@ -208,9 +201,7 @@ describe('Cypress e2e configuration', () => { "**/*.js", "../../cypress.config.ts", "../../**/*.cy.ts", - "../../**/*.cy.tsx", "../../**/*.cy.js", - "../../**/*.cy.jsx", "../../**/*.d.ts", ], } diff --git a/packages/cypress/src/generators/configuration/configuration.ts b/packages/cypress/src/generators/configuration/configuration.ts index 9c226839b86d5..31695f24a21e0 100644 --- a/packages/cypress/src/generators/configuration/configuration.ts +++ b/packages/cypress/src/generators/configuration/configuration.ts @@ -35,6 +35,7 @@ export interface CypressE2EConfigSchema { devServerTarget?: string; linter?: Linter; port?: number | 'cypress-auto'; + jsx?: boolean; } type NormalizedSchema = ReturnType; @@ -55,10 +56,12 @@ export async function configurationGenerator( } await addFiles(tree, opts); addTarget(tree, opts); - addLinterToCyProject(tree, { + + const linterTask = await addLinterToCyProject(tree, { ...opts, cypressDir: opts.directory, }); + tasks.push(linterTask); if (!opts.skipFormat) { await formatFiles(tree); @@ -132,6 +135,7 @@ async function addFiles(tree: Tree, options: NormalizedSchema) { addBaseCypressSetup(tree, { project: options.project, directory: options.directory, + jsx: options.jsx, }); const cyFile = joinPathFragments(projectConfig.root, 'cypress.config.ts'); @@ -197,18 +201,25 @@ function addTarget(tree: Tree, opts: NormalizedSchema) { port: opts.port, }; - projectConfig.targets.e2e.configurations = { - [parsedTarget.configuration || 'production']: { - devServerTarget: `${opts.devServerTarget}${ - parsedTarget.configuration ? '' : ':production' - }`, - }, - }; const devServerProjectConfig = readProjectConfiguration( tree, parsedTarget.project ); + // Add production e2e target if serve target is found + if ( + parsedTarget.configuration !== 'production' && + devServerProjectConfig.targets?.[parsedTarget.target]?.configurations?.[ + 'production' + ] + ) { + projectConfig.targets.e2e.configurations ??= {}; + projectConfig.targets.e2e.configurations['production'] = { + devServerTarget: `${parsedTarget.project}:${parsedTarget.target}:production`, + }; + } + // Add ci/static e2e target if serve target is found if (devServerProjectConfig.targets?.['serve-static']) { + projectConfig.targets.e2e.configurations ??= {}; projectConfig.targets.e2e.configurations.ci = { devServerTarget: `${parsedTarget.project}:serve-static`, }; diff --git a/packages/cypress/src/generators/configuration/schema.json b/packages/cypress/src/generators/configuration/schema.json index 120eb500cd203..9b7025b813a88 100644 --- a/packages/cypress/src/generators/configuration/schema.json +++ b/packages/cypress/src/generators/configuration/schema.json @@ -84,6 +84,11 @@ "enum": ["vite", "webpack", "none"], "x-prompt": "Which Cypress bundler do you want to use?", "default": "webpack" + }, + "jsx": { + "description": "Whether or not this project uses JSX.", + "type": "boolean", + "default": true } }, "required": ["project"], diff --git a/packages/cypress/src/generators/cypress-project/schema.d.ts b/packages/cypress/src/generators/cypress-project/schema.d.ts index 6abafe7f11c3e..d75dd885630a5 100644 --- a/packages/cypress/src/generators/cypress-project/schema.d.ts +++ b/packages/cypress/src/generators/cypress-project/schema.d.ts @@ -11,7 +11,6 @@ export interface Schema { js?: boolean; skipFormat?: boolean; setParserOptionsProject?: boolean; - standaloneConfig?: boolean; skipPackageJson?: boolean; bundler?: 'webpack' | 'vite' | 'none'; } diff --git a/packages/cypress/src/generators/cypress-project/schema.json b/packages/cypress/src/generators/cypress-project/schema.json index 2e6b0c856e960..ba3de2c6c2b74 100644 --- a/packages/cypress/src/generators/cypress-project/schema.json +++ b/packages/cypress/src/generators/cypress-project/schema.json @@ -59,12 +59,6 @@ "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.", "default": false }, - "standaloneConfig": { - "description": "Split the project configuration into `/project.json` rather than including it inside workspace.json.", - "type": "boolean", - "default": true, - "x-deprecated": "Nx only supports standaloneConfig" - }, "skipPackageJson": { "type": "boolean", "default": false, diff --git a/packages/next/src/generators/application/lib/add-e2e.ts b/packages/next/src/generators/application/lib/add-e2e.ts index b68e011d4fc00..15ec56c052335 100644 --- a/packages/next/src/generators/application/lib/add-e2e.ts +++ b/packages/next/src/generators/application/lib/add-e2e.ts @@ -12,18 +12,24 @@ import { NormalizedSchema } from './normalize-options'; export async function addE2e(host: Tree, options: NormalizedSchema) { if (options.e2eTestRunner === 'cypress') { - const { cypressProjectGenerator } = ensurePackage< + const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); - return cypressProjectGenerator(host, { + addProjectConfiguration(host, options.e2eProjectName, { + root: options.e2eProjectRoot, + sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), + targets: {}, + tags: [], + implicitDependencies: [options.projectName], + }); + return configurationGenerator(host, { ...options, linter: Linter.EsLint, - name: options.e2eProjectName, - directory: options.e2eProjectRoot, - // the name and root are already normalized, instruct the generator to use them as is - projectNameAndRootFormat: 'as-provided', - project: options.projectName, + project: options.e2eProjectName, + directory: 'src', skipFormat: true, + devServerTarget: `${options.projectName}:serve`, + jsx: true, }); } else if (options.e2eTestRunner === 'playwright') { const { configurationGenerator } = ensurePackage< diff --git a/packages/next/src/generators/cypress-component-configuration/cypress-component-configuration.ts b/packages/next/src/generators/cypress-component-configuration/cypress-component-configuration.ts index eb6e972ded842..b8e6f67bdd679 100644 --- a/packages/next/src/generators/cypress-component-configuration/cypress-component-configuration.ts +++ b/packages/next/src/generators/cypress-component-configuration/cypress-component-configuration.ts @@ -29,6 +29,7 @@ export async function cypressComponentConfiguration( await baseCyCtConfig(tree, { project: options.project, skipFormat: true, + jsx: true, }) ); diff --git a/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap index 415be766b35d9..41463a5277152 100644 --- a/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap +++ b/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap @@ -132,14 +132,14 @@ exports[`app generated files content - as-provided should create all new files i "my-app/.eslintrc.json", "my-app/vite.config.ts", "my-app/tsconfig.spec.json", - "my-app-e2e/cypress.config.ts", + "my-app-e2e/project.json", "my-app-e2e/src/e2e/app.cy.ts", - "my-app-e2e/src/fixtures/example.json", "my-app-e2e/src/support/app.po.ts", - "my-app-e2e/src/support/commands.ts", "my-app-e2e/src/support/e2e.ts", + "my-app-e2e/src/fixtures/example.json", + "my-app-e2e/src/support/commands.ts", + "my-app-e2e/cypress.config.ts", "my-app-e2e/tsconfig.json", - "my-app-e2e/project.json", "my-app-e2e/.eslintrc.json", ] `; diff --git a/packages/nuxt/src/generators/application/lib/add-e2e.ts b/packages/nuxt/src/generators/application/lib/add-e2e.ts index 54bd212c35da8..d9e53e853c72d 100644 --- a/packages/nuxt/src/generators/application/lib/add-e2e.ts +++ b/packages/nuxt/src/generators/application/lib/add-e2e.ts @@ -12,17 +12,25 @@ import { NormalizedSchema } from '../schema'; export async function addE2e(host: Tree, options: NormalizedSchema) { if (options.e2eTestRunner === 'cypress') { - const { cypressProjectGenerator } = ensurePackage< + const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); - return cypressProjectGenerator(host, { + addProjectConfiguration(host, options.e2eProjectName, { + projectType: 'application', + root: options.e2eProjectRoot, + sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), + targets: {}, + tags: [], + implicitDependencies: [options.projectName], + }); + return await configurationGenerator(host, { ...options, - linter: Linter.EsLint, - name: options.e2eProjectName, - directory: options.e2eProjectRoot, - projectNameAndRootFormat: 'as-provided', - project: options.projectName, + project: options.e2eProjectName, + directory: 'src', + bundler: 'vite', skipFormat: true, + devServerTarget: `${options.projectName}:serve`, + jsx: true, }); } else if (options.e2eTestRunner === 'playwright') { const { configurationGenerator } = ensurePackage< diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts index 10e91148bb87e..b25be440359fc 100644 --- a/packages/react/src/generators/application/application.spec.ts +++ b/packages/react/src/generators/application/application.spec.ts @@ -143,6 +143,7 @@ describe('app', () => { { "compilerOptions": { "allowJs": true, + "module": "commonjs", "outDir": "../dist/out-tsc", "sourceMap": false, "types": [ @@ -152,9 +153,14 @@ describe('app', () => { }, "extends": "../tsconfig.base.json", "include": [ - "src/**/*.ts", - "src/**/*.js", + "**/*.ts", + "**/*.js", "cypress.config.ts", + "**/*.cy.ts", + "**/*.cy.tsx", + "**/*.cy.js", + "**/*.cy.jsx", + "**/*.d.ts", ], } `); diff --git a/packages/react/src/generators/application/lib/add-e2e.ts b/packages/react/src/generators/application/lib/add-e2e.ts index ad63dedf74c64..838fe4ce03ea7 100644 --- a/packages/react/src/generators/application/lib/add-e2e.ts +++ b/packages/react/src/generators/application/lib/add-e2e.ts @@ -15,31 +15,42 @@ export async function addE2e( options: NormalizedSchema ): Promise { switch (options.e2eTestRunner) { - case 'cypress': + case 'cypress': { webStaticServeGenerator(tree, { buildTarget: `${options.projectName}:build`, targetName: 'serve-static', }); - const { cypressProjectGenerator } = ensurePackage< + const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); - return await cypressProjectGenerator(tree, { + addProjectConfiguration(tree, options.e2eProjectName, { + projectType: 'application', + root: options.e2eProjectRoot, + sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), + targets: {}, + implicitDependencies: [options.projectName], + tags: [], + }); + + return await configurationGenerator(tree, { ...options, - name: options.e2eProjectName, - directory: options.e2eProjectRoot, + project: options.e2eProjectName, + directory: 'src', // the name and root are already normalized, instruct the generator to use them as is - projectNameAndRootFormat: 'as-provided', - project: options.projectName, bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler, skipFormat: true, + devServerTarget: `${options.projectName}:serve`, + jsx: true, }); - case 'playwright': + } + case 'playwright': { const { configurationGenerator } = ensurePackage< typeof import('@nx/playwright') >('@nx/playwright', nxVersion); addProjectConfiguration(tree, options.e2eProjectName, { + projectType: 'application', root: options.e2eProjectRoot, sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), targets: {}, @@ -58,6 +69,7 @@ export async function addE2e( }`, webServerAddress: 'http://localhost:4200', }); + } case 'none': default: return () => {}; diff --git a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts index 761ca09d80d13..a756d1aeac202 100644 --- a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts +++ b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts @@ -25,6 +25,7 @@ export async function cypressComponentConfigGenerator( const installTask = await baseCyCtConfig(tree, { project: options.project, skipFormat: true, + jsx: true, }); const found = await addCTTargetWithBuildTarget(tree, { diff --git a/packages/storybook/src/generators/cypress-project/cypress-project.spec.ts b/packages/storybook/src/generators/cypress-project/cypress-project.spec.ts index 3365702123f05..8b5f3ffcd6e47 100644 --- a/packages/storybook/src/generators/cypress-project/cypress-project.spec.ts +++ b/packages/storybook/src/generators/cypress-project/cypress-project.spec.ts @@ -1,19 +1,13 @@ -import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { readJson, readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; import { libraryGenerator } from '@nx/js'; import { cypressProjectGenerator } from './cypress-project'; -jest.mock('@nx/cypress/src/utils/cypress-version'); describe('@nx/storybook:cypress-project', () => { let tree: Tree; - let mockedInstalledCypressVersion: jest.Mock< - ReturnType - > = installedCypressVersion as never; beforeEach(async () => { - mockedInstalledCypressVersion.mockReturnValue(10); tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); await libraryGenerator(tree, { name: 'test-ui-lib', @@ -36,19 +30,6 @@ describe('@nx/storybook:cypress-project', () => { expect(cypressConfig).toMatchSnapshot(); }); - it('should update cypress.json file if present', async () => { - mockedInstalledCypressVersion.mockReturnValue(9); - - await cypressProjectGenerator(tree, { - name: 'test-ui-lib', - linter: Linter.EsLint, - }); - - expect(tree.exists('apps/test-ui-lib-e2e/cypress.json')).toBeTruthy(); - const cypressConfig = readJson(tree, 'apps/test-ui-lib-e2e/cypress.json'); - expect(cypressConfig.baseUrl).toEqual('http://localhost:4400'); - }); - it('should update `angular.json` file', async () => { await cypressProjectGenerator(tree, { name: 'test-ui-lib', diff --git a/packages/storybook/src/generators/cypress-project/cypress-project.ts b/packages/storybook/src/generators/cypress-project/cypress-project.ts index 0b7246091cf4d..a6ad8e1c231bc 100644 --- a/packages/storybook/src/generators/cypress-project/cypress-project.ts +++ b/packages/storybook/src/generators/cypress-project/cypress-project.ts @@ -1,15 +1,11 @@ +import { getE2eProjectName } from '@nx/cypress/src/utils/project-name'; import { - cypressInitGenerator as _cypressInitGenerator, - cypressProjectGenerator as _cypressProjectGenerator, -} from '@nx/cypress'; -import { - getE2eProjectName, - getUnscopedLibName, -} from '@nx/cypress/src/utils/project-name'; -import { + addProjectConfiguration, + ensurePackage, formatFiles, generateFiles, GeneratorCallback, + joinPathFragments, readJson, readProjectConfiguration, runTasksInSerial, @@ -18,9 +14,11 @@ import { updateProjectConfiguration, } from '@nx/devkit'; import { Linter } from '@nx/eslint'; - +import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils'; import { join } from 'path'; + import { safeFileDelete } from '../../utils/utilities'; +import { nxVersion } from '../../utils/versions'; export interface CypressConfigureSchema { name: string; @@ -30,31 +28,61 @@ export interface CypressConfigureSchema { standaloneConfig?: boolean; ciTargetName?: string; skipFormat?: boolean; + projectNameAndRootFormat?: 'as-provided' | 'derived'; } export async function cypressProjectGenerator( tree: Tree, schema: CypressConfigureSchema ) { + return await cypressProjectGeneratorInternal(tree, { + projectNameAndRootFormat: 'derived', + ...schema, + }); +} + +export async function cypressProjectGeneratorInternal( + tree: Tree, + schema: CypressConfigureSchema +) { + const { configurationGenerator, cypressInitGenerator } = ensurePackage< + typeof import('@nx/cypress') + >('@nx/cypress', nxVersion); + + const e2eName = schema.name ? `${schema.name}-e2e` : undefined; + const { projectName, projectRoot } = await determineProjectNameAndRootOptions( + tree, + { + name: e2eName, + projectType: 'application', + directory: schema.directory, + projectNameAndRootFormat: schema.projectNameAndRootFormat, + callingGenerator: '@nx/storybook:cypress-project', + } + ); const libConfig = readProjectConfiguration(tree, schema.name); const libRoot = libConfig.root; - const cypressProjectName = `${ - schema.directory ? getUnscopedLibName(libRoot) : schema.name - }-e2e`; const tasks: GeneratorCallback[] = []; if (!projectAlreadyHasCypress(tree)) { - tasks.push(await _cypressInitGenerator(tree, {})); + tasks.push(await cypressInitGenerator(tree, {})); } - const installTask = await _cypressProjectGenerator(tree, { - name: cypressProjectName, - project: schema.name, + addProjectConfiguration(tree, projectName, { + root: projectRoot, + projectType: 'application', + sourceRoot: joinPathFragments(projectRoot, 'src'), + targets: {}, + implicitDependencies: [projectName], + }); + + const installTask = await configurationGenerator(tree, { + project: projectName, js: schema.js, linter: schema.linter, - directory: schema.directory, - standaloneConfig: schema.standaloneConfig, + directory: projectRoot, + devServerTarget: `${schema.name}:storybook`, skipFormat: true, }); tasks.push(installTask); diff --git a/packages/storybook/src/generators/cypress-project/schema.json b/packages/storybook/src/generators/cypress-project/schema.json index 1a5e689a2f770..15a6bb70c94cd 100644 --- a/packages/storybook/src/generators/cypress-project/schema.json +++ b/packages/storybook/src/generators/cypress-project/schema.json @@ -33,12 +33,6 @@ "enum": ["eslint", "none"], "default": "eslint" }, - "standaloneConfig": { - "description": "Split the project configuration into `/project.json` rather than including it inside `workspace.json`.", - "type": "boolean", - "default": true, - "x-deprecated": "Nx only supports standaloneConfig" - }, "ciTargetName": { "type": "string", "description": "The name of the devServerTarget to use for the Cypress CI configuration. Used to control if using :static-storybook:ci or :storybook:ci", @@ -49,6 +43,11 @@ "type": "boolean", "default": false, "x-priority": "internal" + }, + "projectNameAndRootFormat": { + "description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).", + "type": "string", + "enum": ["as-provided", "derived"] } }, "required": ["name"] diff --git a/packages/vue/src/generators/application/lib/add-e2e.ts b/packages/vue/src/generators/application/lib/add-e2e.ts index 1977289b3cc62..454273847e95d 100644 --- a/packages/vue/src/generators/application/lib/add-e2e.ts +++ b/packages/vue/src/generators/application/lib/add-e2e.ts @@ -15,30 +15,39 @@ export async function addE2e( options: NormalizedSchema ): Promise { switch (options.e2eTestRunner) { - case 'cypress': + case 'cypress': { webStaticServeGenerator(tree, { buildTarget: `${options.projectName}:build`, targetName: 'serve-static', }); - const { cypressProjectGenerator } = ensurePackage< + const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); - - return await cypressProjectGenerator(tree, { + addProjectConfiguration(tree, options.e2eProjectName, { + projectType: 'application', + root: options.e2eProjectRoot, + sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), + targets: {}, + tags: [], + implicitDependencies: [options.projectName], + }); + return await configurationGenerator(tree, { ...options, - name: options.e2eProjectName, - directory: options.e2eProjectRoot, - projectNameAndRootFormat: 'as-provided', - project: options.projectName, + project: options.e2eProjectName, + directory: 'src', bundler: 'vite', skipFormat: true, + devServerTarget: `${options.projectName}:serve`, + jsx: true, }); - case 'playwright': + } + case 'playwright': { const { configurationGenerator } = ensurePackage< typeof import('@nx/playwright') >('@nx/playwright', nxVersion); addProjectConfiguration(tree, options.e2eProjectName, { + projectType: 'application', root: options.e2eProjectRoot, sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), targets: {}, @@ -57,6 +66,7 @@ export async function addE2e( }`, webServerAddress: 'http://localhost:4200', }); + } case 'none': default: return () => {}; diff --git a/packages/web/src/generators/application/application.spec.ts b/packages/web/src/generators/application/application.spec.ts index 1a12bf5790777..3f89a33c022d3 100644 --- a/packages/web/src/generators/application/application.spec.ts +++ b/packages/web/src/generators/application/application.spec.ts @@ -86,6 +86,7 @@ describe('app', () => { { "compilerOptions": { "allowJs": true, + "module": "commonjs", "outDir": "../dist/out-tsc", "sourceMap": false, "types": [ @@ -95,9 +96,12 @@ describe('app', () => { }, "extends": "../tsconfig.base.json", "include": [ - "src/**/*.ts", - "src/**/*.js", + "**/*.ts", + "**/*.js", "cypress.config.ts", + "**/*.cy.ts", + "**/*.cy.js", + "**/*.d.ts", ], } `); diff --git a/packages/web/src/generators/application/application.ts b/packages/web/src/generators/application/application.ts index 601881e2dd9a8..df6840adb06df 100644 --- a/packages/web/src/generators/application/application.ts +++ b/packages/web/src/generators/application/application.ts @@ -6,7 +6,6 @@ import { generateFiles, GeneratorCallback, getPackageManagerCommand, - getWorkspaceLayout, joinPathFragments, names, offsetFromRoot, @@ -282,16 +281,22 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { } if (options.e2eTestRunner === 'cypress') { - const { cypressProjectGenerator } = ensurePackage< + const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); - const cypressTask = await cypressProjectGenerator(host, { + addProjectConfiguration(host, options.e2eProjectName, { + root: options.e2eProjectRoot, + sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), + projectType: 'application', + targets: {}, + tags: [], + implicitDependencies: [options.projectName], + }); + const cypressTask = await configurationGenerator(host, { ...options, - name: options.e2eProjectName, - directory: options.e2eProjectRoot, - // the name and root are already normalized, instruct the generator to use them as is - projectNameAndRootFormat: 'as-provided', - project: options.projectName, + project: options.e2eProjectName, + devServerTarget: `${options.projectName}:serve`, + directory: 'src', skipFormat: true, }); tasks.push(cypressTask); @@ -299,7 +304,6 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { const { configurationGenerator: playwrightConfigGenerator } = ensurePackage< typeof import('@nx/playwright') >('@nx/playwright', nxVersion); - addProjectConfiguration(host, options.e2eProjectName, { root: options.e2eProjectRoot, sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),