Test/694 block explorer refactor (#728)

* test: home page tests done

* test: asset and block tests added

* test: txs, market and network tests added

* chore: remove old test files

* test: remove Cypress command functions

* fix: failing block explorer tests in CI

* test: add wait for blocks

* test: re-add cypress functions

* chore: resolved PR comment
This commit is contained in:
Joe Tsang 2022-07-13 11:17:10 +01:00 committed by GitHub
parent 92011b1bf4
commit ee747aa12d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 520 additions and 886 deletions

View File

@ -1,16 +1,13 @@
const { defineConfig } = require('cypress');
const setupNodeEvents = require('./src/plugins/index.js');
module.exports = defineConfig({
projectId: 'et4snf',
e2e: {
setupNodeEvents,
baseUrl: 'http://localhost:3000',
fileServerFolder: '.',
fixturesFolder: false,
specPattern: '**/*.feature',
excludeSpecPattern: '**/*.js',
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
modifyObstructiveCode: false,
supportFile: './src/support/index.ts',
video: true,

View File

@ -1,11 +0,0 @@
Feature: Asset Page
Scenario: Navigate to Asset Page
Given I am on the homepage
When I navigate to the asset page
Then asset page is correctly displayed
Scenario: Navigate to Asset Page using mobile
Given I am on mobile and open the toggle menu
When I navigate to the asset page
Then asset page is correctly displayed

View File

@ -0,0 +1,20 @@
import '../support/common.functions';
context('Asset page', function () {
describe('Verify elements on page', function () {
const assetsNavigation = 'a[href="/assets"]';
const assetHeader = '[data-testid="asset-header"]';
it('Assets page is displayed', function () {
cy.visit('/');
cy.get(assetsNavigation).click();
cy.common_validate_blocks_data_displayed(assetHeader);
});
it('Assets page displayed in mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(assetsNavigation).click();
cy.common_validate_blocks_data_displayed(assetHeader);
});
});
});

View File

@ -1,38 +0,0 @@
Feature: Blocks Page
Scenario: Navigate to blocks page
Given I am on the homepage
When I navigate to the blocks page
Then blocks page is correctly displayed
Scenario: Navigate to blocks page using mobile
Given I am on mobile and open the toggle menu
When I navigate to the blocks page
Then blocks page is correctly displayed
Scenario: Navigate to block validator page
Given I am on the homepage
When I navigate to the blocks page
And I click on top block
Then validator block page is correctly displayed
Scenario: Navigate to previous block
Given I am on the homepage
When I navigate to the blocks page
And I click on top block
Then I am on the previous block when I click previous
Scenario: Previous button disabled on first block
Given I am on the homepage
When I navigate to the blocks page
And jump to first block
Then previous button is disabled
And I am on the second block when I click next
# Skipping these tests for time being - since blockchain in capsule
# is now too small to show historical data - re-enable once addressed
# Scenario: Infinite scroll shows at least 300 new blocks
# Given I am on the homepage
# When I navigate to the blocks page
# And I scroll down to the last block on the page
# Then I can expect to see at least 100 blocks if i scroll 7 times

View File

@ -0,0 +1,132 @@
import '../support/common.functions';
context('Blocks page', function () {
before('visit token home page', function () {
cy.visit('/');
});
describe('Verify elements on page', function () {
const blockNavigation = 'a[href="/blocks"]';
const blockHeight = '[data-testid="block-height"]';
const blockTime = '[data-testid="block-time"]';
const blockHeader = '[data-testid="block-header"]';
const previousBlockBtn = '[data-testid="previous-block"]';
const infiniteScrollWrapper = '[data-testid="infinite-scroll-wrapper"]';
beforeEach('navigate to blocks page', function () {
cy.get(blockNavigation).click();
});
it('Blocks page is displayed', function () {
validateBlocksDisplayed();
});
it('Blocks page is displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(blockNavigation).click();
validateBlocksDisplayed();
});
it('Block validator page is displayed', function () {
waitForBlocksResponse();
cy.get(blockHeight).eq(0).click();
cy.get('[data-testid="block-validator"]').should('not.be.empty');
cy.get(blockTime).should('not.be.empty');
//TODO: Add assertion for transactions when txs are added
});
it('Navigate to previous block', function () {
waitForBlocksResponse();
cy.get(blockHeight).eq(0).click();
cy.get(blockHeader)
.invoke('text')
.then(($blockHeaderTxt) => {
const blockHeight = parseInt($blockHeaderTxt.replace('BLOCK ', ''));
cy.get(previousBlockBtn).click();
cy.get(blockHeader)
.invoke('text')
.then(($newBlockHeaderTxt) => {
const newBlockHeight = parseInt(
$newBlockHeaderTxt.replace('BLOCK ', '')
);
expect(newBlockHeight).to.be.lessThan(blockHeight);
});
});
});
it('Previous button disabled on first block', function () {
cy.get('[data-testid="block-input"]').type('1');
cy.get('[data-testid="go-submit"]').click();
cy.get(previousBlockBtn).find('button').should('be.disabled');
cy.get(blockHeader)
.invoke('text')
.then(($blockHeaderTxt) => {
const blockHeight = parseInt($blockHeaderTxt.replace('BLOCK ', ''));
cy.get('[data-testid="next-block"]').click();
cy.get(blockHeader)
.invoke('text')
.then(($newBlockHeaderTxt) => {
const newBlockHeight = parseInt(
$newBlockHeaderTxt.replace('BLOCK ', '')
);
expect(newBlockHeight).to.be.greaterThan(blockHeight);
});
});
});
// Skipping these tests for time being - since blockchain in capsule is now too small to show historical data - re-enable once addressed
it.skip('Infinite scroll shows at least 100 new blocks', function () {
const expectedBlocks = 100;
const scrollAttempts = 7;
waitForBlocksResponse();
cy.get(infiniteScrollWrapper).children().scrollTo('bottom');
cy.intercept('*blockchain?maxHeight*').as('blockchain_load');
cy.get(blockHeight)
.last()
.invoke('text')
.then(($initialLastBlockHeight) => {
for (let index = 0; index < scrollAttempts; index++) {
cy.get(infiniteScrollWrapper)
.children()
.children()
.invoke('css', 'height')
.then((scrollTarget) => {
cy.get(infiniteScrollWrapper)
.children()
.scrollTo(0, scrollTarget.toString(), { easing: 'linear' })
.wait('@blockchain_load');
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(50); // Need this as although network response has arrived it takes a few millisecs for the css height to expand
});
}
cy.get(blockHeight)
.last()
.invoke('text')
.then(($lastBlockHeight) => {
const totalBlocksLoadedSinceScrollBegan =
parseInt($initialLastBlockHeight) - parseInt($lastBlockHeight);
expect(totalBlocksLoadedSinceScrollBegan).to.be.at.least(
expectedBlocks
);
});
});
});
function waitForBlocksResponse() {
cy.contains('Loading...').should('not.exist', { timeout: 18000 });
}
function validateBlocksDisplayed() {
waitForBlocksResponse();
cy.get('[data-testid="block-row"]').should('have.length.above', 1);
cy.get(blockHeight).first().should('not.be.empty');
cy.get('[data-testid="num-txs"]').first().should('not.be.empty');
cy.get('[data-testid="validator-link"]').first().should('not.be.empty');
cy.get(blockTime).first().should('not.be.empty');
}
});
});

View File

@ -1,27 +0,0 @@
Feature: Home page
Scenario: Stats page displayed correctly
Given I am on the homepage
Then the stats for deployed environment are correctly displayed
Scenario Outline: Succesfful search for specific id by <IdType>
Given I am on the homepage
When I search for '<Id>'
Then I am redirected to page containing id '<Id>'
Examples:
| IdType | Id |
| Block Id | 973624 |
| Tx Hash | 9ED3718AA8308E7E08EC588EE7AADAF49711D2138860D8914B4D81A2054D9FB8 |
| Tx Id | 0x61DCCEBB955087F50D0B85382DAE138EDA9631BF1A4F92E563D528904AA38898 |
Scenario Outline: Error message displayed when invalid search by <invalidType>
Given I am on the homepage
When I search for '<Id>'
Then search error message "<errorMessage>" is displayed
Examples:
| invalidType | Id | errorMessage |
| wrong string length | 9ED3718AA8308E7E08EC588EE7AADAF497D2138860D8914B4D81A2054D9FB8 | Something doesn't look right |
| invalid hash | 9ED3718AA8308E7E08ECht8EE753DAF49711D2138860D8914B4D81A2054D9FB8 | Transaction is not hexadecimal |
| empty search | | Search required |

View File

@ -0,0 +1,141 @@
context('Home Page', function () {
before('visit home page', function () {
cy.visit('/');
});
describe('Stats page', function () {
const statsValue = '[data-testid="stats-value"]';
it('Should show connected environment', function () {
const deployedEnv = Cypress.env('environment').toUpperCase();
cy.get('[data-testid="stats-environment"]').should(
'have.text',
`/ ${deployedEnv}`
);
});
it('should show connected environment stats', function () {
const statTitles = {
0: 'Status',
1: 'Height',
2: 'Validating nodes',
3: 'Uptime',
4: 'Total nodes',
5: 'Inactive nodes',
6: 'Total staked',
7: 'Backlog',
8: 'Trades / second',
9: 'Orders / block',
10: 'Orders / second',
11: 'Transactions / block',
12: 'Block time',
13: 'Time',
14: 'App',
15: 'Tendermint',
16: 'Up since',
17: 'Chain ID',
};
cy.get('[data-testid="stats-title"]')
.each(($list, index) => {
cy.wrap($list).should('have.text', statTitles[index]);
})
.then(($list) => {
cy.wrap($list).should('have.length', 18);
});
cy.get(statsValue).eq(0).should('have.text', 'CONNECTED');
cy.get(statsValue).eq(1).should('not.be.empty');
cy.get(statsValue).eq(2).should('have.text', '2');
cy.get(statsValue)
.eq(3)
.invoke('text')
.should('match', /\d+d \d+h \d+m \d+s/i);
cy.get(statsValue).eq(4).should('have.text', '2');
cy.get(statsValue).eq(5).should('have.text', '0');
cy.get(statsValue).eq(6).should('have.text', '0.00');
cy.get(statsValue).eq(7).should('have.text', '0');
cy.get(statsValue).eq(8).should('have.text', '0');
cy.get(statsValue).eq(9).should('have.text', '0');
cy.get(statsValue).eq(10).should('have.text', '0');
cy.get(statsValue).eq(11).should('not.be.empty');
cy.get(statsValue).eq(12).should('not.be.empty');
cy.get(statsValue).eq(13).should('not.be.empty');
if (Cypress.env('NIGHTLY_RUN') != true) {
cy.get(statsValue)
.eq(14)
.invoke('text')
.should('match', /v\d+\.\d+\.\d+/i);
}
cy.get(statsValue)
.eq(15)
.invoke('text')
.should('match', /\d+\.\d+\.\d+/i);
cy.get(statsValue).eq(16).should('not.be.empty');
cy.get(statsValue).eq(17).should('not.be.empty');
});
it('Block height should be updating', function () {
cy.get(statsValue)
.eq(1)
.invoke('text')
.then((blockHeightTxt) => {
cy.get(statsValue)
.eq(1)
.invoke('text')
.should((newBlockHeightTxt) => {
expect(blockHeightTxt).not.to.eq(newBlockHeightTxt);
});
});
});
});
describe('Search bar', function () {
it('Successful search for specific id by block id', function () {
const blockId = '973624';
search(blockId);
cy.url().should('include', blockId);
});
it('Successful search for specific id by tx hash', function () {
const txHash =
'9ED3718AA8308E7E08EC588EE7AADAF49711D2138860D8914B4D81A2054D9FB8';
search(txHash);
cy.url().should('include', txHash);
});
it('Successful search for specific id by tx id', function () {
const txId =
'0x61DCCEBB955087F50D0B85382DAE138EDA9631BF1A4F92E563D528904AA38898';
search(txId);
cy.url().should('include', txId);
});
it('Error message displayed when invalid search by wrong string length', function () {
search('9ED3718AA8308E7E08EC588EE7AADAF497D2138860D8914B4D81A2054D9FB8');
validateSearchError("Something doesn't look right");
});
it('Error message displayed when invalid search by invalid hash', function () {
search(
'9ED3718AA8308E7E08ECht8EE753DAF49711D2138860D8914B4D81A2054D9FB8'
);
validateSearchError('Transaction is not hexadecimal');
});
it('Error message displayed when searching empty field', function () {
cy.get('[data-testid="search"]').clear();
cy.get('[data-testid="search-button"]').click();
validateSearchError('Search required');
});
function search(searchTxt) {
cy.get('[data-testid="search"]').clear().type(searchTxt);
cy.get('[data-testid="search-button"]').click();
}
function validateSearchError(expectedError) {
cy.get('[data-testid="search-error"]').should('have.text', expectedError);
}
});
});

View File

@ -0,0 +1,21 @@
import '../support/common.functions';
//Tests set to skip until market bug for capsule checkpoint is fixed
context.skip('Market page', function () {
describe('Verify elements on page', function () {
const marketHeaders = '[data-testid="markets-header"]';
const marketNavigation = 'a[href="/markets"]';
it('Markets page is displayed', function () {
cy.visit('/');
cy.get(marketNavigation).click();
cy.common_validate_blocks_data_displayed(marketHeaders);
});
it('Markets page displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(marketNavigation).click();
cy.common_validate_blocks_data_displayed(marketHeaders);
});
});
});

View File

@ -1,14 +0,0 @@
@todo
Feature: Markets Page
@todo - Needs markets in capsule state
Scenario: Navigate to markets page
Given I am on the homepage
When I navigate to the markets page
Then markets page is correctly displayed
@todo
Scenario: Navigate to markets page using mobile
Given I am on mobile and open the toggle menu
When I navigate to the markets page
Then markets page is correctly displayed

View File

@ -1,11 +0,0 @@
Feature: Network parameters Page
Scenario: Navigate to network parameters page
Given I am on the homepage
When I navigate to network parameters page
Then network parameters page is correctly displayed
Scenario: Navigate to network parameters page using mobile
Given I am on mobile and open the toggle menu
When I navigate to network parameters page
Then network parameters page is correctly displayed

View File

@ -0,0 +1,35 @@
import '../support/common.functions';
context('Network parameters page', function () {
before('visit token home page', function () {
cy.visit('/');
});
describe('Verify elements on page', function () {
const networkParametersNavigation = 'a[href="/network-parameters"]';
beforeEach('Navigate to network parameter page', function () {
cy.get(networkParametersNavigation).click();
});
it('Network paremeter page is displayed', function () {
verifyNetworkParametersPageDisplayed();
});
it('Network parameter page displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(networkParametersNavigation).click();
verifyNetworkParametersPageDisplayed();
});
});
function verifyNetworkParametersPageDisplayed() {
cy.get('[data-testid="network-param-header"]').should(
'have.text',
'Network Parameters'
);
cy.common_verify_json_parameters(18);
cy.common_verify_json_string_values(6);
cy.common_verify_json_int_values(7);
}
});

