From 19a02716def587fd2adab88137db2663bac57039 Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 13:48:34 +0100 Subject: [PATCH 01/11] Vite/Vue3: add client --- .../ViteVueApplicationService.java | 19 +++ .../client/vite/vue/core/domain/ViteVue.java | 27 ++++ .../vue/core/domain/ViteVueDomainService.java | 117 ++++++++++++++++++ .../vite/vue/core/domain/ViteVueService.java | 7 ++ .../config/ViteVueBeanConfiguration.java | 25 ++++ .../primary/rest/ViveVueResource.java | 34 +++++ .../client/vite/vue/core/package-info.java | 2 + .../npm/domain/NpmDomainService.java | 7 +- .../packagemanager/npm/domain/NpmService.java | 1 + .../generator/client/vite/vue3/jest.config.js | 36 ++++++ .../app/App.component.spec.ts.mustache | 11 ++ .../generator/client/vite/vue3/tsconfig.json | 17 +++ .../generator/client/vite/vue3/vite.config.ts | 19 +++ .../primary/app/App.component.ts.mustache | 3 + .../app/common/primary/app/App.vue.mustache | 97 +++++++++++++++ .../vite/vue3/webapp/app/env.d.ts.mustache | 8 ++ .../vite/vue3/webapp/app/main.ts.mustache | 4 + .../images/JHipster-Lite-neon-green.png | Bin 0 -> 35772 bytes .../vite/vue3/webapp/content/images/logo.png | Bin 0 -> 6849 bytes .../vite/vue3/webapp/index.html.mustache | 13 ++ .../dependencies/vite/vue3/package.json | 23 ++++ .../ViteVueApplicationServiceIT.java | 30 +++++ .../vue/core/application/ViteVueAssert.java | 44 +++++++ .../core/domain/ViteVueDomainServiceTest.java | 114 +++++++++++++++++ .../config/ViteVueBeanConfigurationIT.java | 21 ++++ .../primary/rest/ViveVueResourceIT.java | 48 +++++++ .../npm/domain/NpmDomainServiceTest.java | 12 +- 27 files changed, 730 insertions(+), 9 deletions(-) create mode 100644 src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationService.java create mode 100644 src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java create mode 100644 src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java create mode 100644 src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueService.java create mode 100644 src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfiguration.java create mode 100644 src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResource.java create mode 100644 src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/package-info.java create mode 100644 src/main/resources/generator/client/vite/vue3/jest.config.js create mode 100644 src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.component.spec.ts.mustache create mode 100644 src/main/resources/generator/client/vite/vue3/tsconfig.json create mode 100644 src/main/resources/generator/client/vite/vue3/vite.config.ts create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.vue.mustache create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/app/env.d.ts.mustache create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/app/main.ts.mustache create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/content/images/JHipster-Lite-neon-green.png create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/content/images/logo.png create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/index.html.mustache create mode 100644 src/main/resources/generator/dependencies/vite/vue3/package.json create mode 100644 src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java create mode 100644 src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java create mode 100644 src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java create mode 100644 src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfigurationIT.java create mode 100644 src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationService.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationService.java new file mode 100644 index 00000000000..9fa947b5c89 --- /dev/null +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationService.java @@ -0,0 +1,19 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.application; + +import org.springframework.stereotype.Service; +import tech.jhipster.lite.generator.client.vite.vue.core.domain.ViteVueService; +import tech.jhipster.lite.generator.project.domain.Project; + +@Service +public class ViteVueApplicationService { + + private final ViteVueService viteVueService; + + public ViteVueApplicationService(ViteVueService viteVueService) { + this.viteVueService = viteVueService; + } + + public void addViteVue(Project project) { + viteVueService.addViteVue(project); + } +} diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java new file mode 100644 index 00000000000..a6b335e12bd --- /dev/null +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java @@ -0,0 +1,27 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.domain; + +import java.util.List; + +public class ViteVue { + + private ViteVue() {} + + public static List dependencies() { + return List.of("vue", "vue-class-component", "vue-router"); + } + + public static List devDependencies() { + return List.of( + "@types/jest", + "@vitejs/plugin-vue", + "@vue/test-utils", + "jest", + "jest-transform-stub", + "ts-jest", + "typescript", + "vite", + "vue-jest", + "vue-tsc" + ); + } +} diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java new file mode 100644 index 00000000000..308c7538b55 --- /dev/null +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java @@ -0,0 +1,117 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.domain; + +import static tech.jhipster.lite.common.domain.FileUtils.getPath; + +import java.util.List; +import java.util.Map; +import tech.jhipster.lite.error.domain.GeneratorException; +import tech.jhipster.lite.generator.packagemanager.npm.domain.NpmService; +import tech.jhipster.lite.generator.project.domain.Project; +import tech.jhipster.lite.generator.project.domain.ProjectRepository; + +public class ViteVueDomainService implements ViteVueService { + + public static final String SOURCE = "client/vite/vue3"; + + private final ProjectRepository projectRepository; + private final NpmService npmService; + + public ViteVueDomainService(ProjectRepository projectRepository, NpmService npmService) { + this.projectRepository = projectRepository; + this.npmService = npmService; + } + + @Override + public void addViteVue(Project project) { + addDependencies(project); + addDevDependencies(project); + addScripts(project); + + addViteConfigFiles(project); + + addRootFiles(project); + addAppFiles(project); + } + + public void addDependencies(Project project) { + ViteVue.dependencies().forEach(dependency -> addDependency(project, dependency)); + } + + public void addDevDependencies(Project project) { + ViteVue.devDependencies().forEach(devDependency -> addDevDependency(project, devDependency)); + } + + private void addDependency(Project project, String dependency) { + npmService + .getVersion("vite/vue3", dependency) + .ifPresentOrElse( + version -> npmService.addDependency(project, dependency, version), + () -> { + throw new GeneratorException("Dependency not found: " + dependency); + } + ); + } + + private void addDevDependency(Project project, String devDependency) { + npmService + .getVersion("vite/vue3", devDependency) + .ifPresentOrElse( + version -> npmService.addDevDependency(project, devDependency, version), + () -> { + throw new GeneratorException("DevDependency not found: " + devDependency); + } + ); + } + + public void addScripts(Project project) { + // prettier-ignore + Map + .of( + "build", "vue-tsc --noEmit && vite build --emptyOutDir", + "dev", "vite", + "preview", "vite preview", + "test", "jest src/test/javascript/spec" + ) + .forEach((name, cmd) -> npmService.addScript(project, name, cmd)); + } + + public void addViteConfigFiles(Project project) { + List.of("jest.config.js", "tsconfig.json", "vite.config.ts").forEach(file -> projectRepository.add(project, SOURCE, file)); + } + + public void addRootFiles(Project project) { + projectRepository.template(project, getPath(SOURCE, "webapp"), "index.html", "src/main/webapp"); + projectRepository.template(project, getPath(SOURCE, "webapp/app"), "env.d.ts", "src/main/webapp/app"); + projectRepository.template(project, getPath(SOURCE, "webapp/app"), "main.ts", "src/main/webapp/app"); + + projectRepository.add( + project, + getPath(SOURCE, "webapp/content/images"), + "JHipster-Lite-neon-green.png", + "src/main/webapp/content/images" + ); + projectRepository.add(project, getPath(SOURCE, "webapp/content/images"), "logo.png", "src/main/webapp/content/images"); + } + + public void addAppFiles(Project project) { + projectRepository.template( + project, + getPath(SOURCE, "webapp/app/common/primary/app"), + "App.component.ts", + "src/main/webapp/app/common/primary/app" + ); + projectRepository.template( + project, + getPath(SOURCE, "webapp/app/common/primary/app"), + "App.vue", + "src/main/webapp/app/common/primary/app" + ); + + projectRepository.template( + project, + getPath(SOURCE, "test/spec/common/primary/app"), + "App.component.spec.ts", + "src/test/javascript/spec/common/primary/app" + ); + } +} diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueService.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueService.java new file mode 100644 index 00000000000..433ecd7e3cf --- /dev/null +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueService.java @@ -0,0 +1,7 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.domain; + +import tech.jhipster.lite.generator.project.domain.Project; + +public interface ViteVueService { + void addViteVue(Project project); +} diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfiguration.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfiguration.java new file mode 100644 index 00000000000..bb38176d441 --- /dev/null +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfiguration.java @@ -0,0 +1,25 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.infrastructure.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import tech.jhipster.lite.generator.client.vite.vue.core.domain.ViteVueDomainService; +import tech.jhipster.lite.generator.client.vite.vue.core.domain.ViteVueService; +import tech.jhipster.lite.generator.packagemanager.npm.domain.NpmService; +import tech.jhipster.lite.generator.project.domain.ProjectRepository; + +@Configuration +public class ViteVueBeanConfiguration { + + private final ProjectRepository projectRepository; + private final NpmService npmService; + + public ViteVueBeanConfiguration(ProjectRepository projectRepository, NpmService npmService) { + this.projectRepository = projectRepository; + this.npmService = npmService; + } + + @Bean + public ViteVueService viteVueService() { + return new ViteVueDomainService(projectRepository, npmService); + } +} diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResource.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResource.java new file mode 100644 index 00000000000..d9dfe366826 --- /dev/null +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResource.java @@ -0,0 +1,34 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.infrastructure.primary.rest; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import tech.jhipster.lite.generator.client.vite.vue.core.application.ViteVueApplicationService; +import tech.jhipster.lite.generator.project.domain.Project; +import tech.jhipster.lite.generator.project.infrastructure.primary.dto.ProjectDTO; +import tech.jhipster.lite.technical.infrastructure.primary.annotation.GeneratorStep; + +@RestController +@RequestMapping("/api/vite/vue") +@Tag(name = "Vite - Vue") +class ViveVueResource { + + private final ViteVueApplicationService viteVueApplicationService; + + public ViveVueResource(ViteVueApplicationService viteVueApplicationService) { + this.viteVueApplicationService = viteVueApplicationService; + } + + @Operation(summary = "Add Vite+Vue3", description = "Add Vite+Vue3") + @ApiResponse(responseCode = "500", description = "An error occurred while adding Vite+Vue3") + @PostMapping + @GeneratorStep(id = "vite-vue") + public void addViteVue(@RequestBody ProjectDTO projectDTO) { + Project project = ProjectDTO.toProject(projectDTO); + viteVueApplicationService.addViteVue(project); + } +} diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/package-info.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/package-info.java new file mode 100644 index 00000000000..417b06587a2 --- /dev/null +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/package-info.java @@ -0,0 +1,2 @@ +@tech.jhipster.lite.BusinessContext +package tech.jhipster.lite.generator.client.vite.vue.core; diff --git a/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainService.java b/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainService.java index f856e5e7efc..60e532e34f2 100644 --- a/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainService.java +++ b/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainService.java @@ -75,11 +75,12 @@ public Optional getVersionInCommon(String name) { return getVersion("common", name); } - private Optional getVersion(String folderType, String name) { - Assert.notBlank("folderType", folderType); + @Override + public Optional getVersion(String folder, String name) { + Assert.notBlank("folder", folder); Assert.notBlank("name", name); return FileUtils - .readLineInClasspath(getPath(TEMPLATE_FOLDER, DEPENDENCIES_FOLDER, folderType, PACKAGE_JSON), DQ + name + DQ) + .readLineInClasspath(getPath(TEMPLATE_FOLDER, DEPENDENCIES_FOLDER, folder, PACKAGE_JSON), DQ + name + DQ) .map(readValue -> { String[] result = readValue.split(":"); if (result.length == 2) { diff --git a/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmService.java b/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmService.java index ba7c5deec2d..357638062a9 100644 --- a/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmService.java +++ b/src/main/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmService.java @@ -11,5 +11,6 @@ public interface NpmService { void install(Project project); void prettify(Project project); + Optional getVersion(String folder, String name); Optional getVersionInCommon(String name); } diff --git a/src/main/resources/generator/client/vite/vue3/jest.config.js b/src/main/resources/generator/client/vite/vue3/jest.config.js new file mode 100644 index 00000000000..dbd1da6a716 --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/jest.config.js @@ -0,0 +1,36 @@ +// jest.config.js +module.exports = { + moduleFileExtensions: ['js', 'ts', 'json', 'vue'], + transform: { + '^.+\\.ts$': 'ts-jest', + '^.+\\.vue$': 'vue-jest', + '.+\\.(css|styl|less|sass|scss|png|jpg|svg|ttf|woff|woff2)$': 'jest-transform-stub', + }, + collectCoverage: true, + collectCoverageFrom: [ + 'src/main/webapp/**/*.{js,ts,vue}', + '!src/main/webapp/**/*.component.ts', + '!src/main/webapp/app/main.ts', + '!src/main/webapp/app/router/*.ts', + '!src/i18n.ts', + '!**/*.d.ts', + '!**/*AsyncModule.ts', + ], + coveragePathIgnorePatterns: [ + '/node_modules/', + '/src/test/javascript/', + '/src/main/webapp/app/router', + '/src/main/resources', + '.*.json', + ], + coverageReporters: ['html', 'json-summary', 'text-summary', 'lcov', 'clover'], + coverageDirectory: '/target/test-results/', + coverageThreshold: { + global: { + statements: 100, + branches: 100, + functions: 100, + lines: 100, + }, + }, +}; diff --git a/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.component.spec.ts.mustache b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.component.spec.ts.mustache new file mode 100644 index 00000000000..24083a723f8 --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.component.spec.ts.mustache @@ -0,0 +1,11 @@ + +import { mount } from '@vue/test-utils'; +import AppVue from '../../../../../../main/webapp/app/common/primary/app/App.vue'; + +describe('App', () => { + it('should display header text', () => { + const wrapper = mount(AppVue, { props: {} }); + + expect(wrapper.exists()).toBe(true); + }); +}); diff --git a/src/main/resources/generator/client/vite/vue3/tsconfig.json b/src/main/resources/generator/client/vite/vue3/tsconfig.json new file mode 100644 index 00000000000..aa86762fadc --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "esnext", + "useDefineForClassFields": true, + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "jsx": "preserve", + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "lib": ["esnext", "dom"], + "types": ["vite/client", "@types/jest"] + }, + "include": ["src/main/webapp/**/*.ts", "src/main/webapp/**/*.d.ts", "src/main/webapp/**/*.tsx", "src/main/webapp/**/*.vue"], + "exclude": ["./node_modules"] +} diff --git a/src/main/resources/generator/client/vite/vue3/vite.config.ts b/src/main/resources/generator/client/vite/vue3/vite.config.ts new file mode 100644 index 00000000000..93878b7ef7f --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue({ + template: { + compilerOptions: { + isCustomElement: tag => /^x-/.test(tag), + }, + }, + }), + ], + build: { + outDir: '../../../target/classes/static', + }, + root: 'src/main/webapp', +}); diff --git a/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache new file mode 100644 index 00000000000..e631ba7a757 --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache @@ -0,0 +1,3 @@ +import { Vue } from 'vue-class-component'; + +export default class AppComponent extends Vue {} diff --git a/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.vue.mustache b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.vue.mustache new file mode 100644 index 00000000000..0d25e0d4ee6 --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.vue.mustache @@ -0,0 +1,97 @@ + + + + + diff --git a/src/main/resources/generator/client/vite/vue3/webapp/app/env.d.ts.mustache b/src/main/resources/generator/client/vite/vue3/webapp/app/env.d.ts.mustache new file mode 100644 index 00000000000..a735ff23942 --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/webapp/app/env.d.ts.mustache @@ -0,0 +1,8 @@ +/// + +declare module '*.vue' { + import { DefineComponent } from 'vue'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/src/main/resources/generator/client/vite/vue3/webapp/app/main.ts.mustache b/src/main/resources/generator/client/vite/vue3/webapp/app/main.ts.mustache new file mode 100644 index 00000000000..e23d3f7af6e --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/webapp/app/main.ts.mustache @@ -0,0 +1,4 @@ +import { createApp } from 'vue'; +import App from './common/primary/app/App.vue'; + +createApp(App).mount('#app'); diff --git a/src/main/resources/generator/client/vite/vue3/webapp/content/images/JHipster-Lite-neon-green.png b/src/main/resources/generator/client/vite/vue3/webapp/content/images/JHipster-Lite-neon-green.png new file mode 100644 index 0000000000000000000000000000000000000000..a5f20afefe6e6ab96883e841315b5d7a8b8011f4 GIT binary patch literal 35772 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

S50Gj|RBg$)l} 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 Qod5s;07*qoM6N<$f;!F_5&!@I literal 0 HcmV?d00001 diff --git a/src/main/resources/generator/client/vite/vue3/webapp/content/images/logo.png b/src/main/resources/generator/client/vite/vue3/webapp/content/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d2503fc2a44b5053b0837ebea6e87a2d339a43 GIT binary patch literal 6849 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 + + + + + + Vite App + + +

