diff --git a/.gitignore b/.gitignore index de08e3aea..b316115d5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ dist /public reports cypress/screenshots +cypress/snapshots/diff .tmp diff --git a/build/liveserver.mjs b/build/liveserver.mjs index c88a73de4..58a6de3ca 100644 --- a/build/liveserver.mjs +++ b/build/liveserver.mjs @@ -1,9 +1,9 @@ import liveServer from 'alive-server'; -import path from 'path'; -import os from 'os'; import fs from 'fs'; -import { fileURLToPath } from 'url'; +import os from 'os'; +import path from 'path'; import selfsigned from 'selfsigned'; +import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/cypress.config.ts b/cypress.config.ts index 9186acb49..5e9560666 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from 'cypress'; +import { configureVisualRegression } from 'cypress-visual-regression'; export default defineConfig({ e2e: { @@ -7,7 +8,12 @@ export default defineConfig({ baseUrl: 'https://127.0.0.1:8080', scrollBehavior: false, screenshotOnRunFailure: false, + env: { + visualRegressionType: 'regression', + }, setupNodeEvents(on) { + configureVisualRegression(on); + on('before:browser:launch', (browser, launchOptions) => { // should be bigger than the largest viewport used + browser UI elements const width = 1600; diff --git a/cypress/e2e/navbar.cy.ts b/cypress/e2e/navbar.cy.ts index dfcd16dc2..4886f60e9 100644 --- a/cypress/e2e/navbar.cy.ts +++ b/cypress/e2e/navbar.cy.ts @@ -7,11 +7,18 @@ describe('navbar', () => { waitViewerReady(); }); + it('should have a navbar', () => { + cy.get('.psv-navbar') + .should('be.visible') + .compareSnapshot('base'); + }); + it('should have a custom button', () => { const alertStub = cy.stub(); cy.on('window:alert', alertStub); - cy.get('.custom-button:eq(0)').click() + cy.get('.custom-button:eq(0)') + .click() .then(() => { expect(alertStub.getCall(0)).to.be.calledWith('Custom button clicked'); }); @@ -24,6 +31,8 @@ describe('navbar', () => { cy.get('.psv-caption-content').should('have.text', 'Name: Lorem Ipsum'); + cy.get('.psv-navbar').compareSnapshot('update-caption'); + callViewer('change caption via API', viewer => viewer.navbar.setCaption('Loading...')); cy.get('.psv-caption-content').should('have.text', 'Loading...'); @@ -37,7 +46,8 @@ describe('navbar', () => { cy.get('.psv-panel') .should('be.visible') .should('include.text', 'Parc national du Mercantour © Damien Sorel') - .should('include.text', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'); + .should('include.text', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit') + .compareSnapshot('description'); }); // does not work in headless mode @@ -60,11 +70,14 @@ describe('navbar', () => { cy.get('.psv-caption-content').should('not.be.visible'); + cy.get('.psv-navbar').compareSnapshot('no-caption'); + cy.get('.psv-description-button').click(); - cy.get('.psv-notification') + cy.get('.psv-notification-content') .should('be.visible') - .should('have.text', 'Parc national du Mercantour © Damien Sorel'); + .should('have.text', 'Parc national du Mercantour © Damien Sorel') + .compareSnapshot('caption-notification'); cy.get('.psv-description-button').click(); @@ -95,6 +108,8 @@ describe('navbar', () => { cy.get(visible).should('be.visible'); }); + cy.get('.psv-navbar').compareSnapshot('with-menu'); + cy.get('.psv-menu-button').click(); cy.get('.psv-panel') @@ -104,7 +119,8 @@ describe('navbar', () => { cy.contains('Download').should('be.visible'); cy.contains('Click me').should('be.visible'); - }); + }) + .compareSnapshot('menu-content'); cy.get('.psv-panel-close-button').click(); @@ -167,13 +183,13 @@ describe('navbar', () => { }); it('should update the buttons', () => { - function assertButtons(titles: string[]) { + function assertButtons(expected: string[]) { cy.get('.psv-button').then($buttons => { const titles = $buttons .filter(':visible') .map((i, btn) => btn.getAttribute('title')) .get(); - expect(titles).to.have.members(titles); + expect(titles).to.have.members(expected); }); } @@ -181,6 +197,8 @@ describe('navbar', () => { assertButtons(['Zoom out', 'Zoom in', 'Move left', 'Move right', 'Move up', 'Move down']); + cy.get('.psv-navbar').compareSnapshot('update-buttons'); + callViewer('change buttons via API', viewer => viewer.navbar.setButtons(['download', 'fullscreen'])); assertButtons(['Download', 'Fullscreen']); @@ -191,6 +209,8 @@ describe('navbar', () => { cy.get('.psv-fullscreen-button').should('not.be.visible'); + cy.get('.psv-navbar').compareSnapshot('hide-button'); + callViewer('show fullscreen button', viewer => viewer.navbar.getButton('fullscreen').show()); cy.get('.psv-fullscreen-button').should('be.visible'); @@ -201,6 +221,8 @@ describe('navbar', () => { cy.get('.psv-download-button').should('have.class', 'psv-button--disabled'); + cy.get('.psv-navbar').compareSnapshot('disable-button'); + callViewer('enable download button', viewer => viewer.navbar.getButton('download').enable()); cy.get('.psv-download-button').should('not.have.class', 'psv-button--disabled'); @@ -223,5 +245,7 @@ describe('navbar', () => { cy.get('#title').should('have.text', 'Custom element'); cy.get('#value').should('have.text', '50'); }); + + cy.get('.psv-custom-button').compareSnapshot('custom-element'); }); }); diff --git a/cypress/package.json b/cypress/package.json new file mode 100644 index 000000000..da4c03ce7 --- /dev/null +++ b/cypress/package.json @@ -0,0 +1,9 @@ +{ + "name": "photo-sphere-viewer-e2e", + "version": "0.0.0", + "private": true, + "license": "MIT", + "scripts": { + "lint": "eslint . --fix" + } +} diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/base.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/base.png new file mode 100644 index 000000000..043103fff Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/base.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/caption-notification.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/caption-notification.png new file mode 100644 index 000000000..834ca4f09 Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/caption-notification.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/custom-element.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/custom-element.png new file mode 100644 index 000000000..b1c6038f9 Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/custom-element.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/description.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/description.png new file mode 100644 index 000000000..9ce6eafd8 Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/description.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/disable-button.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/disable-button.png new file mode 100644 index 000000000..5ad35f4f6 Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/disable-button.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/hide-button.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/hide-button.png new file mode 100644 index 000000000..d6fd8faad Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/hide-button.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/menu-content.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/menu-content.png new file mode 100644 index 000000000..0948680f9 Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/menu-content.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/no-caption.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/no-caption.png new file mode 100644 index 000000000..3b5fdd115 Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/no-caption.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/update-buttons.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/update-buttons.png new file mode 100644 index 000000000..d3421bf07 Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/update-buttons.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/update-caption.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/update-caption.png new file mode 100644 index 000000000..67e08d9af Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/update-caption.png differ diff --git a/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/with-menu.png b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/with-menu.png new file mode 100644 index 000000000..cabfa382e Binary files /dev/null and b/cypress/snapshots/base/cypress/e2e/navbar.cy.ts/with-menu.png differ diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index 75668a85c..2a078935e 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -1 +1,5 @@ import 'cypress-real-events'; +import { addCompareSnapshotCommand } from 'cypress-visual-regression/dist/command'; +addCompareSnapshotCommand({ + errorThreshold: 0.1, +}); diff --git a/cypress/utils/index.ts b/cypress/utils/index.ts index 678cacedb..1a2004a5a 100644 --- a/cypress/utils/index.ts +++ b/cypress/utils/index.ts @@ -14,3 +14,7 @@ export function callViewer(log: string, cb: (viewer: Viewer) => void) { cy.log(`Viewer: ${log}`); cy.window({ log: false }).its('viewer', { log: false }).then(cb); } + +export function createBaseSnapshot() { + Cypress.env('visualRegressionType', 'base'); +} diff --git a/package.json b/package.json index 8cebb493e..ea925b8dc 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "license": "MIT", "workspaces": [ "docs", + "cypress", "packages/*" ], "scripts": { @@ -37,6 +38,7 @@ "alive-server": "^1.3.0", "cypress": "^13.15.0", "cypress-real-events": "^1.13.0", + "cypress-visual-regression": "^5.2.2", "esbuild-sass-plugin": "^3.3.0", "eslint": "^8.57.0", "inquirer": "^12.0.0", diff --git a/turbo.json b/turbo.json index ebc7f4d28..69c5c97fb 100644 --- a/turbo.json +++ b/turbo.json @@ -16,6 +16,9 @@ "lint": { "inputs": ["src/**"] }, + "photo-sphere-viewer-e2e#lint": { + "inputs": ["e2e/**", "support/**", "utils/**"] + }, "test": { "inputs": ["src/**"], "outputs": ["reports/**"] diff --git a/yarn.lock b/yarn.lock index 7bdff7678..b8ec076c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1807,7 +1807,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2087,6 +2087,16 @@ cypress-real-events@^1.13.0: resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.13.0.tgz#6b7cd32dcac172db1493608f97a2576c7d0bd5af" integrity sha512-LoejtK+dyZ1jaT8wGT5oASTPfsNV8/ClRp99ruN60oPj8cBJYod80iJDyNwfPAu4GCxTXOhhAv9FO65Hpwt6Hg== +cypress-visual-regression@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/cypress-visual-regression/-/cypress-visual-regression-5.2.2.tgz#4dc3e7e223683ffa3419025f397f50dba91ac8e0" + integrity sha512-QWCXlE7GCpNnwVLmkywiIJ8usrIgTdVdUE6j3LYhZPSB35jNR3GmwVihP6NzzAG4CpW4zm+MAEDrkuX1MQzPeA== + dependencies: + chalk "^4.1.2" + pixelmatch "^5.2.1" + pngjs "^6.0.0" + sanitize-filename "^1.6.3" + cypress@^13.15.0: version "13.15.0" resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.15.0.tgz#5eca5387ef34b2e611cfa291967c69c2cd39381d" @@ -4375,6 +4385,18 @@ pirates@^4.0.1: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== +pixelmatch@^5.2.1: + version "5.3.0" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.3.0.tgz#5e5321a7abedfb7962d60dbf345deda87cb9560a" + integrity sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q== + dependencies: + pngjs "^6.0.0" + +pngjs@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" + integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== + postcss-load-config@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096" @@ -4707,6 +4729,13 @@ safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sanitize-filename@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" + integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== + dependencies: + truncate-utf8-bytes "^1.0.0" + sass@^1.23.7, sass@^1.71.1: version "1.71.1" resolved "https://registry.yarnpkg.com/sass/-/sass-1.71.1.tgz#dfb09c63ce63f89353777bbd4a88c0a38386ee54" @@ -5365,6 +5394,13 @@ trim-newlines@^2.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" integrity sha512-MTBWv3jhVjTU7XR3IQHllbiJs8sc75a80OEhB6or/q7pLTWgQ0bMGQXXYQSrSuXe6WiKWDZ5txXY5P59a/coVA== +truncate-utf8-bytes@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" + integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ== + dependencies: + utf8-byte-length "^1.0.1" + ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" @@ -5621,6 +5657,11 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +utf8-byte-length@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e" + integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA== + util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"