View File

@ -1,21 +0,0 @@
@ignore
# tendermint times out getting txs on testnet atm
Feature: Transactions Page
Scenario: Navigate to transactions page
Given I am on the homepage
When I navigate to the transactions page
Then transactions page is correctly displayed
Scenario: Navigate to transaction details page
Given I am on the homepage
When I navigate to the transactions page
And I click on the top transaction
Then transaction details are displayed
Scenario: Navigate to transactions page using mobile
Given I am on mobile and open the toggle menu
When I navigate to the transactions page
Then transactions page is correctly displayed
When I click on the top transaction
Then transaction details are displayed

View File

@ -0,0 +1,87 @@
//Tests set to skip until transactions are generated after capsule start up
context.skip('Transactions page', function () {
before('visit token home page', function () {
cy.visit('/');
});
describe('Verify elements on page', function () {
const transactionNavigation = 'a[href="/txs"]';
const transactionRow = 'transaction-row';
const txHash = 'hash';
beforeEach('Navigate to transactions page', function () {
cy.get(transactionNavigation).click();
});
it('transactions are displayed', function () {
cy.get(transactionRow).should('have.length.above', 1);
});
it('transactions details page is displayed', function () {
clickTopTransaction();
validateTxDetailsAreDisplayed();
});
it('transactions details page is displayed in mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(transactionNavigation).click();
clickTopTransaction();
validateTxDetailsAreDisplayed();
});
function clickTopTransaction() {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000); // Wait for transactions to load if there are any
cy.get('body').then(($body) => {
if ($body.find(transactionRow).length) {
cy.get(transactionRow)
.first()
.find('a')
.first()
.click({ force: true });
} else {
cy.slack('Unable to find any transactions on page');
cy.screenshot();
}
});
}
function validateTxDetailsAreDisplayed() {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000); // Wait for transactions to load if there are any
cy.get('body').then(($body) => {
if ($body.find(txHash).length) {
cy.get(txHash).invoke('text').should('have.length', 64);
cy.get('submitted-by')
.find('a')
.then(($address) => {
cy.wrap($address).should('have.attr', 'href');
cy.wrap($address).invoke('text').should('have.length', 66);
});
cy.get('block').should('not.be.empty');
cy.get('encoded-tnx').should('not.be.empty');
cy.get('tx-type')
.should('not.be.empty')
.invoke('text')
.then((txTypeTxt) => {
if (txTypeTxt == 'Order Submission') {
cy.get('.hljs-attr')
.should('have.length.at.least', 8)
.each(($propertyName) => {
cy.wrap($propertyName).should('not.be.empty');
});
cy.get('.hljs-string')
.should('have.length.at.least', 8)
.each(($propertyValue) => {
cy.wrap($propertyValue).should('not.be.empty');
});
}
});
} else {
cy.slack('Unable to find any transactions on page');
cy.screenshot();
}
});
}
});
});

