Skip to content

Commit

Permalink
Merge pull request #7 from roicarrera/backup-branch
Browse files Browse the repository at this point in the history
Backup branch
  • Loading branch information
roicarrera authored Nov 5, 2024
2 parents 90280d3 + ae8e16f commit 3dca248
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 49 deletions.
48 changes: 34 additions & 14 deletions e2e-cypress/Jenkinsfile.template
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ odsComponentPipeline(
// 'release/': 'test'
]
) { context ->

// Note: Testing in the production environment is not recommended as it can lead to unintended consequences,
// including potential downtime, data corruption, or exposure of sensitive information.
// This block is designed to skip tests in the production environment to avoid these risks.
// If you choose to enable testing in production, do so at your own risk and take all necessary precautions.
if (context.environment == 'prod') {
currentBuild.result = 'SUCCESS'
echo 'Skipping the entire test build for production environment'
return
}

def targetDirectory = "${context.projectId}/${context.componentId}/${context.gitBranch.replaceAll('/', '-')}/${context.buildNumber}"

stageTest(context)
Expand All @@ -49,27 +60,32 @@ odsComponentPipeline(

def stageTest(def context) {
stage('Integration Test') {
// OPTIONAL: load environment variables for Azure SSO with MSALv2; please adapt variable names to your OpenShift config
// Define your DEV and QA base URLs in a config map in OpenShift; please adapt variable names to your OpenShift config
// sh "oc project <project-with-configured-secrets>"
// cypressUser = sh(returnStdout: true, script:"oc get secret e2euser -o jsonpath='{.data.USERNAME}' | base64 -d")
// cypressPassword = sh(returnStdout: true, script:"oc get secret e2euser -o jsonpath='{.data.PASSWORD}' | base64 -d")
// azureClientId = sh(returnStdout: true, script:"oc get secret azure -o jsonpath='{.data.AZURE_CLIENT_ID}' | base64 -d")
// azureClientSecret = sh(returnStdout: true, script:"oc get secret azure -o jsonpath='{.data.AZURE_CLIENT_SECRET}' | base64 -d")
// azureTenantId = sh(returnStdout: true, script:"oc get configmaps azure -o jsonpath='{.data.AZURE_TENANT}'") // config map values are not base64 encoded
// authenticatorOTPSecret = sh(returnStdout: true, script:"oc get secret azure -o jsonpath='{.data.OTP_SECRET}' | base64 -d")
def baseUrls = [
: // remove this line once you have defined the config map and uncommented the next two lines, it's only here to make the example default case work
// dev: sh(returnStdout: true, script:"oc get configmaps cypress-config -o jsonpath='{.data.DEV_BASE_URL}'").trim(),
// test: sh(returnStdout: true, script:"oc get configmaps cypress-config -o jsonpath='{.data.TEST_BASE_URL}'").trim()
]

def baseUrl = baseUrls.get(context.environment ?: 'dev', 'https://www.w3schools.com') // default to W3Schools for demo purposes, replace with your own default

// Example for loading environment variables for Azure SSO; please adapt variable names to your OpenShift config,
// making sure to precede the variable names with the environment name in lowercase (e.g., dev_username, dev_password,
// test_username, test_password, etc.)
// cypressUser = sh(returnStdout: true, script:"oc get secret e2euser -o jsonpath='{.data.${context.environment}_username}' | base64 -d")
// cypressPassword = sh(returnStdout: true, script:"oc get secret e2euser -o jsonpath='{.data.${context.environment}_password}' | base64 -d")

withEnv(["TAGVERSION=${context.tagversion}",
"NEXUS_HOST=${context.nexusHost}",
"OPENSHIFT_PROJECT=${context.targetProject}",
"OPENSHIFT_APP_DOMAIN=${context.getOpenshiftApplicationDomain()}",
// "CYPRESS_TENANT_ID=${azureTenantId}",
// "CYPRESS_CLIENT_ID=${azureClientId}",
// "CYPRESS_CLIENT_SECRET=${azureClientSecret}",
// "CYPRESS_USERNAME=${cypressUser}",
// "CYPRESS_PASSWORD=${cypressPassword}",
// "OTP_SECRET=${authenticatorOTPSecret}",
"COMMIT_INFO_SHA=${context.gitCommit}",
"BUILD_NUMBER=${context.buildNumber}",
"CYPRESS_BASE_URL=${baseUrl}",
]) {
sh 'npm install'
def status = sh(script: 'npm run e2e', returnStatus: true)
Expand All @@ -79,16 +95,20 @@ def stageTest(def context) {
stash(name: "integration-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/integration-junit.xml', allowEmpty: true)
stash(name: "acceptance-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/acceptance-junit.xml', allowEmpty: true)

sh 'npx ts-node ./pdf-generator.ts'
zip zipFile: 'cypress/pdf.zip', archive: false, dir: 'build/test-results/mochawesome/pdf'
archiveArtifacts artifacts: 'cypress/pdf.zip', fingerprint: true, daysToKeep: 2, numToKeep: 3

if (fileExists('cypress/videos')) {
zip zipFile: 'cypress/videos.zip', archive: false, dir: 'cypress/videos'
stash(name: "acceptance-test-videos-${context.componentId}-${context.buildNumber}", includes: 'cypress/videos.zip', allowEmpty: true)
archiveArtifacts artifacts: 'cypress/videos.zip', fingerprint: true, daysToKeep: 2, numToKeep: 3
}

if (fileExists('cypress/screenshots')) {
zip zipFile: 'cypress/screenshots.zip', archive: false, dir: 'cypress/screenshots'
stash(name: "acceptance-test-screenshots-${context.componentId}-${context.buildNumber}", includes: 'cypress/screenshots.zip', allowEmpty: true)
archiveArtifacts artifacts: 'cypress/screenshots.zip', fingerprint: true, daysToKeep: 2, numToKeep: 3
if (fileExists('build/test-results/screenshots')) {
zip zipFile: 'screenshots.zip', archive: false, dir: 'build/test-results/screenshots'
stash(name: "acceptance-test-screenshots-${context.componentId}-${context.buildNumber}", includes: 'screenshots.zip', allowEmpty: true)
archiveArtifacts artifacts: 'screenshots.zip', fingerprint: true, daysToKeep: 2, numToKeep: 3
}

return status
Expand Down
24 changes: 18 additions & 6 deletions e2e-cypress/files/cypress-acceptance.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@ import { defineConfig } from 'cypress'
import setupNodeEvents from './plugins/index.js'
export default defineConfig({
//projectId: '[Your project ID from Cypress cloud]',
reporter: 'reporters/custom-reporter.js',
reporter: 'cypress-multi-reporters',
reporterOptions: {
mochaFile: 'build/test-results/acceptance-junit-[hash].xml',
toConsole: true,
reporterEnabled: 'mochawesome,./reporters/custom-reporter.js',
mochawesomeReporterOptions: {
reportDir: 'build/test-results/mochawesome',
reportFilename: 'acceptance-mochawesome',
charts: true,
html: true,
timestamp: true,
json: true
},
reportersCustomReporterJsReporterOptions: {
mochaFile: 'build/test-results/acceptance-junit-[hash].xml',
toConsole: true,
},
},
e2e: {
baseUrl: 'https://www.w3schools.com',
baseUrl: process.env.CYPRESS_BASE_URL,
fixturesFolder: "fixtures",
specPattern: 'tests/acceptance/*.cy.ts',
supportFile: "support/e2e.ts",
viewportWidth: 1376,
viewportHeight: 660,
screenshotsFolder: 'build/test-results/screenshots',
viewportWidth: 1280,
viewportHeight: 720,
experimentalModifyObstructiveThirdPartyCode:true,
video: true,
async setupNodeEvents(on, config) {
Expand Down
24 changes: 18 additions & 6 deletions e2e-cypress/files/cypress-installation.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@ import { defineConfig } from 'cypress'
import setupNodeEvents from './plugins/index.js'
export default defineConfig({
//projectId: '[Your project ID from Cypress cloud]',
reporter: 'reporters/custom-reporter.js',
reporter: 'cypress-multi-reporters',
reporterOptions: {
mochaFile: 'build/test-results/installation-junit-[hash].xml',
toConsole: true,
reporterEnabled: 'mochawesome,./reporters/custom-reporter.js',
mochawesomeReporterOptions: {
reportDir: 'build/test-results/mochawesome',
reportFilename: 'installation-mochawesome',
charts: true,
html: true,
timestamp: true,
json: true
},
reportersCustomReporterJsReporterOptions: {
mochaFile: 'build/test-results/installation-junit-[hash].xml',
toConsole: true,
},
},
e2e: {
baseUrl: 'https://www.w3schools.com',
baseUrl: process.env.CYPRESS_BASE_URL,
fixturesFolder: "fixtures",
specPattern: 'tests/installation/*.cy.ts',
supportFile: "support/e2e.ts",
viewportWidth: 1376,
viewportHeight: 660,
screenshotsFolder: 'build/test-results/screenshots',
viewportWidth: 1280,
viewportHeight: 720,
experimentalModifyObstructiveThirdPartyCode:true,
video: true,
async setupNodeEvents(on, config) {
Expand Down
24 changes: 18 additions & 6 deletions e2e-cypress/files/cypress-integration.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@ import { defineConfig } from 'cypress'
import setupNodeEvents from './plugins/index.js'
export default defineConfig({
//projectId: '[Your project ID from Cypress cloud]',
reporter: 'reporters/custom-reporter.js',
reporter: 'cypress-multi-reporters',
reporterOptions: {
mochaFile: 'build/test-results/integration-junit-[hash].xml',
toConsole: true,
reporterEnabled: 'mochawesome,./reporters/custom-reporter.js',
cypressMochawesomeReporterReporterOptions: {
reportDir: 'build/test-results/mochawesome',
reportFilename: 'integration-mochawesome',
charts: true,
html: true,
timestamp: true,
json: true
},
reportersCustomReporterJsReporterOptions: {
mochaFile: 'build/test-results/integration-junit-[hash].xml',
toConsole: true,
},
},
e2e: {
baseUrl: 'https://www.w3schools.com',
baseUrl: process.env.CYPRESS_BASE_URL,
fixturesFolder: "fixtures",
specPattern: 'tests/integration/*.cy.ts',
supportFile: "support/e2e.ts",
viewportWidth: 1376,
viewportHeight: 660,
screenshotsFolder: 'build/test-results/screenshots',
viewportWidth: 1280,
viewportHeight: 720,
experimentalModifyObstructiveThirdPartyCode:true,
video: true,
async setupNodeEvents(on, config) {
Expand Down
24 changes: 18 additions & 6 deletions e2e-cypress/files/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import { defineConfig } from 'cypress'
import setupNodeEvents from './plugins/index.js'
export default defineConfig({
reporter: 'reporters/custom-reporter.js',
reporter: 'cypress-multi-reporters',
reporterOptions: {
mochaFile: 'build/test-results/tests-[hash].xml',
toConsole: true,
reporterEnabled: 'mochawesome,./reporters/custom-reporter.js',
mochawesomeReporterOptions: {
reportDir: 'build/test-results/mochawesome',
reportFilename: 'mochawesome',
charts: true,
html: true,
timestamp: true,
json: true
},
reportersCustomReporterJsReporterOptions: {
mochaFile: 'build/test-results/tests-[hash].xml',
toConsole: true,
},
},
e2e: {
baseUrl: 'https://www.w3schools.com',
baseUrl: process.env.CYPRESS_BASE_URL || 'https://www.w3schools.com',
fixturesFolder: "fixtures",
specPattern: 'tests/**/*.cy.ts',
supportFile: "support/e2e.ts",
viewportWidth: 1376,
viewportHeight: 660,
screenshotsFolder: 'build/test-results/screenshots',
viewportWidth: 1280,
viewportHeight: 720,
experimentalModifyObstructiveThirdPartyCode: true,
video: true,
async setupNodeEvents(on, config) {
Expand Down
3 changes: 3 additions & 0 deletions e2e-cypress/files/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
"devDependencies": {
"@types/node": "^22.4.1",
"cypress": "^13.13.1",
"cypress-multi-reporters": "^1.6.4",
"junit-report-merger": "^7.0.0",
"mocha-junit-reporter": "^2.2.1",
"npm-run-all": "^4.1.5",
"otplib": "^12.0.1",
"puppeteer": "^23.5.1",
"rimraf": "^6.0.1",
"sharp": "^0.33.5",
"ts-node": "^10.9.2",
"typescript": "^5.5.4"
}
}
68 changes: 68 additions & 0 deletions e2e-cypress/files/pdf-generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as puppeteer from 'puppeteer';
import * as path from 'path';
import * as fs from 'fs';

async function expandReportTestCases(htmlPage: puppeteer.Page) {
await htmlPage.evaluate(() => {
const expandTestHeaders = document.querySelectorAll('[class^="test--header"], [class*="test--header"]');
for (const testHeader of Array.from(expandTestHeaders)) {
(testHeader as HTMLElement).click();
}
});
}

const isLocal = process.env.NODE_ENV === 'local';

(async () => {
try {
const files = await fs.promises.readdir('build/test-results/mochawesome/');

for (const file of files) {

if (!fs.existsSync(path.resolve(__dirname, 'build/test-results/mochawesome/', 'pdf')))
fs.mkdirSync(path.resolve(__dirname, 'build/test-results/mochawesome/', 'pdf'));
if (!file.endsWith('.html')) {
continue;
}

const executablePath = isLocal ? undefined : '/usr/bin/google-chrome';

const browser = await puppeteer.launch({ args: ['--no-sandbox'],
executablePath
});
const page = await browser.newPage();
const htmlFullFilePath = path.resolve(__dirname, 'build/test-results/mochawesome/', file);

await page.goto(`file://${htmlFullFilePath}`, { waitUntil: 'networkidle2' });

await expandReportTestCases(page);

const images = await page.$$('img');
for (const image of images) {
await page.waitForFunction((img) => img.complete && img.naturalHeight !== 0, {}, image);
}

await page.addStyleTag({
content: `
@media print {
[class*="navbar"] {
position: static !important;
}
}
`
});

await page.pdf({
path: path.resolve(__dirname, 'build/test-results/mochawesome/', 'pdf/', file.replace('.html', '.pdf')),
format: 'A4',
printBackground: true,
});
await browser.close();
}

console.log('PDF files generated successfully');

} catch (error) {
console.error('Error generating PDF:', error);
}
})();
6 changes: 6 additions & 0 deletions e2e-cypress/files/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ const setupNodeEvents: NonNullable<Cypress.ConfigOptions['setupNodeEvents']> = (
return await addEvidenceMetaToScreenshot(data);
}
});
on('before:browser:launch', (browser: Cypress.Browser, launchOptions) => {
if (browser.isHeadless && (browser.name === 'chrome' || browser.name === 'edge')) {
launchOptions.args.push('--disable-gpu');
}
return launchOptions;
});
};

export default setupNodeEvents;
11 changes: 11 additions & 0 deletions e2e-cypress/files/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,14 @@ addGetTOTP();
addSessionLoginWithMFA();
addLoginToAAD();
addLoginToAADWithMFA();

declare global {
namespace Cypress {
interface Chainable<> {
loginToAAD(username: string, password: string);
loginToAADWithMFA(username: string, password: string);
sessionLoginWithMFA(username: string, password: string);
getTOTP();
addScreenshot(title: string, screenshot: string);
}
}
11 changes: 11 additions & 0 deletions e2e-cypress/files/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import './commands';
const addContext = require('mochawesome/addContext');

export const consoleLogs: string[] = [];

Expand All @@ -15,3 +16,13 @@ afterEach(function() {

consoleLogs.splice(0);
})

Cypress.Commands.add('addScreenshot', (title: string, screenshot: string) => {
cy.on('test:after:run', (attributes) => {
// The context needs the screenshot path relative to the build/test-results/mochawesome folder
addContext({ test: attributes }, {
title: title,
value: screenshot
});
});
})
11 changes: 0 additions & 11 deletions e2e-cypress/files/support/login-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,3 @@ const validateLocalStorage = (localStorage: Record<string, unknown>) =>
Cypress._.some(localStorage, (value: unknown, key: string) =>
key.includes('CognitoIdentityServiceProvider'),
)

declare global {
namespace Cypress {
interface Chainable<> {
loginToAAD(username: string, password: string);
loginToAADWithMFA(username: string, password: string);
sessionLoginWithMFA(username: string, password: string);
getTOTP();
}
}
}
4 changes: 4 additions & 0 deletions e2e-cypress/files/support/test-evidence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export const takeScreenshotEvidence = (testName: string, testStep: number, testS
logEvidence(testName, testStep, description, [
`Stored screenshot "${path.basename(result.path)}" with hash (sha256) ${result.hash} taken at ${String(data.takenAt)} as evidence.`
]);

// Create a relative path from the screenshots folder to the mochawesome test-results folder
const relativePath = path.relative('build/test-results/mochawesome', result.path.replace(/^.*(build.*)$/, '$1'));
cy.addScreenshot(`${testName} ${testStep} ${testSubStep}`, relativePath);
});
});
};

0 comments on commit 3dca248

Please sign in to comment.