Update files for Playwright pipeline and reporting
This commit is contained in:
parent
d56629b346
commit
3202f4d933
5 changed files with 4143 additions and 242 deletions
|
|
@ -8,21 +8,28 @@ schedules:
|
||||||
- develop
|
- develop
|
||||||
pool: 'Default'
|
pool: 'Default'
|
||||||
|
|
||||||
|
resources:
|
||||||
|
repositories:
|
||||||
|
- repository: AzureDevOps
|
||||||
|
type: github
|
||||||
|
name: Safelite/AzureDevOps
|
||||||
|
endpoint: Safelite
|
||||||
|
ref: refs/tags/t5.7.40
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
# - group: Digital-Infrastructure
|
# - group: Digital-Infrastructure
|
||||||
# - group: ISS-BuildBranches
|
# - group: ISS-BuildBranches
|
||||||
|
- group: SafelitePlaywright
|
||||||
- name: dockerImageName
|
- name: dockerImageName
|
||||||
value: 'playwright-tests'
|
value: 'playwright-tests'
|
||||||
- name: imageTag
|
- name: imageTag
|
||||||
value: '$(Build.BuildId)'
|
value: '$(Build.BuildId)'
|
||||||
- name: totalShards
|
- name: totalShards
|
||||||
value: 4
|
value: '4'
|
||||||
- name: IS_REGRESSION
|
- name: IS_REGRESSION
|
||||||
value: 'true'
|
value: 'true'
|
||||||
- name: JIRA_BOARD_ID
|
- name: JIRA_BOARD_ID
|
||||||
value: '853'
|
value: '853'
|
||||||
- name: JIRA_EPIC_KEY
|
|
||||||
value: 'INSR-414'
|
|
||||||
- name: JIRA_PROJECT_KEY
|
- name: JIRA_PROJECT_KEY
|
||||||
value: 'INSR'
|
value: 'INSR'
|
||||||
|
|
||||||
|
|
@ -30,158 +37,17 @@ stages:
|
||||||
- stage: TestPr
|
- stage: TestPr
|
||||||
displayName: Run Playwright Test
|
displayName: Run Playwright Test
|
||||||
jobs:
|
jobs:
|
||||||
- job: playwright_tests
|
- template: templates/digital/playwright-test.yml@AzureDevOps
|
||||||
continueOnError: true
|
parameters:
|
||||||
strategy:
|
applicationType: 'vue'
|
||||||
matrix:
|
totalShards: ${{ variables.totalShards }}
|
||||||
shard1:
|
targetUrl: $(BASE_URL)
|
||||||
shardNumber: 1
|
dockerFileName: 'Dockerfile.playwright'
|
||||||
shard2:
|
isRegression: ${{ variables.IS_REGRESSION }}
|
||||||
shardNumber: 2
|
filterTags: ''
|
||||||
shard3:
|
playwrightTestsPath: 'playwright-tests'
|
||||||
shardNumber: 3
|
npmServePath: '.'
|
||||||
shard4:
|
npmrcPath: 'playwright-tests/.npmrc'
|
||||||
shardNumber: 4
|
secrets:
|
||||||
|
CCIS_API_AUTH: $(CCIS_API_AUTH)
|
||||||
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 SHARD=$(shardNumber) \
|
|
||||||
-e CI=true \
|
|
||||||
-e NODE_ENV=$(NODE_ENV) \
|
|
||||||
$(dockerImageName):$(imageTag) \
|
|
||||||
npx concurrently -k -n "server,playwright"\
|
|
||||||
"sed -i \"s|^process\.env\.VUE_APP_CONSUMER_CF_DISTRO = .*|process\.env\.VUE_APP_CONSUMER_CF_DISTRO='https://digitalapi.test.safelite.io'|\" \"./vue.config.js\" && echo \"Updated config file to use TEST APIs\" && npm run serve -- --port=8080"\
|
|
||||||
"npx wait-on http://localhost:8080 && npm run test:playwright -- --shard=$(shardNumber)/$(totalShards) --reporter=list,blob --grep \"@smoke|@Advanced\"")
|
|
||||||
|
|
||||||
# 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: |
|
|
||||||
# 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 IS_REGRESSION=$(IS_REGRESSION) \
|
|
||||||
-e JIRA_BOARD_ID=$(JIRA_BOARD_ID) \
|
|
||||||
-e JIRA_EPIC_KEY=$(JIRA_EPIC_KEY) \
|
|
||||||
-e JIRA_PROJECT_KEY=$(JIRA_PROJECT_KEY) \
|
|
||||||
$(dockerImageName):$(imageTag) \
|
|
||||||
bash -c "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/test-results' PLAYWRIGHT_JUNIT_OUTPUT_NAME='junit_results.xml' npx playwright merge-reports --reporter='playwright-tests/impl/reporter/JiraWritebackReporter.ts',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/test-results' && ls /app/test-results ")
|
|
||||||
|
|
||||||
# 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/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)
|
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()
|
|
||||||
3
playwright-tests/.npmrc
Normal file
3
playwright-tests/.npmrc
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
registry=https://pkgs.dev.azure.com/Safelite/Digital/_packaging/DigitalQA/npm/registry/
|
||||||
|
|
||||||
|
always-auth=true
|
||||||
4013
playwright-tests/package-lock.json
generated
Normal file
4013
playwright-tests/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
37
playwright-tests/package.json
Normal file
37
playwright-tests/package.json
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"name": "safelite-iss-nextgen-playwright-tests",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Playwright tests for ISS Nextgen using Safelite Playwright Core",
|
||||||
|
"directories": {
|
||||||
|
"test": "tests"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "playwright test",
|
||||||
|
"test:headed": "playwright test --headed",
|
||||||
|
"test:debug": "playwright test --debug",
|
||||||
|
"test:smoke": "playwright test --grep @smoke",
|
||||||
|
"test:report": "playwright test --grep @test_report",
|
||||||
|
"report": "playwright show-report",
|
||||||
|
"install": "playwright install",
|
||||||
|
"install:deps": "playwright install-deps"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.9.0",
|
||||||
|
"axios-retry": "^4.5.0",
|
||||||
|
"safelite-playwright-core": "^1.0.26"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@faker-js/faker": "^9.8.0",
|
||||||
|
"@playwright/test": "^1.52.0",
|
||||||
|
"@types/dotenv-safe": "^8.1.6",
|
||||||
|
"@types/node": "^22.15.32",
|
||||||
|
"dotenv-safe": "^9.1.0",
|
||||||
|
"eslint": "^9.28.0",
|
||||||
|
"luxon": "^3.6.1",
|
||||||
|
"ortoni-report": "^3.0.5",
|
||||||
|
"playwright-jira-reporter": "^1.0.16"
|
||||||
|
},
|
||||||
|
"private": "true"
|
||||||
|
}
|
||||||
|
|
@ -1,47 +1,62 @@
|
||||||
|
import { formatDateForFilename } from 'safelite-playwright-core';
|
||||||
import { defineConfig, devices } from '@playwright/test';
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
import { JiraReporterConfig } from 'playwright-jira-reporter'
|
||||||
import dotenv from 'dotenv-safe';
|
import dotenv from 'dotenv-safe';
|
||||||
import { OrtoniReportConfig } from "ortoni-report";
|
import { OrtoniReportConfig } from "ortoni-report";
|
||||||
import * as path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
if (!process.env.CI) {
|
if (!process.env.CI) {
|
||||||
// Environment variables are present in CI environment, no need to read from file
|
// Environment variables are present in CI environment, no need to read from file
|
||||||
if (process.env.NODE_ENV == 'undefined' || process.env.NODE_ENV == null) {
|
const basePath = __dirname; // This gets the directory where the config file is located
|
||||||
dotenv.config({ path: `playwright-tests/.env.dev`, example: 'playwright-tests/.env.example' });
|
|
||||||
}
|
if (process.env.PLAYWRIGHT_ENV == undefined || process.env.PLAYWRIGHT_ENV == null) {
|
||||||
else {
|
dotenv.config({
|
||||||
dotenv.config({ path: `playwright-tests/.env.${process.env.NODE_ENV}`, example: 'playwright-tests/.env.example' });
|
path: path.join(basePath, '.env.dev'),
|
||||||
}
|
example: path.join(basePath, '.env.example')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dotenv.config({
|
||||||
|
path: path.join(basePath, `.env.${process.env.PLAYWRIGHT_ENV}`),
|
||||||
|
example: path.join(basePath, '.env.example')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ortoni config
|
||||||
|
const ortoniReportConfig: OrtoniReportConfig = {
|
||||||
|
open: "never",
|
||||||
|
folderPath: process.env.CI ? 'ortoni-report' : 'test-results',
|
||||||
|
title: "ISS-NextGen Test Report",
|
||||||
|
filename: `iss_nextgen_ortoni_report_${formatDateForFilename(new Date())}.html`,
|
||||||
|
showProject: false,
|
||||||
|
projectName: "ISS-NextGen-Playwright-Report",
|
||||||
|
testType: `E2E- Environment: ${process.env.PLAYWRIGHT_ENV} `,
|
||||||
|
preferredTheme: "light",
|
||||||
|
base64Image: true,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// Jira Report config
|
||||||
* Read environment variables from file.
|
const jiraReportConfig: JiraReporterConfig = {
|
||||||
* https://github.com/motdotla/dotenv
|
// Jira Reporter Config
|
||||||
*/
|
isRegressionRun: process.env.IS_REGRESSION === 'true',
|
||||||
// import dotenv from 'dotenv';
|
jiraProjectKey: process.env.JIRA_PROJECT_KEY || '',
|
||||||
// import path from 'path';
|
jiraEpicKey: process.env.JIRA_EPIC_KEY || '',
|
||||||
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
jiraCardNumber: process.env.JIRA_CARD_NUMBER || '',
|
||||||
|
applicationName: 'ISS NextGen',
|
||||||
/**
|
jiraApiUtilConfig: {
|
||||||
* See https://playwright.dev/docs/test-configuration.
|
jiraUrl: process.env.JIRA_SERVER || '',
|
||||||
*/
|
jiraUsername: process.env.JIRA_USERNAME || '',
|
||||||
const reportConfig: OrtoniReportConfig = {
|
jiraApiKey: process.env.JIRA_API_KEY || '',
|
||||||
port: 1994,
|
jiraBoardId: process.env.JIRA_BOARD_ID || ''
|
||||||
open: "never",
|
},
|
||||||
folderPath: "test-results",
|
jiraCreationPermissions: {
|
||||||
filename: "index.html",
|
isCreateTestSubtasks: process.env.IS_REGRESSION !== 'true',
|
||||||
logo: "../business-logic/data/logo.png",
|
isCreateBugs: process.env.IS_REGRESSION !== 'true'
|
||||||
title: "Test Report",
|
},
|
||||||
showProject: false,
|
// Wrapped ortoni config
|
||||||
projectName: "ISS-Nextgen-Playwright-Report",
|
...ortoniReportConfig
|
||||||
testType: `E2E- Environment: ${process.env.NODE_ENV} `,
|
|
||||||
preferredTheme: "light",
|
|
||||||
base64Image: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reportFilePath = path.resolve(__dirname, './../test-results/accessibility-report.html');
|
|
||||||
export const jsonReportFilePath = path.resolve(__dirname, './../test-results/accessibility-report.json');
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
testDir: './tests',
|
testDir: './tests',
|
||||||
/* Run tests in files in parallel */
|
/* Run tests in files in parallel */
|
||||||
|
|
@ -53,12 +68,16 @@ export default defineConfig({
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 4 : 5,
|
workers: process.env.CI ? 4 : 5,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: [
|
reporter: process.env.CI? [
|
||||||
['ortoni-report', reportConfig],
|
['junit'],
|
||||||
|
['playwright-jira-reporter', jiraReportConfig],
|
||||||
|
['ortoni-report', ortoniReportConfig]
|
||||||
|
]: [
|
||||||
|
['ortoni-report', ortoniReportConfig],
|
||||||
['junit'],
|
['junit'],
|
||||||
['list']
|
['list']
|
||||||
],
|
],
|
||||||
timeout: 120_000,
|
timeout: 240_000,
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
|
@ -68,52 +87,15 @@ export default defineConfig({
|
||||||
trace: 'on-first-retry',
|
trace: 'on-first-retry',
|
||||||
headless: process.env.CI ? true : false,
|
headless: process.env.CI ? true : false,
|
||||||
screenshot: "only-on-failure",
|
screenshot: "only-on-failure",
|
||||||
actionTimeout: 5_000,
|
actionTimeout: 60_000,
|
||||||
navigationTimeout: 20_000
|
navigationTimeout: 60_000
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
/* Configure projects for major browsers */
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
name: 'chromium',
|
name: 'chromium',
|
||||||
use: { ...devices['Desktop Chrome'] },
|
use: { ...devices['Desktop Chrome'] },
|
||||||
},
|
},
|
||||||
|
],
|
||||||
// {
|
|
||||||
// name: 'firefox',
|
|
||||||
// use: { ...devices['Desktop Firefox'] },
|
|
||||||
// },
|
|
||||||
|
|
||||||
// {
|
|
||||||
// name: 'webkit',
|
|
||||||
// use: { ...devices['Desktop Safari'] },
|
|
||||||
// },
|
|
||||||
|
|
||||||
/* Test against mobile viewports. */
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Chrome',
|
|
||||||
// use: { ...devices['Pixel 5'] },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Safari',
|
|
||||||
// use: { ...devices['iPhone 12'] },
|
|
||||||
// },
|
|
||||||
|
|
||||||
/* Test against branded browsers. */
|
|
||||||
// {
|
|
||||||
// name: 'Microsoft Edge',
|
|
||||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Google Chrome',
|
|
||||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
|
||||||
// webServer: {
|
|
||||||
// command: 'npm run start',
|
|
||||||
// url: 'http://127.0.0.1:3000',
|
|
||||||
// reuseExistingServer: !process.env.CI,
|
|
||||||
// },
|
|
||||||
});
|
});
|
||||||
Loading…
Reference in a new issue