View File

@ -0,0 +1,28 @@
import '../support/common.functions';
context('Validator page', function () {
describe('Verify elements on page', function () {
const validatorNavigation = 'a[href="/validators"]';
it('Validator page is displayed', function () {
cy.visit('/');
cy.get(validatorNavigation).click();
validateValidatorsDisplayed();
});
it('Validator page is displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(validatorNavigation).click();
validateValidatorsDisplayed();
});
function validateValidatorsDisplayed() {
cy.get('[data-testid="tendermint-header"]').should(
'have.text',
'Tendermint data'
);
cy.get('[data-testid="vega-header"]').should('have.text', 'Vega data');
cy.get('[data-testid="vega-data"]').should('not.be.empty');
}
});
});

View File

@ -1,11 +0,0 @@
Feature: Validators Page
Scenario: Navigate to validators page
Given I am on the homepage
When I navigate to the validators page
Then validators page is correctly displayed
Scenario: Navigate to validators page using mobile
Given I am on mobile and open the toggle menu
When I navigate to the validators page
Then validators page is correctly displayed

View File

@ -1,75 +0,0 @@
/// <reference types="cypress" />
const webpackPreprocessor = require('@cypress/webpack-preprocessor');
const webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
on(
'file:preprocessor',
webpackPreprocessor({
webpackOptions: {
resolve: {
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
plugins: [
new TsconfigPathsPlugin({
configFile: config.env.tsConfig,
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
}),
],
fallback: {
path: require.resolve('path-browserify'),
},
},
module: {
rules: [
{
test: /\.([jt])sx?$/,
loader: 'ts-loader',
exclude: [/node_modules/],
options: {
configFile: config.env.tsConfig,
// https://github.com/TypeStrong/ts-loader/pull/685
experimentalWatchApi: true,
transpileOnly: true,
},
},
{
test: /\.feature$/,
use: [
{
loader: 'cypress-cucumber-preprocessor/loader',
},
],
},
{
test: /\.features$/,
use: [
{
loader: 'cypress-cucumber-preprocessor/lib/featuresLoader',
},
],
},
],
},
plugins: [
new ForkTsCheckerWebpackPlugin({
typescript: {
enabled: true,
configFile: config.env.tsConfig,
},
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
],
externals: [nodeExternals()],
},
})
);
};

View File

@ -0,0 +1,53 @@
Cypress.Commands.add(
'common_validate_blocks_data_displayed',
function (headerTestId) {
cy.get(headerTestId).then(($assetHeaders) => {
const headersLength = Number($assetHeaders.length);
cy.wrap($assetHeaders).each(($header) => {
expect($header).to.not.be.empty;
});
cy.get('.language-json')
.each(($asset) => {
expect($asset).to.not.be.empty;
})
.then(($list) => {
expect($list).to.have.length(headersLength);
});
});
}
);
Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
cy.viewport('iphone-x');
cy.visit('/');
cy.get('[data-testid="open-menu"]').click();
});
Cypress.Commands.add('common_verify_json_parameters', function (expectedNum) {
cy.get('.hljs-attr')
.should('have.length.at.least', expectedNum)
.each(($paramName) => {
cy.wrap($paramName).should('not.be.empty');
});
});
Cypress.Commands.add(
'common_verify_json_string_values',
function (expectedNum) {
cy.get('.hljs-string')
.should('have.length.at.least', expectedNum)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
}
);
Cypress.Commands.add('common_verify_json_int_values', function (expectedNum) {
cy.get('.hljs-number')
.should('have.length.at.least', expectedNum)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
});

