UNPKG

gen-jhipster

Version:

VHipster - Spring Boot + Angular/React/Vue in one handy generator

384 lines (383 loc) 19.4 kB
/** * Copyright 2013-2026 the original author or authors from the JHipster project. * * This file is part of the JHipster project, see https://www.jhipster.tech/ * for more information. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { clientFrameworkTypes } from "../../lib/jhipster/index.js"; import { mutateData, stringHashCode } from "../../lib/utils/index.js"; import BaseApplicationGenerator from "../base-application/index.js"; import { createFaker } from "../base-application/support/index.js"; import { generateTestEntity } from "../client/support/index.js"; import { CLIENT_MAIN_SRC_DIR } from "../generator-constants.js"; import { cypressEntityFiles, cypressFiles } from "./files.js"; const { ANGULAR } = clientFrameworkTypes; const WAIT_TIMEOUT = 3 * 60000; export default class CypressGenerator extends BaseApplicationGenerator { angularSchematic = false; async beforeQueue() { if (!this.fromBlueprint) { await this.composeWithBlueprints(); } if (!this.delegateToBlueprint) { await this.dependsOnBootstrap('client'); } } get prompting() { return this.asPromptingTaskGroup({ async askForCypressOptions({ control }) { if (control.existingProject && !this.options.askAnswered) return; await this.prompt([ { when: this.jhipsterConfig.clientFramework === ANGULAR, type: 'confirm', name: 'cypressCoverage', message: 'Would you like to generate code coverage for Cypress tests? [Experimental]', }, { type: 'confirm', name: 'cypressAudit', message: 'Would you like to audit Cypress tests?', }, ], this.config); }, }); } get [BaseApplicationGenerator.PROMPTING]() { return this.delegateTasksToBlueprint(() => this.prompting); } get configuring() { return this.asConfiguringTaskGroup({ setCypressTestFramework({ control }) { if (control.isJhipsterVersionLessThan('9.0.0-beta.4')) { // cypressAudit is set to false by default since next release following 9.0.0-beta.3. this.jhipsterConfig.cypressAudit ??= true; } }, }); } get [BaseApplicationGenerator.CONFIGURING]() { return this.delegateTasksToBlueprint(() => this.configuring); } get preparing() { return this.asPreparingTaskGroup({ loadPackageJson({ application }) { this.loadNodeDependenciesFromPackageJson(application.nodeDependencies, this.fetchFromInstalledJHipster('client', 'resources', 'package.json')); }, prepareForTemplates({ applicationDefaults }) { applicationDefaults({ cypressAudit: false, cypressCoverage: false, cypressDir: ({ clientTestDir }) => (clientTestDir ? `${clientTestDir}cypress/` : 'cypress/'), cypressTemporaryDir: ({ temporaryDir }) => (temporaryDir ? `${temporaryDir}cypress/` : '.cypress/'), cypressBootstrapEntities: true, cypressCoverageWebpack: data => Boolean(data.cypressCoverage && data.clientFrameworkAngular && data.clientBundlerWebpack), }); }, npmScripts({ application }) { const { devServerPort, devServerPortProxy: devServerPortE2e = devServerPort } = application; this.angularSchematic = Boolean(application.clientFrameworkAngular && application.clientBundlerEsbuild); Object.assign(application.clientPackageJsonScripts, { cypress: 'cypress open --e2e', e2e: 'npm run e2e:cypress:headed --', 'e2e:cypress': 'cypress run --e2e --browser chrome', 'e2e:cypress:headed': 'npm run e2e:cypress -- --headed', 'e2e:cypress:record': 'npm run e2e:cypress -- --record', 'e2e:headless': 'npm run e2e:cypress --', }); // Scripts that handle server and client concurrently should be added to the root package.json Object.assign(application.packageJsonScripts, { 'ci:e2e:run': 'concurrently -k -s first -n application,e2e -c red,blue npm:ci:e2e:server:start npm:e2e:headless', 'ci:e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue npm:app:start npm:e2e:headless`, 'e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue npm:app:start npm:e2e`, 'e2e:devserver': this.angularSchematic ? `concurrently -k -s first -n backend,e2e -c red,blue npm:backend:start "npm run ci:server:await && ng e2e --configuration ${application.cypressCoverage ? 'coverage' : 'run'}"` : `concurrently -k -s first -n backend,frontend,e2e -c red,yellow,blue npm:backend:start npm:start "wait-on -t ${WAIT_TIMEOUT} http-get://127.0.0.1:${devServerPortE2e} && npm run e2e:headless -- -c baseUrl=http://localhost:${devServerPortE2e}"`, }); if (application.clientRootDir) { // Add scripts to map to client package.json Object.assign(application.packageJsonScripts, { 'e2e:headless': `npm run -w ${application.clientRootDir} e2e:headless`, }); } else if (application.backendTypeJavaAny) { Object.assign(application.clientPackageJsonScripts, { 'pree2e:headless': 'npm run ci:server:await', }); } }, }); } get [BaseApplicationGenerator.PREPARING]() { return this.delegateTasksToBlueprint(() => this.preparing); } get postPreparingEachEntity() { return this.asPreparingEachEntityTaskGroup({ prepareForTemplates({ entity }) { mutateData(entity, { workaroundEntityCannotBeEmpty: false, workaroundInstantReactiveMariaDB: false, generateEntityCypress: ({ builtInUserManagement, skipClient }) => !skipClient || builtInUserManagement, }); }, }); } get [BaseApplicationGenerator.POST_PREPARING_EACH_ENTITY]() { return this.delegateTasksToBlueprint(() => this.postPreparingEachEntity); } get writing() { return this.asWritingTaskGroup({ async cleanup({ control, application: { authenticationTypeOauth2, generateUserManagement, cypressDir } }) { if (control.isJhipsterVersionLessThan('7.0.0-beta.1')) { this.removeFile(`${cypressDir}support/keycloak-oauth2.ts`); this.removeFile(`${cypressDir}fixtures/users/user.json`); } if (control.isJhipsterVersionLessThan('7.8.2')) { this.removeFile('cypress.json'); this.removeFile('cypress-audits.json'); this.removeFile(`${cypressDir}integration/administration/administration.spec.ts`); this.removeFile(`${cypressDir}integration/lighthouse.audits.ts`); if (!authenticationTypeOauth2) { this.removeFile(`${cypressDir}integration/account/login-page.spec.ts`); } if (generateUserManagement) { this.removeFile(`${cypressDir}integration/account/register-page.spec.ts`); this.removeFile(`${cypressDir}integration/account/settings-page.spec.ts`); this.removeFile(`${cypressDir}integration/account/password-page.spec.ts`); this.removeFile(`${cypressDir}integration/account/reset-password-page.spec.ts`); } } await control.cleanupFiles({ '8.6.1': [`${cypressDir}.eslintrc.json`] }); }, async writeFiles({ application }) { const faker = await createFaker(); faker.seed(stringHashCode(application.baseName)); const context = { ...application, faker }; return this.writeFiles({ sections: cypressFiles, context, }); }, }); } get [BaseApplicationGenerator.WRITING]() { return this.delegateTasksToBlueprint(() => this.writing); } get writingEntities() { return this.asWritingEntitiesTaskGroup({ cleanupCypressEntityFiles({ application: { cypressDir }, control, entities }) { for (const entity of entities) { if (control.isJhipsterVersionLessThan('7.8.2')) { this.removeFile(`${cypressDir}integration/entity/${entity.entityFileName}.spec.ts`); } } }, async writeCypressEntityFiles({ application, entities }) { for (const entity of entities.filter(entity => entity.generateEntityCypress && !entity.embedded && !entity.builtInUser && !entity.entityClientModelOnly)) { const context = { ...application, ...entity }; await this.writeFiles({ sections: cypressEntityFiles, context, }); } }, }); } get [BaseApplicationGenerator.WRITING_ENTITIES]() { return this.delegateTasksToBlueprint(() => this.writingEntities); } get postWriting() { return this.asPostWritingTaskGroup({ packageJson({ application }) { const clientPackageJson = this.createStorage(this.destinationPath(application.clientRootDir, 'package.json')); clientPackageJson.merge({ devDependencies: { cypress: application.nodeDependencies.cypress, 'eslint-plugin-cypress': application.nodeDependencies['eslint-plugin-cypress'], }, }); if (application.cypressCoverage && this.angularSchematic) { clientPackageJson.merge({ devDependencies: { 'cypress-monocart-coverage': null, }, scripts: { 'pree2e:cypress:coverage': 'npm run ci:server:await', 'e2e:cypress:coverage': 'ng e2e --configuration coverage', }, }); } }, configureAudits({ application }) { if (!application.cypressAudit) return; const clientPackageJson = this.createStorage(this.destinationPath(application.clientRootDir, 'package.json')); clientPackageJson.merge({ devDependencies: { lighthouse: application.nodeDependencies.lighthouse, 'cypress-audit': application.nodeDependencies['cypress-audit'], }, scripts: { 'cypress:audits': 'cypress open --e2e --config-file cypress-audits.config.js', 'e2e:cypress:audits:headless': 'npm run e2e:cypress -- --config-file cypress-audits.config.js', 'e2e:cypress:audits': 'cypress run --e2e --browser chrome --config-file cypress-audits.config.js', }, }); }, configureWebpackCoverage({ application, source }) { const { cypressCoverageWebpack, clientFrameworkAngular, clientRootDir, dasherizedBaseName } = application; if (!cypressCoverageWebpack) return; const clientPackageJson = this.createStorage(this.destinationPath(application.clientRootDir, 'package.json')); clientPackageJson.merge({ devDependencies: { '@cypress/code-coverage': application.nodeDependencies['@cypress/code-coverage'], 'babel-loader': application.nodeDependencies['babel-loader'], 'babel-plugin-istanbul': application.nodeDependencies['babel-plugin-istanbul'], nyc: application.nodeDependencies.nyc, }, scripts: { 'clean-coverage': 'rimraf .nyc_output coverage', 'pree2e:cypress:coverage': 'npm run clean-coverage && npm run ci:server:await', 'e2e:cypress:coverage': 'npm run e2e:cypress:headed', 'poste2e:cypress:coverage': 'nyc report', 'prewebapp:instrumenter': 'npm run clean-www && npm run clean-coverage', 'webapp:instrumenter': 'ng build --configuration instrumenter', }, }); if (clientFrameworkAngular) { // Add 'ng build --configuration instrumenter' support this.createStorage(`${clientRootDir}angular.json`).setPath(`projects.${dasherizedBaseName}.architect.build.configurations.instrumenter`, {}); source.addWebpackConfig?.({ config: String.raw `targetOptions.configuration === 'instrumenter' ? { module: { rules: [ { test: /\.(js|ts)$/, use: [ { loader: 'babel-loader', options: { plugins: ['istanbul'], }, } ], enforce: 'post', include: path.resolve(__dirname, '../${CLIENT_MAIN_SRC_DIR}'), exclude: [/\.(e2e|spec)\.ts$/, /node_modules/, /(ngfactory|ngstyle)\.js/], }, ], }, } : {}`, }); } }, cypressSchematics({ application, source }) { const { applicationTypeMicroservice, dasherizedBaseName, clientRootDir, gatewayServerPort, serverPort } = application; if (!this.angularSchematic) return; source.mergeClientPackageJson?.({ devDependencies: { '@cypress/schematic': null, }, }); this.mergeDestinationJson(`${clientRootDir}angular.json`, { projects: { [application.dasherizedBaseName]: { architect: { e2e: { builder: '@cypress/schematic:cypress', options: { browser: 'chrome' }, configurations: { baseHref: { headless: true, baseUrl: `http://localhost:${applicationTypeMicroservice ? gatewayServerPort : serverPort}`, }, open: { watch: true, devServerTarget: `${dasherizedBaseName}:serve`, }, openProduction: { watch: true, devServerTarget: `${dasherizedBaseName}:serve:production`, }, run: { headless: true, devServerTarget: `${dasherizedBaseName}:serve`, }, runProduction: { headless: true, devServerTarget: `${dasherizedBaseName}:serve:production`, }, }, defaultConfiguration: 'open', }, }, }, }, }); }, configureV8Coverage({ application }) { const { cypressCoverage, clientRootDir, dasherizedBaseName } = application; if (!cypressCoverage || !this.angularSchematic) return; this.mergeDestinationJson(`${clientRootDir}angular.json`, { projects: { [dasherizedBaseName]: { architect: { e2e: { configurations: { coverage: { headless: true, devServerTarget: `${dasherizedBaseName}:serve:development`, env: { CYPRESS_COVERAGE: true }, }, openCoverage: { watch: true, devServerTarget: `${dasherizedBaseName}:serve:development`, env: { CYPRESS_COVERAGE: true }, }, }, }, }, }, }, }); }, mavenProfile({ source }) { source.addMavenProfile?.({ id: 'e2e', content: ` <properties> <profile.e2e>,e2e</profile.e2e> </properties> <build> <finalName>e2e</finalName> </build> `, }); }, }); } get [BaseApplicationGenerator.POST_WRITING]() { return this.delegateTasksToBlueprint(() => this.postWriting); } generateTestEntity(fields) { return generateTestEntity(fields); } }