diff --git a/frontend/cypress/integration/mainnet/mainnet.spec.ts b/frontend/cypress/integration/mainnet/mainnet.spec.ts index 614e9e9cd..3bd3b1369 100644 --- a/frontend/cypress/integration/mainnet/mainnet.spec.ts +++ b/frontend/cypress/integration/mainnet/mainnet.spec.ts @@ -54,6 +54,126 @@ describe('Mainnet', () => { cy.waitForSkeletonGone(); }); + describe('blocks navigation', () => { + + describe('keyboard events', () => { + it('loads first blockchain blocks visible and keypress arrow right', () => { + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('.blockchain-blocks-0 > a').click().then(() => { + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.waitForPageIdle(); + cy.document().right(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + + it('loads first blockchain blocks visible and keypress arrow left', () => { + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('.blockchain-blocks-0 > a').click().then(() => { + cy.waitForPageIdle(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.document().left(); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + + it('loads last blockchain blocks and keypress arrow right', () => { + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('.blockchain-blocks-4 > a').click().then(() => { + cy.waitForPageIdle(); + + // block 6 + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + // block 7 + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + // block 8 - last visible block + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + // block 9 - not visible at the blochchain blocks visible block + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + }); + }); + + it('loads genesis block and keypress arrow right', () => { + cy.viewport('macbook-16'); + cy.visit('/block/0'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + }); + + it('loads genesis block and keypress arrow left', () => { + cy.viewport('macbook-16'); + cy.visit('/block/0'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + + cy.document().left(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + describe('mouse events', () => { + it('loads first blockchain blocks visible and click on the arrow right', () => { + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('.blockchain-blocks-0 > a').click().then(() => { + cy.waitForPageIdle(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').click().then(() => { + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + }); + + it('loads genesis block and click on the arrow left', () => { + cy.viewport('macbook-16'); + cy.visit('/block/0'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').click().then(() => { + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + }); + }); + + it('loads skeleton when changes between networks', () => { cy.visit('/'); cy.waitForSkeletonGone(); diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index b240a7bc4..e0d07d517 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -42,10 +42,20 @@ // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) +'use strict' + import 'cypress-wait-until'; import { PageIdleDetector } from './PageIdleDetector'; import { mockWebSocket } from './websocket'; +/* global Cypress */ +const codes = { + ArrowLeft: 37, + ArrowUp: 38, + ArrowRight: 39, + ArrowDown: 40 +} + Cypress.Commands.add('waitForSkeletonGone', () => { cy.waitUntil(() => { return Cypress.$('.skeleton-loader').length === 0; @@ -75,3 +85,63 @@ Cypress.Commands.add('changeNetwork', (network: "testnet"|"signet"|"liquid"|"bis }); }); }); + +// https://github.com/bahmutov/cypress-arrows/blob/8f0303842a343550fbeaf01528d01d1ff213b70c/src/index.js +function keydownCommand ($el, key) { + const message = `sending the "${key}" keydown event` + const log = Cypress.log({ + name: `keydown: ${key}`, + message: message, + consoleProps: function () { + return { + Subject: $el + } + } + }) + + const e = $el.createEvent('KeyboardEvent') + + Object.defineProperty(e, 'key', { + get: function () { + return key + } + }) + + Object.defineProperty(e, 'keyCode', { + get: function () { + return this.keyCodeVal + } + }) + Object.defineProperty(e, 'which', { + get: function () { + return this.keyCodeVal + } + }) + var metaKey = false + + Object.defineProperty(e, 'metaKey', { + get: function () { + return metaKey + } + }) + + Object.defineProperty(e, 'shiftKey', { + get: function () { + return false + } + }) + e.keyCodeVal = codes[key] + + e.initKeyboardEvent('keydown', true, true, + $el.defaultView, false, false, false, false, e.keyCodeVal, e.keyCodeVal) + + $el.dispatchEvent(e) + log.snapshot().end() + return $el + } + + Cypress.Commands.add('keydown', { prevSubject: "dom" }, keydownCommand) + Cypress.Commands.add('left', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowLeft')) + Cypress.Commands.add('right', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowRight')) + Cypress.Commands.add('up', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowUp')) + Cypress.Commands.add('down', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowDown')) \ No newline at end of file diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index c9d6145b6..ecfdcb11e 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -44,7 +44,7 @@ import { NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; import { FeesBoxComponent } from './components/fees-box/fees-box.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; -import { faAngleDown, faAngleUp, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, +import { faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons'; import { ApiDocsComponent } from './components/api-docs/api-docs.component'; import { CodeTemplateComponent } from './components/api-docs/code-template.component'; @@ -145,5 +145,7 @@ export class AppModule { library.addIcons(faSortUp); library.addIcons(faCaretUp); library.addIcons(faCaretDown); + library.addIcons(faAngleRight); + library.addIcons(faAngleLeft); } } diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 34cc270c0..f12383deb 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -1,7 +1,39 @@