View File

@ -0,0 +1,2 @@
// type definitions for Cypress object "cy"
/// <reference types="cypress" />

View File

@ -1,9 +0,0 @@
import BasePage from './base-page';
export default class AssetsPage extends BasePage {
assetHeader = 'asset-header';
validateAssetsDisplayed() {
this.validateBlockDataDisplayed(this.assetHeader);
}
}

View File

@ -1,100 +0,0 @@
export default class BasePage {
transactionsUrl = '/txs';
blocksUrl = '/blocks';
partiesUrl = '/parties';
assetsUrl = '/assets';
genesisUrl = '/genesis';
governanceUrl = '/governance';
marketsUrl = '/markets';
networkParametersUrl = '/network-parameters';
validatorsUrl = '/validators';
blockExplorerHeader = 'explorer-header';
searchField = 'search';
searchButton = 'search-button';
searchError = 'search-error';
openMobileMenuBtn = 'open-menu';
navigateToTxs() {
cy.get(`a[href='${this.transactionsUrl}']`).click();
}
navigateToBlocks() {
cy.get(`a[href='${this.blocksUrl}']`).click();
}
navigateToParties() {
cy.get(`a[href='${this.partiesUrl}']`).click();
}
navigateToAssets() {
cy.get(`a[href*='${this.assetsUrl}']`).click();
}
navigateToGenesis() {
cy.get(`a[href='${this.genesisUrl}']`).click();
}
navigateToGovernance() {
cy.get(`a[href='${this.governanceUrl}']`).click();
}
navigateToMarkets() {
cy.get(`a[href='${this.marketsUrl}']`).click();
}
navigateToNetworkParameters() {
cy.get(`a[href='${this.networkParametersUrl}']`).click();
}
navigateToValidators() {
cy.get(`a[href='${this.validatorsUrl}']`).click();
}
search(searchText: string) {
if (searchText) {
cy.getByTestId(this.searchField).type(searchText);
}
}
clickSearch() {
cy.getByTestId(this.searchButton).click();
}
clickOnToggle() {
cy.getByTestId(this.openMobileMenuBtn).click({ force: true });
}
validateUrl(expectedUrl: string) {
cy.url().should('include', expectedUrl);
}
validateSearchDisplayed() {
cy.getByTestId(this.blockExplorerHeader).should(
'have.text',
'Vega Explorer'
);
cy.getByTestId(this.searchField).should('be.visible');
}
validateSearchErrorDisplayed(errorMessage: string) {
cy.getByTestId(this.searchError).should('have.text', errorMessage);
}
validateBlockDataDisplayed(headerTestId: string) {
cy.getByTestId(headerTestId).then(($assetHeaders) => {
const headersAmount = Number($assetHeaders.length);
cy.wrap($assetHeaders).each(($header) => {
expect($header).to.not.be.empty;
});
cy.get('.language-json')
.each(($asset) => {
expect($asset).to.not.be.empty;
})
.then(($list) => {
expect($list).to.have.length(headersAmount);
});
});
}
}

