From 616f6ebe0385d82a827c6679eabdcf4e92a18c11 Mon Sep 17 00:00:00 2001 From: valentinab25 Date: Tue, 31 Oct 2023 02:58:34 +0200 Subject: [PATCH 01/17] chore: [JENKINS] Refactor automated testing --- Dockerfile | 2 +- Jenkinsfile | 286 ++++++++++++++++++++++++++++------------------------ Makefile | 37 ++++++- 3 files changed, 188 insertions(+), 137 deletions(-) diff --git a/Dockerfile b/Dockerfile index bd8e10d..b1ce603 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 ARG VOLTO_VERSION -FROM plone/frontend-builder:${VOLTO_VERSION} +FROM eeacms/frontend-builder:${VOLTO_VERSION} ARG ADDON_NAME ARG ADDON_PATH diff --git a/Jenkinsfile b/Jenkinsfile index 429fc88..9df7f8a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,16 +1,20 @@ pipeline { - agent any + agent { + node { label 'docker-host' } + } environment { - GIT_NAME = "volto-group-block" - NAMESPACE = "@eeacms" - SONARQUBE_TAGS = "volto.eea.europa.eu,forest.eea.europa.eu,www.eea.europa.eu-ims,climate-energy.eea.europa.eu,sustainability.eionet.europa.eu,biodiversity.europa.eu,clms.land.copernicus.eu,industry.eea.europa.eu,water.europa.eu-freshwater,demo-www.eea.europa.eu,clmsdemo.devel6cph.eea.europa.eu,water.europa.eu-marine,climate-adapt.eea.europa.eu,climate-advisory-board.devel4cph.eea.europa.eu,climate-advisory-board.europa.eu,www.eea.europa.eu-en" - DEPENDENCIES = "" - VOLTO = "16" - } + GIT_NAME = "volto-group-block" + NAMESPACE = "@eeacms" + SONARQUBE_TAGS = "volto.eea.europa.eu,forest.eea.europa.eu,www.eea.europa.eu-ims,climate-energy.eea.europa.eu,sustainability.eionet.europa.eu,biodiversity.europa.eu,clms.land.copernicus.eu,industry.eea.europa.eu,water.europa.eu-freshwater,demo-www.eea.europa.eu,clmsdemo.devel6cph.eea.europa.eu,water.europa.eu-marine,climate-adapt.eea.europa.eu,climate-advisory-board.devel4cph.eea.europa.eu,climate-advisory-board.europa.eu,www.eea.europa.eu-en" + DEPENDENCIES = "" + BACKEND_PROFILES = "eea.kitkat:testing" + BACKEND_ADDONS = "" + VOLTO = "16" + IMAGE_NAME = BUILD_TAG.toLowerCase() + } stages { - stage('Release') { when { allOf { @@ -20,52 +24,41 @@ pipeline { } steps { node(label: 'docker') { - withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN'),string(credentialsId: 'eea-jenkins-npm-token', variable: 'NPM_TOKEN')]) { - sh '''docker pull eeacms/gitflow''' - sh '''docker run -i --rm --name="$BUILD_TAG-gitflow-master" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" -e GIT_TOKEN="$GITHUB_TOKEN" -e NPM_TOKEN="$NPM_TOKEN" -e LANGUAGE=javascript eeacms/gitflow''' + withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN'), string(credentialsId: 'eea-jenkins-npm-token', variable: 'NPM_TOKEN')]) { + sh '''docker run -i --rm --pull always --name="$IMAGE_NAME-gitflow-master" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" -e GIT_TOKEN="$GITHUB_TOKEN" -e NPM_TOKEN="$NPM_TOKEN" -e LANGUAGE=javascript eeacms/gitflow''' } } } } - stage('Code') { + stage('Check if testing needed') { when { allOf { - environment name: 'CHANGE_ID', value: '' - not { changelog '.*^Automated release [0-9\\.]+$' } not { branch 'master' } + not { branch 'develop' } + environment name: 'CHANGE_ID', value: '' } } steps { - parallel( - - "ES lint": { - node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-eslint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci eslint''' - } - }, - - "Style lint": { - node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-stylelint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci stylelint''' - } - }, + script { + withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN')]) { + check_result = sh script: '''docker run --pull always -i --rm --name="$IMAGE_NAME-gitflow-check" -e GIT_TOKEN="$GITHUB_TOKEN" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_ORG="$GIT_ORG" -e GIT_NAME="$GIT_NAME" eeacms/gitflow /check_if_testing_needed.sh''', returnStatus: true - "Prettier": { - node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-prettier" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci prettier''' + if (check_result == 0) { + env.SKIP_TESTS = 'yes' + } } - } - ) + } } } - stage('Tests') { + stage('Testing') { when { anyOf { allOf { not { environment name: 'CHANGE_ID', value: '' } environment name: 'CHANGE_TARGET', value: 'develop' + environment name: 'SKIP_TESTS', value: '' } allOf { environment name: 'CHANGE_ID', value: '' @@ -73,26 +66,76 @@ pipeline { not { changelog '.*^Automated release [0-9\\.]+$' } branch 'master' } + environment name: 'SKIP_TESTS', value: '' } } } - steps { - parallel( + stages { + stage('Build test image') { + steps { + checkout scm + sh '''docker build --build-arg="VOLTO_VERSION=$VOLTO" --build-arg="ADDON_NAME=$NAMESPACE/$GIT_NAME" --build-arg="ADDON_PATH=$GIT_NAME" . -t $IMAGE_NAME-frontend''' + } + } + + stage('Fix code') { + when { + environment name: 'CHANGE_ID', value: '' + not { branch 'master' } + } + steps { + script { + fix_result = sh(script: '''docker run --name="$IMAGE_NAME-fix" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend ci-fix''', returnStatus: true) + sh '''docker cp $IMAGE_NAME-fix:/app/src/addons/$GIT_NAME/src .''' + sh '''docker rm -v $IMAGE_NAME-fix''' + FOUND_FIX = sh(script: '''git diff | wc -l''', returnStdout: true).trim() - "Volto": { - node(label: 'docker') { - script { - try { - sh '''docker pull plone/volto-addon-ci''' - sh '''docker run -i --name="$BUILD_TAG-volto" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci''' - sh '''rm -rf xunit-reports''' - sh '''mkdir -p xunit-reports''' - sh '''docker cp $BUILD_TAG-volto:/opt/frontend/my-volto-project/coverage xunit-reports/''' - sh '''docker cp $BUILD_TAG-volto:/opt/frontend/my-volto-project/junit.xml xunit-reports/''' - sh '''docker cp $BUILD_TAG-volto:/opt/frontend/my-volto-project/unit_tests_log.txt xunit-reports/''' - stash name: "xunit-reports", includes: "xunit-reports/**" - archiveArtifacts artifacts: "xunit-reports/unit_tests_log.txt", fingerprint: true - publishHTML (target : [ + if (FOUND_FIX != '0') { + withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN')]) { + sh '''sed -i "s|url = .*|url = https://eea-jenkins:$GITHUB_TOKEN@github.com/eea/$GIT_NAME.git|" .git/config''' + } + sh '''git fetch origin $GIT_BRANCH:$GIT_BRANCH''' + sh '''git checkout $GIT_BRANCH''' + sh '''git add src/''' + sh '''git commit -m "style: Automated code fix" ''' + sh '''git push --set-upstream origin $GIT_BRANCH''' + sh '''exit 1''' + } + } + } + } + + stage('ES lint') { + steps { + sh '''docker run --rm --name="$IMAGE_NAME-eslint" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend lint''' + } + } + + stage('Style lint') { + steps { + sh '''docker run --rm --name="$IMAGE_NAME-stylelint" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend stylelint''' + } + } + + stage('Prettier') { + steps { + sh '''docker run --rm --name="$IMAGE_NAME-prettier" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend prettier''' + } + } + + stage('Coverage Tests') { + parallel { + + stage('Unit tests') { + steps { + script { + try { + sh '''docker run --name="$IMAGE_NAME-volto" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend test-ci''' + sh '''rm -rf xunit-reports''' + sh '''mkdir -p xunit-reports''' + sh '''docker cp $IMAGE_NAME-volto:/app/coverage xunit-reports/''' + sh '''docker cp $IMAGE_NAME-volto:/app/junit.xml xunit-reports/''' + publishHTML(target : [ allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true, @@ -105,75 +148,60 @@ pipeline { catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') { junit testResults: 'xunit-reports/junit.xml', allowEmptyResults: true } - sh script: '''docker rm -v $BUILD_TAG-volto''', returnStatus: true + sh script: '''docker rm -v $IMAGE_NAME-volto''', returnStatus: true + } } } } - } - ) - } - } + + stage('Integration tests') { + steps { + script { + try { + sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend''' + sh '''docker run --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' + } finally { + try { + sh '''rm -rf cypress-videos cypress-results cypress-coverage cypress-screenshots''' + sh '''mkdir -p cypress-videos cypress-results cypress-coverage cypress-screenshots''' + sh '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/videos cypress-videos/''' + sh '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/reports cypress-results/''' + screenshots = sh script: '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/screenshots cypress-screenshots''', returnStatus: true - stage('Integration tests') { - when { - anyOf { - allOf { - not { environment name: 'CHANGE_ID', value: '' } - environment name: 'CHANGE_TARGET', value: 'develop' - } - allOf { - environment name: 'CHANGE_ID', value: '' - anyOf { - not { changelog '.*^Automated release [0-9\\.]+$' } - branch 'master' - } - } - } - } - steps { - parallel( + archiveArtifacts artifacts: 'cypress-screenshots/**', fingerprint: true, allowEmptyArchive: true - "Cypress": { - node(label: 'docker') { - script { - try { - sh '''docker pull eeacms/plone-backend; docker run --rm -d --name="$BUILD_TAG-plone" -e SITE="Plone" -e PROFILES="eea.kitkat:testing" eeacms/plone-backend''' - sh '''docker pull plone/volto-addon-ci; docker run -i --name="$BUILD_TAG-cypress" --link $BUILD_TAG-plone:plone -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e DEPENDENCIES="$DEPENDENCIES" -e NODE_ENV=development -e VOLTO=$VOLTO plone/volto-addon-ci cypress''' - } finally { - try { - sh '''rm -rf cypress-reports cypress-results cypress-coverage''' - sh '''mkdir -p cypress-reports cypress-results cypress-coverage''' - sh '''docker cp $BUILD_TAG-cypress:/opt/frontend/my-volto-project/src/addons/$GIT_NAME/cypress/videos cypress-reports/''' - sh '''docker cp $BUILD_TAG-cypress:/opt/frontend/my-volto-project/src/addons/$GIT_NAME/cypress/reports cypress-results/''' - coverage = sh script: '''docker cp $BUILD_TAG-cypress:/opt/frontend/my-volto-project/src/addons/$GIT_NAME/coverage cypress-coverage/''', returnStatus: true - if ( coverage == 0 ) { - publishHTML (target : [allowMissing: false, + coverage = sh script: '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/coverage cypress-coverage''', returnStatus: true + + if ( coverage == 0 ) { + publishHTML(target : [allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true, reportDir: 'cypress-coverage/coverage/lcov-report', reportFiles: 'index.html', reportName: 'CypressCoverage', reportTitles: 'Integration Tests Code Coverage']) - } - sh '''touch empty_file; for ok_test in $(grep -E 'file=.*failures="0"' $(grep 'testsuites .*failures="0"' $(find cypress-results -name *.xml) empty_file | awk -F: '{print $1}') empty_file | sed 's/.* file="\\(.*\\)" time.*/\\1/' | sed 's#^cypress/integration/##g' | sed 's#^../../../node_modules/@eeacms/##g'); do rm -f cypress-reports/videos/$ok_test.mp4; rm -f cypress-reports/$ok_test.mp4; done''' - archiveArtifacts artifacts: 'cypress-reports/**/*.mp4', fingerprint: true, allowEmptyArchive: true - stash name: "cypress-coverage", includes: "cypress-coverage/**", allowEmpty: true - } - finally { - catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') { + } + sh '''for file in $(find cypress-results -name *.xml); do if [ $(grep -E 'failures="[1-9].*"' $file | wc -l) -eq 0 ]; then testname=$(grep -E 'file=.*failures="0"' $file | sed 's#.* file=".*\\/\\(.*\\.[jsxt]\\+\\)" time.*#\\1#' ); rm -f cypress-videos/videos/$testname.mp4; fi; done''' + archiveArtifacts artifacts: 'cypress-videos/**', fingerprint: true, allowEmptyArchive: true + } finally { + catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') { junit testResults: 'cypress-results/**/*.xml', allowEmptyResults: true + } + sh script: "docker stop $IMAGE_NAME-plone", returnStatus: true + sh script: "docker rm -v $IMAGE_NAME-plone", returnStatus: true + sh script: "docker rm -v $IMAGE_NAME-cypress", returnStatus: true } - sh script: "docker stop $BUILD_TAG-plone", returnStatus: true - sh script: "docker rm -v $BUILD_TAG-plone", returnStatus: true - sh script: "docker rm -v $BUILD_TAG-cypress", returnStatus: true - } } } } } - - ) + } + } + post { + always { + sh script: "docker rmi $IMAGE_NAME-frontend", returnStatus: true + } } } @@ -197,19 +225,16 @@ pipeline { } } steps { - node(label: 'swarm') { - script{ - checkout scm - unstash "xunit-reports" - unstash "cypress-coverage" - def scannerHome = tool 'SonarQubeScanner'; - def nodeJS = tool 'NodeJS'; - withSonarQubeEnv('Sonarqube') { - sh '''sed -i "s#/opt/frontend/my-volto-project/src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info''' - sh '''sed -i "s#src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info''' - sh "export PATH=${scannerHome}/bin:${nodeJS}/bin:$PATH; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER" - sh '''try=2; while [ \$try -gt 0 ]; do curl -s -XPOST -u "${SONAR_AUTH_TOKEN}:" "${SONAR_HOST_URL}api/project_tags/set?project=${GIT_NAME}-${BRANCH_NAME}&tags=${SONARQUBE_TAGS},${BRANCH_NAME}" > set_tags_result; if [ \$(grep -ic error set_tags_result ) -eq 0 ]; then try=0; else cat set_tags_result; echo "... Will retry"; sleep 60; try=\$(( \$try - 1 )); fi; done''' - } + script { + def scannerHome = tool 'SonarQubeScanner' + def nodeJS = tool 'NodeJS' + withSonarQubeEnv('Sonarqube') { + sh '''sed -i "s#/app/src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info''' + sh '''sed -i "s#src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info''' + sh '''cat xunit-reports/coverage/lcov.info''' + sh '''cat cypress-coverage/coverage/lcov.info''' + sh "export PATH=${scannerHome}/bin:${nodeJS}/bin:$PATH; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER" + sh '''try=5; while [ \$try -gt 0 ]; do curl -s -XPOST -u "${SONAR_AUTH_TOKEN}:" "${SONAR_HOST_URL}api/project_tags/set?project=${GIT_NAME}-${BRANCH_NAME}&tags=${SONARQUBE_TAGS},${BRANCH_NAME}" > set_tags_result; if [ \$(grep -ic error set_tags_result ) -eq 0 ]; then try=0; else cat set_tags_result; echo "... Will retry"; sleep 15; try=\$(( \$try - 1 )); fi; done''' } } } @@ -230,18 +255,15 @@ pipeline { } } steps { - node(label: 'docker') { - script { - sh '''docker pull eeacms/gitflow''' - sh '''echo "Error" > checkresult.txt''' - catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { - sh '''set -o pipefail; docker run -i --rm --name="$BUILD_TAG-gitflow-sn" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" eeacms/gitflow /checkSonarqubemaster.sh | grep -v "Found script" | tee checkresult.txt''' - } - - publishChecks name: 'SonarQube', title: 'Sonarqube Code Quality Check', summary: "Quality check on the SonarQube metrics from branch develop, comparing it with the ones from master branch. No bugs are allowed", - text: readFile(file: 'checkresult.txt'), conclusion: "${currentBuild.currentResult}", - detailsURL: "${env.BUILD_URL}display/redirect" + script { + sh '''echo "Error" > checkresult.txt''' + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + sh '''set -o pipefail; docker run -i --rm --pull always --name="$IMAGE_NAME-gitflow-sn" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" eeacms/gitflow /checkSonarqubemaster.sh | grep -v "Found script" | tee checkresult.txt''' } + + publishChecks name: 'SonarQube', title: 'Sonarqube Code Quality Check', summary: 'Quality check on the SonarQube metrics from branch develop, comparing it with the ones from master branch. No bugs are allowed', + text: readFile(file: 'checkresult.txt'), conclusion: "${currentBuild.currentResult}", + detailsURL: "${env.BUILD_URL}display/redirect" } } } @@ -254,20 +276,16 @@ pipeline { environment name: 'CHANGE_TARGET', value: 'master' } steps { - node(label: 'docker') { - script { - if ( env.CHANGE_BRANCH != "develop" ) { - error "Pipeline aborted due to PR not made from develop branch" - } - withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN')]) { - sh '''docker pull eeacms/gitflow''' - sh '''docker run -i --rm --name="$BUILD_TAG-gitflow-pr" -e GIT_CHANGE_TARGET="$CHANGE_TARGET" -e GIT_CHANGE_BRANCH="$CHANGE_BRANCH" -e GIT_CHANGE_AUTHOR="$CHANGE_AUTHOR" -e GIT_CHANGE_TITLE="$CHANGE_TITLE" -e GIT_TOKEN="$GITHUB_TOKEN" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e GIT_ORG="$GIT_ORG" -e GIT_NAME="$GIT_NAME" -e LANGUAGE=javascript eeacms/gitflow''' - } + script { + if (env.CHANGE_BRANCH != 'develop') { + error 'Pipeline aborted due to PR not made from develop branch' + } + withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN')]) { + sh '''docker run --pull always -i --rm --name="$IMAGE_NAME-gitflow-pr" -e GIT_CHANGE_TARGET="$CHANGE_TARGET" -e GIT_CHANGE_BRANCH="$CHANGE_BRANCH" -e GIT_CHANGE_AUTHOR="$CHANGE_AUTHOR" -e GIT_CHANGE_TITLE="$CHANGE_TITLE" -e GIT_TOKEN="$GITHUB_TOKEN" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e GIT_ORG="$GIT_ORG" -e GIT_NAME="$GIT_NAME" -e LANGUAGE=javascript eeacms/gitflow''' } } } } - } post { diff --git a/Makefile b/Makefile index f3614a8..6e221b3 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,11 @@ VOLTO_VERSION?=16 ADDON_PATH="${DIR}" ADDON_NAME="@eeacms/${ADDON_PATH}" DOCKER_COMPOSE=PLONE_VERSION=${PLONE_VERSION} VOLTO_VERSION=${VOLTO_VERSION} ADDON_NAME=${ADDON_NAME} ADDON_PATH=${ADDON_PATH} docker compose +RAZZLE_INTERNAL_API_PATH?="${RAZZLE_DEV_PROXY_API_PATH}" +RAZZLE_DEV_PROXY_API_PATH?="${RAZZLE_INTERNAL_API_PATH}" +CYPRESS_API_PATH="${RAZZLE_DEV_PROXY_API_PATH}" + + # Top-level targets .PHONY: all @@ -77,11 +82,11 @@ shell: ## Start a shell in the frontend container .PHONY: cypress-open cypress-open: ## Open cypress integration tests - NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress open + CYPRESS_API_PATH="${RAZZLE_DEV_PROXY_API_PATH}" NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress open .PHONY: cypress-run cypress-run: ## Run cypress integration tests - NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress run + CYPRESS_API_PATH="${RAZZLE_DEV_PROXY_API_PATH}" NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress run .PHONY: test test: ## Run jest tests @@ -129,3 +134,31 @@ i18n: ## i18n help: ## Show this help. @echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)" head -n 14 Makefile + +.PHONY: ci-fix +ci-fix: + echo "Running lint-fix" + make lint-fix + echo "Running prettier-fix" + make prettier-fix + echo "Running stylelint-fix" + make stylelint-fix + +.PHONY: test-ci +test-ci: + cd /app + RAZZLE_JEST_CONFIG=src/addons/${ADDON_PATH}/jest-addon.config.js CI=true yarn test src/addons/${ADDON_PATH}/src --watchAll=false --reporters=default --reporters=jest-junit --collectCoverage --coverageReporters lcov cobertura text + +.PHONY: start-ci +start-ci: + cd ../.. + yarn start & + +.PHONY: cypress-ci +cypress-ci: + cp .coverage.babel.config.js /app/babel.config.js + make start-ci + $(NODE_MODULES)/.bin/wait-on -t 240000 http://localhost:3000 + NODE_ENV=development make cypress-run + + From d0324f4aad6d94233ca8ce3645ca5162f39d9834 Mon Sep 17 00:00:00 2001 From: valentinab25 Date: Thu, 2 Nov 2023 22:24:14 +0200 Subject: [PATCH 02/17] test: [JENKINS] Improve cypress time --- Jenkinsfile | 14 +++++++------- Makefile | 4 ++-- cypress.config.js | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9df7f8a..2e53c90 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -74,7 +74,7 @@ pipeline { stage('Build test image') { steps { checkout scm - sh '''docker build --build-arg="VOLTO_VERSION=$VOLTO" --build-arg="ADDON_NAME=$NAMESPACE/$GIT_NAME" --build-arg="ADDON_PATH=$GIT_NAME" . -t $IMAGE_NAME-frontend''' + sh '''docker build --pull --build-arg="VOLTO_VERSION=$VOLTO" --build-arg="ADDON_NAME=$NAMESPACE/$GIT_NAME" --build-arg="ADDON_PATH=$GIT_NAME" . -t $IMAGE_NAME-frontend''' } } @@ -159,12 +159,12 @@ pipeline { script { try { sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend''' - sh '''docker run --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' + sh '''timeout 3600 docker run --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' } finally { try { sh '''rm -rf cypress-videos cypress-results cypress-coverage cypress-screenshots''' sh '''mkdir -p cypress-videos cypress-results cypress-coverage cypress-screenshots''' - sh '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/videos cypress-videos/''' + videos = sh script: '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/videos cypress-videos/''', returnStatus: true sh '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/reports cypress-results/''' screenshots = sh script: '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/screenshots cypress-screenshots''', returnStatus: true @@ -181,8 +181,10 @@ pipeline { reportName: 'CypressCoverage', reportTitles: 'Integration Tests Code Coverage']) } - sh '''for file in $(find cypress-results -name *.xml); do if [ $(grep -E 'failures="[1-9].*"' $file | wc -l) -eq 0 ]; then testname=$(grep -E 'file=.*failures="0"' $file | sed 's#.* file=".*\\/\\(.*\\.[jsxt]\\+\\)" time.*#\\1#' ); rm -f cypress-videos/videos/$testname.mp4; fi; done''' - archiveArtifacts artifacts: 'cypress-videos/**', fingerprint: true, allowEmptyArchive: true + if ( videos == 0 ) { + sh '''for file in $(find cypress-results -name *.xml); do if [ $(grep -E 'failures="[1-9].*"' $file | wc -l) -eq 0 ]; then testname=$(grep -E 'file=.*failures="0"' $file | sed 's#.* file=".*\\/\\(.*\\.[jsxt]\\+\\)" time.*#\\1#' ); rm -f cypress-videos/videos/$testname.mp4; fi; done''' + archiveArtifacts artifacts: 'cypress-videos/**/*.mp4', fingerprint: true, allowEmptyArchive: true + } } finally { catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') { junit testResults: 'cypress-results/**/*.xml', allowEmptyResults: true @@ -231,8 +233,6 @@ pipeline { withSonarQubeEnv('Sonarqube') { sh '''sed -i "s#/app/src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info''' sh '''sed -i "s#src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info''' - sh '''cat xunit-reports/coverage/lcov.info''' - sh '''cat cypress-coverage/coverage/lcov.info''' sh "export PATH=${scannerHome}/bin:${nodeJS}/bin:$PATH; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER" sh '''try=5; while [ \$try -gt 0 ]; do curl -s -XPOST -u "${SONAR_AUTH_TOKEN}:" "${SONAR_HOST_URL}api/project_tags/set?project=${GIT_NAME}-${BRANCH_NAME}&tags=${SONARQUBE_TAGS},${BRANCH_NAME}" > set_tags_result; if [ \$(grep -ic error set_tags_result ) -eq 0 ]; then try=0; else cat set_tags_result; echo "... Will retry"; sleep 15; try=\$(( \$try - 1 )); fi; done''' } diff --git a/Makefile b/Makefile index 6e221b3..30b44f0 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ VOLTO_VERSION?=16 ADDON_PATH="${DIR}" ADDON_NAME="@eeacms/${ADDON_PATH}" DOCKER_COMPOSE=PLONE_VERSION=${PLONE_VERSION} VOLTO_VERSION=${VOLTO_VERSION} ADDON_NAME=${ADDON_NAME} ADDON_PATH=${ADDON_PATH} docker compose -RAZZLE_INTERNAL_API_PATH?="${RAZZLE_DEV_PROXY_API_PATH}" +RAZZLE_INTERNAL_API_PATH?="http://localhost:8080/Plone" RAZZLE_DEV_PROXY_API_PATH?="${RAZZLE_INTERNAL_API_PATH}" CYPRESS_API_PATH="${RAZZLE_DEV_PROXY_API_PATH}" @@ -86,7 +86,7 @@ cypress-open: ## Open cypress integration tests .PHONY: cypress-run cypress-run: ## Run cypress integration tests - CYPRESS_API_PATH="${RAZZLE_DEV_PROXY_API_PATH}" NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress run + CYPRESS_API_PATH="${RAZZLE_DEV_PROXY_API_PATH}" NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress run --browser chromium .PHONY: test test: ## Run jest tests diff --git a/cypress.config.js b/cypress.config.js index 4846ce9..7a9e0be 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -2,12 +2,12 @@ const { defineConfig } = require('cypress'); module.exports = defineConfig({ viewportWidth: 1280, - defaultCommandTimeout: 5000, + defaultCommandTimeout: 8888, chromeWebSecurity: false, reporter: 'junit', - video: true, + video: false, retries: { - runMode: 1, + runMode: 2, openMode: 0, }, reporterOptions: { From 8dbdfeb89fe53c6dc2f476b183a53c9266ab2bdf Mon Sep 17 00:00:00 2001 From: valentinab25 Date: Fri, 3 Nov 2023 20:39:57 +0200 Subject: [PATCH 03/17] test: [JENKINS] Increase shm-size to cypress docker --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 2e53c90..fbcba5c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -159,7 +159,7 @@ pipeline { script { try { sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend''' - sh '''timeout 3600 docker run --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' + sh '''timeout 3600 docker run --shm-size=2g --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' } finally { try { sh '''rm -rf cypress-videos cypress-results cypress-coverage cypress-screenshots''' From b0ba5f9c6d37526411a7a984595ac624401f8ac5 Mon Sep 17 00:00:00 2001 From: valentinab25 Date: Mon, 6 Nov 2023 21:53:58 +0200 Subject: [PATCH 04/17] test: [JENKINS] Add cpu limit on cypress docker --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index fbcba5c..835c23f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -159,7 +159,7 @@ pipeline { script { try { sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend''' - sh '''timeout 3600 docker run --shm-size=2g --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' + sh '''timeout -s 9 3600 docker run --shm-size=2g --cpu-quota=150000 --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' } finally { try { sh '''rm -rf cypress-videos cypress-results cypress-coverage cypress-screenshots''' From 1517dbb81cf9128752d835ae59dc22b251f4b035 Mon Sep 17 00:00:00 2001 From: valentinab25 Date: Fri, 17 Nov 2023 04:07:31 +0200 Subject: [PATCH 05/17] test: [JENKINS] Run cypress in started frontend container --- Jenkinsfile | 7 ++++++- Makefile | 6 ++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 835c23f..b5391c6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -159,7 +159,8 @@ pipeline { script { try { sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend''' - sh '''timeout -s 9 3600 docker run --shm-size=2g --cpu-quota=150000 --link $IMAGE_NAME-plone:plone --entrypoint=make --name="$IMAGE_NAME-cypress" --workdir=/app/src/addons/${GIT_NAME} -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" $IMAGE_NAME-frontend cypress-ci''' + sh '''docker run -d --shm-size=3g --link $IMAGE_NAME-plone:plone --name="$IMAGE_NAME-cypress" -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend start-ci''' + sh '''timeout -s 9 1800 docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress make cypress-ci''' } finally { try { sh '''rm -rf cypress-videos cypress-results cypress-coverage cypress-screenshots''' @@ -189,6 +190,10 @@ pipeline { catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') { junit testResults: 'cypress-results/**/*.xml', allowEmptyResults: true } + catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') { + sh '''docker logs $IMAGE_NAME-cypress''' + } + sh script: "docker stop $IMAGE_NAME-cypress", returnStatus: true sh script: "docker stop $IMAGE_NAME-plone", returnStatus: true sh script: "docker rm -v $IMAGE_NAME-plone", returnStatus: true sh script: "docker rm -v $IMAGE_NAME-cypress", returnStatus: true diff --git a/Makefile b/Makefile index 30b44f0..efbf2fb 100644 --- a/Makefile +++ b/Makefile @@ -151,14 +151,12 @@ test-ci: .PHONY: start-ci start-ci: + cp .coverage.babel.config.js /app/babel.config.js cd ../.. - yarn start & + yarn start .PHONY: cypress-ci cypress-ci: - cp .coverage.babel.config.js /app/babel.config.js - make start-ci $(NODE_MODULES)/.bin/wait-on -t 240000 http://localhost:3000 NODE_ENV=development make cypress-run - From 25030fbd69108f90df02130e5010e56398941ad2 Mon Sep 17 00:00:00 2001 From: valentinab25 Date: Fri, 17 Nov 2023 20:07:52 +0200 Subject: [PATCH 06/17] test: [JENKINS] Use java17 for sonarqube scanner --- Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index b5391c6..5d1dfec 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,7 @@ pipeline { + tools { + jdk 'Java17' + } agent { node { label 'docker-host' } } From 87ae0dff17cb508466b17f959e99d62c6ab69a60 Mon Sep 17 00:00:00 2001 From: kreafox Date: Mon, 20 Nov 2023 13:43:10 +0200 Subject: [PATCH 07/17] fix: Pass location to RenderBlocks --- src/components/manage/Blocks/Group/DefaultBody.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/manage/Blocks/Group/DefaultBody.jsx b/src/components/manage/Blocks/Group/DefaultBody.jsx index 20690e1..4235499 100644 --- a/src/components/manage/Blocks/Group/DefaultBody.jsx +++ b/src/components/manage/Blocks/Group/DefaultBody.jsx @@ -1,6 +1,7 @@ import { Button } from 'semantic-ui-react'; import { BlocksForm, Icon, RenderBlocks } from '@plone/volto/components'; import EditBlockWrapper from './EditBlockWrapper'; +import { useLocation } from 'react-router-dom'; import helpSVG from '@plone/volto/icons/help.svg'; @@ -21,6 +22,7 @@ const GroupBlockDefaultBody = (props) => { formDescription, isEditMode, } = props; + const location = useLocation(); const metadata = props.metadata || props.properties; const blockState = {}; @@ -98,7 +100,11 @@ const GroupBlockDefaultBody = (props) => { )} ) : ( - + ); }; From a360401b8ee05e9cb54b253b0e605d0a040c8f78 Mon Sep 17 00:00:00 2001 From: kreafox Date: Wed, 22 Nov 2023 10:30:30 +0200 Subject: [PATCH 08/17] test: mock useLocation --- src/components/manage/Blocks/Group/View.test.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/manage/Blocks/Group/View.test.jsx b/src/components/manage/Blocks/Group/View.test.jsx index b9f96a0..0ad0342 100644 --- a/src/components/manage/Blocks/Group/View.test.jsx +++ b/src/components/manage/Blocks/Group/View.test.jsx @@ -14,6 +14,16 @@ jest.mock('@plone/volto/helpers', () => ({ withBlockExtensions: jest.fn((Component) => Component), })); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/', + hash: '', + search: '', + state: undefined, + }), +})); + describe('View', () => { it('should render without crashing', () => { const props = { From 746887fa0e778f2d4cbe86661fc8c38c8a4bafb5 Mon Sep 17 00:00:00 2001 From: kreafox Date: Wed, 22 Nov 2023 11:20:29 +0200 Subject: [PATCH 09/17] test: mock useLocation --- src/components/manage/Blocks/Group/Edit.test.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/manage/Blocks/Group/Edit.test.jsx b/src/components/manage/Blocks/Group/Edit.test.jsx index aa441db..dc511cb 100644 --- a/src/components/manage/Blocks/Group/Edit.test.jsx +++ b/src/components/manage/Blocks/Group/Edit.test.jsx @@ -30,6 +30,16 @@ jest.mock('@plone/volto/helpers', () => ({ getBlocksLayoutFieldname: jest.fn(), })); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/', + hash: '', + search: '', + state: undefined, + }), +})); + describe('Edit', () => { const onChangeBlock = jest.fn(); const onChangeField = jest.fn(); From 0c5d2d1a494489663cc97c5dc0f4ad13c4b67c8d Mon Sep 17 00:00:00 2001 From: kreafox Date: Wed, 22 Nov 2023 13:43:25 +0200 Subject: [PATCH 10/17] Prettier --- src/components/manage/Blocks/Group/DefaultBody.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/manage/Blocks/Group/DefaultBody.jsx b/src/components/manage/Blocks/Group/DefaultBody.jsx index 4235499..78f4025 100644 --- a/src/components/manage/Blocks/Group/DefaultBody.jsx +++ b/src/components/manage/Blocks/Group/DefaultBody.jsx @@ -6,6 +6,7 @@ import { useLocation } from 'react-router-dom'; import helpSVG from '@plone/volto/icons/help.svg'; const GroupBlockDefaultBody = (props) => { + const location = useLocation(); const { block, data, @@ -22,7 +23,6 @@ const GroupBlockDefaultBody = (props) => { formDescription, isEditMode, } = props; - const location = useLocation(); const metadata = props.metadata || props.properties; const blockState = {}; From 081a2d0bb001c980d2023bcce81830d71d23aeca Mon Sep 17 00:00:00 2001 From: kreafox Date: Wed, 22 Nov 2023 16:34:45 +0200 Subject: [PATCH 11/17] test: increase coverage --- src/components/manage/Blocks/Group/View.test.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/manage/Blocks/Group/View.test.jsx b/src/components/manage/Blocks/Group/View.test.jsx index 0ad0342..99e839d 100644 --- a/src/components/manage/Blocks/Group/View.test.jsx +++ b/src/components/manage/Blocks/Group/View.test.jsx @@ -76,12 +76,19 @@ describe('View', () => { metadata: { meta: 'data' }, properties: { prop: 'erty' }, variation: {}, + location: { + pathname: '/my-page', + search: '', + hash: '', + key: 'q5b96h', + }, }; render(); expect(RenderBlocks).toHaveBeenCalledWith( expect.objectContaining({ metadata: props.metadata, content: props.data.data, + location: props.location, }), {}, ); From 88d9945c6f338992247232325a25ea9795c2fe42 Mon Sep 17 00:00:00 2001 From: kreafox Date: Wed, 22 Nov 2023 16:55:15 +0200 Subject: [PATCH 12/17] test: update jest tests --- src/components/manage/Blocks/Group/Edit.test.jsx | 1 - src/components/manage/Blocks/Group/View.test.jsx | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/manage/Blocks/Group/Edit.test.jsx b/src/components/manage/Blocks/Group/Edit.test.jsx index dc511cb..8083d56 100644 --- a/src/components/manage/Blocks/Group/Edit.test.jsx +++ b/src/components/manage/Blocks/Group/Edit.test.jsx @@ -36,7 +36,6 @@ jest.mock('react-router-dom', () => ({ pathname: '/', hash: '', search: '', - state: undefined, }), })); diff --git a/src/components/manage/Blocks/Group/View.test.jsx b/src/components/manage/Blocks/Group/View.test.jsx index 99e839d..73a5152 100644 --- a/src/components/manage/Blocks/Group/View.test.jsx +++ b/src/components/manage/Blocks/Group/View.test.jsx @@ -20,7 +20,6 @@ jest.mock('react-router-dom', () => ({ pathname: '/', hash: '', search: '', - state: undefined, }), })); @@ -77,10 +76,9 @@ describe('View', () => { properties: { prop: 'erty' }, variation: {}, location: { - pathname: '/my-page', + pathname: '/', search: '', hash: '', - key: 'q5b96h', }, }; render(); From 0c5fc63866d6590e64051483ee8ec97e548d0b14 Mon Sep 17 00:00:00 2001 From: kreafox Date: Wed, 22 Nov 2023 17:51:47 +0200 Subject: [PATCH 13/17] test: add more tests --- .../manage/Blocks/Group/DefaultBody.test.jsx | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/components/manage/Blocks/Group/DefaultBody.test.jsx diff --git a/src/components/manage/Blocks/Group/DefaultBody.test.jsx b/src/components/manage/Blocks/Group/DefaultBody.test.jsx new file mode 100644 index 0000000..0b8d361 --- /dev/null +++ b/src/components/manage/Blocks/Group/DefaultBody.test.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Provider } from 'react-intl-redux'; +import DefaultBody from './DefaultBody'; +import configureStore from 'redux-mock-store'; +import '@testing-library/jest-dom/extend-expect'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/', + hash: '', + search: '', + }), +})); + +jest.mock('@plone/volto/components', () => ({ + BlocksForm: jest.fn(() =>
RenderBlocks
), + RenderBlocks: jest.fn(() =>
RenderBlocks
), +})); + +const mockStore = configureStore(); +const store = mockStore({ + intl: { + locale: 'en', + messages: {}, + }, +}); + +describe('DefaultBody', () => { + it('renders children', () => { + const props = { + data: { + variation: {}, + }, + metadata: {}, + properties: {}, + variation: {}, + }; + + const { getByText } = render( + + + , + ); + expect(getByText('RenderBlocks')).toBeInTheDocument(); + }); +}); From 3599b0f7edf22037729c52e35f29d8919e466e5f Mon Sep 17 00:00:00 2001 From: kreafox Date: Fri, 24 Nov 2023 09:11:33 +0200 Subject: [PATCH 14/17] test: fix bug reported by sonarqube, add more tests --- .../manage/Blocks/Group/CounterComponent.jsx | 2 +- .../manage/Blocks/Group/DefaultBody.test.jsx | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/components/manage/Blocks/Group/CounterComponent.jsx b/src/components/manage/Blocks/Group/CounterComponent.jsx index 8693df9..d6c37c3 100644 --- a/src/components/manage/Blocks/Group/CounterComponent.jsx +++ b/src/components/manage/Blocks/Group/CounterComponent.jsx @@ -36,7 +36,7 @@ const countTextInEachBlock = (countTextIn, ignoreSpaces, groupCharCount) => ([ }; const countTextInBlocks = (blocksObject, ignoreSpaces, maxChars) => { - const { countTextIn } = config.blocks?.blocksConfig?.group; + const { countTextIn } = config.blocks?.blocksConfig?.group || []; // use obj ref to update value - if you send number it will not be updated const groupCharCount = { value: 0 }; diff --git a/src/components/manage/Blocks/Group/DefaultBody.test.jsx b/src/components/manage/Blocks/Group/DefaultBody.test.jsx index 0b8d361..cd9f683 100644 --- a/src/components/manage/Blocks/Group/DefaultBody.test.jsx +++ b/src/components/manage/Blocks/Group/DefaultBody.test.jsx @@ -46,3 +46,30 @@ describe('DefaultBody', () => { expect(getByText('RenderBlocks')).toBeInTheDocument(); }); }); + +describe('DefaultBody Edit', () => { + it('renders children', () => { + const props = { + isEditMode: true, + data: { + variation: {}, + allowedBlocks: ['listing'], + }, + metadata: {}, + properties: {}, + variation: {}, + onSelectBlock: jest.fn(), + onDeleteBlock: jest.fn(), + onMutateBlock: jest.fn(), + onInsertBlock: jest.fn(), + selected: true, + }; + + const { getByText } = render( + + + , + ); + expect(getByText('RenderBlocks')).toBeInTheDocument(); + }); +}); From 7f93774774119fe1fa5e8266e8ec700cd2bc9427 Mon Sep 17 00:00:00 2001 From: kreafox Date: Fri, 24 Nov 2023 13:28:27 +0200 Subject: [PATCH 15/17] more tests --- .../manage/Blocks/Group/CounterComponent.jsx | 10 +--------- src/components/manage/Blocks/Group/utils.js | 8 ++++++++ src/components/manage/Blocks/Group/utils.test.js | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 src/components/manage/Blocks/Group/utils.js create mode 100644 src/components/manage/Blocks/Group/utils.test.js diff --git a/src/components/manage/Blocks/Group/CounterComponent.jsx b/src/components/manage/Blocks/Group/CounterComponent.jsx index d6c37c3..bca416d 100644 --- a/src/components/manage/Blocks/Group/CounterComponent.jsx +++ b/src/components/manage/Blocks/Group/CounterComponent.jsx @@ -7,15 +7,7 @@ import { visitBlocks } from '@plone/volto/helpers/Blocks/Blocks'; import { serializeNodesToText } from '@plone/volto-slate/editor/render'; import delightedSVG from '@plone/volto/icons/delighted.svg'; import dissatisfiedSVG from '@plone/volto/icons/dissatisfied.svg'; - -const countCharsWithoutSpaces = (paragraph) => { - const regex = /[^\s\\]/g; - return (paragraph.match(regex) || []).length; -}; - -const countCharsWithSpaces = (paragraph) => { - return paragraph?.length || 0; -}; +import { countCharsWithoutSpaces, countCharsWithSpaces } from './utils'; const countTextInEachBlock = (countTextIn, ignoreSpaces, groupCharCount) => ([ id, diff --git a/src/components/manage/Blocks/Group/utils.js b/src/components/manage/Blocks/Group/utils.js new file mode 100644 index 0000000..fc1dcfd --- /dev/null +++ b/src/components/manage/Blocks/Group/utils.js @@ -0,0 +1,8 @@ +export function countCharsWithoutSpaces(paragraph) { + const regex = /[^\s\\]/g; + return (paragraph.match(regex) || []).length; +} + +export function countCharsWithSpaces(paragraph) { + return paragraph?.length || 0; +} diff --git a/src/components/manage/Blocks/Group/utils.test.js b/src/components/manage/Blocks/Group/utils.test.js new file mode 100644 index 0000000..4cf02d7 --- /dev/null +++ b/src/components/manage/Blocks/Group/utils.test.js @@ -0,0 +1,15 @@ +import { countCharsWithoutSpaces, countCharsWithSpaces } from './utils'; + +describe('countCharsWithoutSpaces', () => { + it('should return number of charts without spaces', () => { + const paragraph = 'Lorem ipsum dolor sit'; + expect(countCharsWithoutSpaces(paragraph)).toBe(18); + }); +}); + +describe('countCharsWithSpaces', () => { + it('should return number of charts with spaces', () => { + const paragraph = 'Lorem ipsum dolor sit'; + expect(countCharsWithSpaces(paragraph)).toBe(21); + }); +}); From f84a866a313f30f94fd1c0a41737face83dac3e0 Mon Sep 17 00:00:00 2001 From: kreafox Date: Fri, 24 Nov 2023 15:02:20 +0200 Subject: [PATCH 16/17] test: update cypress test --- .../02-dexterity-controlpanel-layout.cy.js | 23 ++++++++++++++++++- cypress/support/e2e.js | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/02-dexterity-controlpanel-layout.cy.js b/cypress/e2e/02-dexterity-controlpanel-layout.cy.js index b7c3dcb..c761d1d 100644 --- a/cypress/e2e/02-dexterity-controlpanel-layout.cy.js +++ b/cypress/e2e/02-dexterity-controlpanel-layout.cy.js @@ -36,6 +36,25 @@ describe('ControlPanel: Dexterity Content-Types Layout', () => { cy.get('.content.active.common .button.group') .contains('Section (Group)') .click({ force: true }); + + cy.get('legend').contains('Section').click(); + cy.get('#sidebar-settings .field-wrapper-title input').type( + 'Intro section', + ); + cy.get('#sidebar-settings .field-wrapper-placeholder input').type( + 'Highlighted description', + ); + cy.get('#sidebar-settings .field-wrapper-maxChars').type('250'); + cy.get( + '#sidebar-settings .field-wrapper-allowedBlocks .react-select__value-container', + ) + .click() + .type('Image{enter}'); + cy.get( + '#sidebar-settings .field-wrapper-ignoreSpaces .ui.checkbox', + ).click(); + cy.get('.block-editor-group .blocks-form .block-editor-slate').click(); + cy.get('.ui.basic.icon.button.group-block-add-button:visible').click(); cy.get('.blocks-chooser .title').contains('Media').click({ force: true }); cy.get('.content.active.media .button.image') @@ -64,7 +83,9 @@ describe('ControlPanel: Dexterity Content-Types Layout', () => { cy.getSlateTitle().type('My First Book'); cy.get('.documentFirstHeading').contains('My First Book'); - cy.get('.section-block .text-slate-editor-inner').click().type('My description'); + cy.get('.section-block .text-slate-editor-inner') + .click() + .type('My description'); cy.get('#toolbar-save').click(); cy.get('.documentFirstHeading').contains('My First Book'); diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js index 90fe032..896ad38 100644 --- a/cypress/support/e2e.js +++ b/cypress/support/e2e.js @@ -36,7 +36,7 @@ export const slateBeforeEach = (contentType = 'Document') => { }); cy.visit('/cypress/my-page'); cy.waitForResourceToLoad('@navigation'); - cy.waitForResourceToLoad('@breadcrumbs'); + // cy.waitForResourceToLoad('@breadcrumbs'); cy.waitForResourceToLoad('@actions'); cy.waitForResourceToLoad('@types'); cy.waitForResourceToLoad('my-page'); From dd726f259f4bfedd528c1a4c5da106e620e5778f Mon Sep 17 00:00:00 2001 From: EEA Jenkins <@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:59:05 +0000 Subject: [PATCH 17/17] Automated release 6.3.5 --- CHANGELOG.md | 27 +++++++++++++++++++++++++-- package.json | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61dd7ca..5414ec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,34 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -### [6.3.4](https://github.com/eea/volto-group-block/compare/6.3.3...6.3.4) - 19 October 2023 +### [6.3.5](https://github.com/eea/volto-group-block/compare/6.3.4...6.3.5) - 24 November 2023 + +#### :bug: Bug Fixes + +- fix: Pass location to RenderBlocks [kreafox - [`87ae0df`](https://github.com/eea/volto-group-block/commit/87ae0dff17cb508466b17f959e99d62c6ab69a60)] + +#### :house: Internal changes + +- chore: [JENKINS] Refactor automated testing [valentinab25 - [`616f6eb`](https://github.com/eea/volto-group-block/commit/616f6ebe0385d82a827c6679eabdcf4e92a18c11)] #### :hammer_and_wrench: Others -- Update README.md [ana-oprea - [`2a956b7`](https://github.com/eea/volto-group-block/commit/2a956b73cf19c1d0ef173bf647fb5fa8d698fb83)] +- test: update cypress test [kreafox - [`f84a866`](https://github.com/eea/volto-group-block/commit/f84a866a313f30f94fd1c0a41737face83dac3e0)] +- more tests [kreafox - [`7f93774`](https://github.com/eea/volto-group-block/commit/7f93774774119fe1fa5e8266e8ec700cd2bc9427)] +- test: fix bug reported by sonarqube, add more tests [kreafox - [`3599b0f`](https://github.com/eea/volto-group-block/commit/3599b0f7edf22037729c52e35f29d8919e466e5f)] +- test: add more tests [kreafox - [`0c5fc63`](https://github.com/eea/volto-group-block/commit/0c5fc63866d6590e64051483ee8ec97e548d0b14)] +- test: update jest tests [kreafox - [`88d9945`](https://github.com/eea/volto-group-block/commit/88d9945c6f338992247232325a25ea9795c2fe42)] +- test: increase coverage [kreafox - [`081a2d0`](https://github.com/eea/volto-group-block/commit/081a2d0bb001c980d2023bcce81830d71d23aeca)] +- Prettier [kreafox - [`0c5d2d1`](https://github.com/eea/volto-group-block/commit/0c5d2d1a494489663cc97c5dc0f4ad13c4b67c8d)] +- test: mock useLocation [kreafox - [`746887f`](https://github.com/eea/volto-group-block/commit/746887fa0e778f2d4cbe86661fc8c38c8a4bafb5)] +- test: mock useLocation [kreafox - [`a360401`](https://github.com/eea/volto-group-block/commit/a360401b8ee05e9cb54b253b0e605d0a040c8f78)] +- test: [JENKINS] Use java17 for sonarqube scanner [valentinab25 - [`25030fb`](https://github.com/eea/volto-group-block/commit/25030fbd69108f90df02130e5010e56398941ad2)] +- test: [JENKINS] Run cypress in started frontend container [valentinab25 - [`1517dbb`](https://github.com/eea/volto-group-block/commit/1517dbb81cf9128752d835ae59dc22b251f4b035)] +- test: [JENKINS] Add cpu limit on cypress docker [valentinab25 - [`b0ba5f9`](https://github.com/eea/volto-group-block/commit/b0ba5f9c6d37526411a7a984595ac624401f8ac5)] +- test: [JENKINS] Increase shm-size to cypress docker [valentinab25 - [`8dbdfeb`](https://github.com/eea/volto-group-block/commit/8dbdfeb89fe53c6dc2f476b183a53c9266ab2bdf)] +- test: [JENKINS] Improve cypress time [valentinab25 - [`d0324f4`](https://github.com/eea/volto-group-block/commit/d0324f4aad6d94233ca8ce3645ca5162f39d9834)] +### [6.3.4](https://github.com/eea/volto-group-block/compare/6.3.3...6.3.4) - 22 October 2023 + ### [6.3.3](https://github.com/eea/volto-group-block/compare/6.3.2...6.3.3) - 17 October 2023 #### :house: Internal changes diff --git a/package.json b/package.json index f4d6bf5..f638ca5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-group-block", - "version": "6.3.4", + "version": "6.3.5", "description": "volto-group-block: Volto block to be used to group other blocks", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team",