diff --git a/.github/file-filters.yml b/.github/file-filters.yml new file mode 100644 index 000000000..80b7482d9 --- /dev/null +++ b/.github/file-filters.yml @@ -0,0 +1,46 @@ +# These file filter patterns are used by the action https://github.com/dorny/paths-filter + +# more differentiated filters for admin interface, which might be used later +# admin_locales: &admin_locales +# - 'admin/src/locales/**' +# - 'admin/scripts/sort*' + +# admin_stylelinting: &admin_stylelinting +# - 'admin/{components,layouts,pages}/**/*.{scss,vue}' +# - 'admin/.stylelintrc.js' + +# admin_linting: &admin_linting +# - 'admin/.eslint*' +# - 'admin/babel.config.js' +# - 'admin/package.json' +# - 'admin/**/*.{js,vue}' +# - *admin_locales + +# admin_unit_testing: &admin_unit_testing +# - 'admin/package.json' +# - 'admin/{jest,vue}.config.js' +# - 'admin/{public,run,test}/**/*' +# - 'admin/src/!(locales)/**/*' + +# admin_docker_building: &admin_docker_building +# - 'admin/.dockerignore' +# - 'admin/Dockerfile' +# - *admin_unit_testing + +admin: &admin + - 'admin/**/*' + +dht_node: &dht_node + - 'dht-node/**/*' + +docker: &docker + - 'docker-compose.*' + +federation: &federation + - 'federation/**/*' + +frontend: &frontend + - 'frontend/**/*' + +nginx: &nginx + - 'nginx/**/*' \ No newline at end of file diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml new file mode 100644 index 000000000..d1dd2851a --- /dev/null +++ b/.github/workflows/e2e-test.yml @@ -0,0 +1,58 @@ +name: Gradido End-to-End Test CI + +on: push + +jobs: + end-to-end-tests: + name: End-to-End Tests + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Boot up test system | docker-compose mariadb + run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb + + - name: Boot up test system | docker-compose database + run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database + + - name: Boot up test system | docker-compose backend + run: | + cd backend + cp .env.test_e2e .env + cd .. + docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps backend + + - name: Sleep for 10 seconds + run: sleep 10s + + - name: Boot up test system | seed backend + run: | + sudo chown runner:docker -R * + cd database + yarn && yarn dev_reset + cd ../backend + yarn && yarn seed + cd .. + + - name: Boot up test system | docker-compose frontends + run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps frontend admin nginx + + - name: Boot up test system | docker-compose mailserver + run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mailserver + + - name: Sleep for 15 seconds + run: sleep 15s + + - name: End-to-end tests | run tests + id: e2e-tests + run: | + cd e2e-tests/ + yarn + yarn run cypress run + - name: End-to-end tests | if tests failed, upload screenshots + if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }} + uses: actions/upload-artifact@v3 + with: + name: cypress-screenshots + path: /home/runner/work/gradido/gradido/e2e-tests/cypress/screenshots/ diff --git a/.github/workflows/test-admin-interface.yml b/.github/workflows/test-admin-interface.yml new file mode 100644 index 000000000..a163af4e9 --- /dev/null +++ b/.github/workflows/test-admin-interface.yml @@ -0,0 +1,84 @@ +name: Gradido Admin Interface Test CI + +on: push + +jobs: + # only (but most important) job from this workflow required for pull requests + # check results serve as run conditions for all other jobs here + files-changed: + name: Detect File Changes - Admin Interface + runs-on: ubuntu-latest + outputs: + admin: ${{ steps.changes.outputs.admin }} + steps: + - uses: actions/checkout@v3.3.0 + + - name: Check for admin interface file changes + uses: dorny/paths-filter@v2.11.1 + id: changes + with: + token: ${{ github.token }} + filters: .github/file-filters.yml + list-files: shell + + + build_test: + if: needs.files-changed.outputs.admin == 'true' + name: Docker Build Test - Admin Interface + needs: files-changed + runs-on: ubuntu-latest + steps: + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Admin Interface | Build 'test' image + run: docker build --target test -t "gradido/admin:test" admin/ --build-arg NODE_ENV="test" + + unit_test: + if: needs.files-changed.outputs.admin == 'true' + name: Unit Tests - Admin Interface + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Admin Interface | Unit tests + run: cd admin && yarn && yarn run test + + lint: + if: needs.files-changed.outputs.admin == 'true' + name: Lint - Admin Interface + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Admin Interface | Lint + run: cd admin && yarn && yarn run lint + + stylelint: + if: needs.files-changed.outputs.admin == 'true' + name: Stylelint - Admin Interface + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Admin Interface | Stylelint + run: cd admin && yarn && yarn run stylelint + + locales: + if: needs.files-changed.outputs.admin == 'true' + name: Locales - Admin Interface + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Admin Interface | Locales + run: cd admin && yarn && yarn run locales diff --git a/.github/workflows/test-nginx.yml b/.github/workflows/test-nginx.yml new file mode 100644 index 000000000..146e7a117 --- /dev/null +++ b/.github/workflows/test-nginx.yml @@ -0,0 +1,32 @@ +name: Gradido Nginx Test CI + +on: push + +jobs: + files-changed: + name: Detect File Changes - Nginx + runs-on: ubuntu-latest + outputs: + nginx: ${{ steps.changes.outputs.nginx }} + steps: + - uses: actions/checkout@v3.3.0 + + - name: Check for nginx file changes + uses: dorny/paths-filter@v2.11.1 + id: changes + with: + token: ${{ github.token }} + filters: .github/file-filters.yml + list-files: shell + + build_test_nginx: + name: Docker Build Test - Nginx + if: needs.files-changed.outputs.nginx == 'true' + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: nginx | Build 'test' image + run: docker build -t "gradido/nginx:test" nginx/ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 573cd911a..0fcedb4ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,57 +3,6 @@ name: gradido test CI on: push jobs: - ############################################################################## - # JOB: DOCKER BUILD TEST FRONTEND ############################################ - ############################################################################## - build_test_frontend: - name: Docker Build Test - Frontend - runs-on: ubuntu-latest - #needs: [nothing] - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # FRONTEND ############################################################### - ########################################################################## - - name: Frontend | Build `test` image - run: | - docker build --target test -t "gradido/frontend:test" frontend/ - docker save "gradido/frontend:test" > /tmp/frontend.tar - - name: Upload Artifact - uses: actions/upload-artifact@v3 - with: - name: docker-frontend-test - path: /tmp/frontend.tar - - ############################################################################## - # JOB: DOCKER BUILD TEST ADMIN INTERFACE ##################################### - ############################################################################## - build_test_admin: - name: Docker Build Test - Admin Interface - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # ADMIN INTERFACE ######################################################## - ########################################################################## - - name: Admin | Build `test` image - run: | - docker build --target test -t "gradido/admin:test" admin/ --build-arg NODE_ENV="test" - docker save "gradido/admin:test" > /tmp/admin.tar - - name: Upload Artifact - uses: actions/upload-artifact@v3 - with: - name: docker-admin-test - path: /tmp/admin.tar - ############################################################################## # JOB: DOCKER BUILD TEST BACKEND ############################################# ############################################################################## @@ -132,139 +81,6 @@ jobs: name: docker-mariadb-test path: /tmp/mariadb.tar - ############################################################################## - # JOB: DOCKER BUILD TEST NGINX ############################################### - ############################################################################## - build_test_nginx: - name: Docker Build Test - Nginx - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # BUILD NGINX DOCKER IMAGE ############################################### - ########################################################################## - - name: nginx | Build `test` image - run: | - docker build -t "gradido/nginx:test" nginx/ - docker save "gradido/nginx:test" > /tmp/nginx.tar - - name: Upload Artifact - uses: actions/upload-artifact@v3 - with: - name: docker-nginx-test - path: /tmp/nginx.tar - - ############################################################################## - # JOB: LOCALES FRONTEND ###################################################### - ############################################################################## - locales_frontend: - name: Locales - Frontend - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # LOCALES FRONTEND ####################################################### - ########################################################################## - - name: Frontend | Locales - run: cd frontend && yarn && yarn run locales - - ############################################################################## - # JOB: LINT FRONTEND ######################################################### - ############################################################################## - lint_frontend: - name: Lint - Frontend - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # LINT FRONTEND ########################################################## - ########################################################################## - - name: Frontend | Lint - run: cd frontend && yarn && yarn run lint - - ############################################################################## - # JOB: STYLELINT FRONTEND #################################################### - ############################################################################## - stylelint_frontend: - name: Stylelint - Frontend - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # STYLELINT FRONTEND ##################################################### - ########################################################################## - - name: Frontend | Stylelint - run: cd frontend && yarn && yarn run stylelint - - ############################################################################## - # JOB: LINT ADMIN INTERFACE ################################################## - ############################################################################## - lint_admin: - name: Lint - Admin Interface - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # LINT ADMIN INTERFACE ################################################### - ########################################################################## - - name: Admin Interface | Lint - run: cd admin && yarn && yarn run lint - - ############################################################################## - # JOB: STYLELINT ADMIN INTERFACE ############################################# - ############################################################################## - stylelint_admin: - name: Stylelint - Admin Interface - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # STYLELINT ADMIN INTERFACE ############################################## - ########################################################################## - - name: Admin Interface | Stylelint - run: cd admin && yarn && yarn run stylelint - - ############################################################################## - # JOB: LOCALES ADMIN ######################################################### - ############################################################################## - locales_admin: - name: Locales - Admin Interface - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # LOCALES FRONTEND ####################################################### - ########################################################################## - - name: Admin | Locales - run: cd admin && yarn && yarn run locales - ############################################################################## # JOB: LINT BACKEND ########################################################## ############################################################################## @@ -319,68 +135,6 @@ jobs: - name: Database | Lint run: cd database && yarn && yarn run lint - ############################################################################## - # JOB: UNIT TEST FRONTEND ################################################### - ############################################################################## - unit_test_frontend: - name: Unit tests - Frontend - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # UNIT TESTS FRONTEND #################################################### - ########################################################################## - - name: Frontend | Unit tests - run: | - cd frontend && yarn && yarn run test - cp -r ./coverage ../ - ########################################################################## - # COVERAGE CHECK FRONTEND ################################################ - ########################################################################## - - name: frontend | Coverage check - uses: webcraftmedia/coverage-check-action@master - with: - report_name: Coverage Frontend - type: lcov - result_path: ./frontend/coverage/lcov.info - min_coverage: 95 - token: ${{ github.token }} - - ############################################################################## - # JOB: UNIT TEST ADMIN INTERFACE ############################################# - ############################################################################## - unit_test_admin: - name: Unit tests - Admin Interface - runs-on: ubuntu-latest - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # UNIT TESTS ADMIN INTERFACE ############################################# - ########################################################################## - - name: Admin Interface | Unit tests - run: | - cd admin && yarn && yarn run test - cp -r ./coverage ../ - ########################################################################## - # COVERAGE CHECK ADMIN INTERFACE ######################################### - ########################################################################## - - name: Admin Interface | Coverage check - uses: webcraftmedia/coverage-check-action@master - with: - report_name: Coverage Admin Interface - type: lcov - result_path: ./admin/coverage/lcov.info - min_coverage: 97 - token: ${{ github.token }} - ############################################################################## # JOB: UNIT TEST BACKEND #################################################### ############################################################################## @@ -415,20 +169,7 @@ jobs: - name: backend | docker-compose database run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database - name: backend Unit tests | test - run: | - cd database && yarn && yarn build && cd ../backend && yarn && yarn test - cp -r ./coverage ../ - ########################################################################## - # COVERAGE CHECK BACKEND ################################################# - ########################################################################## - - name: backend | Coverage check - uses: webcraftmedia/coverage-check-action@master - with: - report_name: Coverage Backend - type: lcov - result_path: ./backend/coverage/lcov.info - min_coverage: 80 - token: ${{ github.token }} + run: cd database && yarn && yarn build && cd ../backend && yarn && yarn test ########################################################################## # DATABASE MIGRATION TEST UP + RESET ##################################### @@ -452,108 +193,3 @@ jobs: run: docker-compose -f docker-compose.yml run -T database yarn up - name: database | reset run: docker-compose -f docker-compose.yml run -T database yarn reset - - ############################################################################## - # JOB: END-TO-END TESTS ##################################################### - ############################################################################## - end-to-end-tests: - name: End-to-End Tests - runs-on: ubuntu-latest - needs: [build_test_mariadb, build_test_database_up, build_test_admin, build_test_frontend, build_test_nginx] - steps: - ########################################################################## - # CHECKOUT CODE ########################################################## - ########################################################################## - - name: Checkout code - uses: actions/checkout@v3 - ########################################################################## - # DOWNLOAD DOCKER IMAGES ################################################# - ########################################################################## - - name: Download Docker Image (Mariadb) - uses: actions/download-artifact@v3 - with: - name: docker-mariadb-test - path: /tmp - - name: Load Docker Image (Mariadb) - run: docker load < /tmp/mariadb.tar - - name: Download Docker Image (Database Up) - uses: actions/download-artifact@v3 - with: - name: docker-database-test_up - path: /tmp - - name: Load Docker Image (Database Up) - run: docker load < /tmp/database_up.tar - - name: Download Docker Image (Frontend) - uses: actions/download-artifact@v3 - with: - name: docker-frontend-test - path: /tmp - - name: Load Docker Image (Frontend) - run: docker load < /tmp/frontend.tar - - name: Download Docker Image (Admin Interface) - uses: actions/download-artifact@v3 - with: - name: docker-admin-test - path: /tmp - - name: Load Docker Image (Admin Interface) - run: docker load < /tmp/admin.tar - - name: Download Docker Image (Nginx) - uses: actions/download-artifact@v3 - with: - name: docker-nginx-test - path: /tmp - - name: Load Docker Image (Nginx) - run: docker load < /tmp/nginx.tar - - ########################################################################## - # BOOT UP THE TEST SYSTEM ################################################ - ########################################################################## - - name: Boot up test system | docker-compose mariadb - run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb - - - name: Boot up test system | docker-compose database - run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database - - - name: Boot up test system | docker-compose backend - run: | - cd backend - cp .env.test_e2e .env - cd .. - docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps backend - - - name: Sleep for 10 seconds - run: sleep 10s - - - name: Boot up test system | seed backend - run: | - sudo chown runner:docker -R * - cd database - yarn && yarn dev_reset - cd ../backend - yarn && yarn seed - cd .. - - - name: Boot up test system | docker-compose frontends - run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps frontend admin nginx - - - name: Boot up test system | docker-compose mailserver - run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mailserver - - - name: Sleep for 15 seconds - run: sleep 15s - - ########################################################################## - # END-TO-END TESTS ####################################################### - ########################################################################## - - name: End-to-end tests | run tests - id: e2e-tests - run: | - cd e2e-tests/ - yarn - yarn run cypress run --spec cypress/e2e/User.Authentication.feature,cypress/e2e/User.Authentication.ResetPassword.feature,cypress/e2e/User.Registration.feature - - name: End-to-end tests | if tests failed, upload screenshots - if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }} - uses: actions/upload-artifact@v3 - with: - name: cypress-screenshots - path: /home/runner/work/gradido/gradido/e2e-tests/cypress/screenshots/ diff --git a/.github/workflows/test_dht-node.yml b/.github/workflows/test_dht-node.yml index 4ac475351..a57f09399 100644 --- a/.github/workflows/test_dht-node.yml +++ b/.github/workflows/test_dht-node.yml @@ -3,17 +3,38 @@ name: Gradido DHT Node Test CI on: push jobs: + # only (but most important) job from this workflow required for pull requests + # check results serve as run conditions for all other jobs here + files-changed: + name: Detect File Changes - DHT Node + runs-on: ubuntu-latest + outputs: + dht_node: ${{ steps.changes.outputs.dht_node }} + docker: ${{ steps.changes.outputs.docker }} + steps: + - uses: actions/checkout@v3.3.0 + + - name: Check for frontend file changes + uses: dorny/paths-filter@v2.11.1 + id: changes + with: + token: ${{ github.token }} + filters: .github/file-filters.yml + list-files: shell + ############################################################################## # JOB: DOCKER BUILD TEST ##################################################### ############################################################################## build: name: Docker Build Test - DHT Node + if: needs.files-changed.outputs.dht_node == 'true' || needs.files-changed.outputs.docker == 'true' + needs: files-changed runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - - name: Build `test` image + - name: Build 'test' image run: | docker build --target test -t "gradido/dht-node:test" -f dht-node/Dockerfile . docker save "gradido/dht-node:test" > /tmp/dht-node.tar @@ -29,30 +50,24 @@ jobs: ############################################################################## lint: name: Lint - DHT Node + if: needs.files-changed.outputs.dht_node == 'true' + needs: files-changed runs-on: ubuntu-latest - needs: [build] steps: - name: Checkout code uses: actions/checkout@v3 - - - name: Download Docker Image - uses: actions/download-artifact@v3 - with: - name: docker-dht-node-test - path: /tmp - - name: Load Docker Image - run: docker load < /tmp/dht-node.tar - name: Lint - run: docker run --rm gradido/dht-node:test yarn run lint + run: cd dht-node && yarn && yarn run lint ############################################################################## # JOB: UNIT TEST ############################################################# ############################################################################## unit_test: name: Unit Tests - DHT Node + if: needs.files-changed.outputs.dht_node == 'true' || needs.files-changed.outputs.docker == 'true' + needs: [files-changed, build] runs-on: ubuntu-latest - needs: [build] steps: - name: Checkout code uses: actions/checkout@v3 @@ -83,16 +98,4 @@ jobs: #- name: Unit tests # run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test - name: Unit tests - run: | - docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net -v ~/coverage:/app/coverage --rm gradido/dht-node:test yarn run test - cp -r ~/coverage ./coverage - - - name: Coverage check - uses: webcraftmedia/coverage-check-action@master - with: - report_name: Coverage DHT Node - type: lcov - #result_path: ./dht-node/coverage/lcov.info - result_path: ./coverage/lcov.info - min_coverage: 79 - token: ${{ github.token }} + run: docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/dht-node:test yarn run test diff --git a/.github/workflows/test_federation.yml b/.github/workflows/test_federation.yml index ab943eedd..fc29a1bf8 100644 --- a/.github/workflows/test_federation.yml +++ b/.github/workflows/test_federation.yml @@ -3,11 +3,32 @@ name: Gradido Federation Test CI on: push jobs: + # only (but most important) job from this workflow required for pull requests + # check results serve as run conditions for all other jobs here + files-changed: + name: Detect File Changes - Federation + runs-on: ubuntu-latest + outputs: + docker: ${{ steps.changes.outputs.docker }} + federation: ${{ steps.changes.outputs.federation }} + steps: + - uses: actions/checkout@v3.3.0 + + - name: Check for frontend file changes + uses: dorny/paths-filter@v2.11.1 + id: changes + with: + token: ${{ github.token }} + filters: .github/file-filters.yml + list-files: shell + ############################################################################## # JOB: DOCKER BUILD TEST ##################################################### ############################################################################## build: name: Docker Build Test - Federation + if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.federation == 'true' + needs: files-changed runs-on: ubuntu-latest steps: - name: Checkout code @@ -29,30 +50,24 @@ jobs: ############################################################################## lint: name: Lint - Federation + if: needs.files-changed.outputs.federation == 'true' + needs: files-changed runs-on: ubuntu-latest - needs: [build] steps: - name: Checkout code uses: actions/checkout@v3 - - - name: Download Docker Image - uses: actions/download-artifact@v3 - with: - name: docker-federation-test - path: /tmp - - name: Load Docker Image - run: docker load < /tmp/federation.tar - name: Lint - run: docker run --rm gradido/federation:test yarn run lint + run: cd federation && yarn && yarn run lint ############################################################################## # JOB: UNIT TEST ############################################################# ############################################################################## unit_test: name: Unit Tests - Federation + if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.federation == 'true' + needs: [files-changed, build] runs-on: ubuntu-latest - needs: [build] steps: - name: Checkout code uses: actions/checkout@v3 @@ -84,15 +99,4 @@ jobs: # run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test - name: Unit tests run: | - docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net -v ~/coverage:/app/coverage --rm gradido/federation:test yarn run test - cp -r ~/coverage ./coverage - - - name: Coverage check - uses: webcraftmedia/coverage-check-action@master - with: - report_name: Coverage Federation - type: lcov - #result_path: ./federation/coverage/lcov.info - result_path: ./coverage/lcov.info - min_coverage: 72 - token: ${{ github.token }} + docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/federation:test yarn run test diff --git a/.github/workflows/test_frontend.yml b/.github/workflows/test_frontend.yml new file mode 100644 index 000000000..6dd527079 --- /dev/null +++ b/.github/workflows/test_frontend.yml @@ -0,0 +1,84 @@ +name: Gradido Frontend Test CI + +on: push + +jobs: + # only (but most important) job from this workflow required for pull requests + # check results serve as run conditions for all other jobs here + files-changed: + name: Detect File Changes - Frontend + runs-on: ubuntu-latest + outputs: + frontend: ${{ steps.changes.outputs.frontend }} + steps: + - uses: actions/checkout@v3.3.0 + + - name: Check for frontend file changes + uses: dorny/paths-filter@v2.11.1 + id: changes + with: + token: ${{ github.token }} + filters: .github/file-filters.yml + list-files: shell + + + build_test: + if: needs.files-changed.outputs.frontend == 'true' + name: Docker Build Test - Frontend + needs: files-changed + runs-on: ubuntu-latest + steps: + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Frontend | Build 'test' image + run: docker build --target test -t "gradido/frontend:test" frontend/ --build-arg NODE_ENV="test" + + unit_test: + if: needs.files-changed.outputs.frontend == 'true' + name: Unit Tests - Frontend + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Frontend | Unit tests + run: cd frontend && yarn && yarn run test + + lint: + if: needs.files-changed.outputs.frontend == 'true' + name: Lint - Frontend + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Frontend | Lint + run: cd frontend && yarn && yarn run lint + + stylelint: + if: needs.files-changed.outputs.frontend == 'true' + name: Stylelint - Frontend + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Frontend | Stylelint + run: cd frontend && yarn && yarn run stylelint + + locales: + if: needs.files-changed.outputs.frontend == 'true' + name: Locales - Frontend + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Frontend | Locales + run: cd frontend && yarn && yarn run locales diff --git a/README.md b/README.md index 3d086018e..87b4f44e5 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,11 @@ git clone git@github.com:gradido/gradido.git git submodule update --recursive --init ``` -### 2. Run docker-compose +### 2. Install modules + +You can go in each under folder (admin, frontend, database, backend, ...) and call ``yarn`` in each folder or you can call ``yarn installAll``. + +### 3. Run docker-compose Run docker-compose to bring up the development environment diff --git a/admin/jest.config.js b/admin/jest.config.js index 9233dd2e7..b6ec1dc80 100644 --- a/admin/jest.config.js +++ b/admin/jest.config.js @@ -1,11 +1,17 @@ module.exports = { verbose: true, + collectCoverage: true, collectCoverageFrom: [ 'src/**/*.{js,vue}', '!**/node_modules/**', '!src/assets/**', '!**/?(*.)+(spec|test).js?(x)', ], + coverageThreshold: { + global: { + lines: 97, + }, + }, moduleFileExtensions: [ 'js', // 'jsx', diff --git a/admin/package.json b/admin/package.json index 10399739d..3406c326a 100644 --- a/admin/package.json +++ b/admin/package.json @@ -14,7 +14,7 @@ "analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json", "lint": "eslint --max-warnings=0 --ext .js,.vue,.json .", "stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'", - "test": "cross-env TZ=UTC jest --coverage", + "test": "cross-env TZ=UTC jest", "locales": "scripts/sort.sh" }, "dependencies": { diff --git a/admin/src/components/ChangeUserRoleFormular.spec.js b/admin/src/components/ChangeUserRoleFormular.spec.js index 7f2154ecc..381d2ce43 100644 --- a/admin/src/components/ChangeUserRoleFormular.spec.js +++ b/admin/src/components/ChangeUserRoleFormular.spec.js @@ -28,6 +28,7 @@ const mocks = { let propsData let wrapper +let spy describe('ChangeUserRoleFormular', () => { const Wrapper = () => { @@ -70,12 +71,16 @@ describe('ChangeUserRoleFormular', () => { expect(wrapper.text()).toContain('userRole.notChangeYourSelf') }) - it('has role select disabled', () => { - expect(wrapper.find('select[disabled="disabled"]').exists()).toBe(true) + it('has no role select', () => { + expect(wrapper.find('select.role-select').exists()).toBe(false) + }) + + it('has no button', () => { + expect(wrapper.find('button.btn.btn-dange').exists()).toBe(false) }) }) - describe('change others role', () => { + describe("change other user's role", () => { let rolesToSelect describe('general', () => { @@ -106,19 +111,12 @@ describe('ChangeUserRoleFormular', () => { expect(wrapper.find('select.role-select[disabled="disabled"]').exists()).toBe(false) }) - describe('on API error', () => { - beforeEach(() => { - apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) - rolesToSelect.at(1).setSelected() - }) - - it('toasts an error message', () => { - expect(toastErrorSpy).toBeCalledWith('Oh no!') - }) + it('has "change_user_role" button', () => { + expect(wrapper.find('button.btn.btn-danger').text()).toBe('change_user_role') }) }) - describe('user is usual user', () => { + describe('user has role "usual user"', () => { beforeEach(() => { apolloMutateMock.mockResolvedValue({ data: { @@ -141,6 +139,10 @@ describe('ChangeUserRoleFormular', () => { describe('change select to', () => { describe('same role', () => { + it('has "change_user_role" button disabled', () => { + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(true) + }) + it('does not call the API', () => { rolesToSelect.at(0).setSelected() expect(apolloMutateMock).not.toHaveBeenCalled() @@ -152,39 +154,75 @@ describe('ChangeUserRoleFormular', () => { rolesToSelect.at(1).setSelected() }) - it('calls the API', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - mutation: setUserRole, - variables: { - userId: 1, - isAdmin: true, - }, - }), + it('has "change_user_role" button enabled', () => { + expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true) + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe( + false, ) }) - it('emits "updateIsAdmin"', () => { - expect(wrapper.emitted('updateIsAdmin')).toEqual( - expect.arrayContaining([ - expect.arrayContaining([ - { - userId: 1, - isAdmin: expect.any(Date), - }, - ]), - ]), - ) - }) + describe('clicking the "change_user_role" button', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + spy.mockImplementation(() => Promise.resolve(true)) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) - it('toasts success message', () => { - expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + it('calls the modal', () => { + expect(wrapper.emitted('showModal')) + expect(spy).toHaveBeenCalled() + }) + + describe('confirm role change with success', () => { + it('calls the API', () => { + expect(apolloMutateMock).toBeCalledWith( + expect.objectContaining({ + mutation: setUserRole, + variables: { + userId: 1, + isAdmin: true, + }, + }), + ) + }) + + it('emits "updateIsAdmin"', () => { + expect(wrapper.emitted('updateIsAdmin')).toEqual( + expect.arrayContaining([ + expect.arrayContaining([ + { + userId: 1, + isAdmin: expect.any(Date), + }, + ]), + ]), + ) + }) + + it('toasts success message', () => { + expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + }) + }) + + describe('confirm role change with error', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) + + it('toasts an error message', () => { + expect(toastErrorSpy).toBeCalledWith('Oh no!') + }) + }) }) }) }) }) - describe('user is admin', () => { + describe('user has role "admin"', () => { beforeEach(() => { apolloMutateMock.mockResolvedValue({ data: { @@ -207,6 +245,10 @@ describe('ChangeUserRoleFormular', () => { describe('change select to', () => { describe('same role', () => { + it('has "change_user_role" button disabled', () => { + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(true) + }) + it('does not call the API', () => { rolesToSelect.at(1).setSelected() expect(apolloMutateMock).not.toHaveBeenCalled() @@ -218,33 +260,69 @@ describe('ChangeUserRoleFormular', () => { rolesToSelect.at(0).setSelected() }) - it('calls the API', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - mutation: setUserRole, - variables: { - userId: 1, - isAdmin: false, - }, - }), + it('has "change_user_role" button enabled', () => { + expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true) + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe( + false, ) }) - it('emits "updateIsAdmin"', () => { - expect(wrapper.emitted('updateIsAdmin')).toEqual( - expect.arrayContaining([ - expect.arrayContaining([ - { - userId: 1, - isAdmin: null, - }, - ]), - ]), - ) - }) + describe('clicking the "change_user_role" button', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + spy.mockImplementation(() => Promise.resolve(true)) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) - it('toasts success message', () => { - expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + it('calls the modal', () => { + expect(wrapper.emitted('showModal')) + expect(spy).toHaveBeenCalled() + }) + + describe('confirm role change with success', () => { + it('calls the API', () => { + expect(apolloMutateMock).toBeCalledWith( + expect.objectContaining({ + mutation: setUserRole, + variables: { + userId: 1, + isAdmin: false, + }, + }), + ) + }) + + it('emits "updateIsAdmin"', () => { + expect(wrapper.emitted('updateIsAdmin')).toEqual( + expect.arrayContaining([ + expect.arrayContaining([ + { + userId: 1, + isAdmin: null, + }, + ]), + ]), + ) + }) + + it('toasts success message', () => { + expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + }) + }) + + describe('confirm role change with error', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) + + it('toasts an error message', () => { + expect(toastErrorSpy).toBeCalledWith('Oh no!') + }) + }) }) }) }) diff --git a/admin/src/components/ChangeUserRoleFormular.vue b/admin/src/components/ChangeUserRoleFormular.vue index 1217ce7f0..677a12f56 100644 --- a/admin/src/components/ChangeUserRoleFormular.vue +++ b/admin/src/components/ChangeUserRoleFormular.vue @@ -4,19 +4,23 @@
{{ $t('userRole.notChangeYourSelf') }}
-
+
- + +
+ + {{ $t('change_user_role') }} + +
- diff --git a/admin/src/components/Tables/OpenCreationsTable.spec.js b/admin/src/components/Tables/OpenCreationsTable.spec.js index 6542dab31..8f91aca03 100644 --- a/admin/src/components/Tables/OpenCreationsTable.spec.js +++ b/admin/src/components/Tables/OpenCreationsTable.spec.js @@ -5,7 +5,6 @@ const localVue = global.localVue const apolloMutateMock = jest.fn().mockResolvedValue({}) const apolloQueryMock = jest.fn().mockResolvedValue({}) -const toggleDetailsMock = jest.fn() const propsData = { items: [ @@ -17,7 +16,7 @@ const propsData = { amount: 300, memo: 'Aktives Grundeinkommen für Januar 2022', date: '2022-01-01T00:00:00.000Z', - moderator: 1, + moderatorId: 1, creation: [700, 1000, 1000], __typename: 'PendingCreation', }, @@ -29,7 +28,7 @@ const propsData = { amount: 210, memo: 'Aktives Grundeinkommen für Januar 2022', date: '2022-01-01T00:00:00.000Z', - moderator: null, + moderatorId: null, creation: [790, 1000, 1000], __typename: 'PendingCreation', }, @@ -41,7 +40,7 @@ const propsData = { amount: 330, memo: 'Aktives Grundeinkommen für Januar 2022', date: '2022-01-01T00:00:00.000Z', - moderator: 1, + moderatorId: 1, creation: [670, 1000, 1000], __typename: 'PendingCreation', }, @@ -83,7 +82,7 @@ const mocks = { $store: { state: { moderator: { - id: 0, + id: 1, name: 'test moderator', }, }, @@ -132,14 +131,6 @@ describe('OpenCreationsTable', () => { }) }) - describe('call updateUserData', () => { - it('user creations has updated data', async () => { - wrapper.vm.updateUserData(propsData.items[0], [444, 555, 666]) - await wrapper.vm.$nextTick() - expect(wrapper.vm.items[0].creation).toEqual([444, 555, 666]) - }) - }) - describe('call updateState', () => { beforeEach(() => { wrapper.vm.updateState(4) @@ -149,40 +140,5 @@ describe('OpenCreationsTable', () => { expect(wrapper.vm.$root.$emit('update-state', 4)).toBeTruthy() }) }) - - describe('call updateCreationData', () => { - const date = new Date() - beforeEach(() => { - wrapper.vm.updateCreationData({ - amount: Number(80.0), - date: date, - memo: 'Test memo', - row: { - item: {}, - detailsShowing: false, - toggleDetails: toggleDetailsMock, - }, - }) - }) - - it('emits update-state', () => { - expect( - wrapper.vm.$emit('update-contributions', { - amount: Number(80.0), - date: date, - memo: 'Test memo', - row: { - item: {}, - detailsShowing: false, - toggleDetails: toggleDetailsMock, - }, - }), - ).toBeTruthy() - }) - - it('calls toggleDetails', () => { - expect(toggleDetailsMock).toBeCalled() - }) - }) }) }) diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index a17d3a185..9d93eba60 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -27,9 +27,10 @@ diff --git a/frontend/src/components/GddTransactionList.vue b/frontend/src/components/GddTransactionList.vue index deed0dedb..63e203f31 100644 --- a/frontend/src/components/GddTransactionList.vue +++ b/frontend/src/components/GddTransactionList.vue @@ -37,7 +37,6 @@ @@ -45,7 +44,6 @@ @@ -53,7 +51,6 @@ diff --git a/frontend/src/components/Menu/Sidebar.spec.js b/frontend/src/components/Menu/Sidebar.spec.js index 321d73a3a..e6e4cfe2a 100644 --- a/frontend/src/components/Menu/Sidebar.spec.js +++ b/frontend/src/components/Menu/Sidebar.spec.js @@ -49,15 +49,15 @@ describe('Sidebar', () => { expect(wrapper.findAll('.nav-item').at(2).text()).toEqual('navigation.transactions') }) - it('has nav-item "gdt.gdt" in navbar', () => { + it('has nav-item "creation" in navbar', () => { expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('creation') }) - it('has nav-item "creation" in navbar', () => { + it('has nav-item "GDT" in navbar', () => { expect(wrapper.findAll('.nav-item').at(4).text()).toContain('GDT') }) - it('has nav-item "Information" in navbar', () => { + it('has nav-item "navigation.info" in navbar', () => { expect(wrapper.findAll('.nav-item').at(5).text()).toContain('navigation.info') }) }) @@ -68,13 +68,13 @@ describe('Sidebar', () => { expect(wrapper.findAll('ul').at(1).findAll('.nav-item')).toHaveLength(2) }) - it('has nav-item "navigation.info" in navbar', () => { + it('has nav-item "navigation.settings" in navbar', () => { expect(wrapper.findAll('ul').at(1).findAll('.nav-item').at(0).text()).toEqual( 'navigation.settings', ) }) - it('has nav-item "navigation.settings" in navbar', () => { + it('has nav-item "navigation.logout" in navbar', () => { expect(wrapper.findAll('ul').at(1).findAll('.nav-item').at(1).text()).toEqual( 'navigation.logout', ) diff --git a/frontend/src/components/Menu/Sidebar.vue b/frontend/src/components/Menu/Sidebar.vue index 83adcb594..644fb37e0 100644 --- a/frontend/src/components/Menu/Sidebar.vue +++ b/frontend/src/components/Menu/Sidebar.vue @@ -48,7 +48,12 @@ {{ $t('navigation.admin_area') }} - + {{ $t('navigation.logout') }} diff --git a/frontend/src/components/QrCode/FigureQrCode.spec.js b/frontend/src/components/QrCode/FigureQrCode.spec.js index 715a5d5d5..0c0b7bf3a 100644 --- a/frontend/src/components/QrCode/FigureQrCode.spec.js +++ b/frontend/src/components/QrCode/FigureQrCode.spec.js @@ -6,12 +6,15 @@ const localVue = global.localVue const propsData = { link: '', } +const mocks = { + $t: jest.fn((t) => t), +} describe('FigureQrCode', () => { let wrapper const Wrapper = () => { - return mount(FigureQrCode, { localVue, propsData }) + return mount(FigureQrCode, { localVue, mocks, propsData }) } describe('mount', () => { @@ -19,12 +22,55 @@ describe('FigureQrCode', () => { wrapper = Wrapper() }) - it('renders the Div Element ".figure-qr-code"', () => { - expect(wrapper.find('div.figure-qr-code').exists()).toBeTruthy() + afterEach(() => { + jest.clearAllMocks() }) - it('renders the Div Element "q-r-canvas"', () => { - expect(wrapper.find('q-r-canvas')) + it('has options filled', () => { + expect(wrapper.vm.options).toEqual({ + cellSize: 8, + correctLevel: 'H', + data: '', + }) + }) + + it('renders the Div Element ".figure-qr-code"', () => { + expect(wrapper.find('div.figure-qr-code').exists()).toBe(true) + }) + + it('renders the Div Element "qrbox"', () => { + expect(wrapper.find('div.qrbox').exists()).toBe(true) + }) + + it('renders the Canvas Element "#qrcanvas"', () => { + const canvas = wrapper.find('#qrcanvas') + + expect(canvas.exists()).toBe(true) + const canvasEl = canvas.element + const canvasWidth = canvasEl.width + const canvasHeight = canvasEl.height + + expect(canvasWidth).toBeGreaterThan(0) + expect(canvasHeight).toBeGreaterThan(0) + + const canvasContext = canvasEl.toDataURL('image/png') + expect(canvasContext).not.toBeNull() + }) + + it('renders the A Element "#download"', () => { + const downloadLink = wrapper.find('#download') + expect(downloadLink.exists()).toBe(true) + }) + + describe('Download QR-Code link', () => { + beforeEach(() => { + const downloadLink = wrapper.find('#download') + downloadLink.trigger('click') + }) + + it('click the A Element "#download" set an href', () => { + expect(wrapper.find('#download').attributes('href')).toEqual('data:image/png;base64,00') + }) }) }) }) diff --git a/frontend/src/components/QrCode/FigureQrCode.vue b/frontend/src/components/QrCode/FigureQrCode.vue index 00f1b54b9..40b1098dc 100644 --- a/frontend/src/components/QrCode/FigureQrCode.vue +++ b/frontend/src/components/QrCode/FigureQrCode.vue @@ -1,7 +1,18 @@ @@ -37,6 +48,13 @@ export default { } } }, + methods: { + downloadImg() { + const canvas = this.$refs.canvas.$el + const image = canvas.toDataURL('image/png') + this.$refs.download.href = image + }, + }, }