View File

@ -1,146 +0,0 @@
import BasePage from './base-page';
export default class BlocksPage extends BasePage {
blockRow = 'block-row';
transactionsRow = 'transaction-row';
blockHeight = 'block-height';
numberOfTransactions = 'num-txs';
validatorLink = 'validator-link';
blockTime = 'block-time';
refreshBtn = 'refresh';
blockHeader = 'block-header';
minedByValidator = 'block-validator';
previousBlockBtn = 'previous-block';
nextBlockBtn = 'next-block';
jumpToBlockInput = 'block-input';
jumpToBlockSubmit = 'go-submit';
infiniteScrollWrapper = 'infinite-scroll-wrapper';
private waitForBlocksResponse() {
cy.contains('Loading...').should('not.exist', { timeout: 18000 });
}
validateBlocksPageDisplayed() {
this.waitForBlocksResponse();
cy.getByTestId(this.blockRow).should('have.length.above', 1);
cy.getByTestId(this.blockHeight).first().should('not.be.empty');
cy.getByTestId(this.numberOfTransactions).first().should('not.be.empty');
cy.getByTestId(this.validatorLink).first().should('not.be.empty');
cy.getByTestId(this.blockTime).first().should('not.be.empty');
}
clickOnTopBlockHeight() {
this.waitForBlocksResponse();
cy.getByTestId(this.blockHeight).first().click();
}
validateBlockValidatorPage() {
cy.getByTestId(this.minedByValidator).should('not.be.empty');
cy.getByTestId(this.blockTime).should('not.be.empty');
cy.get('body').then(($body) => {
if ($body.find(`[data-testid=${this.transactionsRow}] > td`).length) {
cy.get(`[data-testid=${this.transactionsRow}] > td`).each(($cell) => {
cy.wrap($cell).should('not.be.empty');
});
} else {
cy.slack('Unable to find any transactions on page');
cy.screenshot();
}
});
}
navigateToPreviousBlock() {
cy.getByTestId(this.blockHeader)
.invoke('text')
.then(($blockHeaderTxt) => {
const blockHeight = parseInt($blockHeaderTxt.replace('BLOCK ', ''));
this.clickPreviousBlock();
cy.getByTestId(this.blockHeader)
.invoke('text')
.then(($newBlockHeaderTxt) => {
const newBlockHeight = parseInt(
$newBlockHeaderTxt.replace('BLOCK ', '')
);
expect(newBlockHeight).to.be.lessThan(blockHeight);
});
});
}
navigateToNextBlock() {
cy.getByTestId(this.blockHeader)
.invoke('text')
.then(($blockHeaderTxt) => {
const blockHeight = parseInt($blockHeaderTxt.replace('BLOCK ', ''));
this.clickNextBlock();
cy.getByTestId(this.blockHeader)
.invoke('text')
.then(($newBlockHeaderTxt) => {
const newBlockHeight = parseInt(
$newBlockHeaderTxt.replace('BLOCK ', '')
);
expect(newBlockHeight).to.be.greaterThan(blockHeight);
});
});
}
navigateToLastBlockOnPage() {
this.waitForBlocksResponse();
cy.getByTestId(this.infiniteScrollWrapper).children().scrollTo('bottom');
}
navigateToOlderBlocksWithInfiniteScroll(
expectedBlocks: number,
scrollAttempts: number
) {
cy.intercept('*blockchain?maxHeight*').as('blockchain_load');
cy.getByTestId(this.blockHeight)
.last()
.invoke('text')
.then(($initialLastBlockHeight) => {
for (let index = 0; index < scrollAttempts; index++) {
cy.getByTestId(this.infiniteScrollWrapper)
.children()
.children()
.invoke('css', 'height')
.then((scrollTarget) => {
cy.getByTestId(this.infiniteScrollWrapper)
.children()
.scrollTo(0, scrollTarget.toString(), { easing: 'linear' })
.wait('@blockchain_load');
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(50); // Need this as although network response has arrived it takes a few millisecs for the css height to expand
});
}
cy.getByTestId(this.blockHeight)
.last()
.invoke('text')
.then(($lastBlockHeight) => {
const totalBlocksLoadedSinceScrollBegan =
parseInt($initialLastBlockHeight) - parseInt($lastBlockHeight);
expect(totalBlocksLoadedSinceScrollBegan).to.be.at.least(
expectedBlocks
);
});
});
}
clickPreviousBlock() {
cy.getByTestId(this.previousBlockBtn).click();
}
clickNextBlock() {
cy.getByTestId(this.nextBlockBtn).click();
}
jumpToBlock(blockNumber: string) {
cy.getByTestId(this.jumpToBlockInput).type(blockNumber);
cy.getByTestId(this.jumpToBlockSubmit).click();
}
verifyPreviousBtnDisabled() {
cy.getByTestId(this.previousBlockBtn).find('button').should('be.disabled');
}
}

