pool: 'Default' variables: # - group: Digital-Infrastructure # - group: FMG-BuildBranches - name: dockerImageName value: 'playwright-tests' - name: imageTag value: '$(Build.BuildId)' - name: totalShards value: 4 stages: - stage: TestPr displayName: Run Playwright Test jobs: - job: playwright_tests continueOnError: true strategy: matrix: shard1: shardNumber: 1 shard2: shardNumber: 2 shard3: shardNumber: 3 shard4: shardNumber: 4 steps: - task: Docker@2 displayName: 'Build Docker Image' inputs: command: build dockerfile: Dockerfile.playwright repository: $(dockerImageName) tags: $(imageTag) arguments: '--no-cache --pull' - script: | # Create container and run tests container_id=$(docker create \ --ipc=host \ -e CCIS_API_AUTH=$(CCIS_API_AUTH) \ -e BASE_URL="$(BASE_URL)" \ -e CCIS_API_URL=$(CCIS_API_URL) \ -e ADMIN_SERVICE_API_URL=$(ADMIN_SERVICE_API_URL) \ -e SKIP_CONTENT_SITE=$(SKIP_CONTENT_SITE) \ -e CI=true \ -e NODE_ENV=$(NODE_ENV) \ $(dockerImageName):$(imageTag) \ npm run test:playwright -- --shard=$(shardNumber)/$(totalShards) --reporter=list,blob --grep '@(Alert|CASH)') # Start container and stream logs echo "Starting tests for shard $(shardNumber)..." docker start -a $container_id # Create directory for test results echo "Creating test results directory..." mkdir -p $(System.DefaultWorkingDirectory)/blob-reports/shard-$(shardNumber) # Copy test results from container echo "Copying test results..." docker cp $container_id:/app/blob-report/. $(System.DefaultWorkingDirectory)/blob-reports/shard-$(shardNumber)/ # Remove container echo "Cleaning up container..." docker rm $container_id # Check if tests failed if [ $? -ne 0 ]; then echo "Tests failed in shard $(shardNumber) or tests don't exist for this shard number!" exit 0 # Suppress error. It will be visible in report. fi displayName: 'Run Playwright Tests - Shard $(shardNumber)' - task: PublishPipelineArtifact@1 displayName: 'Publish Test Reports - Shard $(shardNumber)' condition: always() inputs: targetPath: '$(System.DefaultWorkingDirectory)/blob-reports/shard-$(shardNumber)' artifact: 'playwright-report-shard-$(shardNumber)' publishLocation: 'pipeline' - script: | docker rmi $(dockerImageName):$(imageTag) -f displayName: 'Cleanup Docker Image' condition: always() - job: download_and_merge_reports dependsOn: playwright_tests timeoutInMinutes: 8 cancelTimeoutInMinutes: 10 steps: - task: DownloadPipelineArtifact@2 inputs: targetPath: '$(System.DefaultWorkingDirectory)/playwright-reports' - task: Docker@2 displayName: 'Build Docker Image' inputs: command: build dockerfile: Dockerfile.playwright repository: $(dockerImageName) tags: $(imageTag) arguments: '--no-cache --pull' - bash: | # Jira credentials and server jira_server=$(JIRA_SERVER) jira_username=$(JIRA_USERNAME) jira_api_key=$(JIRA_API_KEY) echo "Using Jira server: $jira_server" echo "Using Jira username: $jira_username" # Jira card details jira_key="CASH" jira_card_summary="AUTOMATED REGRESSION RUN RESULTS" jira_card_description="This card contains the results of automated regression runs." jira_parent_key="CASH-208" jira_uat_tester_id="557058:a314fc5b-aed9-4472-90f8-00f106e06207" # Get active sprint with CASH in the name echo "Getting active sprint with CASH in the name..." sprint_response=$(curl -s -u "$jira_username:$jira_api_key" -X GET "$jira_server/rest/agile/1.0/board/845/sprint?state=active") # Check if response contains an error if echo "$sprint_response" | grep -q "\"errorMessages\""; then echo "Error retrieving sprints: $(echo $sprint_response | jq -r '.errorMessages[0]')" exit 1 fi active_sprint=$(echo "$sprint_response" | jq -r '.values[] | select(.name | test("CASH"; "i")) | .id') if [ -z "$active_sprint" ]; then echo "No active sprint with CASH in the name found. Response was:" echo "$sprint_response" | jq '.' # Fallback to getting any active sprint active_sprint=$(echo "$sprint_response" | jq -r '.values[0].id') if [ -z "$active_sprint" ]; then echo "No active sprints found at all." exit 1 else echo "Using fallback active sprint: $active_sprint" fi else echo "Found active CASH sprint with ID: $active_sprint" fi # Check if the card exists in the active sprint with detailed error handling echo "Checking for existing card in sprint $active_sprint..." sprint_issues_response=$(curl -s -u "$jira_username:$jira_api_key" -X GET "$jira_server/rest/agile/1.0/sprint/$active_sprint/issue") if echo "$sprint_issues_response" | grep -q "\"errorMessages\""; then echo "Error retrieving sprint issues: $(echo $sprint_issues_response | jq -r '.errorMessages[0]')" # Fall back to searching for the issue directly echo "Falling back to direct issue search..." search_response=$(curl -s -u "$jira_username:$jira_api_key" -X GET "$jira_server/rest/api/2/search?jql=project=$jira_key%20AND%20summary~%22$jira_card_summary%22") existing_card=$(echo "$search_response" | jq -r '.issues[0].key') else existing_card=$(echo "$sprint_issues_response" | jq -r ".issues[] | select(.fields.summary == \"$jira_card_summary\") | .key") fi echo "Existing card on current sprint: $existing_card" if [ -z "$existing_card" ]; then echo "No existing card found. Creating new card..." # Create JSON payload for issue creation creation_payload='{ "fields": { "project": { "key": "'$jira_key'" }, "summary": "'$jira_card_summary'", "description": "'$jira_card_description'", "issuetype": { "name": "Task" }, "parent": { "key": "'$jira_parent_key'" }, "customfield_13100": { "id": "'$jira_uat_tester_id'" } } }' echo "Creation payload: $creation_payload" response=$(curl -s -u "$jira_username:$jira_api_key" \ -X POST \ -H "Content-Type: application/json" \ -d "$creation_payload" \ "$jira_server/rest/api/2/issue") echo "Card creation response: $response" # Check for errors in the response if echo "$response" | grep -q "\"errorMessages\""; then echo "Error creating card: $(echo $response | jq -r '.errorMessages[0]')" exit 1 fi new_card=$(echo $response | jq -r '.key') if [ -z "$new_card" ] || [ "$new_card" == "null" ]; then echo "Failed to create new card. Response: $response" exit 1 fi card_key=$new_card echo "Created new card with key: $card_key" # Move the new card to the active sprint with better error handling echo "Moving card to sprint $active_sprint..." sprint_move_payload="{\"fields\": {\"customfield_10007\": $active_sprint}}" sprint_move_response=$(curl -s -u "$jira_username:$jira_api_key" \ -X PUT \ -H "Content-Type: application/json" \ -d "$sprint_move_payload" \ "$jira_server/rest/api/2/issue/$card_key") # Check for errors in sprint move response (will be empty if successful) if [ ! -z "$sprint_move_response" ] && echo "$sprint_move_response" | grep -q "\"errorMessages\""; then echo "Warning: Error moving card to sprint: $(echo $sprint_move_response | jq -r '.errorMessages[0]')" echo "Continuing anyway..." else echo "Card moved to sprint successfully" fi # Move the new card to In Test Status with better error handling echo "Moving card to In Test status..." transition_id="271" transition_payload="{\"transition\": {\"id\": $transition_id}}" transition_response=$(curl -s -u "$jira_username:$jira_api_key" \ -X POST \ -H "Content-Type: application/json" \ -d "$transition_payload" \ "$jira_server/rest/api/2/issue/$card_key/transitions") # Check for errors in transition response if [ ! -z "$transition_response" ] && echo "$transition_response" | grep -q "\"errorMessages\""; then echo "Warning: Error transitioning card: $(echo $transition_response | jq -r '.errorMessages[0]')" # Try to get available transitions for debugging available_transitions=$(curl -s -u "$jira_username:$jira_api_key" -X GET "$jira_server/rest/api/2/issue/$card_key/transitions") echo "Available transitions: $available_transitions" echo "Continuing anyway..." else echo "Card status changed successfully" fi else card_key=$existing_card echo "Using existing card with key: $card_key" fi # Get current day of week and numeric date for report name current_day=$(date +%A) numeric_date=$(date +%m-%d-%Y) report_name="ortoni-report-${NODE_ENV}-${current_day}-${numeric_date}.html" # Create container for jira writeback container_id=$(docker create \ --ipc=host \ -e JIRA_SERVER=$(JIRA_SERVER) \ -e JIRA_USERNAME=$(JIRA_USERNAME) \ -e JIRA_API_KEY=$(JIRA_API_KEY) \ -e REPORT_NAME="$report_name" \ -e CURRENT_DAY="$current_day" \ -e NUMERIC_DATE="$numeric_date" \ -e NODE_ENV=$(NODE_ENV) \ -e CARD_KEY="$card_key" \ $(dockerImageName):$(imageTag) \ bash -c "chmod +x devops/scripts/jira_writeback.sh echo \"Moving Playwright reports out of subfolders...\" find ./playwright-reports/ -mindepth 2 -type f -exec mv {} ./playwright-reports/ \; echo \"Merging reports...\" PLAYWRIGHT_JUNIT_OUTPUT_DIR='/app/playwright-tests/artifacts/test-results' PLAYWRIGHT_JUNIT_OUTPUT_NAME='junit_results.xml' npx playwright merge-reports --reporter=ortoni-report,junit ./playwright-reports echo \"Contents of ortoni-report:\" && ls ./ortoni-report echo 'Current dir: ' && pwd echo 'Contents of current dir: ' && ls echo 'Contents of /app/playwright-tests/artifacts/test-results' && ls /app/playwright-tests/artifacts/test-results # Rename the report file to include the day and date if [ -f /app/ortoni-report/ortoni-report.html ]; then mv /app/ortoni-report/ortoni-report.html /app/ortoni-report/\${REPORT_NAME} echo \"Renamed report to \${REPORT_NAME}\" else echo \"ortoni-report.html not found!\" fi echo \"Writing report to Jira card '\${CARD_KEY}'...\" /app/devops/scripts/jira_writeback.sh add_comment \"\${CARD_KEY}\" /app/ortoni-report/\${REPORT_NAME} \"AUTOMATED TEST RUN: $(date) - \${CURRENT_DAY} (\${NUMERIC_DATE}) - Environment: \${NODE_ENV}\" ") # Start container and stream logs echo "Starting merge" docker start -a $container_id # Create directory for test results echo "Creating test results directory..." mkdir -p $(System.DefaultWorkingDirectory)/ortoni-report mkdir -p $(System.DefaultWorkingDirectory)/test-results # Copy test results from container echo "Copying test results..." docker cp $container_id:/app/ortoni-report/. $(System.DefaultWorkingDirectory)/ortoni-report docker cp $container_id:/app/playwright-tests/artifacts/test-results/junit_results.xml $(System.DefaultWorkingDirectory)/test-results # Remove container echo "Cleaning up container..." docker rm $container_id env: JIRA_API_KEY: $(JIRA_API_KEY) displayName: merge_and_publish_results_to_jira - task: PublishTestResults@2 displayName: 'Publish test results' inputs: searchFolder: 'test-results' testResultsFormat: 'JUnit' testResultsFiles: 'junit_results.xml' mergeTestResults: true failTaskOnFailedTests: false testRunTitle: 'Playwright Tests' condition: succeededOrFailed() - task: PublishPipelineArtifact@1 displayName: 'Publish Merged Report' condition: always() inputs: targetPath: '$(System.DefaultWorkingDirectory)/ortoni-report' artifact: 'playwright-merged-report' publishLocation: 'pipeline' - script: | docker rmi $(dockerImageName):$(imageTag) -f displayName: 'Cleanup Docker Image' condition: always()