+ + + diff --git a/src/main/resources/generator/dependencies/vite/vue3/package.json b/src/main/resources/generator/dependencies/vite/vue3/package.json new file mode 100644 index 00000000000..032473042e8 --- /dev/null +++ b/src/main/resources/generator/dependencies/vite/vue3/package.json @@ -0,0 +1,23 @@ +{ + "name": "jhlite-dependencies", + "version": "0.0.0", + "description": "JHipster Lite : used for Vite+Vue3 dependencies", + "license": "Apache-2.0", + "dependencies": { + "vue": "^3.2.25", + "vue-class-component": "^8.0.0-0", + "vue-router": "^4.0.0-0" + }, + "devDependencies": { + "@types/jest": "^27.4.0", + "@vitejs/plugin-vue": "^2.0.0", + "@vue/test-utils": "^2.0.0-rc.18", + "jest": "^26.6.3", + "jest-transform-stub": "^2.0.0", + "ts-jest": "^26.5.6", + "typescript": "^4.4.4", + "vite": "^2.7.2", + "vue-jest": "^5.0.0-alpha.10", + "vue-tsc": "^0.29.8" + } +} diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java new file mode 100644 index 00000000000..21739fab9ef --- /dev/null +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java @@ -0,0 +1,30 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.application; + +import static tech.jhipster.lite.TestUtils.tmpProjectWithPackageJson; +import static tech.jhipster.lite.generator.client.vite.vue.core.application.ViteVueAssert.*; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import tech.jhipster.lite.IntegrationTest; +import tech.jhipster.lite.generator.project.domain.Project; + +@IntegrationTest +class ViteVueApplicationServiceIT { + + @Autowired + ViteVueApplicationService viteVueApplicationService; + + @Test + void shouldAddViteVue() { + Project project = tmpProjectWithPackageJson(); + + viteVueApplicationService.addViteVue(project); + + assertDependency(project); + assertScripts(project); + + assertViteConfigFiles(project); + assertRootFiles(project); + assertAppFiles(project); + } +} diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java new file mode 100644 index 00000000000..000a68eaa6c --- /dev/null +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java @@ -0,0 +1,44 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.application; + +import static tech.jhipster.lite.TestUtils.assertFileContent; +import static tech.jhipster.lite.TestUtils.assertFileExist; +import static tech.jhipster.lite.common.domain.WordUtils.DQ; +import static tech.jhipster.lite.generator.project.domain.Constants.PACKAGE_JSON; + +import tech.jhipster.lite.generator.client.vite.vue.core.domain.ViteVue; +import tech.jhipster.lite.generator.project.domain.Project; + +public class ViteVueAssert { + + private ViteVueAssert() {} + + public static void assertDependency(Project project) { + ViteVue.dependencies().forEach(dependency -> assertFileContent(project, PACKAGE_JSON, DQ + dependency + DQ)); + ViteVue.devDependencies().forEach(devDependency -> assertFileContent(project, PACKAGE_JSON, DQ + devDependency + DQ)); + } + + public static void assertScripts(Project project) { + assertFileContent(project, PACKAGE_JSON, "\"build\": \"vue-tsc --noEmit && vite build --emptyOutDir\""); + assertFileContent(project, PACKAGE_JSON, "\"dev\": \"vite\""); + assertFileContent(project, PACKAGE_JSON, "\"preview\": \"vite preview\""); + assertFileContent(project, PACKAGE_JSON, "\"test\": \"jest src/test/javascript/spec\""); + } + + public static void assertViteConfigFiles(Project project) { + assertFileExist(project, "jest.config.js"); + assertFileExist(project, "tsconfig.json"); + assertFileExist(project, "vite.config.ts"); + } + + public static void assertRootFiles(Project project) { + assertFileExist(project, "src/main/webapp/index.html"); + assertFileExist(project, "src/main/webapp/app/env.d.ts"); + assertFileExist(project, "src/main/webapp/app/main.ts"); + } + + public static void assertAppFiles(Project project) { + assertFileExist(project, "src/main/webapp/app/common/primary/app/App.component.ts"); + assertFileExist(project, "src/main/webapp/app/common/primary/app/App.vue"); + assertFileExist(project, "src/test/javascript/spec/common/primary/app/App.component.spec.ts"); + } +} diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java new file mode 100644 index 00000000000..94fa2d9a693 --- /dev/null +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java @@ -0,0 +1,114 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.domain; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import static tech.jhipster.lite.TestUtils.tmpProject; +import static tech.jhipster.lite.TestUtils.tmpProjectWithPackageJson; + +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import tech.jhipster.lite.TestUtils; +import tech.jhipster.lite.UnitTest; +import tech.jhipster.lite.error.domain.GeneratorException; +import tech.jhipster.lite.generator.packagemanager.npm.domain.NpmService; +import tech.jhipster.lite.generator.project.domain.Project; +import tech.jhipster.lite.generator.project.domain.ProjectRepository; + +@UnitTest +@ExtendWith(MockitoExtension.class) +class ViteVueDomainServiceTest { + + @Mock + ProjectRepository projectRepository; + + @Mock + NpmService npmService; + + @InjectMocks + private ViteVueDomainService viteVueDomainService; + + @Test + void shouldAddViteVue() { + Project project = tmpProjectWithPackageJson(); + when(npmService.getVersion(anyString(), anyString())).thenReturn(Optional.of("0.0.0")); + + viteVueDomainService.addViteVue(project); + } + + @Test + void shouldAddDependencies() { + Project project = tmpProjectWithPackageJson(); + when(npmService.getVersion(anyString(), anyString())).thenReturn(Optional.of("0.0.0")); + + viteVueDomainService.addDependencies(project); + + verify(npmService, times(3)).addDependency(any(Project.class), anyString(), anyString()); + } + + @Test + void shouldNotAddDependencies() { + Project project = tmpProjectWithPackageJson(); + + assertThatThrownBy(() -> viteVueDomainService.addDependencies(project)).isExactlyInstanceOf(GeneratorException.class); + } + + @Test + void shouldAddDevDependencies() { + Project project = tmpProjectWithPackageJson(); + when(npmService.getVersion(anyString(), anyString())).thenReturn(Optional.of("0.0.0")); + + viteVueDomainService.addDevDependencies(project); + + verify(npmService, times(10)).addDevDependency(any(Project.class), anyString(), anyString()); + } + + @Test + void shouldNotAddDevDependencies() { + Project project = tmpProjectWithPackageJson(); + + assertThatThrownBy(() -> viteVueDomainService.addDevDependencies(project)).isExactlyInstanceOf(GeneratorException.class); + } + + @Test + void shouldAddScripts() { + Project project = tmpProjectWithPackageJson(); + + viteVueDomainService.addScripts(project); + + verify(npmService, times(4)).addScript(any(Project.class), anyString(), anyString()); + } + + @Test + void shouldAddViteConfigFiles() { + Project project = tmpProjectWithPackageJson(); + + viteVueDomainService.addViteConfigFiles(project); + + verify(projectRepository, times(3)).add(any(Project.class), anyString(), anyString()); + } + + @Test + void shouldAddRootFiles() { + Project project = tmpProject(); + + viteVueDomainService.addRootFiles(project); + + verify(projectRepository, times(3)).template(any(Project.class), anyString(), anyString(), anyString()); + verify(projectRepository, times(2)).add(any(Project.class), anyString(), anyString(), anyString()); + } + + @Test + void shouldAddAppFiles() { + Project project = tmpProject(); + + viteVueDomainService.addAppFiles(project); + + verify(projectRepository, times(3)).template(any(Project.class), anyString(), anyString(), anyString()); + } +} diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfigurationIT.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfigurationIT.java new file mode 100644 index 00000000000..f4b8ef41a29 --- /dev/null +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/config/ViteVueBeanConfigurationIT.java @@ -0,0 +1,21 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.infrastructure.config; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import tech.jhipster.lite.IntegrationTest; +import tech.jhipster.lite.generator.client.vite.vue.core.domain.ViteVueDomainService; + +@IntegrationTest +class ViteVueBeanConfigurationIT { + + @Autowired + ApplicationContext applicationContext; + + @Test + void shouldGetBean() { + assertThat(applicationContext.getBean("viteVueService")).isNotNull().isInstanceOf(ViteVueDomainService.class); + } +} diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java new file mode 100644 index 00000000000..89d9d61fc36 --- /dev/null +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java @@ -0,0 +1,48 @@ +package tech.jhipster.lite.generator.client.vite.vue.core.infrastructure.primary.rest; + +import static org.assertj.core.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static tech.jhipster.lite.TestUtils.readFileToObject; +import static tech.jhipster.lite.common.domain.FileUtils.tmpDirForTest; +import static tech.jhipster.lite.generator.client.vite.vue.core.application.ViteVueAssert.*; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import tech.jhipster.lite.IntegrationTest; +import tech.jhipster.lite.TestUtils; +import tech.jhipster.lite.generator.init.application.InitApplicationService; +import tech.jhipster.lite.generator.project.domain.Project; +import tech.jhipster.lite.generator.project.infrastructure.primary.dto.ProjectDTO; + +@IntegrationTest +@AutoConfigureMockMvc +class ViveVueResourceIT { + + @Autowired + MockMvc mockMvc; + + @Autowired + InitApplicationService initApplicationService; + + @Test + void shouldAddViteVue() throws Exception { + ProjectDTO projectDTO = readFileToObject("json/chips.json", ProjectDTO.class).folder(tmpDirForTest()); + Project project = ProjectDTO.toProject(projectDTO); + initApplicationService.init(project); + + mockMvc + .perform(post("/api/vite/vue").contentType(MediaType.APPLICATION_JSON).content(TestUtils.convertObjectToJsonBytes(projectDTO))) + .andExpect(status().isOk()); + + assertDependency(project); + assertScripts(project); + + assertViteConfigFiles(project); + assertRootFiles(project); + assertAppFiles(project); + } +} diff --git a/src/test/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainServiceTest.java b/src/test/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainServiceTest.java index 6e3695d49f5..fd12971ca05 100644 --- a/src/test/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainServiceTest.java +++ b/src/test/java/tech/jhipster/lite/generator/packagemanager/npm/domain/NpmDomainServiceTest.java @@ -79,36 +79,36 @@ void shouldPrettify() { class GetVersionInCommonTest { @Test - void shouldGetVersion() { + void shouldGetVersionInCommon() { assertThat(npmDomainService.getVersionInCommon("prettier-plugin-java")).isNotEmpty(); } @Test - void shouldNotGetVersionForNull() { + void shouldNotGetVersionInCommonForNull() { assertThatThrownBy(() -> npmDomainService.getVersionInCommon(null)) .isExactlyInstanceOf(MissingMandatoryValueException.class) .hasMessageContaining("name"); } @Test - void shouldNotGetVersionForBlank() { + void shouldNotGetVersionInCommonForBlank() { assertThatThrownBy(() -> npmDomainService.getVersionInCommon(" ")) .isExactlyInstanceOf(MissingMandatoryValueException.class) .hasMessageContaining("name"); } @Test - void shouldNotGetVersion() { + void shouldNotGetVersionInCommon() { assertThat(npmDomainService.getVersionInCommon("unknown")).isEmpty(); } @Test - void shouldNotGetVersionForDescription() { + void shouldNotGetVersionInCommonForDescription() { assertThat(npmDomainService.getVersionInCommon("description")).isEmpty(); } @Test - void shouldNotGetVersionForCloseBracket() { + void shouldNotGetVersionInCommonForCloseBracket() { assertThat(npmDomainService.getVersionInCommon("}")).isEmpty(); } } From 428f40986e3810fdd99be097f316bc386cbc1478 Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 17:53:58 +0100 Subject: [PATCH 02/11] CI: add Vite/Vue --- tests-ci/generate.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests-ci/generate.sh b/tests-ci/generate.sh index 553b801b1f9..6d34c44b929 100755 --- a/tests-ci/generate.sh +++ b/tests-ci/generate.sh @@ -48,6 +48,9 @@ if [[ $filename == 'full-default' ]]; then callApi "/api/servers/spring-boot/cache/ehcache/java-configuration" + callApi "/api/frontend-maven-plugin" + callApi "/api/vite/vue" + elif [[ $filename == 'tomcat-mysql-ehcachexml' ]]; then callApi "/api/projects/init" callApi "/api/build-tools/maven" From d39c1d59928efac84977a0d1fdee961985d8c93c Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 17:58:05 +0100 Subject: [PATCH 03/11] Fix code smells --- .../client/vite/vue/core/domain/ViteVueDomainServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java index 94fa2d9a693..b09a0abb591 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java @@ -38,7 +38,7 @@ void shouldAddViteVue() { Project project = tmpProjectWithPackageJson(); when(npmService.getVersion(anyString(), anyString())).thenReturn(Optional.of("0.0.0")); - viteVueDomainService.addViteVue(project); + assertThatCode(() -> viteVueDomainService.addViteVue(project)).doesNotThrowAnyException(); } @Test From ec161fdff90ec0e0abd75e47a3c96e0b74db804e Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 18:47:34 +0100 Subject: [PATCH 04/11] Vite/Vue3: refactoring --- .../client/vite/vue/core/domain/ViteVue.java | 8 ++++- .../vue/core/domain/ViteVueDomainService.java | 6 ++-- .../generator/client/vite/vue3/.eslintrc.js | 13 +++++++++ .../generator/client/vite/vue3/jest.config.js | 12 +------- ....spec.ts.mustache => App.spec.ts.mustache} | 12 ++++++-- .../dependencies/vite/vue3/package.json | 29 +++++++++++-------- .../vue/core/application/ViteVueAssert.java | 3 +- .../core/domain/ViteVueDomainServiceTest.java | 6 ++-- 8 files changed, 56 insertions(+), 33 deletions(-) create mode 100644 src/main/resources/generator/client/vite/vue3/.eslintrc.js rename src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/{App.component.spec.ts.mustache => App.spec.ts.mustache} (53%) diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java index a6b335e12bd..38e3538353c 100644 --- a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java @@ -7,14 +7,20 @@ public class ViteVue { private ViteVue() {} public static List dependencies() { - return List.of("vue", "vue-class-component", "vue-router"); + return List.of("vue", "vue-class-component"); } public static List devDependencies() { return List.of( + "@rushstack/eslint-patch", "@types/jest", + "@typescript-eslint/parser", "@vitejs/plugin-vue", + "@vue/eslint-config-typescript", "@vue/test-utils", + "eslint", + "eslint-config-prettier", + "eslint-plugin-vue", "jest", "jest-transform-stub", "ts-jest", diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java index 308c7538b55..fa4cd049689 100644 --- a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java @@ -76,7 +76,9 @@ public void addScripts(Project project) { } public void addViteConfigFiles(Project project) { - List.of("jest.config.js", "tsconfig.json", "vite.config.ts").forEach(file -> projectRepository.add(project, SOURCE, file)); + List + .of(".eslintrc.js", "jest.config.js", "tsconfig.json", "vite.config.ts") + .forEach(file -> projectRepository.add(project, SOURCE, file)); } public void addRootFiles(Project project) { @@ -110,7 +112,7 @@ public void addAppFiles(Project project) { projectRepository.template( project, getPath(SOURCE, "test/spec/common/primary/app"), - "App.component.spec.ts", + "App.spec.ts", "src/test/javascript/spec/common/primary/app" ); } diff --git a/src/main/resources/generator/client/vite/vue3/.eslintrc.js b/src/main/resources/generator/client/vite/vue3/.eslintrc.js new file mode 100644 index 00000000000..2f67f9b4e86 --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + env: { + node: true, + }, + extends: ['eslint:recommended', 'plugin:vue/vue3-recommended', '@vue/eslint-config-typescript', 'prettier'], + parserOptions: { + parser: '@typescript-eslint/parser', + }, + rules: { + quotes: ['error', 'single', { avoidEscape: true }], + '@typescript-eslint/no-unused-vars': ['error'], + }, +}; diff --git a/src/main/resources/generator/client/vite/vue3/jest.config.js b/src/main/resources/generator/client/vite/vue3/jest.config.js index dbd1da6a716..6580abe8dc6 100644 --- a/src/main/resources/generator/client/vite/vue3/jest.config.js +++ b/src/main/resources/generator/client/vite/vue3/jest.config.js @@ -1,4 +1,3 @@ -// jest.config.js module.exports = { moduleFileExtensions: ['js', 'ts', 'json', 'vue'], transform: { @@ -11,17 +10,7 @@ module.exports = { 'src/main/webapp/**/*.{js,ts,vue}', '!src/main/webapp/**/*.component.ts', '!src/main/webapp/app/main.ts', - '!src/main/webapp/app/router/*.ts', - '!src/i18n.ts', '!**/*.d.ts', - '!**/*AsyncModule.ts', - ], - coveragePathIgnorePatterns: [ - '/node_modules/', - '/src/test/javascript/', - '/src/main/webapp/app/router', - '/src/main/resources', - '.*.json', ], coverageReporters: ['html', 'json-summary', 'text-summary', 'lcov', 'clover'], coverageDirectory: '/target/test-results/', @@ -33,4 +22,5 @@ module.exports = { lines: 100, }, }, + modulePathIgnorePatterns: ['/src/main/resources/'], }; diff --git a/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.component.spec.ts.mustache b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache similarity index 53% rename from src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.component.spec.ts.mustache rename to src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache index 24083a723f8..7afda391beb 100644 --- a/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.component.spec.ts.mustache +++ b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache @@ -1,10 +1,16 @@ - +import { shallowMount } from '@vue/test-utils'; import { mount } from '@vue/test-utils'; import AppVue from '../../../../../../main/webapp/app/common/primary/app/App.vue'; +let wrapper: VueWrapper; + +const wrap = () => { + wrapper = shallowMount(AppVue); +}; + describe('App', () => { - it('should display header text', () => { - const wrapper = mount(AppVue, { props: {} }); + it('should exist', () => { + wrap(); expect(wrapper.exists()).toBe(true); }); diff --git a/src/main/resources/generator/dependencies/vite/vue3/package.json b/src/main/resources/generator/dependencies/vite/vue3/package.json index 032473042e8..f845ddd0d81 100644 --- a/src/main/resources/generator/dependencies/vite/vue3/package.json +++ b/src/main/resources/generator/dependencies/vite/vue3/package.json @@ -4,20 +4,25 @@ "description": "JHipster Lite : used for Vite+Vue3 dependencies", "license": "Apache-2.0", "dependencies": { - "vue": "^3.2.25", - "vue-class-component": "^8.0.0-0", - "vue-router": "^4.0.0-0" + "vue": "3.2.25", + "vue-class-component": "8.0.0-0" }, "devDependencies": { - "@types/jest": "^27.4.0", - "@vitejs/plugin-vue": "^2.0.0", - "@vue/test-utils": "^2.0.0-rc.18", - "jest": "^26.6.3", - "jest-transform-stub": "^2.0.0", - "ts-jest": "^26.5.6", - "typescript": "^4.4.4", + "@rushstack/eslint-patch": "1.1.0", + "@types/jest": "27.4.0", + "@typescript-eslint/parser": "5.11.0", + "@vitejs/plugin-vue": "2.0.0", + "@vue/eslint-config-typescript": "10.0.0", + "@vue/test-utils": "2.0.0-rc.18", + "eslint": "8.8.0", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-vue": "8.4.1", + "jest": "26.6.3", + "jest-transform-stub": "2.0.0", + "ts-jest": "26.5.6", + "typescript": "4.5.5", "vite": "^2.7.2", - "vue-jest": "^5.0.0-alpha.10", - "vue-tsc": "^0.29.8" + "vue-jest": "5.0.0-alpha.10", + "vue-tsc": "0.29.8" } } diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java index 000a68eaa6c..719cdc9632d 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java @@ -25,6 +25,7 @@ public static void assertScripts(Project project) { } public static void assertViteConfigFiles(Project project) { + assertFileExist(project, ".eslintrc.js"); assertFileExist(project, "jest.config.js"); assertFileExist(project, "tsconfig.json"); assertFileExist(project, "vite.config.ts"); @@ -39,6 +40,6 @@ public static void assertRootFiles(Project project) { public static void assertAppFiles(Project project) { assertFileExist(project, "src/main/webapp/app/common/primary/app/App.component.ts"); assertFileExist(project, "src/main/webapp/app/common/primary/app/App.vue"); - assertFileExist(project, "src/test/javascript/spec/common/primary/app/App.component.spec.ts"); + assertFileExist(project, "src/test/javascript/spec/common/primary/app/App.spec.ts"); } } diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java index b09a0abb591..59f147a4975 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java @@ -48,7 +48,7 @@ void shouldAddDependencies() { viteVueDomainService.addDependencies(project); - verify(npmService, times(3)).addDependency(any(Project.class), anyString(), anyString()); + verify(npmService, times(2)).addDependency(any(Project.class), anyString(), anyString()); } @Test @@ -65,7 +65,7 @@ void shouldAddDevDependencies() { viteVueDomainService.addDevDependencies(project); - verify(npmService, times(10)).addDevDependency(any(Project.class), anyString(), anyString()); + verify(npmService, times(16)).addDevDependency(any(Project.class), anyString(), anyString()); } @Test @@ -90,7 +90,7 @@ void shouldAddViteConfigFiles() { viteVueDomainService.addViteConfigFiles(project); - verify(projectRepository, times(3)).add(any(Project.class), anyString(), anyString()); + verify(projectRepository, times(4)).add(any(Project.class), anyString(), anyString()); } @Test From 7486d90e05b141ada6aac1c7a5f57bf3b2250ba0 Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 18:56:56 +0100 Subject: [PATCH 05/11] Fix tests in generated project with Vite/Vue3 --- .../vue3/test/spec/common/primary/app/App.spec.ts.mustache | 3 +-- .../resources/generator/dependencies/vite/vue3/package.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache index 7afda391beb..f22062f77ab 100644 --- a/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache +++ b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache @@ -1,5 +1,4 @@ -import { shallowMount } from '@vue/test-utils'; -import { mount } from '@vue/test-utils'; +import { shallowMount, VueWrapper } from '@vue/test-utils'; import AppVue from '../../../../../../main/webapp/app/common/primary/app/App.vue'; let wrapper: VueWrapper; diff --git a/src/main/resources/generator/dependencies/vite/vue3/package.json b/src/main/resources/generator/dependencies/vite/vue3/package.json index f845ddd0d81..8edf5ac6fb3 100644 --- a/src/main/resources/generator/dependencies/vite/vue3/package.json +++ b/src/main/resources/generator/dependencies/vite/vue3/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "dependencies": { "vue": "3.2.25", - "vue-class-component": "8.0.0-0" + "vue-class-component": "^8.0.0-0" }, "devDependencies": { "@rushstack/eslint-patch": "1.1.0", From 58b1de3da757690b18b39ce0f5d5fd5c9ac3b1d9 Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 21:22:18 +0100 Subject: [PATCH 06/11] Vite/Vue3: add index.ts --- .../client/vite/vue/core/domain/ViteVueDomainService.java | 6 ++++++ .../vue3/webapp/app/common/primary/app/index.ts.mustache | 4 ++++ .../client/vite/vue/core/application/ViteVueAssert.java | 1 + .../vite/vue/core/domain/ViteVueDomainServiceTest.java | 2 +- 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/index.ts.mustache diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java index fa4cd049689..1991e1c00f8 100644 --- a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java @@ -108,6 +108,12 @@ public void addAppFiles(Project project) { "App.vue", "src/main/webapp/app/common/primary/app" ); + projectRepository.template( + project, + getPath(SOURCE, "webapp/app/common/primary/app"), + "index.ts", + "src/main/webapp/app/common/primary/app" + ); projectRepository.template( project, diff --git a/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/index.ts.mustache b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/index.ts.mustache new file mode 100644 index 00000000000..56c48ccc20e --- /dev/null +++ b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/index.ts.mustache @@ -0,0 +1,4 @@ +import AppComponent from './App.component'; +import AppVue from './App.vue'; + +export { AppComponent, AppVue }; diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java index 719cdc9632d..fe32c744271 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java @@ -40,6 +40,7 @@ public static void assertRootFiles(Project project) { public static void assertAppFiles(Project project) { assertFileExist(project, "src/main/webapp/app/common/primary/app/App.component.ts"); assertFileExist(project, "src/main/webapp/app/common/primary/app/App.vue"); + assertFileExist(project, "src/main/webapp/app/common/primary/app/index.ts"); assertFileExist(project, "src/test/javascript/spec/common/primary/app/App.spec.ts"); } } diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java index 59f147a4975..0cdd7922627 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java @@ -109,6 +109,6 @@ void shouldAddAppFiles() { viteVueDomainService.addAppFiles(project); - verify(projectRepository, times(3)).template(any(Project.class), anyString(), anyString(), anyString()); + verify(projectRepository, times(4)).template(any(Project.class), anyString(), anyString(), anyString()); } } From c2f4a79f4e53057307b15afbfe0ddeeae486fa86 Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 21:28:27 +0100 Subject: [PATCH 07/11] Vite/Vue3: fix import --- .../vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache index f22062f77ab..65ec6acf2f8 100644 --- a/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache +++ b/src/main/resources/generator/client/vite/vue3/test/spec/common/primary/app/App.spec.ts.mustache @@ -1,5 +1,5 @@ import { shallowMount, VueWrapper } from '@vue/test-utils'; -import AppVue from '../../../../../../main/webapp/app/common/primary/app/App.vue'; +import { AppVue } from '../../../../../../main/webapp/app/common/primary/app'; let wrapper: VueWrapper; From cb7ce33c5260de4aa7d5a553cde241e94402185f Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 21:55:21 +0100 Subject: [PATCH 08/11] Vite/Vue3: refactoring to clean code smells --- .../vue/core/domain/ViteVueDomainService.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java index 1991e1c00f8..b666b9dd75d 100644 --- a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java @@ -96,24 +96,12 @@ public void addRootFiles(Project project) { } public void addAppFiles(Project project) { - projectRepository.template( - project, - getPath(SOURCE, "webapp/app/common/primary/app"), - "App.component.ts", - "src/main/webapp/app/common/primary/app" - ); - projectRepository.template( - project, - getPath(SOURCE, "webapp/app/common/primary/app"), - "App.vue", - "src/main/webapp/app/common/primary/app" - ); - projectRepository.template( - project, - getPath(SOURCE, "webapp/app/common/primary/app"), - "index.ts", - "src/main/webapp/app/common/primary/app" - ); + String sourcePrimary = getPath(SOURCE, "webapp/app/common/primary/app"); + String destinationPrimary = "src/main/webapp/app/common/primary/app"; + + projectRepository.template(project, sourcePrimary, "App.component.ts", destinationPrimary); + projectRepository.template(project, sourcePrimary, "App.vue", destinationPrimary); + projectRepository.template(project, sourcePrimary, "index.ts", destinationPrimary); projectRepository.template( project, From 065b15ac05a0fcc4ed7a671451c4dbe05807481d Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Fri, 11 Feb 2022 22:29:01 +0100 Subject: [PATCH 09/11] Vite/Vue3: rename AppComponent to App --- .../webapp/app/common/primary/app/App.component.ts.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache index e631ba7a757..64bbd636024 100644 --- a/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache +++ b/src/main/resources/generator/client/vite/vue3/webapp/app/common/primary/app/App.component.ts.mustache @@ -1,3 +1,3 @@ import { Vue } from 'vue-class-component'; -export default class AppComponent extends Vue {} +export default class App extends Vue {} From fa52ebb870084d71d1936ef02490b81961cbbd7d Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Sat, 12 Feb 2022 12:47:18 +0100 Subject: [PATCH 10/11] Vite/Vue3: add jest-sonar-reporter --- .../client/vite/vue/core/domain/ViteVue.java | 1 + .../vite/vue/core/domain/ViteVueDomainService.java | 14 ++++++++++++++ .../generator/client/vite/vue3/jest.config.js | 1 + .../generator/dependencies/vite/vue3/package.json | 1 + .../application/ViteVueApplicationServiceIT.java | 2 ++ .../vite/vue/core/application/ViteVueAssert.java | 9 +++++++++ .../vue/core/domain/ViteVueDomainServiceTest.java | 2 +- 7 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java index 38e3538353c..ed9fcf0eecc 100644 --- a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVue.java @@ -22,6 +22,7 @@ public static List devDependencies() { "eslint-config-prettier", "eslint-plugin-vue", "jest", + "jest-sonar-reporter", "jest-transform-stub", "ts-jest", "typescript", diff --git a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java index b666b9dd75d..584ddbf53d2 100644 --- a/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java +++ b/src/main/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainService.java @@ -1,6 +1,7 @@ package tech.jhipster.lite.generator.client.vite.vue.core.domain; import static tech.jhipster.lite.common.domain.FileUtils.getPath; +import static tech.jhipster.lite.generator.project.domain.Constants.PACKAGE_JSON; import java.util.List; import java.util.Map; @@ -26,6 +27,7 @@ public void addViteVue(Project project) { addDependencies(project); addDevDependencies(project); addScripts(project); + addJestSonar(project); addViteConfigFiles(project); @@ -110,4 +112,16 @@ public void addAppFiles(Project project) { "src/test/javascript/spec/common/primary/app" ); } + + public void addJestSonar(Project project) { + String oldText = "\"cacheDirectories\": \\["; + String newText = + """ + "jestSonar": \\{ + "reportPath": "target/test-results/jest", + "reportFile": "TESTS-results-sonar.xml" + \\}, + "cacheDirectories": \\["""; + projectRepository.replaceText(project, "", PACKAGE_JSON, oldText, newText); + } } diff --git a/src/main/resources/generator/client/vite/vue3/jest.config.js b/src/main/resources/generator/client/vite/vue3/jest.config.js index 6580abe8dc6..af1a85ab68e 100644 --- a/src/main/resources/generator/client/vite/vue3/jest.config.js +++ b/src/main/resources/generator/client/vite/vue3/jest.config.js @@ -23,4 +23,5 @@ module.exports = { }, }, modulePathIgnorePatterns: ['/src/main/resources/'], + testResultsProcessor: 'jest-sonar-reporter', }; diff --git a/src/main/resources/generator/dependencies/vite/vue3/package.json b/src/main/resources/generator/dependencies/vite/vue3/package.json index 8edf5ac6fb3..06089d68afa 100644 --- a/src/main/resources/generator/dependencies/vite/vue3/package.json +++ b/src/main/resources/generator/dependencies/vite/vue3/package.json @@ -18,6 +18,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-vue": "8.4.1", "jest": "26.6.3", + "jest-sonar-reporter": "2.0.0", "jest-transform-stub": "2.0.0", "ts-jest": "26.5.6", "typescript": "4.5.5", diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java index 21739fab9ef..a4643ec2bdf 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueApplicationServiceIT.java @@ -26,5 +26,7 @@ void shouldAddViteVue() { assertViteConfigFiles(project); assertRootFiles(project); assertAppFiles(project); + + assertJestSonar(project); } } diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java index fe32c744271..3148db02006 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/application/ViteVueAssert.java @@ -5,6 +5,7 @@ import static tech.jhipster.lite.common.domain.WordUtils.DQ; import static tech.jhipster.lite.generator.project.domain.Constants.PACKAGE_JSON; +import java.util.List; import tech.jhipster.lite.generator.client.vite.vue.core.domain.ViteVue; import tech.jhipster.lite.generator.project.domain.Project; @@ -43,4 +44,12 @@ public static void assertAppFiles(Project project) { assertFileExist(project, "src/main/webapp/app/common/primary/app/index.ts"); assertFileExist(project, "src/test/javascript/spec/common/primary/app/App.spec.ts"); } + + public static void assertJestSonar(Project project) { + assertFileContent( + project, + PACKAGE_JSON, + List.of("\"jestSonar\": {", "\"reportPath\": \"target/test-results/jest\",", "\"reportFile\": \"TESTS-results-sonar.xml\"", "}") + ); + } } diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java index 0cdd7922627..4ec505a8f9f 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java @@ -65,7 +65,7 @@ void shouldAddDevDependencies() { viteVueDomainService.addDevDependencies(project); - verify(npmService, times(16)).addDevDependency(any(Project.class), anyString(), anyString()); + verify(npmService, times(17)).addDevDependency(any(Project.class), anyString(), anyString()); } @Test From f464aa1e4b0c728d53774674fe9a2d279f015f7e Mon Sep 17 00:00:00 2001 From: Pascal Grimaud Date: Sat, 12 Feb 2022 12:54:31 +0100 Subject: [PATCH 11/11] Vite/Vue3: clean import --- .../client/vite/vue/core/domain/ViteVueDomainServiceTest.java | 1 - .../vue/core/infrastructure/primary/rest/ViveVueResourceIT.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java index 4ec505a8f9f..0fcfa64585d 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/domain/ViteVueDomainServiceTest.java @@ -13,7 +13,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import tech.jhipster.lite.TestUtils; import tech.jhipster.lite.UnitTest; import tech.jhipster.lite.error.domain.GeneratorException; import tech.jhipster.lite.generator.packagemanager.npm.domain.NpmService; diff --git a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java index 89d9d61fc36..7bbe1f3d132 100644 --- a/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java +++ b/src/test/java/tech/jhipster/lite/generator/client/vite/vue/core/infrastructure/primary/rest/ViveVueResourceIT.java @@ -1,6 +1,5 @@ package tech.jhipster.lite.generator.client.vite.vue.core.infrastructure.primary.rest; -import static org.assertj.core.api.Assertions.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static tech.jhipster.lite.TestUtils.readFileToObject;