name: Tests E2E on: workflow_call: inputs: node-version: required: true type: string deno-version: required: true type: string lowercase-repo: required: true type: string rc-dockerfile: required: true type: string rc-docker-tag: required: true type: string gh-docker-tag: required: true type: string enterprise-license: type: string transporter: type: string mongodb-version: default: "['5.0', '7.0']" required: false type: string release: required: true type: string shard: default: '[1]' required: false type: string total-shard: default: 1 required: false type: number retries: default: 0 required: false type: number type: required: true type: string db-watcher-disabled: default: 'false' required: false type: string secrets: CR_USER: required: true CR_PAT: required: true QASE_API_TOKEN: required: false REPORTER_ROCKETCHAT_URL: required: false REPORTER_ROCKETCHAT_API_KEY: required: false CODECOV_TOKEN: required: false REPORTER_JIRA_ROCKETCHAT_API_KEY: required: false env: MONGO_URL: mongodb://localhost:27017/rocketchat?replicaSet=rs0&directConnection=true TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }} LOWERCASE_REPOSITORY: ${{ inputs.lowercase-repo }} DOCKER_TAG: ${{ inputs.gh-docker-tag }} jobs: test: runs-on: ubuntu-20.04 env: RC_DOCKERFILE: ${{ inputs.rc-dockerfile }}.${{ (matrix.mongodb-version == '7.0' && 'debian' && false) || 'alpine' }} RC_DOCKER_TAG: ${{ inputs.rc-docker-tag }}.${{ (matrix.mongodb-version == '7.0' && 'debian' && false) || 'alpine' }} strategy: fail-fast: false matrix: mongodb-version: ${{ fromJSON(inputs.mongodb-version) }} shard: ${{ fromJSON(inputs.shard) }} name: MongoDB ${{ matrix.mongodb-version }}${{ inputs.db-watcher-disabled == 'true' && ' [no watchers]' || '' }} (${{ matrix.shard }}/${{ inputs.total-shard }}) - ${{ (matrix.mongodb-version == '7.0' && 'Debian' && false) || 'Alpine (Official)' }} steps: - name: Collect Workflow Telemetry uses: catchpoint/workflow-telemetry-action@v2 with: theme: dark job_summary: true comment_on_pr: false - name: Setup kernel limits run: | sudo sysctl -w net.ipv4.ip_local_port_range="500 65535" sudo sysctl -w net.ipv4.tcp_mem="383865 511820 2303190" echo fs.file-max=20000500 | sudo tee -a /etc/sysctl.conf echo fs.nr_open=20000500 | sudo tee -a /etc/sysctl.conf sudo sysctl -p - name: Login to GitHub Container Registry if: (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') && github.actor != 'dependabot[bot]' uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ secrets.CR_USER }} password: ${{ secrets.CR_PAT }} - name: Launch MongoDB uses: supercharge/mongodb-github-action@v1.10.0 with: mongodb-version: ${{ matrix.mongodb-version }} mongodb-replica-set: rs0 - uses: actions/checkout@v4 - name: Setup NodeJS uses: ./.github/actions/setup-node with: node-version: ${{ inputs.node-version }} deno-version: ${{ inputs.deno-version }} cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - uses: rharkor/caching-for-turbo@v1.5 - name: Restore turbo build uses: actions/download-artifact@v4 with: name: turbo-build path: .turbo/cache - run: yarn build # if we are testing a PR from a fork, we need to build the docker image at this point - uses: ./.github/actions/build-docker if: github.event_name == 'pull_request' && (github.event.pull_request.head.repo.full_name != github.repository || github.actor == 'dependabot[bot]') with: CR_USER: ${{ secrets.CR_USER }} CR_PAT: ${{ secrets.CR_PAT }} node-version: ${{ inputs.node-version }} # we already called the turbo cache at this point, so it should be false turbo-cache: false # the same reason we need to rebuild the docker image at this point is the reason we dont want to publish it publish-image: false setup: false NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Start httpbin container and wait for it to be ready if: inputs.type == 'api' run: | docker run -d -p 10000:80 --name httpbin-container kennethreitz/httpbin i=0 while [ $i -lt 10 ]; do if curl -s -o /dev/null http://localhost:10000; then echo "httpbin is running" break fi i=$((i + 1)) sleep 5 done if [ $i -eq 10 ]; then echo "Failed to verify httpbin is running" exit 1 fi - name: Prepare code coverage directory if: inputs.release == 'ee' run: | mkdir -p /tmp/coverage chmod 777 /tmp/coverage - name: Start containers for CE if: inputs.release == 'ce' env: MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true' run: | # when we are testing CE, we only need to start the rocketchat container docker compose -f docker-compose-ci.yml up -d rocketchat - name: Start containers for EE if: inputs.release == 'ee' env: MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true' ENTERPRISE_LICENSE: ${{ inputs.enterprise-license }} TRANSPORTER: ${{ inputs.transporter }} COVERAGE_DIR: '/tmp/coverage' COVERAGE_REPORTER: 'lcov' DISABLE_DB_WATCHERS: ${{ inputs.db-watcher-disabled }} run: | docker compose -f docker-compose-ci.yml up -d - name: Cache Playwright binaries if: inputs.type == 'ui' uses: actions/cache@v4 id: cache-playwright with: path: | ~/.cache/ms-playwright # This is the version of Playwright that we are using, if you are willing to upgrade, you should update this. key: playwright-1.48.2 - name: Install Playwright if: inputs.type == 'ui' && steps.cache-playwright.outputs.cache-hit != 'true' working-directory: ./apps/meteor run: npx playwright install --with-deps - name: Wait for Rocket.Chat to start up uses: cygnetdigital/wait_for_response@v2.0.0 with: url: 'http://localhost:3000/health' responseCode: '200' timeout: 60000 interval: 1000 - name: Wait services to start up if: inputs.release == 'ee' run: | docker ps until echo "$(docker compose -f docker-compose-ci.yml logs ddp-streamer-service)" | grep -q "NetworkBroker started successfully"; do echo "Waiting 'ddp-streamer' to start up" ((c++)) && ((c==10)) && docker compose -f docker-compose-ci.yml logs ddp-streamer-service && exit 1 sleep 10 done; - name: Remove unused Docker images run: docker system prune -af - name: E2E Test API if: inputs.type == 'api' working-directory: ./apps/meteor env: WEBHOOK_TEST_URL: 'http://host.docker.internal:10000' IS_EE: ${{ inputs.release == 'ee' && 'true' || '' }} COVERAGE_DIR: '/tmp/coverage' COVERAGE_REPORTER: 'lcovonly' run: | for i in $(seq 1 2); do npm run testapi && s=0 && break || s=$? docker compose -f ../../docker-compose-ci.yml logs --tail=100 docker compose -f ../../docker-compose-ci.yml stop docker exec mongodb bash -c 'if command -v mongosh ; then mongosh --eval "use rocketchat" --eval "db.dropDatabase()" rocketchat; else mongo rocketchat --eval "db.dropDatabase()"; fi' NOW=$(date "+%Y-%m-%dT%H:%M:%S.000Z") docker compose -f ../../docker-compose-ci.yml restart until echo "$(docker compose -f ../../docker-compose-ci.yml logs rocketchat --since $NOW)" | grep -q "SERVER RUNNING"; do echo "Waiting Rocket.Chat to start up" ((c++)) && ((c==10)) && exit 1 sleep 10 done; done; docker compose -f ../../docker-compose-ci.yml stop ls -l $COVERAGE_DIR exit $s - name: E2E Test UI (${{ matrix.shard }}/${{ inputs.total-shard }}) if: inputs.type == 'ui' env: E2E_COVERAGE: ${{ inputs.release == 'ee' && 'true' || '' }} IS_EE: ${{ inputs.release == 'ee' && 'true' || '' }} REPORTER_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_ROCKETCHAT_API_KEY }} REPORTER_ROCKETCHAT_URL: ${{ secrets.REPORTER_ROCKETCHAT_URL }} REPORTER_JIRA_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_JIRA_ROCKETCHAT_API_KEY }} REPORTER_ROCKETCHAT_REPORT: ${{ github.event.pull_request.draft != 'true' && 'true' || '' }} REPORTER_ROCKETCHAT_RUN: ${{ github.run_number }} REPORTER_ROCKETCHAT_BRANCH: ${{ github.ref }} REPORTER_ROCKETCHAT_DRAFT: ${{ github.event.pull_request.draft }} REPORTER_ROCKETCHAT_HEAD_SHA: ${{ github.event.pull_request.head.sha }} REPORTER_ROCKETCHAT_AUTHOR: ${{ github.event.pull_request.user.login }} REPORTER_ROCKETCHAT_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} REPORTER_ROCKETCHAT_PR: ${{ github.event.pull_request.number }} QASE_API_TOKEN: ${{ secrets.QASE_API_TOKEN }} QASE_REPORT: ${{ github.ref == 'refs/heads/develop' && 'true' || '' }} CI: true PLAYWRIGHT_RETRIES: ${{ inputs.retries }} working-directory: ./apps/meteor run: | yarn prepare yarn test:e2e --shard=${{ matrix.shard }}/${{ inputs.total-shard }} - name: Store playwright test trace if: inputs.type == 'ui' && always() uses: actions/upload-artifact@v4 with: name: playwright-test-trace-${{ inputs.release }}-${{ matrix.mongodb-version }}-${{ matrix.shard }} path: ./apps/meteor/tests/e2e/.playwright* include-hidden-files: true - name: Show server logs if E2E test failed if: failure() && inputs.release == 'ee' run: docker compose -f docker-compose-ci.yml logs - name: Show server logs if E2E test failed if: failure() && inputs.release != 'ee' run: docker compose -f docker-compose-ci.yml logs rocketchat - name: Extract e2e:ee:coverage if: inputs.type == 'ui' && inputs.release == 'ee' working-directory: ./apps/meteor run: yarn test:e2e:nyc - uses: codecov/codecov-action@v3 if: inputs.type == 'ui' && inputs.release == 'ee' with: directory: ./apps/meteor flags: e2e verbose: true token: ${{ secrets.CODECOV_TOKEN }} - uses: codecov/codecov-action@v3 if: inputs.type == 'api' && inputs.release == 'ee' with: directory: /tmp/coverage working-directory: . flags: e2e-api verbose: true token: ${{ secrets.CODECOV_TOKEN }} - name: Store e2e-api-ee-coverage if: inputs.type == 'api' && inputs.release == 'ee' uses: actions/upload-artifact@v4 with: name: e2e-api-ee-coverage-${{ matrix.mongodb-version }}-${{ matrix.shard }} path: /tmp/coverage include-hidden-files: true - name: Store e2e-ee-coverage if: inputs.type == 'ui' && inputs.release == 'ee' uses: actions/upload-artifact@v4 with: name: e2e-ee-coverage-${{ matrix.mongodb-version }}-${{ matrix.shard }} path: ./apps/meteor/coverage* include-hidden-files: true