# Triggers after the layered build has finished, taking the artifact and running cypress on it
#
# Also called by a workflow in matrix-js-sdk.
#
name: Cypress End to End Tests
on:
    workflow_run:
        workflows: ["Element Web - Build"]
        types:
            - completed

    # support calls from other workflows
    workflow_call:
        inputs:
            react-sdk-repository:
                type: string
                required: true
                description: "The name of the github repository to check out and build."
        secrets:
            CYPRESS_RECORD_KEY:
                required: true
            TCMS_USERNAME:
                required: true
            TCMS_PASSWORD:
                required: true

concurrency:
    group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }}
    cancel-in-progress: ${{ github.event.workflow_run.event == 'pull_request' }}

jobs:
    prepare:
        name: Prepare
        if: github.event.workflow_run.conclusion == 'success'
        runs-on: ubuntu-latest
        permissions:
            actions: read
            issues: read
            statuses: write
            pull-requests: read
        outputs:
            uuid: ${{ steps.uuid.outputs.value }}
            pr_id: ${{ steps.prdetails.outputs.pr_id }}
            percy_enable: ${{ steps.percy.outputs.value || '0' }}
        steps:
            # We create the status here and then update it to success/failure in the `report` stage
            # This provides an easy link to this workflow_run from the PR before Cypress is done.
            - uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
              with:
                  authToken: ${{ secrets.GITHUB_TOKEN }}
                  state: pending
                  context: ${{ github.workflow }} / cypress
                  sha: ${{ github.event.workflow_run.head_sha }}
                  target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}

            - id: prdetails
              if: github.event.workflow_run.event == 'pull_request' || github.event.workflow_run.event == 'merge_group'
              uses: matrix-org/pr-details-action@v1.3
              with:
                  owner: ${{ github.event.workflow_run.head_repository.owner.login }}
                  branch: ${{ github.event.workflow_run.head_branch }}

            # Percy is disabled while we're figuring out https://github.com/vector-im/wat-internal/issues/36
            # and https://github.com/vector-im/wat-internal/issues/56. We're hoping to turn it back on or switch
            # to an alternative in the future.
            # # Only run Percy when it is demanded or we are running the daily build
            # - name: Enable Percy
            #   id: percy
            #   if: |
            #       github.event.workflow_run.event == 'schedule' ||
            #       (
            #         github.event.workflow_run.event == 'merge_group' &&
            #         contains(fromJSON(steps.prdetails.outputs.data).labels.*.name, 'X-Needs-Percy')
            #       )
            #   run: echo "value=1" >> $GITHUB_OUTPUT

            - name: Generate unique ID 💎
              id: uuid
              run: echo "value=sha-$GITHUB_SHA-time-$(date +"%s")" >> $GITHUB_OUTPUT

    tests:
        name: "Run Tests (${{ matrix.crypto }} crypto)"
        needs: prepare
        runs-on: ubuntu-latest
        permissions:
            actions: read
            issues: read
            pull-requests: read
        environment: Cypress
        strategy:
            fail-fast: false
            matrix:
                # Run tests using both crypto stacks
                crypto: [legacy, rust]
                ci_node_total: [4]
                ci_node_index: [0, 1, 2, 3]
        steps:
            # The version of chrome shipped by default may not be consistent across runners
            # so we explicitly use a specific version of chrome here.
            - uses: browser-actions/setup-chrome@803ef6dfb4fdf22089c9563225d95e4a515820a0 # v1
            - run: echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV

            # There's a 'download artifact' action, but it hasn't been updated for the workflow_run action
            # (https://github.com/actions/download-artifact/issues/60) so instead we get this mess:
            - name: 📥 Download artifact
              uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2
              with:
                  run_id: ${{ github.event.workflow_run.id }}
                  name: previewbuild
                  path: webapp

            # The workflow_run.head_sha is the sha of the head commit but the element-web was built using a simulated
            # merge commit - https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
            # so use the sha from the tarball for the checkout of the cypress tests
            # to make sure we get a matching set of code and tests.
            - name: Grab sha from webapp
              id: sha
              run: |
                  echo "sha=$(cat webapp/sha)" >> $GITHUB_OUTPUT

            - uses: actions/checkout@v4
              with:
                  # XXX: We're checking out untrusted code in a secure context
                  # We need to be careful to not trust anything this code outputs/may do
                  #
                  # Note that (in the absence of a `react-sdk-repository` input),
                  # we check out from the default repository, which is (for this workflow) the
                  # *target* repository for the pull request.
                  #
                  ref: ${{ steps.sha.outputs.sha }}
                  persist-credentials: false
                  path: matrix-react-sdk
                  repository: ${{ inputs.react-sdk-repository || github.repository }}

            # Enable rust crypto if the calling workflow requests it
            - name: Enable rust crypto
              if: matrix.crypto == 'rust'
              run: |
                  echo "CYPRESS_RUST_CRYPTO=1" >> "$GITHUB_ENV"

            - name: Run Cypress tests via knapsack pro
              uses: cypress-io/github-action@ebe8b24c4428922d0f793a5c4c96853a633180e3 # v6.6.0
              with:
                  working-directory: matrix-react-sdk
                  headed: true
                  start: npx serve -p 8080 -L ../webapp
                  wait-on: "http://localhost:8080"
                  record: false
                  parallel: false
                  # The built-in Electron runner seems to grind to a halt trying to run the tests, so use chrome.
                  command: yarn percy exec --parallel -- npx knapsack-pro-cypress --config trashAssetsBeforeRuns=false --browser ${{ env.BROWSER_PATH }}
              env:
                  # Knapsack token and config
                  KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS: ${{ matrix.crypto == 'rust' && secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS_RUST || secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS_LEGACY }}
                  KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
                  KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
                  KNAPSACK_PRO_TEST_FILE_PATTERN: cypress/e2e/**/*.spec.ts
                  KNAPSACK_PRO_BRANCH: ${{ github.event.workflow_run.head_branch }}
                  KNAPSACK_PRO_COMMIT_HASH: ${{ github.event.workflow_run.head_sha }}

                  # Use existing chromium rather than downloading another
                  PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true

                  # pass GitHub token to allow accurately detecting a build vs a re-run build
                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

                  # make Node's os.tmpdir() return something where we actually have permissions
                  TMPDIR: ${{ runner.temp }}

                  # pass the Percy token as an environment variable
                  PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}

                  # only run percy on legacy crypto (for now)
                  PERCY_ENABLE: ${{ matrix.crypto == 'legacy' && needs.prepare.outputs.percy_enable || 0 }}
                  PERCY_BROWSER_EXECUTABLE: ${{ steps.setup-chrome.outputs.chrome-path }}
                  # tell Percy more details about the context of this run
                  PERCY_BRANCH: ${{ github.event.workflow_run.head_branch }}
                  PERCY_COMMIT: ${{ github.event.workflow_run.head_sha }}
                  PERCY_PULL_REQUEST: ${{ needs.prepare.outputs.pr_id }}
                  PERCY_PARALLEL_NONCE: ${{ needs.prepare.outputs.uuid }}
                  # We manually finalize the build in the report stage
                  PERCY_PARALLEL_TOTAL: -1

            - name: 📤 Upload results artifact
              if: failure()
              uses: actions/upload-artifact@v3
              with:
                  name: cypress-results-${{ matrix.crypto }}-crypto
                  path: |
                      matrix-react-sdk/cypress/screenshots
                      matrix-react-sdk/cypress/videos
                      matrix-react-sdk/cypress/synapselogs
                      matrix-react-sdk/cypress/results/cypresslogs

    report:
        name: Finalize results
        needs:
            - prepare
            - tests
        runs-on: ubuntu-latest
        if: always()
        permissions:
            statuses: write
        steps:
            - name: Finalize Percy
              if: needs.prepare.outputs.percy_enable == '1'
              run: npx -p @percy/cli percy build:finalize
              env:
                  PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
                  PERCY_PARALLEL_NONCE: ${{ needs.prepare.outputs.uuid }}

            - name: Skip Percy required check
              if: needs.prepare.outputs.percy_enable != '1'
              uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
              with:
                  authToken: ${{ secrets.GITHUB_TOKEN }}
                  state: success
                  description: Percy skipped
                  context: percy/matrix-react-sdk
                  sha: ${{ github.event.workflow_run.head_sha }}
                  target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}

            - uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
              with:
                  authToken: ${{ secrets.GITHUB_TOKEN }}
                  state: ${{ needs.tests.result == 'success' && 'success' || 'failure' }}
                  context: ${{ github.workflow }} / cypress
                  sha: ${{ github.event.workflow_run.head_sha }}
                  target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