View File

@ -1,9 +0,0 @@
import BasePage from './base-page';
export default class GenesisPage extends BasePage {
genesisHeader = 'genesis-header';
genesisFieldsDisplayed() {
this.validateBlockDataDisplayed(this.genesisHeader);
}
}

View File

@ -1,95 +0,0 @@
import BasePage from './base-page';
export default class HomePage extends BasePage {
statsEnvironmentTitle = 'stats-environment';
statsTitle = 'stats-title';
statsValue = 'stats-value';
verifyStatsEnvironment() {
const deployedEnv = Cypress.env('environment').toUpperCase();
cy.getByTestId(this.statsEnvironmentTitle).should(
'have.text',
`/ ${deployedEnv}`
);
}
verifyStatsTitlesDisplayed() {
const statTitles = [
'Status',
'Height',
'Validating nodes',
'Uptime',
'Total nodes',
'Inactive nodes',
'Total staked',
'Backlog',
'Trades / second',
'Orders / block',
'Orders / second',
'Transactions / block',
'Block time',
'Time',
'App',
'Tendermint',
'Up since',
'Chain ID',
];
cy.getByTestId(this.statsTitle).then(($list) => {
cy.wrap($list).should('have.length', 18);
});
cy.getByTestId(this.statsTitle)
.each(($title, index) => {
cy.wrap($title).should('have.text', statTitles[index]);
})
.then(($list) => {
cy.wrap($list).should('have.length', 18);
});
}
verifyStatsValuesDisplayed() {
cy.getByTestId(this.statsValue).eq(0).should('have.text', 'CONNECTED');
cy.getByTestId(this.statsValue).eq(1).should('not.be.empty');
cy.getByTestId(this.statsValue).eq(2).should('have.text', '2');
cy.getByTestId(this.statsValue)
.eq(3)
.invoke('text')
.should('match', /\d+d \d+h \d+m \d+s/i);
cy.getByTestId(this.statsValue).eq(4).should('have.text', '2');
cy.getByTestId(this.statsValue).eq(5).should('have.text', '0');
cy.getByTestId(this.statsValue).eq(6).should('not.be.empty');
cy.getByTestId(this.statsValue).eq(7).should('have.text', '0');
cy.getByTestId(this.statsValue).eq(8).should('have.text', '0');
cy.getByTestId(this.statsValue).eq(9).should('have.text', '0');
cy.getByTestId(this.statsValue).eq(10).should('have.text', '0');
cy.getByTestId(this.statsValue).eq(11).should('not.be.empty');
cy.getByTestId(this.statsValue).eq(12).should('not.be.empty');
cy.getByTestId(this.statsValue).eq(13).should('not.be.empty');
if (Cypress.env('NIGHTLY_RUN') != true) {
cy.getByTestId(this.statsValue)
.eq(14)
.invoke('text')
.should('match', /v\d+\.\d+\.\d+/i);
}
cy.getByTestId(this.statsValue)
.eq(15)
.invoke('text')
.should('match', /\d+\.\d+\.\d+/i);
cy.getByTestId(this.statsValue).eq(16).should('not.be.empty');
cy.getByTestId(this.statsValue).eq(17).should('not.be.empty');
}
verifyStatsBlockHeightUpdating() {
cy.getByTestId(this.statsValue)
.eq(1)
.invoke('text')
.then((blockHeightTxt) => {
cy.getByTestId(this.statsValue)
.eq(1)
.invoke('text')
.should((newBlockHeightTxt) => {
expect(blockHeightTxt).not.to.eq(newBlockHeightTxt);
});
});
}
}

