# builds Element Web # runs Playwright tests against the built Element Web # builds Element Desktop using the built Element Web # # Tries to use a matching js-sdk branch for the build. # # Produces a `webapp` artifact # Produces multiple Desktop artifacts # Produces multiple Playwright report artifacts name: Build & Test on: # CRON to run all Projects at 6am UTC schedule: - cron: "0 6 * * *" pull_request: {} merge_group: types: [checks_requested] push: # We do not build on push to develop as the merge_group check handles that branches: [staging, master] # support triggering from other workflows workflow_call: inputs: skip: type: boolean required: false default: false description: "A boolean to skip the playwright check itself while still creating the passing check. Useful when only running in Merge Queues." matrix-js-sdk-sha: type: string required: false description: "The Git SHA of matrix-js-sdk to build against. By default, will use a matching branch name if it exists, or develop." concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} cancel-in-progress: true env: # fetchdep.sh needs to know our PR number PR_NUMBER: ${{ github.event.pull_request.number }} # Use 4 runners in the default case, but only 1 when running on a schedule where we run all 5 projects NUM_RUNNERS: ${{ github.event_name == 'schedule' && 1 || 4 }} NX_DEFAULT_OUTPUT_STYLE: stream-without-prefixes permissions: {} # No permissions required jobs: build_ew: name: "Build Element Web" runs-on: ubuntu-24.04 if: inputs.skip != true outputs: num-runners: ${{ env.NUM_RUNNERS }} runners-matrix: ${{ steps.runner-vars.outputs.matrix }} steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: repository: element-hq/element-web persist-credentials: false - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 with: cache: "pnpm" node-version: "lts/*" - name: Fetch layered build env: # tell layered.sh to check out the right sha of the JS-SDK & EW, if they were given one JS_SDK_GITHUB_BASE_REF: ${{ inputs.matrix-js-sdk-sha }} run: scripts/layered.sh - name: Copy config working-directory: apps/web run: cp element.io/develop/config.json config.json - name: Build env: CI_PACKAGE: true working-directory: apps/web run: VERSION=$(scripts/get-version-from-git.sh) pnpm run build - name: Upload Artifact uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 with: name: webapp path: apps/web/webapp retention-days: 1 - name: Calculate runner variables id: runner-vars uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const numRunners = parseInt(process.env.NUM_RUNNERS, 10); const matrix = Array.from({ length: numRunners }, (_, i) => i + 1); core.setOutput("matrix", JSON.stringify(matrix)); playwright_ew: name: "Run Tests [${{ matrix.project }}] ${{ matrix.runner }}/${{ needs.build_ew.outputs.num-runners }}" needs: build_ew if: inputs.skip != true runs-on: ubuntu-24.04 permissions: actions: read issues: read pull-requests: read strategy: fail-fast: false matrix: # Run multiple instances in parallel to speed up the tests runner: ${{ fromJSON(needs.build_ew.outputs.runners-matrix) }} project: - Chrome - Firefox - WebKit - Dendrite - Pinecone runAllTests: - ${{ github.event_name == 'schedule' || contains(github.event.pull_request.labels.*.name, 'X-Run-All-Tests') }} # Skip the Firefox & Safari runs unless this was a cron trigger or PR has X-Run-All-Tests label exclude: - runAllTests: false project: Firefox - runAllTests: false project: WebKit - runAllTests: false project: Dendrite - runAllTests: false project: Pinecone steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false repository: element-hq/element-web - name: 📥 Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: webapp path: apps/web/webapp - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 with: cache: "pnpm" cache-dependency-path: pnpm-lock.yaml node-version: "lts/*" - name: Install dependencies run: pnpm install --frozen-lockfile - name: Setup playwright uses: ./.github/actions/setup-playwright with: needs-webkit: ${{ matrix.project == 'WebKit' }} write-cache: ${{ github.event_name != 'merge_group' }} # We skip tests tagged with @mergequeue when running on PRs, but run them in MQ and everywhere else - name: Run Playwright tests working-directory: apps/web run: | pnpm test:playwright \ --shard "$SHARD" \ --project="${{ matrix.project }}" \ ${{ (github.event_name == 'pull_request' && matrix.runAllTests == false ) && '--grep-invert @mergequeue' || '' }} env: SHARD: ${{ format('{0}/{1}', matrix.runner, needs.build_ew.outputs.num-runners) }} - name: Upload blob report to GitHub Actions Artifacts if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 with: name: blob-report-${{ matrix.project }}-${{ matrix.runner }} path: apps/web/blob-report retention-days: 1 if-no-files-found: error downstream-modules: name: Downstream Playwright tests [element-modules] needs: build_ew if: inputs.skip != true && github.event_name == 'merge_group' uses: element-hq/element-modules/.github/workflows/reusable-playwright-tests.yml@main # zizmor: ignore[unpinned-uses] with: webapp-artifact: webapp reporter: blob prepare_ed: name: "Prepare Element Desktop" uses: ./.github/workflows/build_desktop_prepare.yaml needs: build_ew if: inputs.skip != true permissions: contents: read with: config: ${{ (github.event.pull_request.base.ref || github.ref_name) == 'develop' && 'element.io/nightly' || 'element.io/release' }} version: ${{ case((github.event.pull_request.base.ref || github.ref_name) == 'develop' || github.event_name == 'merge_group', 'develop', '') }} webapp-artifact: webapp build_ed_windows: needs: prepare_ed name: "Desktop Windows" uses: ./.github/workflows/build_desktop_windows.yaml if: inputs.skip != true strategy: matrix: arch: [x64, ia32, arm64] with: arch: ${{ matrix.arch }} blob_report: true build_ed_linux: needs: prepare_ed name: "Desktop Linux" uses: ./.github/workflows/build_desktop_linux.yaml if: inputs.skip != true strategy: matrix: sqlcipher: [system, static] arch: [amd64, arm64] runAllTests: - ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'X-Run-All-Tests') }} # We ship static sqlcipher builds, so delegate testing the system builds to the merge queue exclude: - runAllTests: false sqlcipher: system with: sqlcipher: ${{ matrix.sqlcipher }} arch: ${{ matrix.arch }} blob_report: true build_ed_macos: needs: prepare_ed name: "Desktop macOS" uses: ./.github/workflows/build_desktop_macos.yaml if: inputs.skip != true with: blob_report: true complete: name: end-to-end-tests needs: - playwright_ew - downstream-modules - prepare_ed - build_ed_windows - build_ed_linux - build_ed_macos if: always() runs-on: ubuntu-24.04 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 if: inputs.skip != true with: persist-credentials: false repository: element-hq/element-web - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 if: inputs.skip != true - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 if: inputs.skip != true with: cache: "pnpm" node-version: "lts/*" - name: Install dependencies if: inputs.skip != true run: pnpm install --frozen-lockfile - name: Download blob reports from GitHub Actions Artifacts if: inputs.skip != true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: pattern: blob-report-* path: all-blob-reports merge-multiple: true - name: Merge into HTML Report if: inputs.skip != true run: | pnpm playwright merge-reports \ --config=playwright-merge.config.ts \ ./all-blob-reports env: # Only pass creds to the flaky-reporter on main branch runs GITHUB_TOKEN: ${{ github.ref_name == 'develop' && secrets.ELEMENT_BOT_TOKEN || '' }} PLAYWRIGHT_HTML_TITLE: ${{ case(github.event_name == 'pull_request', format('Playwright Report PR-{0}', env.PR_NUMBER), 'Playwright Report') }} # Upload the HTML report even if one of our reporters fails, this can happen when stale screenshots are detected - name: Upload HTML report if: always() && inputs.skip != true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 with: name: html-report path: playwright-report retention-days: 14 if-no-files-found: error - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') run: exit 1