mirror of
https://github.com/mempool/mempool.git
synced 2025-01-18 21:32:55 +01:00
Updates to the e2e suite (#659)
* initial version of the update config script
* fix duplicated content
* update cypress ci settings
* add workflow to run e2e tests when pushing
* record cypress results to the dashboard
* pull the cypress record key and project id from the secrets
* add start-server-and-test to replace concurrently
* replace concurrently with start-server-and-test
* remove concurrently
* add new cypress target to record
* update cypress to 7.7.0
* add tests for signet
* add tests for testnet
* run tests on chrome and firefox
* update test matrix: add edge and run firefox on container
* fix copypasta
* update docker image for firefox
* fix task name again
* fix edge tests task name
* improve bisq tests
* update workflow config
* enable cypress debug logs
* add a manual trigger for the e2e tests
* add config:defaults target
* use more of the GHA options
* fix config command
* add cypress-fail-on-console-error
* upgrade cypress to v8.0.0
* add helper to wait for the loader skeleton to be gone
* use skeleton waiter on the tests
* remove manual test trigger
* fix tv test when only one mempool block is available
* add waiter for pagination
* add extra steps to debug firefox launch issue
* remove whoami step
* Revert "upgrade cypress to v8.0.0"
This reverts commit cb3ff7d906
.
* remove userinfo debug step
* enable test retries in run mode
* update proxy config to reduce ECONNRESET errors
* add mock-socket dev dependency
* add helpers to mock websockets and detect page idleness
* stabilize mainnet tests
* fix tv mode test on Liquid
* add basic tests for the mainnet status page
* cleanup mainnet tests
* update bisq tests
* update signet tests
* update testnet tests
* add initial support for parameterized websocket mocks
* move testing dependencies to optionalDependencies
* comment out mempool size check until the live updates are fixed
* comment out tx regex test
* update fixture for the new difficulty adjustment component
* fix the assertions on the status page
This commit is contained in:
parent
723034b3d3
commit
9e46cde9b7
68
.github/workflows/push.yml
vendored
Normal file
68
.github/workflows/push.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
name: Cypress Tests
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
cypress-chrome:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Chrome Browser Tests
|
||||
uses: cypress-io/github-action@v2
|
||||
with:
|
||||
working-directory: frontend
|
||||
build: npm run config:defaults
|
||||
start: npm run start:local-prod
|
||||
wait-on: 'http://localhost:4200'
|
||||
wait-on-timeout: 120
|
||||
record: true
|
||||
browser: chrome
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
#GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
|
||||
DEBUG: 'cypress:*'
|
||||
cypress-firefox:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: cypress/browsers:node14.17.0-chrome88-ff89
|
||||
options: --user 1001
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Firefox Browser Tests
|
||||
uses: cypress-io/github-action@v2
|
||||
with:
|
||||
working-directory: frontend
|
||||
build: npm run config:defaults
|
||||
start: npm run start:local-prod
|
||||
wait-on: 'http://localhost:4200'
|
||||
wait-on-timeout: 120
|
||||
record: true
|
||||
browser: firefox
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
#GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
|
||||
DEBUG: 'cypress:*'
|
||||
cypress-edge:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Edge Browser Tests
|
||||
uses: cypress-io/github-action@v2
|
||||
with:
|
||||
working-directory: frontend
|
||||
build: npm run config:defaults
|
||||
start: npm run start:local-prod
|
||||
wait-on: 'http://localhost:4200'
|
||||
wait-on-timeout: 120
|
||||
record: true
|
||||
browser: edge
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
#GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
|
||||
DEBUG: 'cypress:*'
|
@ -5,5 +5,9 @@
|
||||
"screenshotsFolder": "cypress/screenshots",
|
||||
"pluginsFile": "cypress/plugins/index.js",
|
||||
"fixturesFolder": "cypress/fixtures",
|
||||
"baseUrl": "http://localhost:4200"
|
||||
"baseUrl": "http://localhost:4200",
|
||||
"retries": {
|
||||
"runMode": 3,
|
||||
"openMode": 0
|
||||
}
|
||||
}
|
1
frontend/cypress/fixtures/mainnet_live2hchart.json
Normal file
1
frontend/cypress/fixtures/mainnet_live2hchart.json
Normal file
@ -0,0 +1 @@
|
||||
{"live-2h-chart":{"id":1319298,"added":"2021-07-23T18:27:34.000Z","unconfirmed_transactions":546,"tx_per_second":3.93333,"vbytes_per_second":1926,"mempool_byte_weight":1106656,"total_fee":6198583,"vsizes":[255,18128,43701,58534,17144,5532,4483,1759,2394,1089,1683,7409,751,101010,1151,592,1497,703,1369,4747,800,1221,0,0,712,0,0,0,0,0,0,0,0,0,0,0,0,0]}}
|
1
frontend/cypress/fixtures/mainnet_mempoolInfo.json
Normal file
1
frontend/cypress/fixtures/mainnet_mempoolInfo.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,5 @@
|
||||
describe('Bisq', () => {
|
||||
beforeEach(() => {
|
||||
|
||||
cy.intercept('/sockjs-node/info*').as('socket');
|
||||
cy.intercept('/bisq/api/markets/hloc?market=btc_usd&interval=day').as('hloc');
|
||||
cy.intercept('/bisq/api/markets/ticker').as('ticker');
|
||||
@ -10,32 +9,42 @@ describe('Bisq', () => {
|
||||
cy.intercept('/bisq/api/txs/*/*').as('txs');
|
||||
cy.intercept('/bisq/api/blocks/*/*').as('blocks');
|
||||
cy.intercept('/bisq/api/stats').as('stats');
|
||||
|
||||
Cypress.Commands.add('waitForDashboard', () => {
|
||||
cy.wait('@socket');
|
||||
cy.wait('@hloc');
|
||||
cy.wait('@ticker');
|
||||
cy.wait('@markets');
|
||||
cy.wait('@7d');
|
||||
cy.wait('@trades');
|
||||
});
|
||||
});
|
||||
it('loads the dashboard', () => {
|
||||
cy.visit('/bisq');
|
||||
|
||||
cy.wait('@socket');
|
||||
cy.wait('@hloc');
|
||||
cy.wait('@ticker');
|
||||
cy.wait('@markets');
|
||||
cy.wait('@7d');
|
||||
cy.wait('@trades');
|
||||
it('loads the dashboard', () => {
|
||||
cy.visit('/bisq');
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads the transactions screen', () => {
|
||||
cy.visit('/bisq');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(2) > a').click().then(() => {
|
||||
cy.wait('@txs');
|
||||
cy.get('.table > tr').should('have.length', 50);
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the blocks screen', () => {
|
||||
cy.visit('/bisq');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(3) > a').click().then(() => {
|
||||
cy.wait('@blocks');
|
||||
cy.get('tbody tr').should('have.length', 10);
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the stats screen', () => {
|
||||
cy.visit('/bisq');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(4) > a').click().then(() => {
|
||||
cy.wait('@stats');
|
||||
});
|
||||
@ -43,14 +52,19 @@ describe('Bisq', () => {
|
||||
|
||||
it('loads the api screen', () => {
|
||||
cy.visit('/bisq');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
|
||||
cy.get('.card').should('have.length.at.least', 1);
|
||||
cy.get('.card').first().click();
|
||||
cy.get('.card-body');
|
||||
});
|
||||
});
|
||||
|
||||
it('shows blocks pagination with 5 pages (desktop)', () => {
|
||||
cy.viewport(760, 800);
|
||||
cy.visit('/bisq/transactions');
|
||||
cy.visit('/bisq/blocks');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('tbody tr').should('have.length', 10);
|
||||
// 5 pages + 4 buttons = 9 buttons
|
||||
cy.get('.pagination-container ul.pagination').first().children().should('have.length', 9);
|
||||
});
|
||||
@ -58,6 +72,8 @@ describe('Bisq', () => {
|
||||
it('shows blocks pagination with 3 pages (mobile)', () => {
|
||||
cy.viewport(669, 800);
|
||||
cy.visit('/bisq/blocks');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('tbody tr').should('have.length', 10);
|
||||
// 3 pages + 4 buttons = 7 buttons
|
||||
cy.get('.pagination-container ul.pagination').first().children().should('have.length', 7);
|
||||
});
|
||||
|
@ -1,33 +1,41 @@
|
||||
describe('Liquid', () => {
|
||||
beforeEach(() => {
|
||||
// TODO: Fix ng serve to deliver these files
|
||||
cy.fixture('assets.minimal').then((json) => {
|
||||
cy.intercept('/resources/assets.minimal.json', json);
|
||||
});
|
||||
cy.intercept('/liquid/api/block/**').as('block');
|
||||
cy.intercept('/liquid/api/blocks/').as('blocks');
|
||||
cy.intercept('/liquid/api/tx/**/outspends').as('outspends');
|
||||
cy.intercept('/liquid/api/block/**/txs/**').as('block-txs');
|
||||
cy.intercept('/resources/pools.json').as('pools');
|
||||
|
||||
cy.fixture('assets').then((json) => {
|
||||
cy.intercept('/resources/assets.json', json);
|
||||
});
|
||||
Cypress.Commands.add('waitForBlockData', () => {
|
||||
cy.wait('@socket');
|
||||
cy.wait('@block');
|
||||
cy.wait('@outspends');
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the dashboard', () => {
|
||||
cy.visit('/liquid');
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads the blocks page', () => {
|
||||
cy.visit('/liquid/blocks');
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads a specific block page', () => {
|
||||
cy.visit('/liquid/blocks');
|
||||
cy.visit('/liquid/block/7e1369a23a5ab861e7bdede2aadcccae4ea873ffd9caf11c7c5541eb5bcdff54');
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads the graphs page', () => {
|
||||
cy.visit('/liquid/graphs');
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads the tv page - desktop', () => {
|
||||
cy.visit('/liquid');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(3) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
@ -35,17 +43,18 @@ describe('Liquid', () => {
|
||||
|
||||
it('loads the graphs page - mobile', () => {
|
||||
cy.visit('/liquid');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(3) > a').click().then(() => {
|
||||
cy.viewport('iphone-6');
|
||||
cy.wait(1000);
|
||||
// TODO: Should we really support TV Mode in Mobile for Bisq?
|
||||
// cy.get('.tv-only').should('be.visible')
|
||||
cy.get('.tv-only').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('assets', () => {
|
||||
it('shows the assets screen', () => {
|
||||
cy.visit('/liquid');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
cy.get('table tr').should('have.length', 5);
|
||||
});
|
||||
@ -53,6 +62,7 @@ describe('Liquid', () => {
|
||||
|
||||
it('allows searching assets', () => {
|
||||
cy.visit('/liquid');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
cy.get('.container-xl input').click().type('Liquid Bitcoin').then(() => {
|
||||
cy.get('table tr').should('have.length', 1);
|
||||
@ -62,6 +72,7 @@ describe('Liquid', () => {
|
||||
|
||||
it('shows a specific asset ID', () => {
|
||||
cy.visit('/liquid');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
cy.get('.container-xl input').click().type('Liquid CAD').then(() => {
|
||||
cy.get('table tr td:nth-of-type(4) a').click();
|
||||
@ -71,6 +82,7 @@ describe('Liquid', () => {
|
||||
|
||||
it('shows a specific asset issuance TX', () => {
|
||||
cy.visit('/liquid');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
cy.get('.container-xl input').click().type('Liquid CAD').then(() => {
|
||||
cy.get('table tr td:nth-of-type(5) a').click();
|
||||
@ -83,18 +95,21 @@ describe('Liquid', () => {
|
||||
describe('unblinded TX', () => {
|
||||
it('show unblinded TX', () => {
|
||||
cy.visit('/liquid/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc,2364760,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,90c7a43b15b905bca045ca42a01271cfe71d2efe3133f4197792c24505cb32ed,12eb5959d9293b8842e7dd8bc9aa9639fd3fd031c5de3ba911adeca94eb57a3a');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('#table-tx-vin tr').should('have.class', 'assetBox');
|
||||
cy.get('#table-tx-vout tr').should('have.class', 'assetBox');
|
||||
});
|
||||
|
||||
it('show empty unblinded TX', () => {
|
||||
cy.visit('/liquid/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('#table-tx-vin tr').should('have.class', '');
|
||||
cy.get('#table-tx-vout tr').should('have.class', '');
|
||||
});
|
||||
|
||||
it('show invalid unblinded TX hex', () => {
|
||||
cy.visit('/liquid/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=123');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('#table-tx-vin tr').should('have.class', '');
|
||||
cy.get('#table-tx-vout tr').should('have.class', '');
|
||||
cy.get('.error-unblinded' ).contains('Error: Invalid blinding data (invalid hex)');
|
||||
@ -102,6 +117,7 @@ describe('Liquid', () => {
|
||||
|
||||
it('show first unblinded vout', () => {
|
||||
cy.visit('/liquid/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('#table-tx-vout tr:first-child()').should('have.class', 'assetBox');
|
||||
});
|
||||
|
||||
@ -112,9 +128,15 @@ describe('Liquid', () => {
|
||||
|
||||
it('show invalid error unblinded TX', () => {
|
||||
cy.visit('/liquid/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc,2364760,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,90c7a43b15b905bca045ca42a01271cfe71d2efe3133f4197792c24505cb32ed,12eb5959d9293b8842e7dd8bc9aa9639fd3fd031c5de3ba911adeca94eb57a3c');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('#table-tx-vout tr').should('have.class', 'assetBox');
|
||||
cy.get('.error-unblinded' ).contains('Error: Invalid blinding data.');
|
||||
});
|
||||
|
||||
it('prevents regressing issue #644', () => {
|
||||
cy.visit('/liquid/tx/393b890966f305e7c440fcfb12a13f51a7a9011cc59ff5f14f6f93214261bd82');
|
||||
cy.waitForSkeletonGone();
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -1,41 +1,72 @@
|
||||
import { emitMempoolInfo } from "../../support/websocket";
|
||||
|
||||
describe('Mainnet', () => {
|
||||
beforeEach(() => {
|
||||
//cy.intercept('/sockjs-node/info*').as('socket');
|
||||
cy.intercept('/api/block-height/*').as('block-height');
|
||||
cy.intercept('/api/block/*').as('block');
|
||||
cy.intercept('/api/block/*/txs/0').as('block-txs');
|
||||
cy.intercept('/api/tx/*/outspends').as('tx-outspends');
|
||||
cy.intercept('/resources/pools.json').as('pools');
|
||||
|
||||
// TODO: Fix ng serve to deliver this file
|
||||
cy.fixture('pools').then((json) => {
|
||||
cy.intercept('/resources/pools.json', json);
|
||||
});
|
||||
Cypress.Commands.add('waitForBlockData', () => {
|
||||
cy.wait('@tx-outspends');
|
||||
cy.wait('@pools');
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the status screen', () => {
|
||||
cy.visit('/status');
|
||||
cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('[id^="bitcoin-block-"]').should('have.length', 8);
|
||||
cy.get('.footer').should('be.visible');
|
||||
cy.get('.row > :nth-child(1)').invoke('text').then((text) => {
|
||||
expect(text).to.match(/Tx vBytes per second:.* vB\/s/);
|
||||
});
|
||||
cy.get('.row > :nth-child(2)').invoke('text').then((text) => {
|
||||
expect(text).to.match(/Unconfirmed:(.*)/);
|
||||
});
|
||||
cy.get('.row > :nth-child(3)').invoke('text').then((text) => {
|
||||
expect(text).to.match(/Mempool size:(.*) (kB|MB) \((\d+) (block|blocks)\)/);
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the dashboard', () => {
|
||||
cy.visit('/');
|
||||
cy.wait(1000);
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads the dashboard with the skeleton blocks', () => {
|
||||
cy.visit('/');
|
||||
cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-1').should('be.visible');
|
||||
cy.get('#mempool-block-2').should('be.visible');
|
||||
cy.get(':nth-child(1) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(2) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(3) > #bitcoin-block-0').should('be.visible');
|
||||
cy.wait(1000);
|
||||
cy.mockMempoolSocket();
|
||||
cy.visit("/");
|
||||
cy.get(':nth-child(1) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(2) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(3) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-1').should('be.visible');
|
||||
cy.get('#mempool-block-2').should('be.visible');
|
||||
|
||||
emitMempoolInfo({
|
||||
'params': {
|
||||
loaded: true
|
||||
}
|
||||
});
|
||||
cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist');
|
||||
cy.get(':nth-child(2) > #bitcoin-block-0').should('not.exist');
|
||||
cy.get(':nth-child(3) > #bitcoin-block-0').should('not.exist');
|
||||
});
|
||||
|
||||
it('loads the blocks screen', () => {
|
||||
cy.visit('/');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(2) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
cy.waitForPageIdle();
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the graphs screen', () => {
|
||||
cy.visit('/');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(3) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
@ -45,29 +76,29 @@ describe('Mainnet', () => {
|
||||
it('loads the tv screen - desktop', () => {
|
||||
cy.viewport('macbook-16');
|
||||
cy.visit('/');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(4) > a').click().then(() => {
|
||||
cy.viewport('macbook-16');
|
||||
cy.wait(1000);
|
||||
cy.get('.chart-holder');
|
||||
cy.get('.blockchain-wrapper').should('be.visible');
|
||||
cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-1').should('be.visible');
|
||||
cy.get('#mempool-block-2').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the tv screen - mobile', () => {
|
||||
cy.visit('/');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(4) > a').click().then(() => {
|
||||
cy.viewport('iphone-6');
|
||||
cy.wait(1000);
|
||||
cy.get('.chart-holder');
|
||||
cy.get('.blockchain-wrapper').should('not.be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('loads the api screen', () => {
|
||||
cy.visit('/');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
@ -76,12 +107,15 @@ describe('Mainnet', () => {
|
||||
describe('blocks', () => {
|
||||
it('shows empty blocks properly', () => {
|
||||
cy.visit('/block/0000000000000000000bd14f744ef2e006e61c32214670de7eb891a5732ee775');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.waitForPageIdle();
|
||||
cy.get('h2').invoke('text').should('equal', '1 transaction');
|
||||
});
|
||||
|
||||
it('expands and collapses the block details', () => {
|
||||
cy.visit('/block/0');
|
||||
cy.wait('@tx-outspends');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.waitForPageIdle();
|
||||
cy.get('.btn.btn-outline-info').click().then(() => {
|
||||
cy.get('#details').should('be.visible');
|
||||
});
|
||||
@ -91,17 +125,21 @@ describe('Mainnet', () => {
|
||||
});
|
||||
});
|
||||
it('shows blocks with no pagination', () => {
|
||||
cy.viewport('iphone-6');
|
||||
cy.visit('/block/00000000000000000001ba40caf1ad4cec0ceb77692662315c151953bfd7c4c4');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.waitForPageIdle();
|
||||
cy.get('.block-tx-title h2').invoke('text').should('equal', '19 transactions');
|
||||
cy.get('.pagination-container ul.pagination').first().children().should('have.length', 6);
|
||||
cy.get('.pagination-container ul.pagination').first().children().should('have.length', 5);
|
||||
});
|
||||
|
||||
it('supports pagination on the block screen', () => {
|
||||
// 41 txs
|
||||
cy.visit('/block/00000000000000000009f9b7b0f63ad50053ad12ec3b7f5ca951332f134f83d8');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('.pagination-container a').invoke('text').then((text1) => {
|
||||
cy.get('.active + li').first().click().then(() => {
|
||||
cy.waitForSkeletonGone();
|
||||
cy.waitForPageIdle();
|
||||
cy.get('.header-bg.box > a').invoke('text').then((text2) => {
|
||||
expect(text1).not.to.eq(text2);
|
||||
});
|
||||
@ -111,14 +149,22 @@ describe('Mainnet', () => {
|
||||
|
||||
it('shows blocks pagination with 5 pages (desktop)', () => {
|
||||
cy.viewport(760, 800);
|
||||
cy.visit('/block/000000000000000000049281946d26fcba7d99fdabc1feac524bc3a7003d69b3');
|
||||
cy.visit('/block/000000000000000000049281946d26fcba7d99fdabc1feac524bc3a7003d69b3').then(() => {
|
||||
cy.waitForSkeletonGone();
|
||||
cy.waitForPageIdle();
|
||||
});
|
||||
|
||||
// 5 pages + 4 buttons = 9 buttons
|
||||
cy.get('.pagination-container ul.pagination').first().children().should('have.length', 9);
|
||||
});
|
||||
|
||||
it('shows blocks pagination with 3 pages (mobile)', () => {
|
||||
cy.viewport(669, 800);
|
||||
cy.visit('/block/000000000000000000049281946d26fcba7d99fdabc1feac524bc3a7003d69b3');
|
||||
cy.visit('/block/000000000000000000049281946d26fcba7d99fdabc1feac524bc3a7003d69b3').then(() => {
|
||||
cy.waitForSkeletonGone();
|
||||
cy.waitForPageIdle();
|
||||
});
|
||||
|
||||
// 3 pages + 4 buttons = 7 buttons
|
||||
cy.get('.pagination-container ul.pagination').first().children().should('have.length', 7);
|
||||
});
|
||||
|
@ -1,10 +1,126 @@
|
||||
import { emitMempoolInfo } from "../../support/websocket";
|
||||
|
||||
describe('Signet', () => {
|
||||
it('loads the dashboard', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('/api/block-height/*').as('block-height');
|
||||
cy.intercept('/api/block/*').as('block');
|
||||
cy.intercept('/api/block/*/txs/0').as('block-txs');
|
||||
cy.intercept('/api/tx/*/outspends').as('tx-outspends');
|
||||
});
|
||||
|
||||
it('loads the dashboard', () => {
|
||||
cy.visit('/signet');
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads the dashboard with the skeleton blocks', () => {
|
||||
cy.mockMempoolSocket();
|
||||
cy.visit("/signet");
|
||||
cy.get(':nth-child(1) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(2) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(3) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-1').should('be.visible');
|
||||
cy.get('#mempool-block-2').should('be.visible');
|
||||
|
||||
emitMempoolInfo({
|
||||
'params': {
|
||||
"network": "signet"
|
||||
}
|
||||
});
|
||||
cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist');
|
||||
cy.get(':nth-child(2) > #bitcoin-block-0').should('not.exist');
|
||||
cy.get(':nth-child(3) > #bitcoin-block-0').should('not.exist');
|
||||
});
|
||||
|
||||
it('loads the blocks screen', () => {
|
||||
cy.visit('/signet');
|
||||
});
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(2) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('loads all the pages properly', () => {
|
||||
it('loads the graphs screen', () => {
|
||||
cy.visit('/signet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(3) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
describe('tv mode', () => {
|
||||
it('loads the tv screen - desktop', () => {
|
||||
cy.viewport('macbook-16');
|
||||
cy.visit('/signet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(4) > a').click().then(() => {
|
||||
cy.get('.chart-holder').should('be.visible');
|
||||
cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('.tv-only').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the tv screen - mobile', () => {
|
||||
cy.visit('/signet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(4) > a').click().then(() => {
|
||||
cy.viewport('iphone-8');
|
||||
cy.get('.chart-holder').should('be.visible');
|
||||
//TODO: Remove comment when the bug is fixed
|
||||
//cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('.tv-only').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('loads the api screen', () => {
|
||||
cy.visit('/signet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('blocks', () => {
|
||||
it('shows empty blocks properly', () => {
|
||||
cy.visit('/signet/block/00000133d54e4589f6436703b067ec23209e0a21b8a9b12f57d0592fd85f7a42');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('h2').invoke('text').should('equal', '1 transaction');
|
||||
});
|
||||
|
||||
it('expands and collapses the block details', () => {
|
||||
cy.visit('/signet/block/0');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('.btn.btn-outline-info').click().then(() => {
|
||||
cy.get('#details').should('be.visible');
|
||||
});
|
||||
|
||||
cy.get('.btn.btn-outline-info').click().then(() => {
|
||||
cy.get('#details').should('not.be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('shows blocks with no pagination', () => {
|
||||
cy.visit('/signet/block/00000078f920a96a69089877b934ce7fd009ab55e3170920a021262cb258e7cc');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('h2').invoke('text').should('equal', '13 transactions');
|
||||
cy.get('ul.pagination').first().children().should('have.length', 5);
|
||||
});
|
||||
|
||||
it('supports pagination on the block screen', () => {
|
||||
// 43 txs
|
||||
cy.visit('/signet/block/00000094bd52f73bdbfc4bece3a94c21fec2dc968cd54210496e69e4059d66a6');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('.header-bg.box > a').invoke('text').then((text1) => {
|
||||
cy.get('.active + li').first().click().then(() => {
|
||||
cy.get('.header-bg.box > a').invoke('text').then((text2) => {
|
||||
expect(text1).not.to.eq(text2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -1,9 +1,123 @@
|
||||
import { emitMempoolInfo } from "../../support/websocket";
|
||||
|
||||
describe('Testnet', () => {
|
||||
it('loads the dashboard', () => {
|
||||
cy.visit('/testnet');
|
||||
});
|
||||
|
||||
it.skip('loads all the pages properly', () => {
|
||||
|
||||
});
|
||||
beforeEach(() => {
|
||||
cy.intercept('/api/block-height/*').as('block-height');
|
||||
cy.intercept('/api/block/*').as('block');
|
||||
cy.intercept('/api/block/*/txs/0').as('block-txs');
|
||||
cy.intercept('/api/tx/*/outspends').as('tx-outspends');
|
||||
});
|
||||
|
||||
it('loads the dashboard', () => {
|
||||
cy.visit('/testnet');
|
||||
cy.waitForSkeletonGone();
|
||||
});
|
||||
|
||||
it('loads the dashboard with the skeleton blocks', () => {
|
||||
cy.mockMempoolSocket();
|
||||
cy.visit("/signet");
|
||||
cy.get(':nth-child(1) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(2) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get(':nth-child(3) > #bitcoin-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-0').should('be.visible');
|
||||
cy.get('#mempool-block-1').should('be.visible');
|
||||
cy.get('#mempool-block-2').should('be.visible');
|
||||
|
||||
emitMempoolInfo({
|
||||
'params': {
|
||||
loaded: true
|
||||
}
|
||||
});
|
||||
cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist');
|
||||
cy.get(':nth-child(2) > #bitcoin-block-0').should('not.exist');
|
||||
cy.get(':nth-child(3) > #bitcoin-block-0').should('not.exist');
|
||||
});
|
||||
|
||||
it('loads the blocks screen', () => {
|
||||
cy.visit('/testnet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(2) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the graphs screen', () => {
|
||||
cy.visit('/testnet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(3) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tv mode', () => {
|
||||
it('loads the tv screen - desktop', () => {
|
||||
cy.viewport('macbook-16');
|
||||
cy.visit('/testnet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(4) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
cy.get('.tv-only').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('loads the tv screen - mobile', () => {
|
||||
cy.visit('/testnet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(4) > a').click().then(() => {
|
||||
cy.viewport('iphone-6');
|
||||
cy.wait(1000);
|
||||
cy.get('.tv-only').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('loads the api screen', () => {
|
||||
cy.visit('/testnet');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||
cy.wait(1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('blocks', () => {
|
||||
it('shows empty blocks properly', () => {
|
||||
cy.visit('/testnet/block/0');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('h2').invoke('text').should('equal', '1 transaction');
|
||||
});
|
||||
|
||||
it('expands and collapses the block details', () => {
|
||||
cy.visit('/testnet/block/0');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('.btn.btn-outline-info').click().then(() => {
|
||||
cy.get('#details').should('be.visible');
|
||||
});
|
||||
|
||||
cy.get('.btn.btn-outline-info').click().then(() => {
|
||||
cy.get('#details').should('not.be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('shows blocks with no pagination', () => {
|
||||
cy.visit('/testnet/block/000000000000002f8ce27716e74ecc7ad9f7b5101fed12d09e28bb721b9460ea');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('h2').invoke('text').should('equal', '11 transactions');
|
||||
cy.get('ul.pagination').first().children().should('have.length', 5);
|
||||
});
|
||||
|
||||
it('supports pagination on the block screen', () => {
|
||||
// 48 txs
|
||||
cy.visit('/testnet/block/000000000000002ca3878ebd98b313a1c2d531f2e70a6575d232ca7564dea7a9');
|
||||
cy.waitForSkeletonGone();
|
||||
cy.get('.header-bg.box > a').invoke('text').then((text1) => {
|
||||
cy.get('.active + li').first().click().then(() => {
|
||||
cy.get('.header-bg.box > a').invoke('text').then((text2) => {
|
||||
expect(text1).not.to.eq(text2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
63
frontend/cypress/support/PageIdleDetector.ts
Normal file
63
frontend/cypress/support/PageIdleDetector.ts
Normal file
@ -0,0 +1,63 @@
|
||||
// source: chrisp_68 @ https://stackoverflow.com/questions/50525143/how-do-you-reliably-wait-for-page-idle-in-cypress-io-test
|
||||
export class PageIdleDetector
|
||||
{
|
||||
defaultOptions: Object = { timeout: 60000 };
|
||||
|
||||
public WaitForPageToBeIdle(): void
|
||||
{
|
||||
this.WaitForPageToLoad();
|
||||
this.WaitForAngularRequestsToComplete();
|
||||
this.WaitForAngularDigestCycleToComplete();
|
||||
this.WaitForAnimationsToStop();
|
||||
}
|
||||
|
||||
public WaitForPageToLoad(options: Object = this.defaultOptions): void
|
||||
{
|
||||
cy.document(options).should((myDocument: any) =>
|
||||
{
|
||||
expect(myDocument.readyState, "WaitForPageToLoad").to.be.oneOf(["interactive", "complete"]);
|
||||
});
|
||||
}
|
||||
|
||||
public WaitForAngularRequestsToComplete(options: Object = this.defaultOptions): void
|
||||
{
|
||||
cy.window(options).should((myWindow: any) =>
|
||||
{
|
||||
if (!!myWindow.angular)
|
||||
{
|
||||
expect(this.NumberOfPendingAngularRequests(myWindow), "WaitForAngularRequestsToComplete").to.have.length(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public WaitForAngularDigestCycleToComplete(options: Object = this.defaultOptions): void
|
||||
{
|
||||
cy.window(options).should((myWindow: any) =>
|
||||
{
|
||||
if (!!myWindow.angular)
|
||||
{
|
||||
expect(this.AngularRootScopePhase(myWindow), "WaitForAngularDigestCycleToComplete").to.be.null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public WaitForAnimationsToStop(options: Object = this.defaultOptions): void
|
||||
{
|
||||
cy.get(":animated", options).should("not.exist");
|
||||
}
|
||||
|
||||
private getInjector(myWindow: any)
|
||||
{
|
||||
return myWindow.angular.element(myWindow.document.body).injector();
|
||||
}
|
||||
|
||||
private NumberOfPendingAngularRequests(myWindow: any)
|
||||
{
|
||||
return this.getInjector(myWindow).get('$http').pendingRequests;
|
||||
}
|
||||
|
||||
private AngularRootScopePhase(myWindow: any)
|
||||
{
|
||||
return this.getInjector(myWindow).get("$rootScope").$$phase;
|
||||
}
|
||||
}
|
@ -43,3 +43,24 @@
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
|
||||
import 'cypress-wait-until';
|
||||
import { PageIdleDetector } from './PageIdleDetector';
|
||||
import { mockWebSocket } from './websocket';
|
||||
|
||||
Cypress.Commands.add('waitForSkeletonGone', () => {
|
||||
cy.waitUntil(() => {
|
||||
return Cypress.$('.skeleton-loader').length === 0;
|
||||
}, { verbose: true, description: "waitForSkeletonGone", errorMsg: "skeleton loaders never went away", timeout: 7000, interval: 50});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
"waitForPageIdle",
|
||||
() => {
|
||||
console.warn("Waiting for page idle state");
|
||||
const pageIdleDetector = new PageIdleDetector();
|
||||
pageIdleDetector.WaitForPageToBeIdle();
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.Commands.add('mockMempoolSocket', () => {
|
||||
mockWebSocket();
|
||||
});
|
||||
|
@ -15,3 +15,6 @@
|
||||
|
||||
// When a command from ./commands is ready to use, import with `import './commands'` syntax
|
||||
import './commands';
|
||||
import failOnConsoleError from 'cypress-fail-on-console-error';
|
||||
|
||||
failOnConsoleError();
|
84
frontend/cypress/support/websocket.ts
Normal file
84
frontend/cypress/support/websocket.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { WebSocket, Server } from 'mock-socket';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
mockServer: Server;
|
||||
mockSocket: WebSocket;
|
||||
}
|
||||
}
|
||||
|
||||
const mocks: { [key: string]: { server: Server; websocket: WebSocket } } = {};
|
||||
|
||||
const cleanupMock = (url: string) => {
|
||||
if (mocks[url]) {
|
||||
mocks[url].websocket.close();
|
||||
mocks[url].server.stop();
|
||||
delete mocks[url];
|
||||
}
|
||||
};
|
||||
|
||||
const createMock = (url: string) => {
|
||||
cleanupMock(url);
|
||||
const server = new Server(url);
|
||||
const websocket = new WebSocket(url);
|
||||
mocks[url] = { server, websocket };
|
||||
|
||||
return mocks[url];
|
||||
};
|
||||
|
||||
export const mockWebSocket = () => {
|
||||
cy.on('window:before:load', (win) => {
|
||||
const winWebSocket = win.WebSocket;
|
||||
cy.stub(win, 'WebSocket').callsFake((url) => {
|
||||
console.log(url);
|
||||
if ((new URL(url).pathname.indexOf('/sockjs-node/') !== 0)) {
|
||||
const { server, websocket } = createMock(url);
|
||||
|
||||
win.mockServer = server;
|
||||
win.mockServer.on('connection', (socket) => {
|
||||
win.mockSocket = socket;
|
||||
});
|
||||
|
||||
win.mockServer.on('message', (message) => {
|
||||
console.log(message);
|
||||
});
|
||||
|
||||
return websocket;
|
||||
} else {
|
||||
return new winWebSocket(url);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
cy.on('window:before:unload', () => {
|
||||
for (const url in mocks) {
|
||||
cleanupMock(url);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const emitMempoolInfo = ({
|
||||
params
|
||||
}: { params?: any } = {}) => {
|
||||
cy.window().then((win) => {
|
||||
//TODO: Refactor to take into account different parameterized mocking scenarios
|
||||
switch (params.network) {
|
||||
//TODO: Use network specific mocks
|
||||
case "signet":
|
||||
case "testnet":
|
||||
default:
|
||||
win.mockSocket.send('{"action":"init"}');
|
||||
win.mockSocket.send('{"action":"want","data":["blocks","stats","mempool-blocks","live-2h-chart"]}');
|
||||
cy.readFile('cypress/fixtures/mainnet_mempoolInfo.json', 'ascii').then((fixture) => {
|
||||
win.mockSocket.send(JSON.stringify(fixture));
|
||||
});
|
||||
win.mockSocket.send('{"conversions":{"USD":32365.338815782445}}');
|
||||
cy.readFile('cypress/fixtures/mainnet_live2hchart.json', 'ascii').then((fixture) => {
|
||||
win.mockSocket.send(JSON.stringify(fixture));
|
||||
});
|
||||
}
|
||||
});
|
||||
cy.waitForSkeletonGone();
|
||||
return cy.get('#mempool-block-0');
|
||||
};
|
2859
frontend/package-lock.json
generated
2859
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -38,12 +38,17 @@
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"e2e:ci": "npm run cypress:run:ci",
|
||||
"config:defaults": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config",
|
||||
"dev:ssr": "npm run generate-config && ng run mempool:serve-ssr",
|
||||
"serve:ssr": "node server.run.js",
|
||||
"build:ssr": "npm run build && ng run mempool:server:production && ./node_modules/typescript/bin/tsc server.run.ts",
|
||||
"prerender": "ng run mempool:prerender",
|
||||
"cypress:open": "concurrently \"ng serve -c local-prod\" \"cypress open\" --kill-others",
|
||||
"cypress:run": "concurrently \"ng serve -c local-prod\" \"cypress run\" --kill-others"
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run",
|
||||
"cypress:run:record": "cypress run --record",
|
||||
"cypress:open:ci": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:open",
|
||||
"cypress:run:ci": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:run:record"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "~11.2.8",
|
||||
@ -85,15 +90,12 @@
|
||||
"@angular/cli": "~11.2.7",
|
||||
"@angular/compiler-cli": "~11.2.8",
|
||||
"@angular/language-service": "~11.2.8",
|
||||
"@cypress/schematic": "^1.3.0",
|
||||
"@nguniversal/builders": "^11.2.1",
|
||||
"@types/express": "^4.17.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.1",
|
||||
"concurrently": "^6.2.0",
|
||||
"cypress-wait-until": "^1.7.1",
|
||||
"http-proxy-middleware": "^1.0.5",
|
||||
"jasmine-core": "~3.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
@ -107,6 +109,11 @@
|
||||
"typescript": "~4.1.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"cypress": "^7.4.0"
|
||||
"cypress": "^7.7.0",
|
||||
"@cypress/schematic": "^1.3.0",
|
||||
"cypress-fail-on-console-error": "^2.1.0",
|
||||
"cypress-wait-until": "^1.7.1",
|
||||
"start-server-and-test": "^1.12.6",
|
||||
"mock-socket": "^9.0.3"
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,11 @@
|
||||
"secure": false,
|
||||
"ws": true
|
||||
},
|
||||
"/api/*": {
|
||||
"/api": {
|
||||
"target": "https://mempool.space",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
"logLevel": "debug",
|
||||
"pathRewrite": {
|
||||
"^/api": "https://mempool.space/api"
|
||||
},
|
||||
"timeout": 3600000
|
||||
},
|
||||
"/testnet/api/v1/ws": {
|
||||
@ -23,7 +20,7 @@
|
||||
"^/testnet/api": "/api/v1/ws"
|
||||
}
|
||||
},
|
||||
"/testnet/api/*": {
|
||||
"/testnet/api": {
|
||||
"target": "https://mempool.space",
|
||||
"secure": true,
|
||||
"changeOrigin": true,
|
||||
@ -42,7 +39,7 @@
|
||||
"^/signet/api": "/api/v1/ws"
|
||||
}
|
||||
},
|
||||
"/signet/api/*": {
|
||||
"/signet/api": {
|
||||
"target": "https://mempool.space",
|
||||
"secure": true,
|
||||
"changeOrigin": true,
|
||||
@ -61,7 +58,7 @@
|
||||
"^/bisq/api": "/api/v1/ws"
|
||||
}
|
||||
},
|
||||
"/bisq/api/*": {
|
||||
"/bisq/api": {
|
||||
"target": "https://mempool.space/bisq",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
@ -75,7 +72,7 @@
|
||||
"secure": false,
|
||||
"ws": true
|
||||
},
|
||||
"/liquid/api/*": {
|
||||
"/liquid/api": {
|
||||
"target": "https://mempool.space",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
|
95
frontend/update-config.js
Normal file
95
frontend/update-config.js
Normal file
@ -0,0 +1,95 @@
|
||||
const fs = require('fs');
|
||||
|
||||
const CONFIG_FILE_NAME = 'mempool-frontend-config.json';
|
||||
const GENERATED_CONFIG_FILE_NAME = 'generated-config.js';
|
||||
|
||||
let settings = [];
|
||||
let configContent = {};
|
||||
const packageSettings = ['GIT_COMMIT_HASH', 'PACKAGE_JSON_VERSION']; //These will be handled by generate-config
|
||||
|
||||
var args = process.argv.slice(2);
|
||||
|
||||
function addSetting(key, value) {
|
||||
settings.push({
|
||||
key: key,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
|
||||
function normalizedValue(value) {
|
||||
if (Number(value)) {
|
||||
value = Number(value);
|
||||
} else if ((value === 'true') || (value !== 'true')) {
|
||||
value = !!JSON.parse(String(value).toLowerCase());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseGeneratedFile() {
|
||||
const generatedConfig = fs.readFileSync(GENERATED_CONFIG_FILE_NAME);
|
||||
if (generatedConfig) {
|
||||
const configContents = generatedConfig.toString();
|
||||
const regexp = new RegExp(/window.__env.(\w+) = '(.*)'/,'g');
|
||||
while ((match = regexp.exec(configContents)) !== null) {
|
||||
// Do not add setting if it's the git hash or package json version
|
||||
if (!packageSettings.includes(match[1])) {
|
||||
const key = match[1];
|
||||
const value = match[2];
|
||||
console.log(typeof(value));
|
||||
addSetting(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function saveSettingsJson() {
|
||||
settings.forEach(setting => {
|
||||
if (configContent.hasOwnProperty(setting['key']) && normalizedValue(configContent[setting['key']]) !== normalizedValue(setting['value'])) {
|
||||
console.log(setting['key'] + " updated from " + configContent[setting['key']] + " to " + setting['value']);
|
||||
} else if (configContent.hasOwnProperty(setting['key']) && normalizedValue(configContent[setting['key']]) === normalizedValue(setting['value'])) {
|
||||
console.log(setting['key'] + " unchanged, skipping");
|
||||
} else {
|
||||
console.log(setting['key'] + " set to " + setting['value']);
|
||||
}
|
||||
configContent[setting['key']] = setting['value'];
|
||||
});
|
||||
fs.writeFileSync(CONFIG_FILE_NAME, JSON.stringify(configContent));
|
||||
}
|
||||
|
||||
function configToJson() {
|
||||
for (setting in configContent) {
|
||||
settings.push({
|
||||
key: setting,
|
||||
value: configContent[setting]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const rawConfig = fs.readFileSync(CONFIG_FILE_NAME);
|
||||
configContent = JSON.parse(rawConfig);
|
||||
console.log(`${CONFIG_FILE_NAME} file found, using provided config`);
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT') {
|
||||
throw new Error(e);
|
||||
} else {
|
||||
|
||||
if (fs.existsSync(GENERATED_CONFIG_FILE_NAME)) {
|
||||
console.log(`${CONFIG_FILE_NAME} file not found, reading current config from generated-config.js`);
|
||||
parseGeneratedFile();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
args.forEach(setting => {
|
||||
setting = setting.split('=');
|
||||
const key = setting[0];
|
||||
let value = setting[1];
|
||||
addSetting(key, normalizedValue(value));
|
||||
});
|
||||
}
|
||||
|
||||
saveSettingsJson();
|
||||
console.log('new json', configContent);
|
Loading…
Reference in New Issue
Block a user