View File

@ -1,9 +0,0 @@
import BasePage from './base-page';
export default class MarketsPage extends BasePage {
marketHeaders = 'markets-header';
validateMarketDataDisplayed() {
this.validateBlockDataDisplayed(this.marketHeaders);
}
}

View File

@ -1,39 +0,0 @@
import BasePage from './base-page';
export default class NetworkParametersPage extends BasePage {
networkParametersHeader = 'network-param-header';
parameters = 'parameters';
jsonParamNameClassName = '.hljs-attr';
jsonParamValueStringClassName = '.hljs-string';
jsonParamValueNumberClassName = '.hljs-number';
parameterKeyValueRow = 'key-value-table-row';
verifyNetworkParametersDisplayed() {
cy.getByTestId(this.networkParametersHeader).should(
'have.text',
'Network Parameters'
);
cy.get(this.jsonParamNameClassName)
.should('have.length.at.least', 18)
.each(($paramName) => {
cy.wrap($paramName).should('not.be.empty');
});
cy.get(this.jsonParamValueStringClassName)
.should('have.length.at.least', 6)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
cy.get(this.jsonParamValueNumberClassName)
.should('have.length.at.least', 7)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
cy.getByTestId(this.parameterKeyValueRow).each(($row) => {
cy.wrap($row).find('dt').should('not.be.empty');
cy.wrap($row).find('dd').should('not.be.empty');
});
}
}

View File

@ -1,85 +0,0 @@
import BasePage from './base-page';
export default class TransactionsPage extends BasePage {
transactionsList = 'transactions-list';
transactionRow = 'transaction-row';
blockHeight = 'block-height';
numberOfTransactions = 'num-txs';
validatorLink = 'validator-link';
blockTime = 'block-time';
refreshBtn = 'refresh';
txHash = 'hash';
txSubmittedBy = 'submitted-by';
txBlock = 'block';
txEncodedTnx = 'encoded-tnx';
txType = 'tx-type';
validateTransactionsPagedisplayed() {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(5000); // Wait for transactions to load if there are any
cy.getByTestId(this.transactionRow).should('have.length.above', 1);
}
validateRefreshBtn() {
cy.intercept('GET', '**/blockchain').as('get-blockchain');
cy.getByTestId(this.refreshBtn).click();
cy.wait('@get-blockchain').its('response.statusCode').should('eq', 200);
}
validateTxDetailsAreDisplayed() {
// TODO fail test when there are no txs once running with Capsule
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000); // Wait for transactions to load if there are any
cy.get('body').then(($body) => {
if ($body.find(`[data-testid=${this.txHash}]`).length) {
cy.getByTestId(this.txHash).invoke('text').should('have.length', 64);
cy.getByTestId(this.txSubmittedBy)
.find('a')
.then(($address) => {
cy.wrap($address).should('have.attr', 'href');
cy.wrap($address).invoke('text').should('have.length', 66);
});
cy.getByTestId(this.txBlock).should('not.be.empty');
cy.getByTestId(this.txEncodedTnx).should('not.be.empty');
cy.getByTestId(this.txType)
.should('not.be.empty')
.invoke('text')
.then((txTypeTxt) => {
if (txTypeTxt == 'Order Submission') {
cy.get('.hljs-attr')
.should('have.length.at.least', 8)
.each(($propertyName) => {
cy.wrap($propertyName).should('not.be.empty');
});
cy.get('.hljs-string')
.should('have.length.at.least', 8)
.each(($propertyValue) => {
cy.wrap($propertyValue).should('not.be.empty');
});
}
});
} else {
cy.slack('Unable to find any transactions on page');
cy.screenshot();
}
});
}
clickOnTopTransaction() {
// TODO fail test when there are no txs once running with Capsule
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000); // Wait for transactions to load if there are any
cy.get('body').then(($body) => {
if ($body.find(`[data-testid=${this.transactionRow}]`).length) {
cy.getByTestId(this.transactionRow)
.first()
.find('a')
.first()
.click({ force: true });
} else {
cy.slack('Unable to find any transactions on page');
cy.screenshot();
}
});
}
}

