diff --git a/Jenkinsfile b/Jenkinsfile index 8377babe503d988ed3b9a0176e984a541601821e..13a8ec027e00c9f9177d830ffe6a467074fd33c6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -78,11 +78,11 @@ pipeline { } } } - post { - always{ - junit testResults: 'alfa-client/test-report.xml', skipPublishingChecks: true - } - } + // post { + // always{ + // junit testResults: 'alfa-client/test-report.xml', skipPublishingChecks: true + // } + // } } stage('Build and push client container') { diff --git a/alfa-client/apps/alfa-e2e/Jenkinsfile b/alfa-client/Jenkinsfile.e2e similarity index 69% rename from alfa-client/apps/alfa-e2e/Jenkinsfile rename to alfa-client/Jenkinsfile.e2e index 4d9192728334431b0219afb7c8ac6372cf9bdaab..9b55f66a5146de14b99bdb88d22821c906c2d13e 100644 --- a/alfa-client/apps/alfa-e2e/Jenkinsfile +++ b/alfa-client/Jenkinsfile.e2e @@ -23,7 +23,10 @@ pipeline { FAILED_PARALLEL_STAGE = " " EA_BEZEICHNER = generateBezeichner("e2e-ea") MAIN_BEZEICHNER = generateBezeichner("e2e-main") + ADMIN_BEZEICHNER = generateBezeichner("e2e-admin") SH_SUCCESS_STATUS_CODE = 0 + KEYCLOAK_CLIENT_ADMIN_APP = "admin" + KEYCLOAK_CLIENT_ALFA_APP = "alfa" } options { @@ -98,6 +101,7 @@ pipeline { script { FAILED_STAGE = env.STAGE_NAME + initEnvAdminDefaultVersions() initEnvAlfaDefaultVersions() initEnvVorgangManagerDefaultVersions() initEnvUserManagerDefaultVersions() @@ -122,6 +126,12 @@ pipeline { string(name: "AlfaImageTag", defaultValue: env.ALFA_IMAGE_TAG, trim: true), string(name: "AlfaHelmChartVersion", defaultValue: env.ALFA_HELM_CHART_VERSION, trim: true), string(name: "AlfaHelmRepoUrl", defaultValue: env.ALFA_HELM_REPO_URL, trim: true), + string(name: "AdministrationImageTag", defaultValue: env.ADMINISTRATION_IMAGE_TAG, trim: true), + string(name: "AdministrationHelmChartVersion", defaultValue: env.ADMINISTRATION_HELM_CHART_VERSION, trim: true), + string(name: "AdministrationHelmRepoUrl", defaultValue: env.ADMINISTRATION_HELM_REPO_URL, trim: true), + string(name: "AdminClientImageTag", defaultValue: env.ADMIN_CLIENT_IMAGE_TAG, trim: true), + string(name: "AdminClientHelmChartVersion", defaultValue: env.ADMIN_CLIENT_HELM_CHART_VERSION, trim: true), + string(name: "AdminClientHelmRepoUrl", defaultValue: env.ADMIN_CLIENT_HELM_REPO_URL, trim: true), string(name: "VorgangManagerImageTag", defaultValue: env.VORGANG_MANAGER_IMAGE_TAG, trim: true), string(name: "VorgangManagerHelmChartVersion", defaultValue: env.VORGANG_MANAGER_HELM_CHART_VERSION, trim: true), string(name: "VorgangManagerHelmRepoUrl", defaultValue: env.VORGANG_MANAGER_HELM_REPO_URL, trim: true), @@ -165,10 +175,9 @@ pipeline { checkoutGitopsE2eBranch() - deleteOzgCloudStack([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER]) + deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER]) - generateMainNamespaceYaml() - generateEaNamespaceYaml() + generateNamespaces() pushGitopsRepo() } @@ -176,7 +185,7 @@ pipeline { post { failure { script { - deleteOzgCloudStack([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER]) + deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER]) } } } @@ -211,13 +220,14 @@ pipeline { script { FAILED_STAGE = env.STAGE_NAME - waitForOzgCloudStackRollout([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER]) + waitForAdminRollout(env.ADMIN_BEZEICHNER) + waitForAlfaRollout([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER]) } } post { failure { script { - deleteOzgCloudStack([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER]) + deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER]) } } } @@ -236,14 +246,14 @@ pipeline { } } -// stage('Run E2E-Tests') { -// when { -// expression { !SKIP_RUN } -// } -// failFast false + stage('Run E2E-Tests') { + when { + expression { !SKIP_RUN } + } + failFast false -// parallel { - stage('E2E-EA') { + parallel { + stage('E2E-Alfa-EA') { when { expression { !SKIP_RUN } } @@ -254,7 +264,7 @@ pipeline { Integer mongoDbPort = forwardMongoDbPort(generateNamespace(bezeichner)) - runTests(bezeichner, 'einheitlicher-ansprechpartner', mongoDbPort, env.STAGE_NAME) + runTests(bezeichner, 'alfa-e2e', 'einheitlicher-ansprechpartner', env.KEYCLOAK_CLIENT_ALFA_APP, mongoDbPort, env.STAGE_NAME) stopForwardMongoDbPort(generateNamespace(bezeichner)) } @@ -268,13 +278,13 @@ pipeline { } always { script { - publishE2ETestResult("einheitlicher-ansprechpartner", "Alfa E2E-Tests EA") + publishAlfaE2ETestResult("einheitlicher-ansprechpartner", "Alfa E2E-Tests EA") } } } } - stage('E2E-Main') { + stage('E2E-Alfa-Main') { when { expression { !SKIP_RUN } } @@ -285,7 +295,7 @@ pipeline { Integer mongoDbPort = forwardMongoDbPort(generateNamespace(bezeichner)) - runTests(bezeichner, 'main-tests', mongoDbPort, env.STAGE_NAME) + runTests(bezeichner, 'alfa-e2e', 'main-tests', env.KEYCLOAK_CLIENT_ALFA_APP, mongoDbPort, env.STAGE_NAME) stopForwardMongoDbPort(generateNamespace(bezeichner)) } @@ -299,13 +309,43 @@ pipeline { } always { script { - publishE2ETestResult("main-tests", "Alfa E2E-Tests main") + publishAlfaE2ETestResult("main-tests", "Alfa E2E-Tests main") } } } } -// } -// } + stage('E2E-Admin-Main') { + when { + expression { !SKIP_RUN } + } + steps { + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + script { + String bezeichner = env.ADMIN_BEZEICHNER + + Integer mongoDbPort = forwardMongoDbPort(generateNamespace(bezeichner)) + + runTests(bezeichner, 'admin-e2e', 'main-tests', env.KEYCLOAK_CLIENT_ADMIN_APP, mongoDbPort, env.STAGE_NAME) + + stopForwardMongoDbPort(generateNamespace(bezeichner)) + } + } + } + post { + failure { + script { + FAILED_PARALLEL_STAGE += "${env.STAGE_NAME} " + } + } + always { + script { + publishAdminE2ETestResult() + } + } + } + } + } + } stage('Delete E2E Namespaces') { when { @@ -315,7 +355,7 @@ pipeline { script { FAILED_STAGE = env.STAGE_NAME - deleteOzgCloudStack([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER]) + deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER]) } } } @@ -376,21 +416,6 @@ String getHelmChartVersion(Map applicationValues) { return applicationValues.helm.version } -Void initEnvAlfaDefaultVersions() { - if (isMasterBranch() || isReleaseBranch()) { - values = getApplicationValues('alfa') - - env.ALFA_IMAGE_TAG = getImageTag(values) - env.ALFA_HELM_CHART_VERSION = getHelmChartVersion(values) - } - else { - env.ALFA_IMAGE_TAG = getFeatureBranchImageTag() - env.ALFA_HELM_CHART_VERSION = getFeatureBranchHelmChartVersion() - } - - env.ALFA_HELM_REPO_URL = getHelmRepoUrl() -} - Boolean isMasterBranch() { return env.BRANCH_NAME == 'master' } @@ -417,6 +442,33 @@ String getRootPomVersion() { return rootPom.version } +Void initEnvAdminDefaultVersions() { + def values = getApplicationValues('administration') + env.ADMINISTRATION_IMAGE_TAG = getImageTag(values) + env.ADMINISTRATION_HELM_CHART_VERSION = getHelmChartVersion(values) + env.ADMINISTRATION_HELM_REPO_URL = getHelmRepoUrl() + + values = getApplicationValues('admin-client') + env.ADMIN_CLIENT_IMAGE_TAG = getImageTag(values) + env.ADMIN_CLIENT_HELM_CHART_VERSION = getHelmChartVersion(values) + env.ADMIN_CLIENT_HELM_REPO_URL = getHelmRepoUrl() +} + +Void initEnvAlfaDefaultVersions() { + if (isMasterBranch() || isReleaseBranch()) { + values = getApplicationValues('alfa') + + env.ALFA_IMAGE_TAG = getImageTag(values) + env.ALFA_HELM_CHART_VERSION = getHelmChartVersion(values) + } + else { + env.ALFA_IMAGE_TAG = getFeatureBranchImageTag() + env.ALFA_HELM_CHART_VERSION = getFeatureBranchHelmChartVersion() + } + + env.ALFA_HELM_REPO_URL = getHelmRepoUrl() +} + Void initEnvVorgangManagerDefaultVersions() { def values = getApplicationValues('vorgang-manager') @@ -437,6 +489,12 @@ Void initEnvUserVersions(userVersions) { env.ALFA_IMAGE_TAG = userVersions.AlfaImageTag env.ALFA_HELM_CHART_VERSION = userVersions.AlfaHelmChartVersion env.ALFA_HELM_REPO_URL = userVersions.AlfaHelmRepoUrl + env.ADMINISTRATION_IMAGE_TAG = userVersions.AdministrationImageTag + env.ADMINISTRATION_HELM_CHART_VERSION = userVersions.AdministrationHelmChartVersion + env.ADMINISTRATION_HELM_REPO_URL = userVersions.AdministrationHelmRepoUrl + env.ADMIN_CLIENT_IMAGE_TAG = userVersions.AdminClientImageTag + env.ADMIN_CLIENT_HELM_CHART_VERSION = userVersions.AdminClientHelmChartVersion + env.ADMIN_CLIENT_HELM_REPO_URL = userVersions.AdminClientHelmRepoUrl env.VORGANG_MANAGER_IMAGE_TAG = userVersions.VorgangManagerImageTag env.VORGANG_MANAGER_HELM_CHART_VERSION = userVersions.VorgangManagerHelmChartVersion env.VORGANG_MANAGER_HELM_REPO_URL = userVersions.VorgangManagerHelmRepoUrl @@ -468,15 +526,43 @@ Void checkoutGitopsE2eBranch() { } } -Void generateEaNamespaceYaml() { - generateNamespaceYaml(env.EA_BEZEICHNER, "by-ea-dev.yaml"); +Void generateNamespaces() { + def y1 = generateAdminNamespaceYaml() + def y2 = generateEaNamespaceYaml() + def y3 = generateMainNamespaceYaml() + + dir("gitops") { + sh "git add ${y1} ${y2} ${y3}" + sh "git commit -m 'add e2e namespaces for testrun'" + } + +} + +Void generateAdminNamespaceYaml() { + def bezeichner = env.ADMIN_BEZEICHNER + def envValues + dir("alfa-client/apps/admin-e2e/") { + envValues = readYaml file: "src/fixtures/argocd/by-admin-dev.yaml"; + + envValues.ozgcloud.bezeichner = bezeichner + envValues.administration.put("image", ['tag': env.ADMINISTRATION_IMAGE_TAG]) + envValues.administration.put("helm", ['version': env.ADMINISTRATION_HELM_CHART_VERSION, 'repoUrl': env.ADMINISTRATION_HELM_REPO_URL]) + + envValues.admin_client.put("image", ['tag': env.ADMIN_CLIENT_IMAGE_TAG]) + envValues.admin_client.put("helm", ['version': env.ADMIN_CLIENT_HELM_CHART_VERSION, 'repoUrl': env.ADMIN_CLIENT_HELM_REPO_URL]) + } + return writeYamlToGitOps(bezeichner, envValues); +} + +String generateEaNamespaceYaml() { + return generateNamespaceYaml(env.EA_BEZEICHNER, "by-ea-dev.yaml"); } -Void generateMainNamespaceYaml() { - generateNamespaceYaml(env.MAIN_BEZEICHNER, "by-main-dev.yaml"); +String generateMainNamespaceYaml() { + return generateNamespaceYaml(env.MAIN_BEZEICHNER, "by-main-dev.yaml"); } -Void generateNamespaceYaml(String bezeichner, String valuesPathSuffix) { +String generateNamespaceYaml(String bezeichner, String valuesPathSuffix) { def envValues dir('alfa-client/apps/alfa-e2e/') { envValues = readYaml file: "src/fixtures/argocd/" + valuesPathSuffix; @@ -491,18 +577,20 @@ Void generateNamespaceYaml(String bezeichner, String valuesPathSuffix) { envValues.user_manager.put("image", ['tag': env.USER_MANAGER_IMAGE_TAG]) envValues.user_manager.put("helm", ['version': env.USER_MANAGER_HELM_CHART_VERSION, 'repoUrl': env.USER_MANAGER_HELM_REPO_URL]) } + return writeYamlToGitOps(bezeichner, envValues); +} - writeYaml file: "gitops/dev/namespace/namespaces/by-${bezeichner}-dev.yaml", data: envValues, overwrite: true +String writeYamlToGitOps(String bezeichner, Object envValues){ + def bezeichnerYaml = "dev/namespace/namespaces/by-${bezeichner}-dev.yaml" - sh "cat gitops/dev/namespace/namespaces/by-${bezeichner}-dev.yaml" + writeYaml file: "gitops/${bezeichnerYaml}", data: envValues, overwrite: true - dir("gitops") { - sh "git add dev/namespace/namespaces/by-${bezeichner}-dev.yaml" - sh "git commit -m 'add e2e by-${bezeichner}-dev'" - } + sh "cat gitops/${bezeichnerYaml}" + + return bezeichnerYaml; } -Void deleteOzgCloudStack(ozgCloudBezeichner) { +Void deleteNamespaces(ozgCloudBezeichner) { for(bezeichner in ozgCloudBezeichner) { if (hasNamespaceFile(bezeichner)) { removeNamespaceFile(bezeichner) @@ -536,13 +624,19 @@ Void waitForDeletion(String bezeichner) { } } -Void waitForOzgCloudStackRollout(ozgCloudBezeichner) { +Void waitForAlfaRollout(ozgCloudBezeichner) { for(bezeichner in ozgCloudBezeichner) { - waitForRollout(bezeichner) + waitForAlfaRollout(bezeichner) } } -Void waitForRollout(String bezeichner) { +Void waitForAdminRollout(String bezeichner) { + waitForAlfaRollout([bezeichner]) + waitForHealthyApplication(bezeichner, 'administration') + waitForHealthyApplication(bezeichner, 'admin-client') +} + +Void waitForAlfaRollout(String bezeichner) { waitForHealthyApplication(bezeichner, 'application') waitForHealthyApplication(bezeichner, 'vorgang-manager') waitForHealthyApplication(bezeichner, 'user-manager') @@ -580,32 +674,41 @@ Void waitForHealthyStatus(String bezeichner, String application) { sh "kubectl wait --for=jsonpath='{.status.health.status}'=Healthy applications/by-${bezeichner}-dev-${application} -n argocd --timeout=900s" } -Void publishE2ETestResult(String reportFolder, String reportName) { - publishHTML ( - target: [ - allowMissing: false, - alwaysLinkToLastBuild: false, - keepAll: true, - reportDir: "alfa-client/apps/alfa-e2e/reports/${reportFolder}", - reportFiles: 'report.html', - reportName: reportName - ] - ) +Void publishAlfaE2ETestResult(String appVariant, String reportName) { + publishE2ETestResult("alfa-e2e", appVariant, reportName); } -String runTests(String bezeichner, String reportFolder, Integer dbPort, String stageName) { - def config = generateCypressConfig(bezeichner, reportFolder, dbPort) +Void publishAdminE2ETestResult() { + publishE2ETestResult("admin-e2e", "main-tests", "Admin E2E-Tests main"); +} - try { - dir('alfa-client'){ - sh "npm run cypress:version" - sh "apps/alfa-e2e/run-tests.sh ${reportFolder} ${config}" - } - } catch (Exception e) { - printNpmDebugLog() +Void publishE2ETestResult(String appName, String appVariant, String reportName) { + def reportDir = "alfa-client/apps/"+appName+"/reports/"+appVariant; - error("Fehler in Stage ${stageName}") + publishHTML ( + target: [ + allowMissing: false, + alwaysLinkToLastBuild: false, + keepAll: true, + reportDir: reportDir, + reportFiles: 'report.html', + reportName: reportName + ] + ) +} + +String runTests(String bezeichner, String appName, String appVariant, String keycloakClientName, Integer dbPort, String stageName) { + def config = generateCypressConfig(bezeichner, appName, appVariant, keycloakClientName, dbPort) + try { + dir('alfa-client'){ + sh "npm run cypress:version" + sh "apps/run-tests.sh ${appName} ${appVariant} ${config}" } + } catch (Exception e) { + printNpmDebugLog() + + error("Fehler in Stage ${stageName}") + } } Void printNpmDebugLog() { @@ -636,39 +739,49 @@ String cutBranchNameForKeycloakRealm(String branchName, String stageName) { return branchName.take(cutBranchNamePosition) } -String generateCypressConfig(String bezeichner, String testFolder, Integer dbPort) { - def namespace = generateNamespace(bezeichner) - def configName = "cypress-ci-"+testFolder+".json" +String generateCypressConfig(String bezeichner, String appName, String appVariant, String keycloakClientName, Integer dbPort) { + def namespace = generateNamespace(bezeichner) + def configName = "cypress-ci-"+appVariant+".json" - dir('alfa-client/apps/alfa-e2e/'){ - def config = readJSON file: 'cypress-ci.json' + dir("alfa-client/apps/${appName}/"){ + def config = readJSON file: 'cypress-ci.json' - def vorgangManagerDatabaseSecret = getVorgangManagerDatabaseSecret(namespace); - def decodedPassword = decodeString(vorgangManagerDatabaseSecret.password); - def parsablePassword = makePasswordUrlConform(decodedPassword); + def vorgangManagerDatabaseSecret = getVorgangManagerDatabaseSecret(namespace); + def decodedPassword = decodeString(vorgangManagerDatabaseSecret.password); + def parsablePassword = makePasswordUrlConform(decodedPassword); - config.baseUrl = "https://${bezeichner}.${env.CLUSTER_BASE_URL}" as String - config.env.dbUrl = "mongodb://${decodeString(vorgangManagerDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true&socketTimeoutMS=30000&heartbeatFrequencyMS=10000" as String - config.env.keycloakUrl = "https://${env.SSO_URL}/" as String - config.env.keycloakRealm = namespace as String - config.videosFolder = "./reports/${testFolder}/videos" as String - config.screenshotsFolder = "./reports/${testFolder}/screenshots" as String - config.reporterOptions.reportDir = "./reports/${testFolder}/mochawesome-report" as String + config.baseUrl = "https://${generateUrlBezeichner(bezeichner, appName)}.${env.CLUSTER_BASE_URL}" as String + config.env.dbUrl = "mongodb://${decodeString(vorgangManagerDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true&socketTimeoutMS=30000&heartbeatFrequencyMS=10000" as String + config.env.keycloakUrl = "https://${env.SSO_URL}/" as String + config.env.keycloakRealm = namespace as String + config.env.keycloakClient = keycloakClientName as String + config.videosFolder = "./reports/${appVariant}/videos" as String + config.screenshotsFolder = "./reports/${appVariant}/screenshots" as String + config.reporterOptions.reportDir = "./reports/${appVariant}/mochawesome-report" as String - config.specPattern = "src/e2e/${testFolder}/**/*.cy.{js,jsx,ts,tsx}" as String + config.specPattern = "src/e2e/${appVariant}/**/*.cy.{js,jsx,ts,tsx}" as String - config.env.put("search", getElasticsearchEnv(namespace)) - config.env.put("userManager", getUserManagerEnv(namespace, dbPort)) - config.env.put("smocker", getSmockerEnv(namespace)) + config.env.put("search", getElasticsearchEnv(namespace)) + config.env.put("userManager", getUserManagerEnv(namespace, dbPort)) + config.env.put("smocker", getSmockerEnv(namespace)) - writeJSON file: configName, json: config + writeJSON file: configName, json: config - sh "cat ${configName}" - } + sh "cat ${configName}" + } - return "cypress-ci-"+testFolder+".config.ts" + return "cypress-ci-"+appVariant+".config.ts" } +String generateUrlBezeichner(String bezeichner, String appName){ + if(appName == 'admin-e2e'){ + return "${bezeichner}-admin"; + } + return bezeichner; +} + + + String makePasswordUrlConform(String password) { return sh (script: "printf %s ${password} | jq -sRr @uri", returnStdout: true); } @@ -793,7 +906,7 @@ String generateNamespace(String bezeichner) { } String decodeString(String encoded) { - return sh (script: "echo -n ${encoded} | base64 --decode", returnStdout: true) + return sh (script: "echo -n ${encoded} | base64 --decode", returnStdout: true) } Map getElasticsearchSecret(String namespace) { diff --git a/alfa-client/apps/alfa-e2e/Jenkinsfile-static b/alfa-client/Jenkinsfile.e2e.static similarity index 99% rename from alfa-client/apps/alfa-e2e/Jenkinsfile-static rename to alfa-client/Jenkinsfile.e2e.static index 49a92dd823cb02a53f072fa3a55f21facc3c6527..2e499f9abbaf8c2918628b462f2f79a056df66d6 100644 --- a/alfa-client/apps/alfa-e2e/Jenkinsfile-static +++ b/alfa-client/Jenkinsfile.e2e.static @@ -16,7 +16,7 @@ pipeline { environment { BLUE_OCEAN_URL = "https://jenkins.ozg-sh.de/job/E2E%20Tests/job/${env.BRANCH_NAME}/${env.BUILD_NUMBER}/" BUNDESLAND = 'by' - ENVIRONMENT = 'dev' + ENVIRONMENT = 'dev' SSO_URL = 'sso.dev.by.ozg-cloud.de' CLUSTER_BASE_URL = 'dev.by.ozg-cloud.de' FAILED_STAGE = '' @@ -552,7 +552,7 @@ String generateNamespace(String bezeichner) { } String decodeString(String encoded) { - return sh(script: "echo -n ${encoded} | base64 --decode", returnStdout: true) + return sh(script: "echo -n ${encoded} | base64 --decode", returnStdout: true) } Map getElasticsearchSecret(String namespace) { diff --git a/alfa-client/apps/admin-e2e/README.md b/alfa-client/apps/admin-e2e/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cc1f1c46a2e2c7c034d661d9595990bbd606b370 --- /dev/null +++ b/alfa-client/apps/admin-e2e/README.md @@ -0,0 +1,9 @@ +## Allgemein + +Dieses Teilprojekt enthält die End-2-End Tests für die Admin-Anwendung. + +Der Aufbau ist analog der [E2E-Tests für Alfa](../alfa-e2e/README.md). + +Bei Ausführung mit Jenkins im Cluster wird das [Jenkinsfile.e2e](../../Jenkinsfile.e2e) verwendet. + +Bei lokaler Ausführung die hier abgelegte [docker-compose.yml](docker-compose.yml) verwenden. diff --git a/alfa-client/apps/admin-e2e/cypress-ci-main-tests.config.ts b/alfa-client/apps/admin-e2e/cypress-ci-main-tests.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..debc5e3e19864e0afbd6b3376b24aec1be23d3c4 --- /dev/null +++ b/alfa-client/apps/admin-e2e/cypress-ci-main-tests.config.ts @@ -0,0 +1,25 @@ +import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset'; +import { defineConfig } from 'cypress'; + +//Cypress config is generated by JenkinsFile +const cypressConfig = require('./cypress-ci-main-tests.json'); +const cypressEvents = require('./src/support/cypress-tasks.ts'); + +export default defineConfig({ + e2e: { + ...nxE2EPreset(__dirname), + ...cypressConfig, + setupNodeEvents(on, config) { + return cypressEvents(on, config); + }, + }, + retries: { + experimentalStrategy: 'detect-flake-and-pass-on-threshold', + experimentalOptions: { + maxRetries: 2, + passesRequired: 1, + }, + openMode: true, + runMode: true, + }, +}); diff --git a/alfa-client/apps/admin-e2e/cypress-ci.json b/alfa-client/apps/admin-e2e/cypress-ci.json new file mode 100644 index 0000000000000000000000000000000000000000..ca9f95c11d0896e1559b198fe1521e9f5c95b423 --- /dev/null +++ b/alfa-client/apps/admin-e2e/cypress-ci.json @@ -0,0 +1,22 @@ +{ + "env": { + "database": "vorgang-manager-database", + "keycloakClient": "admin" + }, + "fileServerFolder": ".", + "fixturesFolder": "./src/fixtures", + "modifyObstructiveCode": false, + "video": true, + "chromeWebSecurity": false, + "reporter": "../../node_modules/cypress-mochawesome-reporter", + "defaultCommandTimeout": 10000, + "supportFile": "./src/support/e2e.ts", + "testIsolation": false, + "reporterOptions": { + "html": false, + "json": true, + "quite": true, + "reportFilename": "report", + "overwrite": false + } +} diff --git a/alfa-client/apps/admin-e2e/cypress.config.json b/alfa-client/apps/admin-e2e/cypress.config.json index 136d40d4f8a967df5e477627ba6c81b37d58080d..7bab4470a97551fc92eee55d557dfd983d382fe3 100644 --- a/alfa-client/apps/admin-e2e/cypress.config.json +++ b/alfa-client/apps/admin-e2e/cypress.config.json @@ -19,7 +19,7 @@ "reporterOptions": { "html": false, "json": true, - "reportDir": "./reports/mochawesome-report", + "reportDir": "./reports/main-tests/mochawesome-report", "reportFilename": "report", "overwrite": true } diff --git a/alfa-client/apps/admin-e2e/src/e2e/app/0-login-logout.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/app/0-login-logout.cy.ts similarity index 68% rename from alfa-client/apps/admin-e2e/src/e2e/app/0-login-logout.cy.ts rename to alfa-client/apps/admin-e2e/src/e2e/main-tests/app/0-login-logout.cy.ts index fc19b08d96e0a250e5fa64f323c0e44095458ab1..cbee0dcfa84f4ca39bc865b67cebb499194b7920 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/app/0-login-logout.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/app/0-login-logout.cy.ts @@ -1,8 +1,8 @@ -import { HeaderE2EComponent } from '../../page-objects/header.po'; -import { MainPage } from '../../page-objects/main.po'; -import { reload } from '../../support/cypress-helper'; -import { exist } from '../../support/cypress.util'; -import { loginByUi } from '../../support/user-util'; +import { HeaderE2EComponent } from '../../../page-objects/header.po'; +import { MainPage } from '../../../page-objects/main.po'; +import { reload } from '../../../support/cypress-helper'; +import { exist } from '../../../support/cypress.util'; +import { loginByUi } from '../../../support/user-util'; describe('Login and Logout', () => { const mainPage: MainPage = new MainPage(); diff --git a/alfa-client/apps/admin-e2e/src/e2e/app/buildinfo.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/app/buildinfo.cy.ts similarity index 57% rename from alfa-client/apps/admin-e2e/src/e2e/app/buildinfo.cy.ts rename to alfa-client/apps/admin-e2e/src/e2e/main-tests/app/buildinfo.cy.ts index 18e94c6e8ac38641fb5555c55e5ae4f17b0e33a7..aa93008afd7b2a61765af4cfc88fc712fe691dec 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/app/buildinfo.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/app/buildinfo.cy.ts @@ -1,8 +1,8 @@ -import { BuildInfoE2EComponent } from '../../components/buildinfo/buildinfo.e2e.component'; -import { HeaderE2EComponent } from '../../page-objects/header.po'; -import { MainPage } from '../../page-objects/main.po'; -import { exist } from '../../support/cypress.util'; -import { loginAsAriane } from '../../support/user-util'; +import { BuildInfoE2EComponent } from '../../../components/buildinfo/buildinfo.e2e.component'; +import { HeaderE2EComponent } from '../../../page-objects/header.po'; +import { MainPage } from '../../../page-objects/main.po'; +import { exist } from '../../../support/cypress.util'; +import { loginAsAriane } from '../../../support/user-util'; describe('Buildinfo', () => { const mainPage: MainPage = new MainPage(); diff --git a/alfa-client/apps/admin-e2e/src/e2e/benutzer_rollen/benutzer_rollen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts similarity index 82% rename from alfa-client/apps/admin-e2e/src/e2e/benutzer_rollen/benutzer_rollen.cy.ts rename to alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts index 45b22031b07206ebfc1b7a5ce62c288c99f62e95..d1c52395edf3286ee593f72c2f5cc5c752a7de4b 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/benutzer_rollen/benutzer_rollen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts @@ -1,7 +1,7 @@ -import { BenutzerE2EComponent } from '../../components/benutzer/benutzer.e2e.component'; -import { MainPage } from '../../page-objects/main.po'; -import { exist } from '../../support/cypress.util'; -import { loginAsAriane } from '../../support/user-util'; +import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po'; +import { exist } from 'apps/admin-e2e/src/support/cypress.util'; +import { loginAsAriane } from 'apps/admin-e2e/src/support/user-util'; +import { BenutzerE2EComponent } from 'apps/admin-e2e/src/components/benutzer/benutzer.e2e.component'; const mainPage: MainPage = new MainPage(); const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); diff --git a/alfa-client/apps/admin-e2e/src/e2e/postfach/signatur.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/postfach/signatur.cy.ts similarity index 67% rename from alfa-client/apps/admin-e2e/src/e2e/postfach/signatur.cy.ts rename to alfa-client/apps/admin-e2e/src/e2e/main-tests/postfach/signatur.cy.ts index 1a9d07d9cd02a699d33ad6f24e3df8fb94d24d89..884093ac7af1a52e3485bd8133a431515fa3f095 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/postfach/signatur.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/postfach/signatur.cy.ts @@ -1,8 +1,8 @@ -import { PostfachE2EComponent } from '../../components/postfach/postfach.e2e.component'; -import { HeaderE2EComponent } from '../../page-objects/header.po'; -import { MainPage, waitForSpinnerToDisappear } from '../../page-objects/main.po'; -import { exist } from '../../support/cypress.util'; -import { loginAsAriane } from '../../support/user-util'; +import { PostfachE2EComponent } from '../../../components/postfach/postfach.e2e.component'; +import { HeaderE2EComponent } from '../../../page-objects/header.po'; +import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; +import { exist } from '../../../support/cypress.util'; +import { loginAsAriane } from '../../../support/user-util'; describe('Signatur', () => { const mainPage: MainPage = new MainPage(); diff --git a/alfa-client/apps/admin-e2e/src/fixtures/argocd/by-admin-dev.yaml b/alfa-client/apps/admin-e2e/src/fixtures/argocd/by-admin-dev.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f307b1c0c8ff3aaf6d33b000ec7500a4e55ae065 --- /dev/null +++ b/alfa-client/apps/admin-e2e/src/fixtures/argocd/by-admin-dev.yaml @@ -0,0 +1,37 @@ +ozgcloud: + bezeichner: admine2emain + environment: dev +e2eTest: true +project: + destinations: + - namespace: "*" + server: https://kubernetes.default.svc + +administration: + enabled: true + +admin_client: + enabled: true + ingress: + use_staging_cert: true + +alfa: + env: + overrideSpringProfiles: "oc,e2e,dev" + ingress: + use_staging_cert: true + +vorgang_manager: + env: + overrideSpringProfiles: "oc,e2e,dev" + +user_manager: + ozgcloud: + usersync: + onstart: false + period: disabled + ingress: + use_staging_cert: true + +smocker: + enabled: false \ No newline at end of file diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts index 818658ddd7ad7ec20ab2e1e48086d50628123f3e..ea31dd492f621f9e87b99f9ebee7d26f26014677 100644 --- a/alfa-client/apps/admin/src/app/app.component.spec.ts +++ b/alfa-client/apps/admin/src/app/app.component.spec.ts @@ -1,5 +1,5 @@ import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared'; -import { BuildInfoComponent } from '@alfa-client/common-lib'; +import { BuildInfoComponent } from '@alfa-client/common'; import { HasLinkPipe, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; import { Mock, diff --git a/alfa-client/apps/admin/src/app/app.module.ts b/alfa-client/apps/admin/src/app/app.module.ts index 05eb114fe4b711dbcf2f993a4f7cddf41e0d2d11..8758a051d1c6f6ef28a9ec6be4620cb3eb3dec5e 100644 --- a/alfa-client/apps/admin/src/app/app.module.ts +++ b/alfa-client/apps/admin/src/app/app.module.ts @@ -1,6 +1,6 @@ import { AdminSettingsModule } from '@admin-client/admin-settings'; import { ApiRootModule } from '@alfa-client/api-root-shared'; -import { BuildInfoComponent } from '@alfa-client/common-lib'; +import { BuildInfoComponent } from '@alfa-client/common'; import { EnvironmentModule } from '@alfa-client/environment-shared'; import { TechSharedModule } from '@alfa-client/tech-shared'; import { CommonModule, registerLocaleData } from '@angular/common'; diff --git a/alfa-client/apps/alfa-e2e/README.md b/alfa-client/apps/alfa-e2e/README.md index e54e685002d7a1d2eddf7ddbcf68214f741a5f0f..e8fd2fba20457053b9a043e3cdbadfa696692c5e 100644 --- a/alfa-client/apps/alfa-e2e/README.md +++ b/alfa-client/apps/alfa-e2e/README.md @@ -1,14 +1,39 @@ -# E2E - ## Allgemein -Die E2E Tests werden in parallen Jenkins Stages in seperaten Namespaces durchgeführt. -`einheitlicher-ansprechpartener` -> 'EA'-Umgebung -`main-tests` -> 'Dev'-Umgebung --> es dürfen nur die der Umgebung entsprechenden User für die Tests genutzt werden. -(siehe dokumentation/Anwender/Standardbenutzer.md) +Dieses Teilprojekt bündelt: +* Die End-2-End Tests für die Alfa-Anwendung +* Das Setup für verschiedene Konfigurationsvarianten + +Die Konfigurationsvarianten sind: +* Ausführungsart und Umgebung + * lokal + * Im Cluster (dynamisch deployed) + * Im Cluster (statisch) +* Fachlich unterschiedliche Testgruppen + * `einheitlicher-ansprechpartner` -> 'EA'-Umgebung + * `main-tests` -> 'Dev'-Umgebung + +Dabei benötigen die Testgruppen (sogenannte "App-Varianten", siehe Verzeichnis [src/e2e](src/e2e)) jeweils eine eigene Umgebung in der gewählten Ausführungsart. + +## Lokale Ausführung +Siehe [Entwicklungsdokumentation](https://git.ozg-sh.de/ozgcloud-doc/dokumentation/src/branch/master/Entwicklungsumgebung#e2e-tests). + +## Jenkins/Cluster Ausführung +Die E2E Tests werden in parallelen Jenkins Stages in separaten Namespaces durchgeführt. -## Gegen ein bestehenden Namespace testen +Es dürfen nur die der Umgebung entsprechenden User für die Tests genutzt werden (siehe [Standardbenutzer](https://git.ozg-sh.de/ozgcloud-doc/dokumentation/src/branch/master/Anwender/Standardbenutzer.md)). + +Es gibt 2 Jenkinsfiles: +* E2E ("main") - Das derzeit benutzte Hauptprofil. Namespaces werden hier neu aufgebaut. +* Static - Profil, wenn eine bestehender Namespace (ggf. in ganz bestimmter Konfiguration) getestet werden soll. + +### Dynamisch deployed +* siehe: [Jenkinsfile.e2e](../../Jenkinsfile.e2e) +* Im Verzeichnis 'src/fixtures/argocd' liegen die Kubernetes Templates (ArgoCD-Namespace-Helm-Charts) +* Neue Umgebungen werden im Repo [gitops im Branch "e2e"](https://git.ozg-sh.de/ozgcloud-devops/gitops/src/branch/e2e) eingetragen. + +### Gegen ein bestehenden Namespace testen +Siehe: [Jenkinsfile.e2e](../../Jenkinsfile.e2e.static) Beispiel Namespace: sh-mastere2emain-dev @@ -20,10 +45,11 @@ Beispiel Namespace: sh-mastere2emain-dev 4. Cypress mit entsprechender config starten: `npm run cypress:open -- --config-file cypress-master-main.json` -## docker-compose +## Dev Hinweise ### -march Architektur In die `.env` Datei eintragen: - - USER_MANAGER_DOCKER_IMAGE=march-snapshot-latest \ No newline at end of file +``` +USER_MANAGER_DOCKER_IMAGE=march-snapshot-latest +``` \ No newline at end of file diff --git a/alfa-client/apps/alfa-e2e/cypress.config.json b/alfa-client/apps/alfa-e2e/cypress.config.json index 3a604c010deb694376105420fb38252bc1029efe..10160a6f1a1a224da71dcdc3671381d635fed8b9 100644 --- a/alfa-client/apps/alfa-e2e/cypress.config.json +++ b/alfa-client/apps/alfa-e2e/cypress.config.json @@ -34,7 +34,7 @@ "reporterOptions": { "html": false, "json": true, - "reportDir": "./reports/mochawesome-report", + "reportDir": "./reports/main-tests/mochawesome-report", "reportFilename": "report", "overwrite": true } diff --git a/alfa-client/apps/alfa-e2e/run-tests.sh b/alfa-client/apps/alfa-e2e/run-tests.sh deleted file mode 100755 index 6b7f5098a285a5417326b611f500c686fcd1f08f..0000000000000000000000000000000000000000 --- a/alfa-client/apps/alfa-e2e/run-tests.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -export NO_COLOR=1 - -REPORT_FOLDER=$1 -CONFIG_FILE="${2:-cypress.config.ts}" - -echo "Run E2E for $REPORT_FOLDER with configuration apps/alfa-e2e/$CONFIG_FILE..." - -rm -rf apps/alfa-e2e/reports/${REPORT_FOLDER} - -npx cypress run --project apps/alfa-e2e --spec apps/alfa-e2e/src/e2e/${REPORT_FOLDER} --config-file $CONFIG_FILE - -TEST_RESULT=$? - -if [ -d "apps/alfa-e2e/reports/${REPORT_FOLDER}/mochawesome-report/.jsons" ]; then - mv apps/alfa-e2e/reports/${REPORT_FOLDER}/mochawesome-report/.jsons apps/alfa-e2e/reports/${REPORT_FOLDER}/mochawesome-report/jsons - npx mochawesome-merge apps/alfa-e2e/reports/${REPORT_FOLDER}/mochawesome-report/**/*.json > apps/alfa-e2e/reports/${REPORT_FOLDER}/report.json - # Workaround: mochawesome's "screenshotsFolder" value is not added in the generated HTML file. Add "screenshots" to image paths. - sed --in-place --regexp-extended 's/"([^"]*\.png)/"screenshots\1/' apps/alfa-e2e/reports/${REPORT_FOLDER}/report.json - npx marge apps/alfa-e2e/reports/${REPORT_FOLDER}/report.json -f report -o apps/alfa-e2e/reports/${REPORT_FOLDER} -else - echo "ERROR: Reports do not exist at apps/alfa-e2e/reports/${REPORT_FOLDER}/mochawesome-report/.jsons" -fi - -exit $TEST_RESULT \ No newline at end of file diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts index 2ba36a2468e8cf3c13653885f476e7d047da1d59..859b21033851742a71a4a6daf921ee0fc5b9f12e 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts @@ -80,78 +80,78 @@ describe('User Settings', () => { }); describe('click on neuer Vorgang toggle', () => { - it('should have initial unchecked toggle', () => { - isNotChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); + it('should have initial checked toggle', () => { + isChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); }); it('should switch toggle status', () => { userSettings.getEmailBenachrichtigungForNewVorgang().getToggle().click(); - isChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); }); it('should be loaded after page reload', () => { reload(); userSettings.getRoot().click(); - isChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); }); }); describe('click on neue nachricht antragsteller toggle', () => { - it('should have initial unchecked toggle', () => { - isNotChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); + it('should have initial checked toggle', () => { + isChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); }); it('should switch toggle status', () => { userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle().click(); - isChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); }); it('should be loaded after page reload', () => { reload(); userSettings.getRoot().click(); - isChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); }); }); describe('click on vorgang mir zugewiesen toggle', () => { - it('should have initial unchecked toggle', () => { - isNotChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); + it('should have initial checked toggle', () => { + isChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); }); it('should switch toggle status', () => { userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle().click(); - isChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); }); it('should be loaded after page reload', () => { reload(); userSettings.getRoot().click(); - isChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); }); }); describe('click on faellige wiedervorlage toggle', () => { - it('should have initial unchecked toggle', () => { - isNotChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); + it('should have initial checked toggle', () => { + isChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); }); it('should switch toggle status', () => { userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle().click(); - isChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); }); it('should be loaded after page reload', () => { reload(); userSettings.getRoot().click(); - isChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml index 58e0660e0f37cba42cc6ab8ed1b0c824d5e3902d..d045ee9c6f58b1df37fc04f1260c0b75178a4bb1 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml +++ b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml @@ -7,6 +7,14 @@ project: - namespace: '*' server: https://kubernetes.default.svc +administration: + enabled: true + +admin_client: + enabled: true + ingress: + use_staging_cert: true + alfa: env: overrideSpringProfiles: 'oc,ea,e2e,dev' diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml index ed32236cd2d0a9b3c211c4c54b7a726e212cf500..1bcb0012c4aa771b977d6834c8d9825b20cb4f11 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml +++ b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml @@ -6,11 +6,10 @@ project: destinations: - namespace: "*" server: https://kubernetes.default.svc + alfa: env: overrideSpringProfiles: "oc,e2e,dev" - customList: - ozgcloud_feature_bescheid-wizard: "true" ingress: use_staging_cert: true ozgcloud: diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json index 814e061ad715953b45342a9fde9a3dab6f7b17c3..7e02474fe5f97aaa5a7f7161d6476fc04462c046 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json @@ -10,7 +10,7 @@ "firstName": "Ariane", "fullName": "Ariane Admin", "lastName": "Admin", - "email": "ariane-admin@ozg-sh.de", + "email": "ariane-admin@e2e-ozg-sh.de", "lastSyncTimestamp": 1663585874687, "organisationsEinheitIds": [], "roles": ["ADMIN_ADMIN", "VERWALTUNG_USER"], diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_dorothea.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_dorothea.json index 8c8a317b75a24343340390cc1e8bd722e3948d93..2c87f7fdacacfdbde9da6c1283556a12e73add3e 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_dorothea.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_dorothea.json @@ -10,7 +10,7 @@ "firstName": "Dorothea", "fullName": "Dorothea Doe", "lastName": "Doe", - "email": "dorothea.doe@ozg-sh.de", + "email": "dorothea.doe@e2e-ozg-sh.de", "lastSyncTimestamp": 1663585874687, "organisationsEinheitIds": ["9030229", "10363455", "248240886"], "roles": ["VERWALTUNG_USER"], diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_emil.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_emil.json index 2919f1b73675781d3f0b6b508a689f8587553216..f84b1f7bd73abde3e5a0eafe096e7e989f7f0f6f 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_emil.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_emil.json @@ -10,7 +10,7 @@ "firstName": "Emil", "fullName": "Emil Ansprechpartner", "lastName": "Ansprechpartner", - "email": "emil.ansprechpartner@ozg-sh.de", + "email": "emil.ansprechpartner@e2e-ozg-sh.de", "lastSyncTimestamp": 1663585874687, "organisationsEinheitIds": [], "roles": ["EINHEITLICHER_ANSPRECHPARTNER"], diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json index 9bc95422fb2c6d99c6ea408d684e73b13fde1e08..6c0d961bd99a0f997153343106a8ca82b473d82c 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json @@ -10,7 +10,7 @@ "firstName": "Peter", "fullName": "Peter von der Post", "lastName": "von der Post", - "email": "peter.von.der.post@ozg-sh.de", + "email": "peter.von.der.post@e2e-ozg-sh.de", "lastSyncTimestamp": 1663585874687, "organisationsEinheitIds": [], "roles": ["VERWALTUNG_POSTSTELLE"], diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_sabine.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_sabine.json index afc4c87496649073054973b8e9944a7740fe4d49..f6be06faa2fb4f03c6e7981399201d000f263dc9 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_sabine.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_sabine.json @@ -10,7 +10,7 @@ "firstName": "Sabine", "fullName": "Sabine Sach", "lastName": "Sach", - "email": "sabine.sach@ozg-sh.de", + "email": "sabine.sach@e2e-ozg-sh.de", "lastSyncTimestamp": 1663585874687, "organisationsEinheitIds": ["248240886"], "roles": ["VERWALTUNG_USER"], diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json index 013cd251b1f3d1e20c6b775c61c1f0a11471b50f..466f127e1c848d66409fc46da37b0482933d4eba 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json @@ -10,7 +10,7 @@ "firstName": "Zelda", "fullName": "Zelda Zusammen", "lastName": "Zusammen", - "email": "zelda-z@ozg-sh.de", + "email": "zelda-z@e2e-ozg-sh.de", "lastSyncTimestamp": 1663585874687, "organisationsEinheitIds": ["9797773", "9093371"], "roles": ["VERWALTUNG_USER"], diff --git a/alfa-client/apps/alfa-e2e/src/support/cypress-tasks.ts b/alfa-client/apps/alfa-e2e/src/support/cypress-tasks.ts index 827b7b3d31d21f7c991796b5256302ae28354466..a1926d26e2cd70c9e92fc9fc40271a782ac16859 100644 --- a/alfa-client/apps/alfa-e2e/src/support/cypress-tasks.ts +++ b/alfa-client/apps/alfa-e2e/src/support/cypress-tasks.ts @@ -1,5 +1,6 @@ import { readdir, remove } from 'fs-extra'; import { Db, Long, MongoClient, ObjectId } from 'mongodb'; + const fs = require('fs'); const decompress = require('decompress'); @@ -212,9 +213,7 @@ function createDate(field) { } function parseVorgangAttachedItemData(vorgangAttachedItems) { - vorgangAttachedItems.forEach((vorgangAttachedItem) => - parseVorgangAttachedItem(vorgangAttachedItem), - ); + vorgangAttachedItems.forEach((vorgangAttachedItem) => parseVorgangAttachedItem(vorgangAttachedItem)); return vorgangAttachedItems; } @@ -247,7 +246,21 @@ function insertIntoDatabase(config, collection, data) { } function insertIntoUserManagerDatabase(config, collection, data) { - insert(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collection, data); + insertWithoutDrop(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collection, data); +} + +function insertWithoutDrop(databaseUrl, databaseName, collection, data) { + MongoClient.connect(databaseUrl, (error, connection) => { + console.log(`connect to ${databaseName} database with ${databaseUrl}`); + if (!error) { + console.log('success'); + const db: Db = connection.db(databaseName); + + db.createCollection(collection, (error) => handleCreateCollection(db, connection, collection, data, error)); + } else { + console.error('Error: ', error); + } + }); } function insert(databaseUrl, databaseName, collection, data) { @@ -258,9 +271,7 @@ function insert(databaseUrl, databaseName, collection, data) { const db: Db = connection.db(databaseName); db.collection(collection).drop(() => { - db.createCollection(collection, (error) => - handleCreateCollection(db, connection, collection, data, error), - ); + db.createCollection(collection, (error) => handleCreateCollection(db, connection, collection, data, error)); }); } else { console.error('Error: ', error); diff --git a/alfa-client/apps/alfa/src/app/app.component.spec.ts b/alfa-client/apps/alfa/src/app/app.component.spec.ts index f20f5bc5f23bd56572d7b5d78c8117f5f83341e6..8824da3647969782aab53105663e18e44105a01a 100644 --- a/alfa-client/apps/alfa/src/app/app.component.spec.ts +++ b/alfa-client/apps/alfa/src/app/app.component.spec.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { ApiRootFacade } from '@alfa-client/api-root-shared'; -import { BuildInfoComponent } from '@alfa-client/common-lib'; +import { BuildInfoComponent } from '@alfa-client/common'; import { ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; import { createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; diff --git a/alfa-client/apps/alfa/src/app/app.module.ts b/alfa-client/apps/alfa/src/app/app.module.ts index d9adaece899487f8d6d584d8ea20ff641578c7e9..8e35a1cb4ea3831bccdbb142b68d8844cb53582d 100644 --- a/alfa-client/apps/alfa/src/app/app.module.ts +++ b/alfa-client/apps/alfa/src/app/app.module.ts @@ -23,7 +23,7 @@ */ import { ApiRootModule } from '@alfa-client/api-root-shared'; import { AppSharedModule } from '@alfa-client/app-shared'; -import { BuildInfoComponent } from '@alfa-client/common-lib'; +import { BuildInfoComponent } from '@alfa-client/common'; import { EnvironmentModule } from '@alfa-client/environment-shared'; import { HintSharedModule } from '@alfa-client/hint-shared'; import { NavigationModule } from '@alfa-client/navigation'; diff --git a/alfa-client/apps/run-tests.sh b/alfa-client/apps/run-tests.sh new file mode 100755 index 0000000000000000000000000000000000000000..eadee4428cd9620ad5c66da8d44a0459f1e42c58 --- /dev/null +++ b/alfa-client/apps/run-tests.sh @@ -0,0 +1,44 @@ +#!/bin/bash +export NO_COLOR=1 + +if [ $# -eq 0 ]; then + >&2 echo "This script is for Jenkins Execution of E2E-Tests" + >&2 echo "Example: ./run-tests.sh admin-e2e main-tests cypress.config.ts" + exit 1 +fi +APP_NAME="${1:-alfa-e2e}" +APP_VARIATION="${2:-main-tests}" +CONFIG_FILE="${3:-cypress.config.ts}" + +if [ -z $APP_NAME ]; then echo "App Folder not set" && exit 1; fi +if [ -z $APP_VARIATION ]; then echo "Variation Name not set" && exit 1; fi +if [ -z $CONFIG_FILE ]; then echo "Config File not set" && exit 1; fi + +SCRIPT_DIR="$(dirname "$0")" +BASE_PATH=${SCRIPT_DIR}/${APP_NAME} +SPEC_GROUP=${BASE_PATH}/src/e2e/${APP_VARIATION} +COMMAND="npx cypress run --project ${BASE_PATH} --spec ${SPEC_GROUP} --config-file ${CONFIG_FILE}" +REPORT_PATH=${BASE_PATH}/reports/${APP_VARIATION} + +echo "Run E2E for ${APP_NAME} with command: '$COMMAND'" + +rm -rf ${REPORT_PATH} + +eval $COMMAND +TEST_RESULT=$? + +if [ -d "${REPORT_PATH}" ]; then + MOCHA_REPORT_PATH=${REPORT_PATH}/mochawesome-report/ + MOCHA_REPORT_JSONS=${MOCHA_REPORT_PATH}.jsons + MOCHA_REPORT_FILE=${MOCHA_REPORT_PATH}report.json + + mv ${MOCHA_REPORT_JSONS} ${MOCHA_REPORT_PATH}/jsons + npx mochawesome-merge ${MOCHA_REPORT_PATH}**/*.json > ${MOCHA_REPORT_FILE} + # Workaround: mochawesome's "screenshotsFolder" value is not added in the generated HTML file. Add "screenshots" to image paths. + sed --in-place --regexp-extended 's/"([^"]*\.png)/"screenshots\1/' ${MOCHA_REPORT_FILE} + npx marge ${MOCHA_REPORT_FILE} -f report -o ${REPORT_PATH} +else + echo "ERROR: Reports do not exist at ${REPORT_PATH}" +fi + +exit $TEST_RESULT \ No newline at end of file diff --git a/alfa-client/libs/common-lib/.eslintrc.json b/alfa-client/libs/common/.eslintrc.json similarity index 100% rename from alfa-client/libs/common-lib/.eslintrc.json rename to alfa-client/libs/common/.eslintrc.json diff --git a/alfa-client/libs/common-lib/README.md b/alfa-client/libs/common/README.md similarity index 54% rename from alfa-client/libs/common-lib/README.md rename to alfa-client/libs/common/README.md index f56ea72f2a6f3e405f04f090fb7d2670a8913dcf..dd1a64c606a0de52c0f174b2239362bd9ea5a717 100644 --- a/alfa-client/libs/common-lib/README.md +++ b/alfa-client/libs/common/README.md @@ -1,7 +1,7 @@ -# common-lib +# common This library was generated with [Nx](https://nx.dev). ## Running unit tests -Run `nx test common-lib` to execute the unit tests. +Run `nx test common` to execute the unit tests. diff --git a/alfa-client/libs/common-lib/jest.config.ts b/alfa-client/libs/common/jest.config.ts similarity index 87% rename from alfa-client/libs/common-lib/jest.config.ts rename to alfa-client/libs/common/jest.config.ts index 5126e9a7275f05132fe089f9560dd29e561a732e..cc270a9a40a45f60ca8b165405c609383b92ebc6 100644 --- a/alfa-client/libs/common-lib/jest.config.ts +++ b/alfa-client/libs/common/jest.config.ts @@ -1,8 +1,8 @@ export default { - displayName: 'common-lib', + displayName: 'common', preset: '../../jest.preset.js', setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], - coverageDirectory: '../../coverage/libs/common-lib', + coverageDirectory: '../../coverage/libs/common', transform: { '^.+\\.(ts|mjs|js|html)$': [ 'jest-preset-angular', diff --git a/alfa-client/libs/common-lib/project.json b/alfa-client/libs/common/project.json similarity index 74% rename from alfa-client/libs/common-lib/project.json rename to alfa-client/libs/common/project.json index 8a477e97d512ef3eac6cfe8ff272ed0754b5991c..75ea075f15e55a052c0cc5e7f02564ae3748e547 100644 --- a/alfa-client/libs/common-lib/project.json +++ b/alfa-client/libs/common/project.json @@ -1,7 +1,7 @@ { - "name": "common-lib", + "name": "common", "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/common-lib/src", + "sourceRoot": "libs/common/src", "prefix": "lib", "projectType": "library", "tags": [], @@ -10,7 +10,7 @@ "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "jestConfig": "libs/common-lib/jest.config.ts" + "jestConfig": "libs/common/jest.config.ts" } }, "lint": { diff --git a/alfa-client/libs/common-lib/src/index.ts b/alfa-client/libs/common/src/index.ts similarity index 100% rename from alfa-client/libs/common-lib/src/index.ts rename to alfa-client/libs/common/src/index.ts diff --git a/alfa-client/libs/common-lib/src/lib/build-info/build-info.component.html b/alfa-client/libs/common/src/lib/build-info/build-info.component.html similarity index 100% rename from alfa-client/libs/common-lib/src/lib/build-info/build-info.component.html rename to alfa-client/libs/common/src/lib/build-info/build-info.component.html diff --git a/alfa-client/libs/common-lib/src/lib/build-info/build-info.component.scss b/alfa-client/libs/common/src/lib/build-info/build-info.component.scss similarity index 100% rename from alfa-client/libs/common-lib/src/lib/build-info/build-info.component.scss rename to alfa-client/libs/common/src/lib/build-info/build-info.component.scss diff --git a/alfa-client/libs/common-lib/src/lib/build-info/build-info.component.spec.ts b/alfa-client/libs/common/src/lib/build-info/build-info.component.spec.ts similarity index 100% rename from alfa-client/libs/common-lib/src/lib/build-info/build-info.component.spec.ts rename to alfa-client/libs/common/src/lib/build-info/build-info.component.spec.ts diff --git a/alfa-client/libs/common-lib/src/lib/build-info/build-info.component.ts b/alfa-client/libs/common/src/lib/build-info/build-info.component.ts similarity index 100% rename from alfa-client/libs/common-lib/src/lib/build-info/build-info.component.ts rename to alfa-client/libs/common/src/lib/build-info/build-info.component.ts diff --git a/alfa-client/libs/common-lib/src/test-setup.ts b/alfa-client/libs/common/src/test-setup.ts similarity index 100% rename from alfa-client/libs/common-lib/src/test-setup.ts rename to alfa-client/libs/common/src/test-setup.ts diff --git a/alfa-client/libs/common-lib/tailwind.config.js b/alfa-client/libs/common/tailwind.config.js similarity index 100% rename from alfa-client/libs/common-lib/tailwind.config.js rename to alfa-client/libs/common/tailwind.config.js diff --git a/alfa-client/libs/common-lib/tsconfig.json b/alfa-client/libs/common/tsconfig.json similarity index 100% rename from alfa-client/libs/common-lib/tsconfig.json rename to alfa-client/libs/common/tsconfig.json diff --git a/alfa-client/libs/common-lib/tsconfig.lib.json b/alfa-client/libs/common/tsconfig.lib.json similarity index 100% rename from alfa-client/libs/common-lib/tsconfig.lib.json rename to alfa-client/libs/common/tsconfig.lib.json diff --git a/alfa-client/libs/common-lib/tsconfig.lib.prod.json b/alfa-client/libs/common/tsconfig.lib.prod.json similarity index 100% rename from alfa-client/libs/common-lib/tsconfig.lib.prod.json rename to alfa-client/libs/common/tsconfig.lib.prod.json diff --git a/alfa-client/libs/common-lib/tsconfig.spec.json b/alfa-client/libs/common/tsconfig.spec.json similarity index 100% rename from alfa-client/libs/common-lib/tsconfig.spec.json rename to alfa-client/libs/common/tsconfig.spec.json diff --git a/alfa-client/libs/design-system/src/lib/list/list-item/list-item.component.spec.ts b/alfa-client/libs/design-system/src/lib/list/list-item/list-item.component.spec.ts index 0aef13978f11b606c0be0d6e0dbb6c297e8149e0..04eeffba56f4a341b60d448202972da84925cf35 100644 --- a/alfa-client/libs/design-system/src/lib/list/list-item/list-item.component.spec.ts +++ b/alfa-client/libs/design-system/src/lib/list/list-item/list-item.component.spec.ts @@ -27,7 +27,7 @@ describe('ListItemComponent', () => { describe('input', () => { describe('routerLink', () => { it('should set href attribute', () => { - component.path = faker.system.filePath(); + component.path = encodeURI(faker.system.filePath()); const resultingLink: string = 'http://localhost' + component.path; const linkElement: HTMLLinkElement = getElementFromFixture(fixture, getDataTestClassOf('list-item-link')); diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts index ca73c782d282523f6ae32f0ef50fa9ec872d217f..6fa40dfad1eb725845134bfb68d2259d0e6ae6ea 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts @@ -30,21 +30,11 @@ import { createEmptyStateResource, createStateResource, } from '@alfa-client/tech-shared'; -import { - dispatchEventFromFixture, - getElementFromFixture, - mock, - useFromMock, -} from '@alfa-client/test-utils'; +import { dispatchEventFromFixture, getElementFromFixture, mock, useFromMock } from '@alfa-client/test-utils'; import { SpinnerComponent } from '@alfa-client/ui'; import { VorgangHeaderLinkRel, VorgangListService } from '@alfa-client/vorgang-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - ReactiveFormsModule, - UntypedFormBuilder, - UntypedFormControl, - UntypedFormGroup, -} from '@angular/forms'; +import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButton } from '@angular/material/button'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -224,21 +214,15 @@ describe('VorgangSearchComponent', () => { const result = component.buildSearchResultPreviewLabel(vorgangList); - expect(result).toBe( - '10 Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen', - ); + expect(result).toBe('10 Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen'); }); it('should return label for one search result', () => { - const vorgangList = createStateResource( - createVorgangListResourceWithResource([createVorgangResource()]), - ); + const vorgangList = createStateResource(createVorgangListResourceWithResource([createVorgangResource()])); const result = component.buildSearchResultPreviewLabel(vorgangList); - expect(result).toBe( - 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen', - ); + expect(result).toBe('Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um diesen zu erreichen'); }); it('should return empty string', () => { @@ -298,6 +282,17 @@ describe('VorgangSearchComponent', () => { }); }); + describe('onKeydownHandler', () => { + it('should call formService setLastKeyPressed with key', () => { + const setLastKeyPressedSpy = jest.spyOn(VorgangSearchFormService.prototype, 'setLastKeyPressed'); + const keyboardEvent: KeyboardEvent = new KeyboardEvent('keydown', { key: 'Enter' }); + + component.onKeydownHandler(keyboardEvent); + + expect(setLastKeyPressedSpy).toHaveBeenCalledWith('Enter'); + }); + }); + describe('submit', () => { it('should not navigate to search if search field is empty', () => { const submitSpy = jest.spyOn(NavigationService.prototype, 'search'); diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts index 7857c502c95a7b38bed14c9a85ef50d8a748a68a..e0c72ccc0a96eb5fd90cd4d66d262ea0484dfeea 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts @@ -21,27 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - EMPTY_STRING, - StateResource, - getEmbeddedResources, - isNotNil, -} from '@alfa-client/tech-shared'; -import { - VorgangHeaderLinkRel, - VorgangListLinkRel, - VorgangListResource, -} from '@alfa-client/vorgang-shared'; -import { - Component, - ElementRef, - EventEmitter, - Input, - OnDestroy, - OnInit, - Output, - ViewChild, -} from '@angular/core'; +import { EMPTY_STRING, StateResource, getEmbeddedResources, isNotNil } from '@alfa-client/tech-shared'; +import { VorgangHeaderLinkRel, VorgangListLinkRel, VorgangListResource } from '@alfa-client/vorgang-shared'; +import { Component, ElementRef, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { MatAutocomplete } from '@angular/material/autocomplete'; import { MatButton } from '@angular/material/button'; import { Event, NavigationEnd, Router } from '@angular/router'; @@ -56,9 +38,7 @@ import { VorgangSearchFormService } from './vorgang-search.formservice'; providers: [VorgangSearchFormService], }) export class VorgangSearchComponent implements OnInit, OnDestroy { - @Input() set vorgangSearchPreviewList( - vorgangListStateResource: StateResource<VorgangListResource>, - ) { + @Input() set vorgangSearchPreviewList(vorgangListStateResource: StateResource<VorgangListResource>) { this.vorgangListPreview = vorgangListStateResource; this.searchResultPreviewLabel = this.buildSearchResultPreviewLabel(vorgangListStateResource); } @@ -93,6 +73,11 @@ export class VorgangSearchComponent implements OnInit, OnDestroy { }); } + @HostListener('keydown', ['$event']) + onKeydownHandler(e: KeyboardEvent): void { + this.formService.setLastKeyPressed(e.key); + } + submit(): void { this.previouslyEnteredSearchValue = this.formService.getValue(); this.formService.submit(); @@ -113,15 +98,9 @@ export class VorgangSearchComponent implements OnInit, OnDestroy { } } - buildSearchResultPreviewLabel( - vorgangListStateResource: StateResource<VorgangListResource>, - ): string { - const previewListLength = getEmbeddedResources( - vorgangListStateResource, - this.vorgangListLinkRel.VORGANG_HEADER_LIST, - )?.length; - if (previewListLength === 1) - return 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen'; + buildSearchResultPreviewLabel(vorgangListStateResource: StateResource<VorgangListResource>): string { + const previewListLength = getEmbeddedResources(vorgangListStateResource, this.vorgangListLinkRel.VORGANG_HEADER_LIST)?.length; + if (previewListLength === 1) return 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um diesen zu erreichen'; if (previewListLength > 1) return `${previewListLength} Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen`; return EMPTY_STRING; diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts index 9e639e1a9c66bf31e06c51de51d176fffeb94321..45a888657048c0f222495b8fe905fe58b21ae3e6 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts @@ -24,11 +24,8 @@ import { NavigationService } from '@alfa-client/navigation-shared'; import { EMPTY_STRING, encodeUrlForEmbedding } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; -import { - VorgangHeaderLinkRel, - VorgangListService, - VorgangResource, -} from '@alfa-client/vorgang-shared'; +import { VorgangHeaderLinkRel, VorgangListService, VorgangResource } from '@alfa-client/vorgang-shared'; +import { fakeAsync, tick } from '@angular/core/testing'; import { FormControl, UntypedFormBuilder } from '@angular/forms'; import { Params } from '@angular/router'; import { faker } from '@faker-js/faker'; @@ -74,6 +71,40 @@ describe('VorgangSearchFormService', () => { }); }); + describe('subscribeToValueChanges', () => { + it('should call setHasSearchString after debounce time', fakeAsync(() => { + const value = faker.word.sample(); + const setHasSearchString = jest.spyOn(formService, 'setHasSearchString'); + + formService.subscribeToValueChanges(); + formService.form.controls[formService.SEARCH_FIELD].patchValue(value); + tick(300); + + expect(setHasSearchString).toHaveBeenCalledWith(value); + })); + + it('should call handleValueChange after debounce time', fakeAsync(() => { + const value = faker.word.sample(); + const handleValueChanges = jest.spyOn(formService, 'handleValueChanges'); + + formService.subscribeToValueChanges(); + formService.form.controls[formService.SEARCH_FIELD].patchValue(value); + tick(300); + + expect(handleValueChanges).toHaveBeenCalledWith(value); + })); + + it('should not call handleValueChange if lastKeyPressed is Enter', fakeAsync(() => { + const handleValueChanges = jest.spyOn(formService, 'handleValueChanges'); + formService.setLastKeyPressed('Enter'); + + formService.subscribeToValueChanges(); + tick(300); + + expect(handleValueChanges).not.toHaveBeenCalled(); + })); + }); + describe('handleValueChanges', () => { describe('on should search for preview', () => { beforeEach(() => { @@ -234,9 +265,7 @@ describe('VorgangSearchFormService', () => { }); describe('submitByPreviewList', () => { - const vorgang: VorgangResource = createVorgangResource([ - VorgangHeaderLinkRel.VORGANG_WITH_EINGANG, - ]); + const vorgang: VorgangResource = createVorgangResource([VorgangHeaderLinkRel.VORGANG_WITH_EINGANG]); const searchString: string = faker.person.firstName(); it('should clear searchString', () => { diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts index bf88a1381c9a827c61a71dc204f5cbaf820ca63a..b8449f8efc8fff93dda751c99212eb4a67b3bc41 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts @@ -22,23 +22,13 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { NavigationService } from '@alfa-client/navigation-shared'; -import { - EMPTY_STRING, - hasMinLength, - isNotEmpty, - isNotNil, - toResourceUri, -} from '@alfa-client/tech-shared'; -import { - VorgangHeaderLinkRel, - VorgangListService, - VorgangResource, -} from '@alfa-client/vorgang-shared'; +import { EMPTY_STRING, hasMinLength, isNotEmpty, isNotNil, toResourceUri } from '@alfa-client/tech-shared'; +import { VorgangHeaderLinkRel, VorgangListService, VorgangResource } from '@alfa-client/vorgang-shared'; import { Injectable, OnDestroy } from '@angular/core'; import { FormGroup, UntypedFormBuilder, UntypedFormControl } from '@angular/forms'; import { Params } from '@angular/router'; import { isEmpty } from 'lodash-es'; -import { Observable, Subscription } from 'rxjs'; +import { filter, Observable, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged, first, tap } from 'rxjs/operators'; @Injectable() @@ -54,6 +44,8 @@ export class VorgangSearchFormService implements OnDestroy { public lastSearchString: string; public hasSearchString: boolean = false; + private lastKeyPressed: string; + constructor( private formBuilder: UntypedFormBuilder, private navigationService: NavigationService, @@ -78,17 +70,24 @@ export class VorgangSearchFormService implements OnDestroy { subscribeToValueChanges(): void { this.fromControlSubscription = this.getSearchFormControl() .valueChanges.pipe( + distinctUntilChanged(), debounceTime(300), + filter(() => this.lastKeyPressedIsNotEnter()), tap((value) => this.setHasSearchString(value)), - distinctUntilChanged(), ) - .subscribe((value) => this.handleValueChanges(value)); + .subscribe((value) => { + this.handleValueChanges(value); + }); } setHasSearchString(value: string): void { this.hasSearchString = isNotEmpty(value); } + private lastKeyPressedIsNotEnter(): boolean { + return this.lastKeyPressed !== 'Enter'; + } + handleValueChanges(value: string): void { if (this.shouldSearchForPreview(value)) { this.vorgangListService.setSearchString(value); @@ -99,9 +98,7 @@ export class VorgangSearchFormService implements OnDestroy { } shouldSearchForPreview(value: string): boolean { - return ( - this.isSearchInputNotPristine() && hasMinLength(value, this.PREVIEW_SEARCH_STRING_MIN_LENGTH) - ); + return this.isSearchInputNotPristine() && hasMinLength(value, this.PREVIEW_SEARCH_STRING_MIN_LENGTH); } isSearchInputNotPristine(): boolean { @@ -150,9 +147,7 @@ export class VorgangSearchFormService implements OnDestroy { } private navigateToVorgang(resource: VorgangResource): void { - this.navigationService.navigateToVorgang( - toResourceUri(resource, VorgangHeaderLinkRel.VORGANG_WITH_EINGANG), - ); + this.navigationService.navigateToVorgang(toResourceUri(resource, VorgangHeaderLinkRel.VORGANG_WITH_EINGANG)); } navigateToVorgangListOnSearch(params: Params) { @@ -178,4 +173,8 @@ export class VorgangSearchFormService implements OnDestroy { public getValueChanges(): Observable<string> { return this.getSearchFormControl().valueChanges; } + + public setLastKeyPressed(key: string): void { + this.lastKeyPressed = key; + } } diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json index 1123019a134bc3716bf6280a1115b72261f6a2db..5fa256e28ccf0dd8ac93135af48e7e0180ed359d 100644 --- a/alfa-client/tsconfig.base.json +++ b/alfa-client/tsconfig.base.json @@ -62,7 +62,7 @@ "@ods/component": ["libs/design-component/src/index.ts"], "@ods/system": ["libs/design-system/src/index.ts"], "authentication": ["libs/authentication/src/index.ts"], - "@alfa-client/common-lib": ["libs/common-lib/src/index.ts"] + "@alfa-client/common": ["libs/common/src/index.ts"] } }, "exclude": ["node_modules", "tmp"] diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoServiceTest.java index f314dbef0bf2c48ccfb35d1f974ce9e6edaa91cc..19bea4224f26612e6447965cc090ab8eb52efbec 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoServiceTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoServiceTest.java @@ -33,9 +33,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; -import org.mockito.Mock; import org.mockito.Spy; -import org.springframework.core.io.ResourceLoader; import org.springframework.test.util.ReflectionTestUtils; class ForwardingLandesnetzInfoServiceTest { @@ -43,8 +41,6 @@ class ForwardingLandesnetzInfoServiceTest { @Spy @InjectMocks private ForwardingLandesnetzInfoService service; - @Mock - private ResourceLoader resourceLoader; @DisplayName("Is email in landesnetz") @Nested