diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 71806a9c46..09e8546ff7 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -9,8 +9,44 @@ permissions: contents: read jobs: + cache: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v2 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + + - name: Cache snapshots + id: cache-snapshot + uses: actions/cache@v4 + with: + save-always: true + path: ./cypress/snapshots + key: ${{ runner.os }}-snapshots + + - name: Switch to base branch + if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }} + uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event_name == 'merge_group' && github.event.merge_group.base.sha || 'develop' }} + + - name: Cypress run + uses: cypress-io/github-action@v4 + id: cypress-snapshot-gen + if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }} + with: + start: pnpm run dev + wait-on: 'http://localhost:9000' + browser: chrome + spec: | + cypress/integration/rendering/flowchart-v2.spec.js + e2e: runs-on: ubuntu-latest + needs: cache strategy: fail-fast: false matrix: @@ -27,6 +63,13 @@ jobs: with: node-version: ${{ matrix.node-version }} + - name: Cache snapshots + id: cache-snapshot + uses: actions/cache/restore@v3 + with: + path: ./cypress/snapshots + key: ${{ runner.os }}-snapshots + # Install NPM dependencies, cache them correctly # and run all Cypress tests - name: Cypress run @@ -38,14 +81,19 @@ jobs: with: start: pnpm run dev:coverage wait-on: 'http://localhost:9000' + browser: chrome # Disable recording if we don't have an API key # e.g. if this action was run from a fork record: ${{ secrets.CYPRESS_RECORD_KEY != '' }} parallel: ${{ secrets.CYPRESS_RECORD_KEY != '' }} + # TODO: Remove + spec: | + cypress/integration/rendering/flowchart-v2.spec.js env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} VITEST_COVERAGE: true CYPRESS_COMMIT: ${{ github.sha }} + - name: Upload Coverage to Codecov uses: codecov/codecov-action@v3 # Run step only pushes to develop and pull_requests @@ -57,6 +105,7 @@ jobs: fail_ci_if_error: false verbose: true token: 6845cc80-77ee-4e17-85a1-026cd95e0766 + - name: Upload Artifacts uses: actions/upload-artifact@v3 if: ${{ failure() && steps.cypress.conclusion == 'failure' }} diff --git a/cSpell.json b/cSpell.json index 3ea9594f75..82c1c81c41 100644 --- a/cSpell.json +++ b/cSpell.json @@ -124,6 +124,7 @@ "sidharth", "sidharthv", "sphinxcontrib", + "ssim", "startx", "starty", "statediagram", diff --git a/cypress.config.cjs b/cypress.config.cjs index 30076c56ef..c754b465f9 100644 --- a/cypress.config.cjs +++ b/cypress.config.cjs @@ -4,12 +4,21 @@ const { defineConfig } = require('cypress'); const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin'); const coverage = require('@cypress/code-coverage/task'); + module.exports = defineConfig({ projectId: 'n2sma2', + viewportWidth: 1440, + viewportHeight: 1024, e2e: { - specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}', + specPattern: 'cypress/integration/**/*.{js,ts}', setupNodeEvents(on, config) { coverage(on, config); + on('before:browser:launch', (browser = {}, launchOptions) => { + if (browser.name === 'chrome' && browser.isHeadless) { + launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1'); + } + return launchOptions; + }); addMatchImageSnapshotPlugin(on, config); // copy any needed variables from process.env to config.env config.env.useAppli = process.env.USE_APPLI ? true : false; diff --git a/cypress/integration/other/configuration.spec.js b/cypress/integration/other/configuration.spec.js index 7cbc5d1059..23338271f5 100644 --- a/cypress/integration/other/configuration.spec.js +++ b/cypress/integration/other/configuration.spec.js @@ -117,7 +117,6 @@ describe('Configuration', () => { }); it('should not taint the initial configuration when using multiple directives', () => { const url = 'http://localhost:9000/regression/issue-1874.html'; - cy.viewport(1440, 1024); cy.visit(url); cy.get('svg'); diff --git a/cypress/integration/other/rerender.spec.js b/cypress/integration/other/rerender.spec.js index f160a2e273..d14c6257e0 100644 --- a/cypress/integration/other/rerender.spec.js +++ b/cypress/integration/other/rerender.spec.js @@ -1,14 +1,12 @@ describe('Rerendering', () => { it('should be able to render after an error has occurred', () => { const url = 'http://localhost:9000/render-after-error.html'; - cy.viewport(1440, 1024); cy.visit(url); cy.get('#graphDiv').should('exist'); }); it('should be able to render and rerender a graph via API', () => { const url = 'http://localhost:9000/rerender.html'; - cy.viewport(1440, 1024); cy.visit(url); cy.get('#graph [id^=flowchart-A]').should('have.text', 'XMas'); diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js index 998a092c24..73ff4ee005 100644 --- a/cypress/integration/rendering/gantt.spec.js +++ b/cypress/integration/rendering/gantt.spec.js @@ -245,7 +245,10 @@ describe('Gantt diagram', () => { const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); - expect(maxWidthValue).to.be.within(984 * 0.95, 984 * 1.05); + expect(maxWidthValue).to.be.within( + Cypress.config().viewportWidth * 0.95, + Cypress.config().viewportWidth * 1.05 + ); }); }); @@ -285,11 +288,11 @@ describe('Gantt diagram', () => { { gantt: { useMaxWidth: false } } ); cy.get('svg').should((svg) => { - // const height = parseFloat(svg.attr('height')); const width = parseFloat(svg.attr('width')); - // use within because the absolute value can be slightly different depending on the environment ±5% - // expect(height).to.be.within(484 * 0.95, 484 * 1.05); - expect(width).to.be.within(984 * 0.95, 984 * 1.05); + expect(width).to.be.within( + Cypress.config().viewportWidth * 0.95, + Cypress.config().viewportWidth * 1.05 + ); expect(svg).to.not.have.attr('style'); }); }); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 3589640d98..7a77b3ba61 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -24,8 +24,14 @@ // -- This is will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) -// import '@percy/cypress'; - import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command'; -addMatchImageSnapshotCommand(); +addMatchImageSnapshotCommand({ + comparisonMethod: 'ssim', + failureThreshold: 0.01, + failureThresholdType: 'percent', + customDiffConfig: { + ssim: 'fast', + }, + blur: 1, +});