UI/UX: Fix Blockchain skeleton preloader. (#696)
* Fix Blockchain skeleton preloader. * Fix Mempool Blocks skeleton preloader. * Add e2e test. * Add shared command to cyrpress e2e test.
This commit is contained in:
		
							parent
							
								
									9f645e0bee
								
							
						
					
					
						commit
						63e14f454c
					
				@ -12,28 +12,40 @@ describe('Mainnet', () => {
 | 
			
		||||
        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)\)/);
 | 
			
		||||
      });
 | 
			
		||||
        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.waitForSkeletonGone();
 | 
			
		||||
        cy.visit('/');
 | 
			
		||||
        cy.waitForSkeletonGone();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('loads skeleton when changes between networks', () => {
 | 
			
		||||
        cy.visit('/');
 | 
			
		||||
        cy.waitForSkeletonGone();
 | 
			
		||||
 | 
			
		||||
        cy.changeNetwork("testnet");
 | 
			
		||||
        cy.changeNetwork("signet");
 | 
			
		||||
        cy.changeNetwork("liquid");
 | 
			
		||||
        cy.changeNetwork("mainnet");
 | 
			
		||||
        cy.changeNetwork("bisq");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('loads the dashboard with the skeleton blocks', () => {
 | 
			
		||||
 | 
			
		||||
@ -64,3 +64,14 @@ Cypress.Commands.add(
 | 
			
		||||
Cypress.Commands.add('mockMempoolSocket', () => {
 | 
			
		||||
  mockWebSocket();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Cypress.Commands.add('changeNetwork', (network: "testnet"|"signet"|"liquid"|"bisq"|"mainnet" ) => {
 | 
			
		||||
    cy.get('.dropdown-toggle').click().then(() => {
 | 
			
		||||
        cy.get(`.${network}`).click().then(() => {
 | 
			
		||||
            cy.waitForPageIdle();
 | 
			
		||||
            if(network !== 'bisq'){
 | 
			
		||||
                cy.waitForSkeletonGone();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
<div class="blocks-container" *ngIf="loadingBlocks">
 | 
			
		||||
<div class="blocks-container" *ngIf="!loadingBlocks; else loadingBlocksTemplate">
 | 
			
		||||
  <div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn" >
 | 
			
		||||
    <div class="text-center bitcoin-block mined-block" id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]">
 | 
			
		||||
      <a [routerLink]="['/block/' | relativeUrl, block.id]" [state]="{ data: { block: block } }" class="blockLink"> </a>
 | 
			
		||||
@ -25,11 +25,13 @@
 | 
			
		||||
  <div [hidden]="!arrowVisible" id="arrow-up" [style.transition]="transition" [ngStyle]="{'left': arrowLeftPx + 'px' }"></div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="blocks-container" *ngIf="!loadingBlocks">
 | 
			
		||||
  <div class="flashing">
 | 
			
		||||
    <div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn" >
 | 
			
		||||
      <div class="text-center bitcoin-block mined-block" id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]"></div>
 | 
			
		||||
<ng-template #loadingBlocksTemplate >
 | 
			
		||||
  <div class="blocks-container">
 | 
			
		||||
    <div class="flashing">
 | 
			
		||||
      <div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn" >
 | 
			
		||||
        <div class="text-center bitcoin-block mined-block" id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]"></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,9 +16,10 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
  blocks: Block[] = this.mountEmptyBlocks();
 | 
			
		||||
  markHeight: number;
 | 
			
		||||
  blocksSubscription: Subscription;
 | 
			
		||||
  networkSubscriotion: Subscription;
 | 
			
		||||
  networkSubscription: Subscription;
 | 
			
		||||
  tabHiddenSubscription: Subscription;
 | 
			
		||||
  markBlockSubscription: Subscription;
 | 
			
		||||
  isLoadingWebsocketSubscription: Subscription;
 | 
			
		||||
  blockStyles = [];
 | 
			
		||||
  interval: any;
 | 
			
		||||
  tabHidden = false;
 | 
			
		||||
@ -45,7 +46,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.blocks.forEach((b) => this.blockStyles.push(this.getStyleForBlock(b)));
 | 
			
		||||
    this.networkSubscriotion = this.stateService.networkChanged$.subscribe((network) => this.network = network);
 | 
			
		||||
    this.isLoadingWebsocketSubscription = this.stateService.isLoadingWebSocket$.subscribe((loading) => this.loadingBlocks = loading);
 | 
			
		||||
    this.networkSubscription = this.stateService.networkChanged$.subscribe((network) => this.network = network);
 | 
			
		||||
    this.tabHiddenSubscription = this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden);
 | 
			
		||||
 | 
			
		||||
    this.blocksSubscription = this.stateService.blocks$
 | 
			
		||||
@ -54,8 +56,6 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.loadingBlocks = true;
 | 
			
		||||
 | 
			
		||||
        if (this.blocks.length && block.height !== this.blocks[0].height + 1) {
 | 
			
		||||
          this.blocks = [];
 | 
			
		||||
          this.blocksFilled = false;
 | 
			
		||||
@ -75,13 +75,15 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
          this.moveArrowToPosition(true, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.blockStyles = [];
 | 
			
		||||
        this.blocks.forEach((b) => this.blockStyles.push(this.getStyleForBlock(b)));
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
        if (!this.loadingBlocks) {
 | 
			
		||||
          this.blockStyles = [];
 | 
			
		||||
          this.blocks.forEach((b) => this.blockStyles.push(this.getStyleForBlock(b)));
 | 
			
		||||
          this.cd.markForCheck();
 | 
			
		||||
        }, 50);
 | 
			
		||||
          setTimeout(() => {
 | 
			
		||||
            this.blockStyles = [];
 | 
			
		||||
            this.blocks.forEach((b) => this.blockStyles.push(this.getStyleForBlock(b)));
 | 
			
		||||
            this.cd.markForCheck();
 | 
			
		||||
          }, 50);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.blocks.length === this.stateService.env.KEEP_BLOCKS_AMOUNT) {
 | 
			
		||||
          this.blocksFilled = true;
 | 
			
		||||
@ -124,9 +126,10 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    this.blocksSubscription.unsubscribe();
 | 
			
		||||
    this.networkSubscriotion.unsubscribe();
 | 
			
		||||
    this.networkSubscription.unsubscribe();
 | 
			
		||||
    this.tabHiddenSubscription.unsubscribe();
 | 
			
		||||
    this.markBlockSubscription.unsubscribe();
 | 
			
		||||
    this.isLoadingWebsocketSubscription.unsubscribe();
 | 
			
		||||
    clearInterval(this.interval);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet" [class.active]="network.val === 'signet'" routerLink="/signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</button>
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</button>
 | 
			
		||||
      <h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="mainnet" [class.active]="network.val === 'bisq'" routerLink="/bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="bisq" [class.active]="network.val === 'bisq'" routerLink="/bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid" [class.active]="network.val === 'liquid'" routerLink="/liquid"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<div class="mempool-blocks-container">
 | 
			
		||||
  <div class="flashing" *ngIf="(timeAvg$ | async) as timeAvg;">
 | 
			
		||||
  <div class="flashing" *ngIf="!loadingMempoolBlocks && (timeAvg$ | async) as timeAvg;">      
 | 
			
		||||
    <ng-template ngFor let-projectedBlock [ngForOf]="mempoolBlocks$ | async" let-i="index" [ngForTrackBy]="trackByFn">
 | 
			
		||||
      <div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]">
 | 
			
		||||
        <a [routerLink]="['/mempool-block/' | relativeUrl, i]" class="blockLink"> </a>
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
  mempoolBlocksFull: MempoolBlock[] = this.mountEmptyBlocks();
 | 
			
		||||
  mempoolBlockStyles = [];
 | 
			
		||||
  markBlocksSubscription: Subscription;
 | 
			
		||||
  isLoadingWebsocketSubscription: Subscription;
 | 
			
		||||
  blockSubscription: Subscription;
 | 
			
		||||
  networkSubscription: Subscription;
 | 
			
		||||
  network = '';
 | 
			
		||||
@ -55,6 +56,11 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
    });
 | 
			
		||||
    this.reduceMempoolBlocksToFitScreen(this.mempoolBlocks);
 | 
			
		||||
    this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden);
 | 
			
		||||
    
 | 
			
		||||
    this.isLoadingWebsocketSubscription = this.stateService.isLoadingWebSocket$.subscribe((loading) => {
 | 
			
		||||
      this.loadingMempoolBlocks = loading;
 | 
			
		||||
      this.cd.markForCheck();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.mempoolBlocks$ = merge(
 | 
			
		||||
      of(true),
 | 
			
		||||
@ -164,6 +170,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
    this.markBlocksSubscription.unsubscribe();
 | 
			
		||||
    this.blockSubscription.unsubscribe();
 | 
			
		||||
    this.networkSubscription.unsubscribe();
 | 
			
		||||
    this.isLoadingWebsocketSubscription.unsubscribe();
 | 
			
		||||
    clearTimeout(this.resetTransitionTimeout);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user