From b89ee364481c22bab309b32cfc946e0da2bd5976 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 22 May 2023 09:02:54 -0700 Subject: [PATCH] test(e2e): attempt to de-flake (#6611) * test(e2e): improve memory mgmt * test(e2e): record flakes * test(e2e): simplify tests in attempt to de-flake * test(e2e): more simplification * test(e2e): disable transaction popup checks * test(e2e): better wrap assertions * test(e2e): always assert both inputs --- cypress.config.ts | 14 +- .../mini-portfolio/activity-history.test.ts | 22 +-- cypress/e2e/swap/errors.test.ts | 173 ++++++++++-------- cypress/e2e/swap/settings.test.ts | 14 ++ cypress/e2e/swap/swap.test.ts | 159 ++++------------ cypress/e2e/swap/wrap.test.ts | 56 +++--- cypress/utils/index.ts | 10 + 7 files changed, 203 insertions(+), 245 deletions(-) create mode 100644 cypress/e2e/swap/settings.test.ts diff --git a/cypress.config.ts b/cypress.config.ts index a4eb31a854..c585f847d3 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,17 +1,29 @@ import codeCoverageTask from '@cypress/code-coverage/task' import { defineConfig } from 'cypress' import { setupHardhatEvents } from 'cypress-hardhat' +import { unlinkSync } from 'fs' export default defineConfig({ projectId: 'yp82ef', - videoUploadOnPasses: false, defaultCommandTimeout: 24000, // 2x average block time chromeWebSecurity: false, + experimentalMemoryManagement: true, // better memory management, see https://github.com/cypress-io/cypress/pull/25462 retries: { runMode: 2 }, e2e: { async setupNodeEvents(on, config) { await setupHardhatEvents(on, config) codeCoverageTask(on, config) + + // Delete recorded videos for specs that passed without flakes. + on('after:spec', async (spec, results) => { + if (results && results.video) { + // If there were no failures (including flakes), delete the recorded video. + if (!results.tests?.some((test) => test.attempts.some((attempt) => attempt?.state === 'failed'))) { + unlinkSync(results.video) + } + } + }) + return { ...config, // Only enable Chrome. diff --git a/cypress/e2e/mini-portfolio/activity-history.test.ts b/cypress/e2e/mini-portfolio/activity-history.test.ts index f7cdb1b57e..62a4e7c8b6 100644 --- a/cypress/e2e/mini-portfolio/activity-history.test.ts +++ b/cypress/e2e/mini-portfolio/activity-history.test.ts @@ -1,3 +1,4 @@ +import { USDC_MAINNET } from '../../../src/constants/tokens' import { getTestSelector } from '../../utils' describe('mini-portfolio activity history', () => { @@ -93,24 +94,15 @@ describe('mini-portfolio activity history', () => { }) it('should deduplicate activity history by nonce', () => { - cy.visit('/swap', { ethereum: 'hardhat' }).hardhat({ automine: false }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }).hardhat({ + automine: false, + }) // Input swap info. - cy.get('#swap-currency-input .token-amount-input').clear().type('1') - cy.get('#swap-currency-output .open-currency-select-button').click() - cy.contains('USDC').click() - cy.get('#swap-currency-output .token-amount-input').should('not.equal', '') + cy.get('#swap-currency-input .token-amount-input').clear().type('1').should('have.value', '1') + cy.get('#swap-currency-output .token-amount-input').should('not.have.value', '') - // Set slippage to a high value. - cy.get(getTestSelector('open-settings-dialog-button')).click() - cy.get(getTestSelector('max-slippage-settings')).click() - cy.get(getTestSelector('slippage-input')).clear().type('5') - cy.get('body').click('topRight') - cy.get(getTestSelector('slippage-input')).should('not.exist') - - // Click swap button. - cy.contains('1 USDC = ').should('exist') - cy.get('#swap-button').should('not.be', 'disabled').click() + cy.get('#swap-button').click() cy.get('#confirm-swap-or-send').click() cy.get(getTestSelector('dismiss-tx-confirmation')).click() diff --git a/cypress/e2e/swap/errors.test.ts b/cypress/e2e/swap/errors.test.ts index 27389925ad..0f1ab41044 100644 --- a/cypress/e2e/swap/errors.test.ts +++ b/cypress/e2e/swap/errors.test.ts @@ -1,89 +1,114 @@ import { BigNumber } from '@ethersproject/bignumber' -import { parseEther } from '@ethersproject/units' +import { SupportedChainId } from '@uniswap/sdk-core' -import { USDC_MAINNET } from '../../../src/constants/tokens' -import { getTestSelector } from '../../utils' +import { UNI, USDC_MAINNET } from '../../../src/constants/tokens' +import { getBalance, getTestSelector } from '../../utils' -describe('Swap', () => { - it('should render and dismiss the wallet rejection modal', () => { - cy.visit('/swap', { ethereum: 'hardhat' }) - .hardhat() - .then((hardhat) => { - cy.stub(hardhat.wallet, 'sendTransaction').log(false).rejects(new Error('user cancelled')) +const UNI_MAINNET = UNI[SupportedChainId.MAINNET] - cy.get('#swap-currency-output .open-currency-select-button').click() - cy.get(getTestSelector('token-search-input')).clear().type(USDC_MAINNET.address) - cy.contains('USDC').click() - cy.get('#swap-currency-output .token-amount-input').clear().type('1') - cy.get('#swap-currency-input .token-amount-input').should('not.equal', '') - cy.get('#swap-button').click() - cy.get('#confirm-swap-or-send').click() - cy.contains('Transaction rejected').should('exist') - cy.contains('Dismiss').click() - cy.contains('Transaction rejected').should('not.exist') - }) +describe('Swap errors', () => { + it('wallet rejection', () => { + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.hardhat().then((hardhat) => { + // Stub the wallet to reject any transaction. + cy.stub(hardhat.wallet, 'sendTransaction').log(false).rejects(new Error('user cancelled')) + + // Attempt to swap. + cy.get('#swap-currency-output .token-amount-input').clear().type('1').should('have.value', '1') + cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '') + cy.get('#swap-button').click() + cy.get('#confirm-swap-or-send').click() + + cy.contains('Transaction rejected').should('exist') + cy.contains('Dismiss').click() + cy.contains('Transaction rejected').should('not.exist') + }) }) - it.skip('should render an error for slippage failure', () => { - cy.visit('/swap', { ethereum: 'hardhat' }) - .hardhat({ automine: false }) - .then((hardhat) => { - cy.then(() => hardhat.provider.getBalance(hardhat.wallet.address)).then((initialBalance) => { - // Gas estimation fails for this transaction (that would normally fail), so we stub it. - const send = cy.stub(hardhat.provider, 'send').log(false) - send.withArgs('eth_estimateGas').resolves(BigNumber.from(2_000_000)) - send.callThrough() + it('transaction past deadline', () => { + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.hardhat({ automine: false }) + getBalance(USDC_MAINNET).then((initialBalance) => { + // Set deadline to minimum. (1 minute) + cy.get(getTestSelector('open-settings-dialog-button')).click() + cy.get(getTestSelector('transaction-deadline-settings')).click() + cy.get(getTestSelector('deadline-input')).clear().type('1') // 1 minute - // Set slippage to a very low value. - cy.get(getTestSelector('open-settings-dialog-button')).click() - cy.get(getTestSelector('max-slippage-settings')).click() - cy.get(getTestSelector('slippage-input')).clear().type('0.01') - cy.get('body').click('topRight') - cy.get(getTestSelector('slippage-input')).should('not.exist') + // Click outside of modal to dismiss it. + cy.get('body').click('topRight') + cy.get(getTestSelector('deadline-input')).should('not.exist') - // Open the currency select modal. - cy.get('#swap-currency-output .open-currency-select-button').click() + // Attempt to swap. + cy.get('#swap-currency-output .token-amount-input').clear().type('1').should('have.value', '1') + cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '') + cy.get('#swap-button').click() + cy.get('#confirm-swap-or-send').click() + cy.get(getTestSelector('dismiss-tx-confirmation')).click() - // Select UNI as output token - cy.get(getTestSelector('token-search-input')).clear().type('Uniswap') - cy.get(getTestSelector('currency-list-wrapper')) - .contains(/^Uniswap$/) - .first() - // Our scrolling library (react-window) seems to freeze when acted on by cypress, with this element set to - // `pointer-events: none`. This can be ignored using `{force: true}`. - .click({ force: true }) + // The pending transaction indicator should reflect the state. + cy.get(getTestSelector('web3-status-connected')).should('contain', '1 Pending') + cy.hardhat().then((hardhat) => hardhat.mine(1, /* 10 minutes */ 1000 * 60 * 10)) // mines past the deadline + cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending') - // Swap 2 times. - const AMOUNT_TO_SWAP = 400 - const NUMBER_OF_SWAPS = 2 - const INDIVIDUAL_SWAP_INPUT = AMOUNT_TO_SWAP / NUMBER_OF_SWAPS - cy.get('#swap-currency-input .token-amount-input').clear().type(INDIVIDUAL_SWAP_INPUT.toString()) - cy.get('#swap-currency-output .token-amount-input').should('not.equal', '') - cy.get('#swap-button').click() - cy.get('#confirm-swap-or-send').click() - cy.get(getTestSelector('dismiss-tx-confirmation')).click() - cy.get('#swap-currency-input .token-amount-input').clear().type(INDIVIDUAL_SWAP_INPUT.toString()) - cy.get('#swap-currency-output .token-amount-input').should('not.equal', '') - cy.get('#swap-button').click() - cy.get('#confirm-swap-or-send').click() - cy.get(getTestSelector('dismiss-tx-confirmation')).click() + // TODO(WEB-2085): Fix this test - transaction popups are flakey. + // cy.get(getTestSelector('transaction-popup')).contains('Swap failed') - // The pending transaction indicator should be visible. - cy.contains('Pending').should('exist') + // Verify the balance is unchanged. + cy.get('#swap-currency-output [data-testid="balance-text"]').should('have.text', `Balance: ${initialBalance}`) + getBalance(USDC_MAINNET).should('eq', initialBalance) + }) + }) - cy.then(() => hardhat.mine()).then(() => { - // The pending transaction indicator should not be visible. - cy.contains('Pending').should('not.exist') - - // Check for a failed transaction notification. - cy.contains('Swap failed').should('exist') - - // Assert that at least one of the swaps failed due to slippage. - cy.then(() => hardhat.provider.getBalance(hardhat.wallet.address)).then((finalBalance) => { - expect(finalBalance.gt(initialBalance.sub(parseEther(AMOUNT_TO_SWAP.toString())))).to.be.true - }) - }) - }) + it('slippage failure', () => { + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${UNI_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.hardhat({ automine: false }) + getBalance(USDC_MAINNET).then((initialBalance) => { + // Gas estimation fails for this transaction (that would normally fail), so we stub it. + cy.hardhat().then((hardhat) => { + const send = cy.stub(hardhat.provider, 'send').log(false) + send.withArgs('eth_estimateGas').resolves(BigNumber.from(2_000_000)) + send.callThrough() }) + + // Set slippage to a very low value. + cy.get(getTestSelector('open-settings-dialog-button')).click() + cy.get(getTestSelector('max-slippage-settings')).click() + cy.get(getTestSelector('slippage-input')).clear().type('0.01') + + // Click outside of modal to dismiss it. + cy.get('body').click('topRight') + cy.get(getTestSelector('slippage-input')).should('not.exist') + + // Swap 2 times. + const AMOUNT_TO_SWAP = 200 + cy.get('#swap-currency-input .token-amount-input') + .clear() + .type(AMOUNT_TO_SWAP.toString()) + .should('have.value', AMOUNT_TO_SWAP.toString()) + cy.get('#swap-currency-output .token-amount-input').should('not.have.value', '') + cy.get('#swap-button').click() + cy.get('#confirm-swap-or-send').click() + cy.get(getTestSelector('dismiss-tx-confirmation')).click() + + cy.get('#swap-currency-input .token-amount-input') + .clear() + .type(AMOUNT_TO_SWAP.toString()) + .should('have.value', AMOUNT_TO_SWAP.toString()) + cy.get('#swap-currency-output .token-amount-input').should('not.have.value', '') + cy.get('#swap-button').click() + cy.get('#confirm-swap-or-send').click() + cy.get(getTestSelector('dismiss-tx-confirmation')).click() + + // The pending transaction indicator should reflect the state. + cy.get(getTestSelector('web3-status-connected')).should('contain', '2 Pending') + cy.hardhat().then((hardhat) => hardhat.mine()) + cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending') + + // TODO(WEB-2085): Fix this test - transaction popups are flakey. + // cy.get(getTestSelector('transaction-popup')).contains('Swap failed') + + // Assert that the transactions were unsuccessful by checking on-chain balance. + getBalance(UNI_MAINNET).should('equal', initialBalance) + }) }) }) diff --git a/cypress/e2e/swap/settings.test.ts b/cypress/e2e/swap/settings.test.ts new file mode 100644 index 0000000000..01285ed0de --- /dev/null +++ b/cypress/e2e/swap/settings.test.ts @@ -0,0 +1,14 @@ +import { getTestSelector } from '../../utils' + +describe('Swap settings', () => { + it('Opens and closes the settings menu', () => { + cy.visit('/swap') + cy.contains('Settings').should('not.exist') + cy.get(getTestSelector('open-settings-dialog-button')).click() + cy.contains('Max slippage').should('exist') + cy.contains('Transaction deadline').should('exist') + cy.contains('Auto Router API').should('exist') + cy.get(getTestSelector('open-settings-dialog-button')).click() + cy.contains('Settings').should('not.exist') + }) +}) diff --git a/cypress/e2e/swap/swap.test.ts b/cypress/e2e/swap/swap.test.ts index 7719011ff2..5c5c8ac7ab 100644 --- a/cypress/e2e/swap/swap.test.ts +++ b/cypress/e2e/swap/swap.test.ts @@ -1,162 +1,69 @@ import { SupportedChainId } from '@uniswap/sdk-core' import { UNI, USDC_MAINNET } from '../../../src/constants/tokens' -import { getTestSelector } from '../../utils' +import { getBalance, getTestSelector } from '../../utils' const UNI_MAINNET = UNI[SupportedChainId.MAINNET] describe('Swap', () => { describe('Swap on main page', () => { - beforeEach(() => { - cy.visit('/swap', { ethereum: 'hardhat' }) - }) - it('starts with ETH selected by default', () => { + cy.visit('/swap') cy.get(`#swap-currency-input .token-amount-input`).should('have.value', '') cy.get(`#swap-currency-input .token-symbol-container`).should('contain.text', 'ETH') cy.get(`#swap-currency-output .token-amount-input`).should('not.have.value') cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'Select token') }) - it('can enter an amount into input', () => { - cy.get('#swap-currency-input .token-amount-input').clear().type('0.001').should('have.value', '0.001') - }) - - it('zero swap amount', () => { - cy.get('#swap-currency-input .token-amount-input').clear().type('0.0').should('have.value', '0.0') - }) - - it('invalid swap amount', () => { - cy.get('#swap-currency-input .token-amount-input').clear().type('\\').should('have.value', '') - }) - - it('can enter an amount into output', () => { - cy.get('#swap-currency-output .token-amount-input').clear().type('0.001').should('have.value', '0.001') - }) - - it('zero output amount', () => { - cy.get('#swap-currency-output .token-amount-input').clear().type('0.0').should('have.value', '0.0') - }) - - it('should render an error when a transaction fails due to a passed deadline', () => { - const DEADLINE_MINUTES = 1 - const TEN_MINUTES_MS = 1000 * 60 * DEADLINE_MINUTES * 10 - cy.hardhat({ automine: false }).then((hardhat) => { - cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET)) - .then((balance) => Number(balance.toFixed(1))) - .then((initialBalance) => { - // Input swap info. - cy.get('#swap-currency-output .open-currency-select-button').click() - cy.contains('USDC').click() - cy.get('#swap-currency-output .token-amount-input').clear().type('1') - cy.get('#swap-currency-input .token-amount-input').should('not.equal', '') - - // Set deadline to minimum. (1 minute) - cy.get(getTestSelector('open-settings-dialog-button')).click() - cy.get(getTestSelector('transaction-deadline-settings')).click() - cy.get(getTestSelector('deadline-input')).clear().type(DEADLINE_MINUTES.toString()) - cy.get('body').click('topRight') - cy.get(getTestSelector('deadline-input')).should('not.exist') - - cy.get('#swap-button').click() - cy.get('#confirm-swap-or-send').click() - - // Dismiss the modal that appears when a transaction is broadcast to the network. - cy.get(getTestSelector('dismiss-tx-confirmation')).click() - - // The UI should show the transaction as pending. - cy.contains('1 Pending').should('exist') - - // Mine a block past the deadline. - cy.then(() => hardhat.mine(1, TEN_MINUTES_MS)).then(() => { - // The UI should no longer show the transaction as pending. - cy.contains('1 Pending').should('not.exist') - - // Check that the user is informed of the failure - cy.contains('Swap failed').should('exist') - - // Check that the balance is unchanged in the UI - cy.get('#swap-currency-output [data-testid="balance-text"]').should( - 'have.text', - `Balance: ${initialBalance}` - ) - - // Check that the balance is unchanged on chain - cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET)) - .then((balance) => Number(balance.toFixed(1))) - .should('eq', initialBalance) - }) - }) - }) - }) - it('should default inputs from URL params ', () => { - cy.visit(`/swap?inputCurrency=${UNI_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?inputCurrency=${UNI_MAINNET.address}`) cy.get(`#swap-currency-input .token-symbol-container`).should('contain.text', 'UNI') cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'Select token') - cy.visit(`/swap?outputCurrency=${UNI_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?outputCurrency=${UNI_MAINNET.address}`) cy.get(`#swap-currency-input .token-symbol-container`).should('contain.text', 'Select token') cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'UNI') - cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${UNI_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${UNI_MAINNET.address}`) cy.get(`#swap-currency-input .token-symbol-container`).should('contain.text', 'ETH') cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'UNI') }) - it('ETH to wETH is same value (wrapped swaps have no price impact)', () => { - cy.get(`#swap-currency-output .open-currency-select-button`).click() - cy.contains('WETH').click() - cy.get('#swap-currency-input .token-amount-input').clear().type('0.01') - cy.get('#swap-currency-output .token-amount-input').should('have.value', '0.01') - }) - - it('Opens and closes the settings menu', () => { - cy.contains('Settings').should('not.exist') - cy.get(getTestSelector('open-settings-dialog-button')).click() - cy.contains('Max slippage').should('exist') - cy.contains('Transaction deadline').should('exist') - cy.contains('Auto Router API').should('exist') - cy.get(getTestSelector('open-settings-dialog-button')).click() - cy.contains('Settings').should('not.exist') - }) - it('inputs reset when navigating between pages', () => { - cy.get('#swap-currency-input .token-amount-input').clear().type('0.01') - cy.get('#swap-currency-output .token-amount-input').should('not.equal', '') - cy.visit('/pool') cy.visit('/swap') cy.get('#swap-currency-input .token-amount-input').should('have.value', '') - cy.get('#swap-currency-output .token-amount-input').should('not.equal', '') + cy.get('#swap-currency-input .token-amount-input').type('0.01').should('have.value', '0.01') + cy.visit('/pool').visit('/swap') + cy.get('#swap-currency-input .token-amount-input').should('have.value', '') }) - it('can swap ETH for USDC', () => { - const TOKEN_ADDRESS = USDC_MAINNET.address - const BALANCE_INCREMENT = 1 - cy.hardhat().then((hardhat) => { - cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET)) - .then((balance) => Number(balance.toFixed(1))) - .then((initialBalance) => { - cy.get('#swap-currency-output .open-currency-select-button').click() - cy.get(getTestSelector('token-search-input')).clear().type(TOKEN_ADDRESS) - cy.contains('USDC').click() - cy.get('#swap-currency-output .token-amount-input').clear().type(BALANCE_INCREMENT.toString()) - cy.get('#swap-currency-input .token-amount-input').should('not.equal', '') - cy.get('#swap-button').click() - cy.get('#confirm-swap-or-send').click() - cy.get(getTestSelector('dismiss-tx-confirmation')).click() + it('swaps ETH for USDC', () => { + cy.visit('/swap', { ethereum: 'hardhat' }) + cy.hardhat({ automine: false }) + getBalance(USDC_MAINNET).then((initialBalance) => { + cy.get('#swap-currency-output .open-currency-select-button').click() + cy.get(getTestSelector('token-search-input')).clear().type(USDC_MAINNET.address) + cy.contains('USDC').click() + cy.get('#swap-currency-output .token-amount-input').clear().type('1').should('have.value', '1') + cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '') + cy.get('#swap-button').click() + cy.get('#confirm-swap-or-send').click() + cy.get(getTestSelector('dismiss-tx-confirmation')).click() - // ui check - cy.get('#swap-currency-output [data-testid="balance-text"]').should( - 'have.text', - `Balance: ${initialBalance + BALANCE_INCREMENT}` - ) + // The pending transaction indicator should reflect the state. + cy.get(getTestSelector('web3-status-connected')).should('contain', '1 Pending') + cy.hardhat().then((hardhat) => hardhat.mine()) + cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending') - // chain state check - cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET)) - .then((balance) => Number(balance.toFixed(1))) - .should('eq', initialBalance + BALANCE_INCREMENT) - }) + // TODO(WEB-2085): Fix this test - transaction popups are flakey. + // cy.get(getTestSelector('transaction-popup')).contains('Swapped') + + // Verify the balance is updated. + cy.get('#swap-currency-output [data-testid="balance-text"]').should( + 'have.text', + `Balance: ${initialBalance + 1}` + ) + getBalance(USDC_MAINNET).should('eq', initialBalance + 1) }) }) }) diff --git a/cypress/e2e/swap/wrap.test.ts b/cypress/e2e/swap/wrap.test.ts index bc691ac0fd..d7218659d5 100644 --- a/cypress/e2e/swap/wrap.test.ts +++ b/cypress/e2e/swap/wrap.test.ts @@ -1,30 +1,31 @@ import { CurrencyAmount, SupportedChainId, WETH9 } from '@uniswap/sdk-core' -import { getTestSelector } from '../../utils' +import { getBalance, getTestSelector } from '../../utils' const WETH = WETH9[SupportedChainId.MAINNET] -function getWethBalance() { - return cy - .hardhat() - .then((hardhat) => hardhat.getBalance(hardhat.wallet, WETH)) - .then((balance) => Number(balance.toFixed(1))) -} - -describe('Swap', () => { +describe('Swap wrap', () => { beforeEach(() => { - cy.visit('/swap', { ethereum: 'hardhat' }).hardhat({ automine: false }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${WETH.address}`, { ethereum: 'hardhat' }).hardhat({ + automine: false, + }) + }) + + it('ETH to wETH is same value (wrapped swaps have no price impact)', () => { + cy.get('#swap-currency-input .token-amount-input').clear().type('0.01').should('have.value', '0.01') + cy.get('#swap-currency-output .token-amount-input').should('have.value', '0.01') + + cy.get('#swap-currency-output .token-amount-input').clear().type('0.02').should('have.value', '0.02') + cy.get('#swap-currency-input .token-amount-input').should('have.value', '0.02') }) it('should be able to wrap ETH', () => { - getWethBalance().then((initialWethBalance) => { - // Select WETH for the token output. - cy.get('#swap-currency-output').contains('Select token').click() - cy.contains('WETH').click() + getBalance(WETH).then((initialWethBalance) => { cy.contains('Enter ETH amount') // Enter the amount to wrap. - cy.get('#swap-currency-output .token-amount-input').click().type('1') + cy.get('#swap-currency-output .token-amount-input').click().type('1').should('have.value', 1) + // This also ensures we don't click "Wrap" before the UI has caught up. cy.get('#swap-currency-input .token-amount-input').should('have.value', 1) // Click the wrap button. @@ -35,15 +36,15 @@ describe('Swap', () => { cy.hardhat().then((hardhat) => hardhat.mine()) cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending') - // There should be a successful wrap notification. - cy.get(getTestSelector('transaction-popup')).contains('Wrapped') - cy.get(getTestSelector('transaction-popup')).contains('1.00 ETH for 1.00 WETH') + // TODO(WEB-2085): Fix this test - transaction popups are flakey. + // cy.get(getTestSelector('transaction-popup')).contains('Wrapped') + // cy.get(getTestSelector('transaction-popup')).contains('1.00 ETH for 1.00 WETH') // The UI balance should have increased. cy.get('#swap-currency-output').should('contain', `Balance: ${initialWethBalance + 1}`) // The user's WETH account balance should have increased - getWethBalance().should('equal', initialWethBalance + 1) + getBalance(WETH).should('equal', initialWethBalance + 1) }) }) @@ -53,17 +54,14 @@ describe('Swap', () => { await hardhat.mine() }) - getWethBalance().then((initialWethBalance) => { - // Select WETH for the token output. - cy.get('#swap-currency-output').contains('Select token').click() - cy.contains('WETH').click() - + getBalance(WETH).then((initialWethBalance) => { // Swap input/output to unwrap WETH. cy.get(getTestSelector('swap-currency-button')).click() cy.contains('Enter WETH amount') // Enter the amount to unwrap. - cy.get('#swap-currency-output .token-amount-input').click().type('1') + cy.get('#swap-currency-output .token-amount-input').click().type('1').should('have.value', 1) + // This also ensures we don't click "Wrap" before the UI has caught up. cy.get('#swap-currency-input .token-amount-input').should('have.value', 1) // Click the unwrap button. @@ -74,15 +72,15 @@ describe('Swap', () => { cy.hardhat().then((hardhat) => hardhat.mine()) cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending') - // There should be a successful wrap notification. - cy.get(getTestSelector('transaction-popup')).contains('Unwrapped') - cy.get(getTestSelector('transaction-popup')).contains('1.00 WETH for 1.00 ETH') + // TODO(WEB-2085): Fix this test - transaction popups are flakey. + // cy.get(getTestSelector('transaction-popup')).contains('Unwrapped') + // cy.get(getTestSelector('transaction-popup')).contains('1.00 WETH for 1.00 ETH') // The UI balance should have increased. cy.get('#swap-currency-input').should('contain', `Balance: ${initialWethBalance - 1}`) // The user's WETH account balance should have increased - getWethBalance().should('equal', initialWethBalance - 1) + getBalance(WETH).should('equal', initialWethBalance - 1) }) }) }) diff --git a/cypress/utils/index.ts b/cypress/utils/index.ts index cf4e53960f..2c3fc2218b 100644 --- a/cypress/utils/index.ts +++ b/cypress/utils/index.ts @@ -1,3 +1,13 @@ +import { Currency } from '@uniswap/sdk-core' + export const getTestSelector = (selectorId: string) => `[data-testid=${selectorId}]` export const getTestSelectorStartsWith = (selectorId: string) => `[data-testid^=${selectorId}]` + +/** Gets the balance of a token as a Chainable. */ +export function getBalance(token: Currency) { + return cy + .hardhat() + .then((hardhat) => hardhat.getBalance(hardhat.wallet, token)) + .then((balance) => Number(balance.toFixed(1))) +}