Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8ec793b65 | ||
|
|
927fe2cb4a | ||
|
|
e205c9df8b | ||
|
|
2c2251e953 | ||
|
|
d73080965b |
@@ -3,9 +3,9 @@
|
||||
"tranche_id": 54,
|
||||
"tranche_start": "2023-04-06T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-06T00:00:00.000Z",
|
||||
"total_added": "1338",
|
||||
"total_added": "1584",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1338",
|
||||
"locked_amount": "1584",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "111",
|
||||
@@ -36,6 +36,16 @@
|
||||
"amount": "111",
|
||||
"user": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
|
||||
"tx": "0x99aeaedef27b5fb693485f4e21d434e343b30fa100945a4ff65386de8801c87e"
|
||||
},
|
||||
{
|
||||
"amount": "114",
|
||||
"user": "0x8D416A61bCccf4E6aF5598302BC4e41f97401652",
|
||||
"tx": "0x09d7342bca4e0fdc9f5a40e18e402b0328991d0df5da17b834c67b149e270808"
|
||||
},
|
||||
{
|
||||
"amount": "132",
|
||||
"user": "0x9E53F72210479BF46aE7ABF77c48B0d611b3c3dB",
|
||||
"tx": "0xcb0f255003872ac506798efa97744868e11ceab2f2f03d96da605d8674f783f6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
@@ -129,6 +139,36 @@
|
||||
"total_tokens": "111",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "111"
|
||||
},
|
||||
{
|
||||
"address": "0x8D416A61bCccf4E6aF5598302BC4e41f97401652",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "114",
|
||||
"user": "0x8D416A61bCccf4E6aF5598302BC4e41f97401652",
|
||||
"tranche_id": 54,
|
||||
"tx": "0x09d7342bca4e0fdc9f5a40e18e402b0328991d0df5da17b834c67b149e270808"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "114",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "114"
|
||||
},
|
||||
{
|
||||
"address": "0x9E53F72210479BF46aE7ABF77c48B0d611b3c3dB",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "132",
|
||||
"user": "0x9E53F72210479BF46aE7ABF77c48B0d611b3c3dB",
|
||||
"tranche_id": 54,
|
||||
"tx": "0xcb0f255003872ac506798efa97744868e11ceab2f2f03d96da605d8674f783f6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "132",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "132"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -237,7 +277,7 @@
|
||||
"tranche_end": "2023-04-06T00:00:00.000Z",
|
||||
"total_added": "14099",
|
||||
"total_removed": "22.78816420236",
|
||||
"locked_amount": "9888.9977516427704009",
|
||||
"locked_amount": "9775.8699107676210698",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "30",
|
||||
@@ -2930,7 +2970,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "62861.1571212942085110557",
|
||||
"locked_amount": "62802.0961944541744214653",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -2996,7 +3036,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1067.9026124338625",
|
||||
"locked_amount": "1064.48587581400075",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -3117,7 +3157,7 @@
|
||||
"tranche_end": "2023-09-01T00:00:00.000Z",
|
||||
"total_added": "17500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "16144.06482739533",
|
||||
"locked_amount": "16120.4076401469395",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "12500",
|
||||
@@ -3384,7 +3424,7 @@
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "3992.79801615",
|
||||
"locked_amount": "28745.160949969305",
|
||||
"locked_amount": "28693.62674570288625",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -3627,7 +3667,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "62803.8042249150901849635",
|
||||
"locked_amount": "62744.797183739481485052",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -3693,7 +3733,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "29455.15402080162128",
|
||||
"locked_amount": "29412.49367706747522",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -3886,7 +3926,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2544.428906646372",
|
||||
"locked_amount": "2541.021530948757",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -4097,7 +4137,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "4826.8831285567535664111",
|
||||
"locked_amount": "4769.0027179179875744514",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@@ -4130,7 +4170,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "98230.390980249184455396",
|
||||
"locked_amount": "6597.515910129377760093140184",
|
||||
"locked_amount": "6518.4033814222176646361931672",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@@ -4176,7 +4216,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2030.5863763707597222158",
|
||||
"locked_amount": "2006.2370871562641268176",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@@ -4209,7 +4249,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "660.9361611648969862",
|
||||
"locked_amount": "653.010703805487814995",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@@ -4242,7 +4282,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "22749.93",
|
||||
"total_removed": "4720.860935375",
|
||||
"locked_amount": "2470.7269878599475445005",
|
||||
"locked_amount": "2441.0998581315436582191",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "6500",
|
||||
@@ -4394,7 +4434,7 @@
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "5529.83377455",
|
||||
"locked_amount": "5810.63248158379425",
|
||||
"locked_amount": "5779.71195902394075",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -4757,7 +4797,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "418510.6360640652716794746",
|
||||
"locked_amount": "417188.6231006399309246128",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -10200,7 +10240,7 @@
|
||||
"tranche_start": "2021-09-03T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-03T00:00:00.000Z",
|
||||
"total_added": "56798.000000000000000003",
|
||||
"total_removed": "44482.21518131551",
|
||||
"total_removed": "48097.21518131551",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -20725,6 +20765,21 @@
|
||||
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
|
||||
"tx": "0xc1d1e0a03a5ace0a8c61f58c81a407867a2d3195d2249df11d2eb630949d4ea2"
|
||||
},
|
||||
{
|
||||
"amount": "1925",
|
||||
"user": "0xA260d0f8070b2A85B3C00ADb1f0046f20ca85AAa",
|
||||
"tx": "0xd2190b942a3b15e97692b9007c71b2cf3b887aaff782a73b23b9dfa7369b9c84"
|
||||
},
|
||||
{
|
||||
"amount": "1690",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tx": "0x3e3247a9cf87d30ca8436606fe8f0cc01cba11fbd798a5aff4f8a7bbf3247af5"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tx": "0x11c2f143f1fccec8d746a0760ada1f4abf9fbce7ee76835a8da17bcfc4d2c7f5"
|
||||
},
|
||||
{
|
||||
"amount": "130",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
@@ -23503,10 +23558,17 @@
|
||||
"tx": "0x62b105e7c569b195b3a3625869c62e4cd307fbda5b0c1e5931a857e376ef6c09"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1925",
|
||||
"user": "0xA260d0f8070b2A85B3C00ADb1f0046f20ca85AAa",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xd2190b942a3b15e97692b9007c71b2cf3b887aaff782a73b23b9dfa7369b9c84"
|
||||
}
|
||||
],
|
||||
"total_tokens": "1925",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "1925"
|
||||
"withdrawn_tokens": "1925",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
|
||||
@@ -32337,10 +32399,23 @@
|
||||
"tx": "0x248d34bdf3224997d3f0e2cd55f75e1b13937591a64cff99abf513bada6da087"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1690",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x3e3247a9cf87d30ca8436606fe8f0cc01cba11fbd798a5aff4f8a7bbf3247af5"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x11c2f143f1fccec8d746a0760ada1f4abf9fbce7ee76835a8da17bcfc4d2c7f5"
|
||||
}
|
||||
],
|
||||
"total_tokens": "1690",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "1690"
|
||||
"withdrawn_tokens": "1690",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xfeDf4b4406B3126744047be05A013570b09DC0cC",
|
||||
@@ -38221,7 +38296,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "700133.348465855088393",
|
||||
"locked_amount": "667606.462432296455376981036",
|
||||
"locked_amount": "665574.988783539092352126032",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -39603,7 +39678,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "803126.94523812819680452",
|
||||
"locked_amount": "7666977.23699395663856772391215730126493643",
|
||||
"locked_amount": "7659773.76186853928704096963886072002784536",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -45730,7 +45805,7 @@
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "5735873.982235800798313006",
|
||||
"locked_amount": "1356659.204790641720440640129577783",
|
||||
"locked_amount": "1350009.002549479199448998084455602",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -53074,7 +53149,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "3362269.76579626473241024",
|
||||
"locked_amount": "219120.853279161821111689561756935",
|
||||
"locked_amount": "216493.318153589487100687138655917",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@@ -55179,8 +55254,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "37637.6576293990685",
|
||||
"locked_amount": "105786.04519533285014909089193304",
|
||||
"total_removed": "37672.6965943910685",
|
||||
"locked_amount": "105464.16156158729024788626382548",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@@ -61834,6 +61909,11 @@
|
||||
"user": "0x1010101036EA85caAC4BB82D953f26cAf14a9Ebc",
|
||||
"tx": "0xd6774c065c0e886d82445f16909e9dec106e3c6714cad682ed4102470403aace"
|
||||
},
|
||||
{
|
||||
"amount": "35.038964992",
|
||||
"user": "0x046717d8914087EB6890dFdF78ebD0f1343F15F6",
|
||||
"tx": "0xa90a66881bf15cc988e22cebc0b0fa29e6421ddda8480c13b32dc3ca0a784ea1"
|
||||
},
|
||||
{
|
||||
"amount": "129.867928716",
|
||||
"user": "0x09996E1a67c371400bD5f52DF841f77B1741eB9d",
|
||||
@@ -77080,6 +77160,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "35.038964992",
|
||||
"user": "0x046717d8914087EB6890dFdF78ebD0f1343F15F6",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xa90a66881bf15cc988e22cebc0b0fa29e6421ddda8480c13b32dc3ca0a784ea1"
|
||||
},
|
||||
{
|
||||
"amount": "84.425145866",
|
||||
"user": "0x046717d8914087EB6890dFdF78ebD0f1343F15F6",
|
||||
@@ -77094,8 +77180,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "120.243144342",
|
||||
"remaining_tokens": "79.756855658"
|
||||
"withdrawn_tokens": "155.282109334",
|
||||
"remaining_tokens": "44.717890666"
|
||||
},
|
||||
{
|
||||
"address": "0x8847EBaaf29A18396e49191602f8d8D141b98aa7",
|
||||
|
||||
@@ -71,7 +71,8 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
validateMarketDataRow(3, 'Quote Name', 'BTC');
|
||||
});
|
||||
|
||||
it('settlement asset displayed', () => {
|
||||
// need to check why data are not visible
|
||||
it.skip('settlement asset displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Settlement asset').click();
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT');
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { connectEthereumWallet } from '../support/ethereum-wallet';
|
||||
|
||||
const connectEthWalletBtn = 'connect-eth-wallet-btn';
|
||||
|
||||
describe('ethereum wallet', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockWeb3Provider();
|
||||
// Using portfolio withdrawals tab is it requires Ethereum wallet connection
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
});
|
||||
|
||||
it('can connect', () => {
|
||||
// 0004-EWAL-001
|
||||
|
||||
cy.wait('@NetworkParams');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
cy.getByTestId('connect-eth-wallet-btn').click();
|
||||
cy.getByTestId('web3-connector-list').should('exist');
|
||||
cy.getByTestId('web3-connector-MetaMask').click();
|
||||
cy.getByTestId('web3-connector-list').should('not.exist');
|
||||
cy.getByTestId('tab-deposits').should('not.be.empty');
|
||||
});
|
||||
|
||||
it('should see an option to cancel the attempted connection', () => {
|
||||
// 0004-EWAL-003
|
||||
|
||||
cy.wait('@NetworkParams');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
cy.getByTestId('connect-eth-wallet-btn').click();
|
||||
cy.getByTestId('web3-connector-list').should('exist');
|
||||
cy.getByTestId('web3-connector-WalletConnect').click();
|
||||
cy.get('#walletconnect-qrcode-text').should('exist');
|
||||
cy.get('#walletconnect-qrcode-close').click();
|
||||
});
|
||||
|
||||
it('able to disconnect eth wallet', () => {
|
||||
// 0004-EWAL-004
|
||||
// 0004-EWAL-005
|
||||
// 0004-EWAL-006
|
||||
|
||||
const ethWalletAddress = Cypress.env('ETHEREUM_WALLET_ADDRESS');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('MetaMask');
|
||||
cy.getByTestId('ethereum-address').should('have.text', ethWalletAddress);
|
||||
cy.getByTestId('disconnect-ethereum-wallet')
|
||||
.should('have.text', 'Disconnect')
|
||||
.click();
|
||||
cy.getByTestId(connectEthWalletBtn).should('exist');
|
||||
});
|
||||
});
|
||||
+19
-39
@@ -1,7 +1,8 @@
|
||||
import { mockConnectWallet } from '@vegaprotocol/cypress';
|
||||
import { connectEthereumWallet } from '../support/ethereum-wallet';
|
||||
import {
|
||||
mockConnectWallet,
|
||||
mockConnectWalletWithUserError,
|
||||
} from '@vegaprotocol/cypress';
|
||||
|
||||
const connectEthWalletBtn = 'connect-eth-wallet-btn';
|
||||
const connectVegaBtn = 'connect-vega-wallet';
|
||||
const manageVegaBtn = 'manage-vega-wallet';
|
||||
const form = 'rest-connector-form';
|
||||
@@ -127,6 +128,21 @@ describe('connect vega wallet', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(manageVegaBtn).should('exist');
|
||||
});
|
||||
|
||||
it.only('can not connect', () => {
|
||||
// 0002-WCON-002
|
||||
// 0002-WCON-005
|
||||
// 0002-WCON-007
|
||||
|
||||
mockConnectWalletWithUserError();
|
||||
cy.getByTestId(connectVegaBtn).click();
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-jsonRpc"]')
|
||||
.click();
|
||||
cy.getByTestId('dialog-content')
|
||||
.should('contain.text', 'User error')
|
||||
.and('contain.text', 'the user rejected the wallet connection');
|
||||
});
|
||||
|
||||
it('can change selected public key and disconnect', () => {
|
||||
// 0002-WCON-022
|
||||
// 0002-WCON-023
|
||||
@@ -164,39 +180,3 @@ describe('connect vega wallet', { tags: '@smoke' }, () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ethereum wallet', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockWeb3Provider();
|
||||
// Using portfolio withdrawals tab is it requires Ethereum wallet connection
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
});
|
||||
|
||||
it('can connect', () => {
|
||||
cy.wait('@NetworkParams');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
cy.getByTestId('connect-eth-wallet-btn').click();
|
||||
cy.getByTestId('web3-connector-list').should('exist');
|
||||
cy.getByTestId('web3-connector-MetaMask').click();
|
||||
cy.getByTestId('web3-connector-list').should('not.exist');
|
||||
cy.getByTestId('tab-deposits').should('not.be.empty');
|
||||
});
|
||||
|
||||
it('able to disconnect eth wallet', () => {
|
||||
const ethWalletAddress = Cypress.env('ETHEREUM_WALLET_ADDRESS');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('MetaMask');
|
||||
cy.getByTestId('ethereum-address').should('have.text', ethWalletAddress);
|
||||
cy.getByTestId('disconnect-ethereum-wallet')
|
||||
.should('have.text', 'Disconnect')
|
||||
.click();
|
||||
cy.getByTestId(connectEthWalletBtn).should('exist');
|
||||
});
|
||||
});
|
||||
@@ -25,7 +25,8 @@ export const DepositsContainer = () => {
|
||||
<div className="h-full relative">
|
||||
<DepositsTable
|
||||
rowData={data || []}
|
||||
noRowsOverlayComponent={() => null}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
ref={gridRef}
|
||||
{...bottomPlaceholderProps}
|
||||
/>
|
||||
|
||||
@@ -24,7 +24,8 @@ export const WithdrawalsContainer = () => {
|
||||
<WithdrawalsTable
|
||||
data-testid="withdrawals-history"
|
||||
rowData={data}
|
||||
noRowsOverlayComponent={() => null}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { NodeHealth, NodeUrl, HealthIndicator } from './footer';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
jest.mock('@vegaprotocol/environment', () => ({
|
||||
...jest.requireActual('@vegaprotocol/environment'),
|
||||
useEnvironment: jest
|
||||
.fn()
|
||||
.mockImplementation(() => ({ VEGA_URL: 'https://vega-url.wtf' })),
|
||||
}));
|
||||
|
||||
const mockSetNodeSwitcher = jest.fn();
|
||||
jest.mock('../../stores', () => ({
|
||||
...jest.requireActual('../../stores'),
|
||||
useGlobalStore: () => mockSetNodeSwitcher,
|
||||
}));
|
||||
|
||||
describe('NodeHealth', () => {
|
||||
it('controls the node switcher dialog', async () => {
|
||||
const mockOnClick = jest.fn();
|
||||
render(
|
||||
<NodeHealth
|
||||
onClick={mockOnClick}
|
||||
url={'https://api.n99.somenetwork.vega.xyz'}
|
||||
blockHeight={100}
|
||||
blockDiff={0}
|
||||
/>
|
||||
);
|
||||
render(<NodeHealth />, { wrapper: MockedProvider });
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
expect(mockOnClick).toHaveBeenCalled();
|
||||
expect(mockSetNodeSwitcher).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,14 +41,22 @@ describe('NodeUrl', () => {
|
||||
|
||||
describe('HealthIndicator', () => {
|
||||
const cases = [
|
||||
{ diff: 0, classname: 'bg-vega-green-550', text: 'Operational' },
|
||||
{ diff: 5, classname: 'bg-warning', text: '5 Blocks behind' },
|
||||
{ diff: null, classname: 'bg-danger', text: 'Non operational' },
|
||||
{
|
||||
intent: Intent.Success,
|
||||
text: 'Operational',
|
||||
classname: 'bg-vega-green-550',
|
||||
},
|
||||
{
|
||||
intent: Intent.Warning,
|
||||
text: '5 Blocks behind',
|
||||
classname: 'bg-warning',
|
||||
},
|
||||
{ intent: Intent.Danger, text: 'Non operational', classname: 'bg-danger' },
|
||||
];
|
||||
it.each(cases)(
|
||||
'renders correct text and indicator color for $diff block difference',
|
||||
(elem) => {
|
||||
render(<HealthIndicator blockDiff={elem.diff} />);
|
||||
render(<HealthIndicator text={elem.text} intent={elem.intent} />);
|
||||
expect(screen.getByTestId('indicator')).toHaveClass(elem.classname);
|
||||
expect(screen.getByText(elem.text)).toBeInTheDocument();
|
||||
}
|
||||
|
||||
@@ -1,60 +1,45 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useEnvironment, useNodeHealth } from '@vegaprotocol/environment';
|
||||
import { useNavigatorOnline } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Indicator, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import type { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { Indicator } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
export const Footer = () => {
|
||||
const { VEGA_URL } = useEnvironment();
|
||||
const setNodeSwitcher = useGlobalStore(
|
||||
(store) => (open: boolean) => store.update({ nodeSwitcherDialog: open })
|
||||
);
|
||||
const { blockDiff, datanodeBlockHeight } = useNodeHealth();
|
||||
|
||||
return (
|
||||
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300 lg:fixed bottom-0 left-0 border-r bg-white dark:bg-black">
|
||||
{/* Pull left to align with top nav, due to button padding */}
|
||||
<div className="-ml-2">
|
||||
{VEGA_URL && (
|
||||
<NodeHealth
|
||||
url={VEGA_URL}
|
||||
blockHeight={datanodeBlockHeight}
|
||||
blockDiff={blockDiff}
|
||||
onClick={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
)}
|
||||
<NodeHealth />
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
interface NodeHealthProps {
|
||||
url: string;
|
||||
blockHeight: number | undefined;
|
||||
blockDiff: number | null;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const NodeHealth = ({
|
||||
url,
|
||||
blockHeight,
|
||||
blockDiff,
|
||||
onClick,
|
||||
}: NodeHealthProps) => {
|
||||
return (
|
||||
export const NodeHealth = () => {
|
||||
const { VEGA_URL } = useEnvironment();
|
||||
const setNodeSwitcher = useGlobalStore(
|
||||
(store) => (open: boolean) => store.update({ nodeSwitcherDialog: open })
|
||||
);
|
||||
const { datanodeBlockHeight, text, intent } = useNodeHealth();
|
||||
const onClick = useCallback(() => {
|
||||
setNodeSwitcher(true);
|
||||
}, [setNodeSwitcher]);
|
||||
return VEGA_URL ? (
|
||||
<FooterButton onClick={onClick} data-testid="node-health">
|
||||
<FooterButtonPart>
|
||||
<HealthIndicator blockDiff={blockDiff} />
|
||||
<HealthIndicator text={text} intent={intent} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<NodeUrl url={url} />
|
||||
<NodeUrl url={VEGA_URL} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<span title={t('Block height')}>{blockHeight}</span>
|
||||
<span title={t('Block height')}>{datanodeBlockHeight}</span>
|
||||
</FooterButtonPart>
|
||||
</FooterButton>
|
||||
);
|
||||
) : null;
|
||||
};
|
||||
|
||||
interface NodeUrlProps {
|
||||
@@ -69,31 +54,11 @@ export const NodeUrl = ({ url }: NodeUrlProps) => {
|
||||
};
|
||||
|
||||
interface HealthIndicatorProps {
|
||||
blockDiff: number | null;
|
||||
text: string;
|
||||
intent: Intent;
|
||||
}
|
||||
|
||||
// How many blocks behind the most advanced block that is
|
||||
// deemed acceptable for "Good" status
|
||||
const BLOCK_THRESHOLD = 3;
|
||||
|
||||
export const HealthIndicator = ({ blockDiff }: HealthIndicatorProps) => {
|
||||
const online = useNavigatorOnline();
|
||||
|
||||
let intent = Intent.Success;
|
||||
let text = 'Operational';
|
||||
|
||||
if (!online) {
|
||||
text = t('Offline');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff === null) {
|
||||
// Block height query failed and null was returned
|
||||
text = t('Non operational');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff >= BLOCK_THRESHOLD) {
|
||||
text = t(`${blockDiff} Blocks behind`);
|
||||
intent = Intent.Warning;
|
||||
}
|
||||
|
||||
export const HealthIndicator = ({ text, intent }: HealthIndicatorProps) => {
|
||||
return (
|
||||
<span title={t('Node health')}>
|
||||
<Indicator variant={intent} />
|
||||
|
||||
@@ -15,51 +15,29 @@ jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||
}));
|
||||
|
||||
describe('AccountManager', () => {
|
||||
beforeEach(() => {
|
||||
mockedUseDataProvider
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
})
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [
|
||||
{ asset: { id: 'a1' }, party: { id: 't1' } },
|
||||
{ asset: { id: 'a2' }, party: { id: 't2' } },
|
||||
],
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
it('change partyId should reload data provider', async () => {
|
||||
const { rerender } = render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[0][0].variables.partyId
|
||||
).toEqual('partyOne');
|
||||
await act(() => {
|
||||
rerender(
|
||||
<AccountManager
|
||||
partyId="partyTwo"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
describe('when rerender', () => {
|
||||
beforeEach(() => {
|
||||
mockedUseDataProvider
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
})
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [
|
||||
{ asset: { id: 'a1' }, party: { id: 't1' } },
|
||||
{ asset: { id: 'a2' }, party: { id: 't2' } },
|
||||
],
|
||||
};
|
||||
});
|
||||
});
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[1][0].variables.partyId
|
||||
).toEqual('partyTwo');
|
||||
});
|
||||
|
||||
it('update method should return proper result', async () => {
|
||||
let rerenderer: (ui: React.ReactElement) => void;
|
||||
await act(() => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('change partyId should reload data provider', async () => {
|
||||
const { rerender } = render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
@@ -67,13 +45,67 @@ describe('AccountManager', () => {
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
rerenderer = rerender;
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[0][0].variables
|
||||
.partyId
|
||||
).toEqual('partyOne');
|
||||
await act(() => {
|
||||
rerender(
|
||||
<AccountManager
|
||||
partyId="partyTwo"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[1][0].variables
|
||||
.partyId
|
||||
).toEqual('partyTwo');
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No accounts')).toBeInTheDocument();
|
||||
|
||||
it('update method should return proper result', async () => {
|
||||
let rerenderer: (ui: React.ReactElement) => void;
|
||||
await act(() => {
|
||||
const { rerender } = render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
rerenderer = rerender;
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No accounts')).toBeInTheDocument();
|
||||
});
|
||||
await act(() => {
|
||||
rerenderer(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
await waitFor(() => {
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('splash loading should be displayed', async () => {
|
||||
mockedUseDataProvider.mockImplementation((args) => {
|
||||
return {
|
||||
loading: true,
|
||||
data: null,
|
||||
};
|
||||
});
|
||||
await act(() => {
|
||||
rerenderer(
|
||||
render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
@@ -81,11 +113,15 @@ describe('AccountManager', () => {
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
await waitFor(() => {
|
||||
expect(container).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
(content, element) =>
|
||||
Boolean(
|
||||
element?.className.endsWith('flex items-center justify-center')
|
||||
) && content.startsWith('Loading')
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,7 +60,8 @@ export const AccountManager = ({
|
||||
onClickDeposit={onClickDeposit}
|
||||
onClickWithdraw={onClickWithdraw}
|
||||
isReadOnly={isReadOnly}
|
||||
noRowsOverlayComponent={() => null}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
pinnedAsset={pinnedAsset}
|
||||
getRowHeight={getRowHeight}
|
||||
{...bottomPlaceholderProps}
|
||||
|
||||
@@ -59,13 +59,19 @@ export function createClient({
|
||||
const timestamp = r?.headers.get('x-block-timestamp');
|
||||
if (blockHeight && timestamp) {
|
||||
const state = useHeaderStore.getState();
|
||||
useHeaderStore.setState({
|
||||
...state,
|
||||
[r.url]: {
|
||||
blockHeight: Number(blockHeight),
|
||||
timestamp: new Date(Number(timestamp.slice(0, -6))),
|
||||
},
|
||||
});
|
||||
const urlState = state[r.url];
|
||||
if (
|
||||
!urlState?.blockHeight ||
|
||||
urlState.blockHeight !== blockHeight
|
||||
) {
|
||||
useHeaderStore.setState({
|
||||
...state,
|
||||
[r.url]: {
|
||||
blockHeight: Number(blockHeight),
|
||||
timestamp: new Date(Number(timestamp.slice(0, -6))),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
return response;
|
||||
});
|
||||
|
||||
@@ -46,7 +46,10 @@ addVegaWalletSubmitProposal();
|
||||
addVegaWalletSubmitLiquidityProvision();
|
||||
addImportNodeWallets();
|
||||
|
||||
export { mockConnectWallet } from './lib/commands/vega-wallet-connect';
|
||||
export {
|
||||
mockConnectWallet,
|
||||
mockConnectWalletWithUserError,
|
||||
} from './lib/commands/vega-wallet-connect';
|
||||
export type { onMessage } from './lib/mock-ws';
|
||||
export { aliasGQLQuery } from './lib/mock-gql';
|
||||
export { aliasWalletQuery } from './lib/mock-rest';
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { aliasWalletConnectQuery } from '../mock-rest';
|
||||
import {
|
||||
aliasWalletConnectQuery,
|
||||
aliasWalletConnectWithUserError,
|
||||
} from '../mock-rest';
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
@@ -20,6 +23,12 @@ export const mockConnectWallet = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const mockConnectWalletWithUserError = () => {
|
||||
cy.mockWallet((req) => {
|
||||
aliasWalletConnectWithUserError(req, Cypress.env('VEGA_WALLET_API_TOKEN'));
|
||||
});
|
||||
};
|
||||
|
||||
export function addVegaWalletConnect() {
|
||||
Cypress.Commands.add('connectVegaWallet', (isMobile) => {
|
||||
mockConnectWallet();
|
||||
|
||||
@@ -63,3 +63,24 @@ export const aliasWalletConnectQuery = (
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const aliasWalletConnectWithUserError = (
|
||||
req: CyHttpMessages.IncomingHttpRequest,
|
||||
token: string
|
||||
) => {
|
||||
if (hasMethod(req, 'client.connect_wallet')) {
|
||||
req.alias = 'client.connect_wallet';
|
||||
req.reply({
|
||||
statusCode: 400,
|
||||
body: {
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: 3001,
|
||||
data: 'the user rejected the wallet connection',
|
||||
message: 'User error',
|
||||
},
|
||||
id: '0',
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { MockedProvider } from '@apollo/react-testing';
|
||||
import type { StatisticsQuery } from '../utils/__generated__/Node';
|
||||
import { StatisticsDocument } from '../utils/__generated__/Node';
|
||||
import { useHeaderStore } from '@vegaprotocol/apollo-client';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
const vegaUrl = 'https://foo.bar.com';
|
||||
|
||||
@@ -55,9 +56,24 @@ function setup(
|
||||
|
||||
describe('useNodeHealth', () => {
|
||||
it.each([
|
||||
{ core: 1, node: 1, expected: 0 },
|
||||
{ core: 1, node: 5, expected: -4 },
|
||||
{ core: 10, node: 5, expected: 5 },
|
||||
{
|
||||
core: 1,
|
||||
node: 1,
|
||||
expectedText: 'Operational',
|
||||
expectedIntent: Intent.Success,
|
||||
},
|
||||
{
|
||||
core: 1,
|
||||
node: 5,
|
||||
expectedText: 'Operational',
|
||||
expectedIntent: Intent.Success,
|
||||
},
|
||||
{
|
||||
core: 10,
|
||||
node: 5,
|
||||
expectedText: '5 Blocks behind',
|
||||
expectedIntent: Intent.Warning,
|
||||
},
|
||||
])(
|
||||
'provides difference core block $core and node block $node',
|
||||
async (cases) => {
|
||||
@@ -65,12 +81,12 @@ describe('useNodeHealth', () => {
|
||||
blockHeight: cases.node,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(cases.node);
|
||||
await waitFor(() => {
|
||||
expect(result.current.blockDiff).toEqual(cases.expected);
|
||||
expect(result.current.coreBlockHeight).toEqual(cases.core);
|
||||
expect(result.current.text).toEqual(cases.expectedText);
|
||||
expect(result.current.intent).toEqual(cases.expectedIntent);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(cases.node);
|
||||
});
|
||||
}
|
||||
@@ -90,25 +106,64 @@ describe('useNodeHealth', () => {
|
||||
blockHeight: 1,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(1);
|
||||
await waitFor(() => {
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 0 if no headers are found (waits until stats query resolves)', async () => {
|
||||
const { result } = setup(createStatsMock(1), undefined);
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(undefined);
|
||||
await waitFor(() => {
|
||||
expect(result.current.blockDiff).toEqual(0);
|
||||
expect(result.current.coreBlockHeight).toEqual(1);
|
||||
expect(result.current.text).toEqual('Operational');
|
||||
expect(result.current.intent).toEqual(Intent.Success);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it('Warning latency', async () => {
|
||||
const now = 1678800900087;
|
||||
const headerTimestamp = now - 4000;
|
||||
const dateNow = new Date(now);
|
||||
const dateHeaderTimestamp = new Date(headerTimestamp);
|
||||
jest.useFakeTimers().setSystemTime(dateNow);
|
||||
|
||||
const { result } = setup(createStatsMock(2), {
|
||||
blockHeight: 2,
|
||||
timestamp: dateHeaderTimestamp,
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(result.current.text).toEqual('Warning delay ( >3 sec): 4.05 sec');
|
||||
expect(result.current.intent).toEqual(Intent.Warning);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('Erroneous latency', async () => {
|
||||
const now = 1678800900087;
|
||||
const headerTimestamp = now - 11000;
|
||||
const dateNow = new Date(now);
|
||||
const dateHeaderTimestamp = new Date(headerTimestamp);
|
||||
jest.useFakeTimers().setSystemTime(dateNow);
|
||||
|
||||
const { result } = setup(createStatsMock(2), {
|
||||
blockHeight: 2,
|
||||
timestamp: dateHeaderTimestamp,
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(result.current.text).toEqual(
|
||||
'Erroneous latency ( >10 sec): 11.05 sec'
|
||||
);
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(2);
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,30 +2,35 @@ import { useEffect, useMemo } from 'react';
|
||||
import { useStatisticsQuery } from '../utils/__generated__/Node';
|
||||
import { useHeaderStore } from '@vegaprotocol/apollo-client';
|
||||
import { useEnvironment } from './use-environment';
|
||||
import { fromNanoSeconds } from '@vegaprotocol/utils';
|
||||
import { useNavigatorOnline } from '@vegaprotocol/react-helpers';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
|
||||
const POLL_INTERVAL = 1000;
|
||||
const BLOCK_THRESHOLD = 3;
|
||||
const ERROR_LATENCY = 10000;
|
||||
const WARNING_LATENCY = 3000;
|
||||
|
||||
export const useNodeHealth = () => {
|
||||
const online = useNavigatorOnline();
|
||||
const url = useEnvironment((store) => store.VEGA_URL);
|
||||
const headerStore = useHeaderStore();
|
||||
const headers = url ? headerStore[url] : undefined;
|
||||
const { data, error, loading, startPolling, stopPolling } =
|
||||
useStatisticsQuery({
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
const { data, error, startPolling, stopPolling } = useStatisticsQuery({
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
|
||||
const blockDiff = useMemo(() => {
|
||||
if (!data?.statistics.blockHeight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!headers) {
|
||||
if (!headers?.blockHeight) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Number(data.statistics.blockHeight) - headers.blockHeight;
|
||||
}, [data, headers]);
|
||||
}, [data?.statistics.blockHeight, headers?.blockHeight]);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
@@ -38,17 +43,43 @@ export const useNodeHealth = () => {
|
||||
}
|
||||
}, [error, startPolling, stopPolling]);
|
||||
|
||||
const blockUpdateMsLatency = headers?.timestamp
|
||||
? Date.now() - headers.timestamp.getTime()
|
||||
: 0;
|
||||
|
||||
const [text, intent] = useMemo(() => {
|
||||
let intent = Intent.Success;
|
||||
let text = 'Operational';
|
||||
|
||||
if (!online) {
|
||||
text = t('Offline');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff === null) {
|
||||
// Block height query failed and null was returned
|
||||
text = t('Non operational');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockUpdateMsLatency > ERROR_LATENCY) {
|
||||
text = t('Erroneous latency ( >%s sec): %s sec', [
|
||||
(ERROR_LATENCY / 1000).toString(),
|
||||
(blockUpdateMsLatency / 1000).toFixed(2),
|
||||
]);
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff >= BLOCK_THRESHOLD) {
|
||||
text = t(`%s Blocks behind`, String(blockDiff));
|
||||
intent = Intent.Warning;
|
||||
} else if (blockUpdateMsLatency > WARNING_LATENCY) {
|
||||
text = t('Warning delay ( >%s sec): %s sec', [
|
||||
(WARNING_LATENCY / 1000).toString(),
|
||||
(blockUpdateMsLatency / 1000).toFixed(2),
|
||||
]);
|
||||
intent = Intent.Warning;
|
||||
}
|
||||
return [text, intent];
|
||||
}, [online, blockDiff, blockUpdateMsLatency]);
|
||||
|
||||
return {
|
||||
error,
|
||||
loading,
|
||||
coreBlockHeight: data?.statistics
|
||||
? Number(data.statistics.blockHeight)
|
||||
: undefined,
|
||||
coreVegaTime: data?.statistics
|
||||
? fromNanoSeconds(data?.statistics.vegaTime)
|
||||
: undefined,
|
||||
datanodeBlockHeight: headers?.blockHeight,
|
||||
datanodeVegaTime: headers?.timestamp,
|
||||
blockDiff,
|
||||
text,
|
||||
intent,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import type { Position } from '../';
|
||||
import { usePositionsData, PositionsTable } from '../';
|
||||
import type { FilterChangedEvent } from 'ag-grid-community';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
|
||||
@@ -22,6 +23,7 @@ export const PositionsManager = ({
|
||||
noBottomPlaceholder,
|
||||
}: PositionsManagerProps) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const [dataCount, setDataCount] = useState(0);
|
||||
const { data, error, loading, reload } = usePositionsData(
|
||||
partyId,
|
||||
gridRef,
|
||||
@@ -67,7 +69,12 @@ export const PositionsManager = ({
|
||||
gridRef,
|
||||
setId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||
}, [data]);
|
||||
const onFilterChanged = useCallback((event: FilterChangedEvent) => {
|
||||
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||
}, []);
|
||||
return (
|
||||
<div className="h-full relative">
|
||||
<PositionsTable
|
||||
@@ -75,8 +82,10 @@ export const PositionsManager = ({
|
||||
ref={gridRef}
|
||||
onMarketClick={onMarketClick}
|
||||
onClose={onClose}
|
||||
noRowsOverlayComponent={() => null}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
isReadOnly={isReadOnly}
|
||||
onFilterChanged={onFilterChanged}
|
||||
{...(noBottomPlaceholder ? null : bottomPlaceholderProps)}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
@@ -85,7 +94,7 @@ export const PositionsManager = ({
|
||||
error={error}
|
||||
data={data}
|
||||
noDataMessage={t('No positions')}
|
||||
noDataCondition={(data) => !(data && data.length)}
|
||||
noDataCondition={(data) => !dataCount}
|
||||
reload={reload}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user