diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a01c4db34..d6cc78fbd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,7 +64,7 @@ jobs: if: success() || failure() with: name: e2e results - path: target/test-classes/e2e/cypress/reports/ + path: target/test-classes/e2e/cypress/ - name: Publish Test Report if: success() || failure() uses: scacap/action-surefire-report@v1 diff --git a/package-lock.json b/package-lock.json index 995eca39b..91c7f7b1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ }, "devDependencies": { "@commitlint/config-conventional": "^18.4.3", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^27.6.0", "eslint-plugin-n": "^16.2.0", "eslint-plugin-promise": "^6.1.1" @@ -87,9 +87,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -944,15 +944,15 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", + "@eslint/js": "8.56.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1105,9 +1105,9 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", - "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { "array-includes": "^3.1.7", @@ -1126,7 +1126,7 @@ "object.groupby": "^1.0.1", "object.values": "^1.1.7", "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -2848,9 +2848,9 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", diff --git a/package.json b/package.json index 61a4d1142..38f9872b3 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "devDependencies": { "@commitlint/config-conventional": "^18.4.3", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^27.6.0", "eslint-plugin-n": "^16.2.0", "eslint-plugin-promise": "^6.1.1" diff --git a/src/test/e2e/cypress/README.md b/src/test/e2e/cypress/README.md index 2bc3cd50e..6f01c4ac4 100644 --- a/src/test/e2e/cypress/README.md +++ b/src/test/e2e/cypress/README.md @@ -8,7 +8,7 @@ Go to `CypressIntegrationTest` and run it as a normal unit test in IntelliJ. Thi a `SpringBootTest` which uses Testcontainers to start running the Cypress tests. The test then gathers all the output from the Cypress tests and displays them as normal unit test output in IntelliJ. -The reporting of the tests themselves will be located in `target/test-classes/e2e/cypress/reports`. +The reporting of the tests themselves will be located in `target/test-classes/e2e/cypress/reports/mochawesome`. Please note that cypress requires the templates to have been build first. diff --git a/src/test/e2e/cypress/integration/challenges.cy.js b/src/test/e2e/cypress/integration/challenges.cy.js index 76eb7b912..c906f3519 100644 --- a/src/test/e2e/cypress/integration/challenges.cy.js +++ b/src/test/e2e/cypress/integration/challenges.cy.js @@ -88,6 +88,7 @@ describe('Challenge Tests', () => { cy.dataCy(ChallengesPage.SUBMIT_TEXTBOX_BTN).click() cy.dataCy(ChallengesPage.SUCCESS_ALERT).should('contain', 'Your answer is correct!') cy.dataCy(ChallengesPage.PROGRESS_BAR).should('be.visible').should('not.have.attr', 'aria-valuenow', '0') + cy.screenshot() }) it('Submitting right answer gives visual cue on homepage that the challenge is successfully solved', () => { diff --git a/src/test/e2e/cypress/integration/themeSwitch.cy.js b/src/test/e2e/cypress/integration/themeSwitch.cy.js index e656c352b..2fc6b0b6c 100644 --- a/src/test/e2e/cypress/integration/themeSwitch.cy.js +++ b/src/test/e2e/cypress/integration/themeSwitch.cy.js @@ -29,12 +29,21 @@ describe('Theme Switching Tests', () => { it('Light mode persists on each page', () => { cy.visit('/') cy.dataCy(ThemeSwitchPage.LIGHT_MODE_RADIO).click() + cy.screenshot() cy.wrap(['', 'challenge/challenge-0', 'stats', 'about']).each((endpoint) => { cy.visit(`/${endpoint}`) cy.get(ThemeSwitchPage.DARK_MODE).should('not.exist') }) }) - + it('Dark mode persists on each page', () => { + cy.visit('/') + cy.dataCy(ThemeSwitchPage.DARK_MODE_RADIO).click() + cy.screenshot() + cy.wrap(['', 'challenge/challenge-0', 'stats', 'about']).each((endpoint) => { + cy.visit(`/${endpoint}`) + cy.get(ThemeSwitchPage.DARK_MODE).should('exist') + }) + }) it('A user can switch theme to dark and back to light on each page', () => { cy.wrap(['', 'challenge/challenge-0', 'stats', 'about']).each((endpoint) => { cy.visit(`/${endpoint}`) diff --git a/src/test/e2e/cypress/support/e2e.js b/src/test/e2e/cypress/support/e2e.js index d1dd1353e..dab7636e5 100644 --- a/src/test/e2e/cypress/support/e2e.js +++ b/src/test/e2e/cypress/support/e2e.js @@ -15,6 +15,17 @@ // Import commands.js using ES2015 syntax: import './commands' +import addContext from 'mochawesome/addContext' +import fs from 'fs' + +Cypress.on('test:after:run', (test, runnable) => { + const screenshot = `../screenshots/${Cypress.spec.name}/${runnable.parent.title} -- ${test.title}.png` + if (fs.existsSync(screenshot)) { + addContext({ test }, screenshot) + } else { + console.log(screenshot + 'not found') + } +}) // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/src/test/e2e/reporter-config.json b/src/test/e2e/reporter-config.json index b9b2078fe..605035cd3 100644 --- a/src/test/e2e/reporter-config.json +++ b/src/test/e2e/reporter-config.json @@ -1,9 +1,12 @@ { "reporterEnabled": "spec, mochawesome", "mochawesomeReporterOptions": { + "screenshotOnRunFailure": true, + "video": true, + "videoCompression": true, "reportDir": "cypress/reports/mochawesome", "overwrite": false, - "html": false, + "html": true, "json": true } } diff --git a/src/test/java/org/owasp/wrongsecrets/CypressIntegrationTest.java b/src/test/java/org/owasp/wrongsecrets/CypressIntegrationTest.java index 28e2af2ff..52a0424fe 100644 --- a/src/test/java/org/owasp/wrongsecrets/CypressIntegrationTest.java +++ b/src/test/java/org/owasp/wrongsecrets/CypressIntegrationTest.java @@ -5,6 +5,7 @@ import io.github.wimdeblauwe.testcontainers.cypress.CypressTestResults; import io.github.wimdeblauwe.testcontainers.cypress.CypressTestSuite; import java.io.IOException; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeoutException; @@ -54,6 +55,8 @@ List runCypressTests() Testcontainers.exposeHostPorts(port); try (CypressContainer container = new CypressContainer().withLocalServerPort(port)) { + container.withMaximumTotalTestDuration(Duration.ofMinutes(15)); + container.start(); CypressTestResults testResults = container.getTestResults();