#!/bin/bash set -e -u -o pipefail cd "$(dirname "$0")" . .e2erc mme2e_log "Prepare Playwright: clean and initialize report and logs directory" ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- playwright bash </dev/null 2>&1; then for f in e2e-tests/playwright/results/blob-report/*.zip; do mv \"\$f\" \"${STASH_DIR}/first-\$(basename \"\$f\")\" done fi " || true RESULTS_FILE="../playwright/results/reporter/results.json" FAILED_SPECS="" if [ -f "$RESULTS_FILE" ]; then FAILED_SPECS=$(jq -r ' [.suites[] | . as $top | (recurse(.suites[]?) | .specs[]? | .tests[]? | select((.results | length) > 0) | select((.results | last).status == "failed" or (.results | last).status == "timedOut") | (.location.file // $top.file)) ] | map(select(. != null)) | unique | join(",") ' "$RESULTS_FILE" 2>/dev/null || echo "") fi if [ -n "$FAILED_SPECS" ]; then mme2e_log "Retrying failed specs on the same runner: $FAILED_SPECS" # Split the comma-separated list into an array and shell-quote every entry # with printf '%q' so that filenames containing shell metacharacters # (;, &&, $(), etc.) are treated as literals by the inner bash -lc shell # and cannot be used for command injection. IFS=',' read -ra _spec_array <<< "$FAILED_SPECS" SPEC_ARGS=$(printf '%q ' "${_spec_array[@]}") ${MME2E_DC_SERVER} exec -i -T -u "$MME2E_UID" \ -e TEST_FILTER \ -e PW_SHARD \ -- playwright bash -lc "cd e2e-tests/playwright && npm run test:ci -- $SPEC_ARGS \${TEST_FILTER:+\$TEST_FILTER} \${PW_SHARD:+\$PW_SHARD}" | tee ../playwright/logs/playwright-retry.log || true # Stash retry blobs alongside the first-pass blobs. ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- playwright bash -lc " if compgen -G 'e2e-tests/playwright/results/blob-report/*.zip' >/dev/null 2>&1; then for f in e2e-tests/playwright/results/blob-report/*.zip; do mv \"\$f\" \"${STASH_DIR}/retry-\$(basename \"\$f\")\" done fi " || true fi # Move all stashed blobs back into blob-report/ for final merge-reports # and for upload-artifact. This step runs whether or not retries ran: # if no retries, we just put the first-pass blobs back. ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- playwright bash -lc " mkdir -p e2e-tests/playwright/results/blob-report if compgen -G '${STASH_DIR}/*.zip' >/dev/null 2>&1; then mv ${STASH_DIR}/*.zip e2e-tests/playwright/results/blob-report/ fi rmdir ${STASH_DIR} 2>/dev/null || true " || true # Merge the combined blob set into a single results.json so the per-shard # `summary.json` below reflects first-pass + retry outcomes. The cross- # shard merge in the CI template's `calculate-results` job will re-merge # all shards' blobs from the same `blob-report/` contents. if [ -n "$FAILED_SPECS" ]; then mme2e_log "Merging first-pass + retry blob reports" ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- playwright bash -lc " cd e2e-tests/playwright rm -rf results/reporter mkdir -p results/reporter npx playwright merge-reports --config merge.config.mjs results/blob-report " || true else mme2e_log "No failed specs in shard; skipping inline retry" fi # Keep a combined tail log for backwards-compat with anything grepping # playwright.log. The authoritative results are the merged blob reports. cat ../playwright/logs/playwright-first.log \ ../playwright/logs/playwright-retry.log \ >../playwright/logs/playwright.log 2>/dev/null || true # Collect run results from the merged results.json. This summary is used # only by local dev / the cypress-oriented template; the playwright CI # template computes authoritative totals from the merged blob reports it # downloads across all shards. # Documentation: https://playwright.dev/docs/api/class-testcase#test-case-expected-status if [ -f ../playwright/results/reporter/results.json ]; then jq -f /dev/stdin ../playwright/results/reporter/results.json >../playwright/results/summary.json <../playwright/logs/mattermost.log 2>&1