View File

@ -1,18 +0,0 @@
import BasePage from './base-page';
export default class ValidatorPage extends BasePage {
tendermintHeader = 'tendermint-header';
vegaHeader = 'vega-header';
tendermintData = 'tendermint-data';
vegaData = 'vega-data';
validateValidatorsDisplayed() {
cy.getByTestId(this.tendermintHeader).should(
'have.text',
'Tendermint data'
);
cy.getByTestId(this.tendermintData).should('not.be.empty');
cy.getByTestId(this.vegaHeader).should('have.text', 'Vega data');
cy.getByTestId(this.vegaData).should('not.be.empty');
}
}

View File

@ -1,12 +0,0 @@
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
import AssetsPage from '../pages/assets-page';
const assetPage = new AssetsPage();
When('I navigate to the asset page', () => {
assetPage.navigateToAssets();
});
Then('asset page is correctly displayed', () => {
assetPage.validateAssetsDisplayed();
});

View File

@ -1,50 +0,0 @@
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
import BlocksPage from '../pages/blocks-page';
const blocksPage = new BlocksPage();
When('I navigate to the blocks page', () => {
blocksPage.navigateToBlocks();
});
When('I click on top block', () => {
blocksPage.clickOnTopBlockHeight();
});
When('jump to first block', () => {
blocksPage.jumpToBlock('1');
});
Then('blocks page is correctly displayed', () => {
blocksPage.validateBlocksPageDisplayed();
});
Then('validator block page is correctly displayed', () => {
blocksPage.validateBlockValidatorPage();
});
Then('I am on the previous block when I click previous', () => {
blocksPage.navigateToPreviousBlock();
});
Then('previous button is disabled', () => {
blocksPage.verifyPreviousBtnDisabled();
});
Then('I am on the second block when I click next', () => {
blocksPage.navigateToNextBlock();
});
Then('I scroll down to the last block on the page', () => {
blocksPage.navigateToLastBlockOnPage();
});
Then(
'I can expect to see at least {int} blocks if i scroll {int} times',
(expectedBlocks, scrollAttempts) => {
blocksPage.navigateToOlderBlocksWithInfiniteScroll(
expectedBlocks,
scrollAttempts
);
}
);

View File

@ -1,26 +0,0 @@
import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps';
import BasePage from '../pages/base-page';
const basePage = new BasePage();
Given('I am on mobile and open the toggle menu', () => {
cy.viewport('iphone-x');
cy.visit('/');
basePage.clickOnToggle();
});
Given('I am on the homepage', () => {
cy.visit('/');
});
When('I search for {string}', (searchText) => {
basePage.search(searchText);
basePage.clickSearch();
});
Then('I am redirected to page containing id {string}', (expectedUrl) => {
basePage.validateUrl(expectedUrl);
});
Then('search error message {string} is displayed', (expectedErrorMsg) => {
basePage.validateSearchErrorDisplayed(expectedErrorMsg);
});

View File

@ -1,11 +0,0 @@
import { Then } from 'cypress-cucumber-preprocessor/steps';
import HomePage from '../pages/home-page';
const homePage = new HomePage();
Then('the stats for deployed environment are correctly displayed', () => {
homePage.verifyStatsEnvironment();
homePage.verifyStatsTitlesDisplayed();
homePage.verifyStatsValuesDisplayed();
homePage.verifyStatsBlockHeightUpdating();
});

View File

@ -1,12 +0,0 @@
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
import MarketsPage from '../pages/markets-page';
const marketsPage = new MarketsPage();
When('I navigate to the markets page', () => {
marketsPage.navigateToMarkets();
});
Then('markets page is correctly displayed', () => {
marketsPage.validateMarketDataDisplayed();
});

View File

@ -1,11 +0,0 @@
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
import NetworkPage from '../pages/network-page';
const networkPage = new NetworkPage();
When('I navigate to network parameters page', () => {
networkPage.navigateToNetworkParameters();
});
Then('network parameters page is correctly displayed', () => {
networkPage.verifyNetworkParametersDisplayed();
});

View File

@ -1,30 +0,0 @@
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
import TransactionsPage from '../pages/transactions-page';
const transactionsPage = new TransactionsPage();
When('I navigate to the transactions page', () => {
transactionsPage.navigateToTxs();
});
When('I navigate to the blocks page', () => {
transactionsPage.navigateToBlocks();
});
When('I click on the top transaction', () => {
transactionsPage.clickOnTopTransaction();
});
Then('transactions page is correctly displayed', () => {
transactionsPage.validateTransactionsPagedisplayed();
transactionsPage.validateRefreshBtn();
});
Then('blocks page is correctly displayed', () => {
transactionsPage.validateTransactionsPagedisplayed();
transactionsPage.validateRefreshBtn();
});
Then('transaction details are displayed', () => {
transactionsPage.validateTxDetailsAreDisplayed();
});

View File

@ -1,12 +0,0 @@
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
import ValidatorPage from '../pages/validators-page';
const validatorsPage = new ValidatorPage();
When('I navigate to the validators page', () => {
validatorsPage.navigateToValidators();
});
Then('validators page is correctly displayed', () => {
validatorsPage.validateValidatorsDisplayed();
});