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
This commit is contained in:
parent
fbc55db937
commit
b89ee36448
@ -1,17 +1,29 @@
|
|||||||
import codeCoverageTask from '@cypress/code-coverage/task'
|
import codeCoverageTask from '@cypress/code-coverage/task'
|
||||||
import { defineConfig } from 'cypress'
|
import { defineConfig } from 'cypress'
|
||||||
import { setupHardhatEvents } from 'cypress-hardhat'
|
import { setupHardhatEvents } from 'cypress-hardhat'
|
||||||
|
import { unlinkSync } from 'fs'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
projectId: 'yp82ef',
|
projectId: 'yp82ef',
|
||||||
videoUploadOnPasses: false,
|
|
||||||
defaultCommandTimeout: 24000, // 2x average block time
|
defaultCommandTimeout: 24000, // 2x average block time
|
||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
|
experimentalMemoryManagement: true, // better memory management, see https://github.com/cypress-io/cypress/pull/25462
|
||||||
retries: { runMode: 2 },
|
retries: { runMode: 2 },
|
||||||
e2e: {
|
e2e: {
|
||||||
async setupNodeEvents(on, config) {
|
async setupNodeEvents(on, config) {
|
||||||
await setupHardhatEvents(on, config)
|
await setupHardhatEvents(on, config)
|
||||||
codeCoverageTask(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 {
|
return {
|
||||||
...config,
|
...config,
|
||||||
// Only enable Chrome.
|
// Only enable Chrome.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { USDC_MAINNET } from '../../../src/constants/tokens'
|
||||||
import { getTestSelector } from '../../utils'
|
import { getTestSelector } from '../../utils'
|
||||||
|
|
||||||
describe('mini-portfolio activity history', () => {
|
describe('mini-portfolio activity history', () => {
|
||||||
@ -93,24 +94,15 @@ describe('mini-portfolio activity history', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should deduplicate activity history by nonce', () => {
|
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.
|
// Input swap info.
|
||||||
cy.get('#swap-currency-input .token-amount-input').clear().type('1')
|
cy.get('#swap-currency-input .token-amount-input').clear().type('1').should('have.value', '1')
|
||||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
cy.get('#swap-currency-output .token-amount-input').should('not.have.value', '')
|
||||||
cy.contains('USDC').click()
|
|
||||||
cy.get('#swap-currency-output .token-amount-input').should('not.equal', '')
|
|
||||||
|
|
||||||
// Set slippage to a high value.
|
cy.get('#swap-button').click()
|
||||||
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('#confirm-swap-or-send').click()
|
cy.get('#confirm-swap-or-send').click()
|
||||||
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
|
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
|
||||||
|
|
||||||
|
@ -1,89 +1,114 @@
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import { parseEther } from '@ethersproject/units'
|
import { SupportedChainId } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
import { USDC_MAINNET } from '../../../src/constants/tokens'
|
import { UNI, USDC_MAINNET } from '../../../src/constants/tokens'
|
||||||
import { getTestSelector } from '../../utils'
|
import { getBalance, getTestSelector } from '../../utils'
|
||||||
|
|
||||||
describe('Swap', () => {
|
const UNI_MAINNET = UNI[SupportedChainId.MAINNET]
|
||||||
it('should render and dismiss the wallet rejection modal', () => {
|
|
||||||
cy.visit('/swap', { ethereum: 'hardhat' })
|
describe('Swap errors', () => {
|
||||||
.hardhat()
|
it('wallet rejection', () => {
|
||||||
.then((hardhat) => {
|
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'))
|
cy.stub(hardhat.wallet, 'sendTransaction').log(false).rejects(new Error('user cancelled'))
|
||||||
|
|
||||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
// Attempt to swap.
|
||||||
cy.get(getTestSelector('token-search-input')).clear().type(USDC_MAINNET.address)
|
cy.get('#swap-currency-output .token-amount-input').clear().type('1').should('have.value', '1')
|
||||||
cy.contains('USDC').click()
|
cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '')
|
||||||
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('#swap-button').click()
|
||||||
cy.get('#confirm-swap-or-send').click()
|
cy.get('#confirm-swap-or-send').click()
|
||||||
|
|
||||||
cy.contains('Transaction rejected').should('exist')
|
cy.contains('Transaction rejected').should('exist')
|
||||||
cy.contains('Dismiss').click()
|
cy.contains('Dismiss').click()
|
||||||
cy.contains('Transaction rejected').should('not.exist')
|
cy.contains('Transaction rejected').should('not.exist')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('should render an error for slippage failure', () => {
|
it('transaction past deadline', () => {
|
||||||
cy.visit('/swap', { ethereum: 'hardhat' })
|
cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' })
|
||||||
.hardhat({ automine: false })
|
cy.hardhat({ automine: false })
|
||||||
.then((hardhat) => {
|
getBalance(USDC_MAINNET).then((initialBalance) => {
|
||||||
cy.then(() => hardhat.provider.getBalance(hardhat.wallet.address)).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
|
||||||
|
|
||||||
|
// Click outside of modal to dismiss it.
|
||||||
|
cy.get('body').click('topRight')
|
||||||
|
cy.get(getTestSelector('deadline-input')).should('not.exist')
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
// 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')
|
||||||
|
|
||||||
|
// TODO(WEB-2085): Fix this test - transaction popups are flakey.
|
||||||
|
// cy.get(getTestSelector('transaction-popup')).contains('Swap failed')
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
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.
|
// 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)
|
const send = cy.stub(hardhat.provider, 'send').log(false)
|
||||||
send.withArgs('eth_estimateGas').resolves(BigNumber.from(2_000_000))
|
send.withArgs('eth_estimateGas').resolves(BigNumber.from(2_000_000))
|
||||||
send.callThrough()
|
send.callThrough()
|
||||||
|
})
|
||||||
|
|
||||||
// Set slippage to a very low value.
|
// Set slippage to a very low value.
|
||||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||||
cy.get(getTestSelector('max-slippage-settings')).click()
|
cy.get(getTestSelector('max-slippage-settings')).click()
|
||||||
cy.get(getTestSelector('slippage-input')).clear().type('0.01')
|
cy.get(getTestSelector('slippage-input')).clear().type('0.01')
|
||||||
|
|
||||||
|
// Click outside of modal to dismiss it.
|
||||||
cy.get('body').click('topRight')
|
cy.get('body').click('topRight')
|
||||||
cy.get(getTestSelector('slippage-input')).should('not.exist')
|
cy.get(getTestSelector('slippage-input')).should('not.exist')
|
||||||
|
|
||||||
// Open the currency select modal.
|
|
||||||
cy.get('#swap-currency-output .open-currency-select-button').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 })
|
|
||||||
|
|
||||||
// Swap 2 times.
|
// Swap 2 times.
|
||||||
const AMOUNT_TO_SWAP = 400
|
const AMOUNT_TO_SWAP = 200
|
||||||
const NUMBER_OF_SWAPS = 2
|
cy.get('#swap-currency-input .token-amount-input')
|
||||||
const INDIVIDUAL_SWAP_INPUT = AMOUNT_TO_SWAP / NUMBER_OF_SWAPS
|
.clear()
|
||||||
cy.get('#swap-currency-input .token-amount-input').clear().type(INDIVIDUAL_SWAP_INPUT.toString())
|
.type(AMOUNT_TO_SWAP.toString())
|
||||||
cy.get('#swap-currency-output .token-amount-input').should('not.equal', '')
|
.should('have.value', AMOUNT_TO_SWAP.toString())
|
||||||
cy.get('#swap-button').click()
|
cy.get('#swap-currency-output .token-amount-input').should('not.have.value', '')
|
||||||
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('#swap-button').click()
|
||||||
cy.get('#confirm-swap-or-send').click()
|
cy.get('#confirm-swap-or-send').click()
|
||||||
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
|
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
|
||||||
|
|
||||||
// The pending transaction indicator should be visible.
|
cy.get('#swap-currency-input .token-amount-input')
|
||||||
cy.contains('Pending').should('exist')
|
.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.then(() => hardhat.mine()).then(() => {
|
// The pending transaction indicator should reflect the state.
|
||||||
// The pending transaction indicator should not be visible.
|
cy.get(getTestSelector('web3-status-connected')).should('contain', '2 Pending')
|
||||||
cy.contains('Pending').should('not.exist')
|
cy.hardhat().then((hardhat) => hardhat.mine())
|
||||||
|
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
||||||
|
|
||||||
// Check for a failed transaction notification.
|
// TODO(WEB-2085): Fix this test - transaction popups are flakey.
|
||||||
cy.contains('Swap failed').should('exist')
|
// cy.get(getTestSelector('transaction-popup')).contains('Swap failed')
|
||||||
|
|
||||||
// Assert that at least one of the swaps failed due to slippage.
|
// Assert that the transactions were unsuccessful by checking on-chain balance.
|
||||||
cy.then(() => hardhat.provider.getBalance(hardhat.wallet.address)).then((finalBalance) => {
|
getBalance(UNI_MAINNET).should('equal', initialBalance)
|
||||||
expect(finalBalance.gt(initialBalance.sub(parseEther(AMOUNT_TO_SWAP.toString())))).to.be.true
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
14
cypress/e2e/swap/settings.test.ts
Normal file
14
cypress/e2e/swap/settings.test.ts
Normal file
@ -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')
|
||||||
|
})
|
||||||
|
})
|
@ -1,162 +1,69 @@
|
|||||||
import { SupportedChainId } from '@uniswap/sdk-core'
|
import { SupportedChainId } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
import { UNI, USDC_MAINNET } from '../../../src/constants/tokens'
|
import { UNI, USDC_MAINNET } from '../../../src/constants/tokens'
|
||||||
import { getTestSelector } from '../../utils'
|
import { getBalance, getTestSelector } from '../../utils'
|
||||||
|
|
||||||
const UNI_MAINNET = UNI[SupportedChainId.MAINNET]
|
const UNI_MAINNET = UNI[SupportedChainId.MAINNET]
|
||||||
|
|
||||||
describe('Swap', () => {
|
describe('Swap', () => {
|
||||||
describe('Swap on main page', () => {
|
describe('Swap on main page', () => {
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit('/swap', { ethereum: 'hardhat' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('starts with ETH selected by default', () => {
|
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-amount-input`).should('have.value', '')
|
||||||
cy.get(`#swap-currency-input .token-symbol-container`).should('contain.text', 'ETH')
|
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-amount-input`).should('not.have.value')
|
||||||
cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'Select token')
|
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 ', () => {
|
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-input .token-symbol-container`).should('contain.text', 'UNI')
|
||||||
cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'Select token')
|
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-input .token-symbol-container`).should('contain.text', 'Select token')
|
||||||
cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'UNI')
|
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-input .token-symbol-container`).should('contain.text', 'ETH')
|
||||||
cy.get(`#swap-currency-output .token-symbol-container`).should('contain.text', 'UNI')
|
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', () => {
|
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.visit('/swap')
|
||||||
cy.get('#swap-currency-input .token-amount-input').should('have.value', '')
|
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', () => {
|
it('swaps ETH for USDC', () => {
|
||||||
const TOKEN_ADDRESS = USDC_MAINNET.address
|
cy.visit('/swap', { ethereum: 'hardhat' })
|
||||||
const BALANCE_INCREMENT = 1
|
cy.hardhat({ automine: false })
|
||||||
cy.hardhat().then((hardhat) => {
|
getBalance(USDC_MAINNET).then((initialBalance) => {
|
||||||
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('#swap-currency-output .open-currency-select-button').click()
|
||||||
cy.get(getTestSelector('token-search-input')).clear().type(TOKEN_ADDRESS)
|
cy.get(getTestSelector('token-search-input')).clear().type(USDC_MAINNET.address)
|
||||||
cy.contains('USDC').click()
|
cy.contains('USDC').click()
|
||||||
cy.get('#swap-currency-output .token-amount-input').clear().type(BALANCE_INCREMENT.toString())
|
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.equal', '')
|
cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '')
|
||||||
cy.get('#swap-button').click()
|
cy.get('#swap-button').click()
|
||||||
cy.get('#confirm-swap-or-send').click()
|
cy.get('#confirm-swap-or-send').click()
|
||||||
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
|
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
|
||||||
|
|
||||||
// ui check
|
// 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')
|
||||||
|
|
||||||
|
// 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(
|
cy.get('#swap-currency-output [data-testid="balance-text"]').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
`Balance: ${initialBalance + BALANCE_INCREMENT}`
|
`Balance: ${initialBalance + 1}`
|
||||||
)
|
)
|
||||||
|
getBalance(USDC_MAINNET).should('eq', initialBalance + 1)
|
||||||
// chain state check
|
|
||||||
cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET))
|
|
||||||
.then((balance) => Number(balance.toFixed(1)))
|
|
||||||
.should('eq', initialBalance + BALANCE_INCREMENT)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,30 +1,31 @@
|
|||||||
import { CurrencyAmount, SupportedChainId, WETH9 } from '@uniswap/sdk-core'
|
import { CurrencyAmount, SupportedChainId, WETH9 } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
import { getTestSelector } from '../../utils'
|
import { getBalance, getTestSelector } from '../../utils'
|
||||||
|
|
||||||
const WETH = WETH9[SupportedChainId.MAINNET]
|
const WETH = WETH9[SupportedChainId.MAINNET]
|
||||||
|
|
||||||
function getWethBalance() {
|
describe('Swap wrap', () => {
|
||||||
return cy
|
|
||||||
.hardhat()
|
|
||||||
.then((hardhat) => hardhat.getBalance(hardhat.wallet, WETH))
|
|
||||||
.then((balance) => Number(balance.toFixed(1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Swap', () => {
|
|
||||||
beforeEach(() => {
|
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', () => {
|
it('should be able to wrap ETH', () => {
|
||||||
getWethBalance().then((initialWethBalance) => {
|
getBalance(WETH).then((initialWethBalance) => {
|
||||||
// Select WETH for the token output.
|
|
||||||
cy.get('#swap-currency-output').contains('Select token').click()
|
|
||||||
cy.contains('WETH').click()
|
|
||||||
cy.contains('Enter ETH amount')
|
cy.contains('Enter ETH amount')
|
||||||
|
|
||||||
// Enter the amount to wrap.
|
// 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)
|
cy.get('#swap-currency-input .token-amount-input').should('have.value', 1)
|
||||||
|
|
||||||
// Click the wrap button.
|
// Click the wrap button.
|
||||||
@ -35,15 +36,15 @@ describe('Swap', () => {
|
|||||||
cy.hardhat().then((hardhat) => hardhat.mine())
|
cy.hardhat().then((hardhat) => hardhat.mine())
|
||||||
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
||||||
|
|
||||||
// There should be a successful wrap notification.
|
// TODO(WEB-2085): Fix this test - transaction popups are flakey.
|
||||||
cy.get(getTestSelector('transaction-popup')).contains('Wrapped')
|
// cy.get(getTestSelector('transaction-popup')).contains('Wrapped')
|
||||||
cy.get(getTestSelector('transaction-popup')).contains('1.00 ETH for 1.00 WETH')
|
// cy.get(getTestSelector('transaction-popup')).contains('1.00 ETH for 1.00 WETH')
|
||||||
|
|
||||||
// The UI balance should have increased.
|
// The UI balance should have increased.
|
||||||
cy.get('#swap-currency-output').should('contain', `Balance: ${initialWethBalance + 1}`)
|
cy.get('#swap-currency-output').should('contain', `Balance: ${initialWethBalance + 1}`)
|
||||||
|
|
||||||
// The user's WETH account balance should have increased
|
// 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()
|
await hardhat.mine()
|
||||||
})
|
})
|
||||||
|
|
||||||
getWethBalance().then((initialWethBalance) => {
|
getBalance(WETH).then((initialWethBalance) => {
|
||||||
// Select WETH for the token output.
|
|
||||||
cy.get('#swap-currency-output').contains('Select token').click()
|
|
||||||
cy.contains('WETH').click()
|
|
||||||
|
|
||||||
// Swap input/output to unwrap WETH.
|
// Swap input/output to unwrap WETH.
|
||||||
cy.get(getTestSelector('swap-currency-button')).click()
|
cy.get(getTestSelector('swap-currency-button')).click()
|
||||||
cy.contains('Enter WETH amount')
|
cy.contains('Enter WETH amount')
|
||||||
|
|
||||||
// Enter the amount to unwrap.
|
// 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)
|
cy.get('#swap-currency-input .token-amount-input').should('have.value', 1)
|
||||||
|
|
||||||
// Click the unwrap button.
|
// Click the unwrap button.
|
||||||
@ -74,15 +72,15 @@ describe('Swap', () => {
|
|||||||
cy.hardhat().then((hardhat) => hardhat.mine())
|
cy.hardhat().then((hardhat) => hardhat.mine())
|
||||||
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
||||||
|
|
||||||
// There should be a successful wrap notification.
|
// TODO(WEB-2085): Fix this test - transaction popups are flakey.
|
||||||
cy.get(getTestSelector('transaction-popup')).contains('Unwrapped')
|
// cy.get(getTestSelector('transaction-popup')).contains('Unwrapped')
|
||||||
cy.get(getTestSelector('transaction-popup')).contains('1.00 WETH for 1.00 ETH')
|
// cy.get(getTestSelector('transaction-popup')).contains('1.00 WETH for 1.00 ETH')
|
||||||
|
|
||||||
// The UI balance should have increased.
|
// The UI balance should have increased.
|
||||||
cy.get('#swap-currency-input').should('contain', `Balance: ${initialWethBalance - 1}`)
|
cy.get('#swap-currency-input').should('contain', `Balance: ${initialWethBalance - 1}`)
|
||||||
|
|
||||||
// The user's WETH account balance should have increased
|
// The user's WETH account balance should have increased
|
||||||
getWethBalance().should('equal', initialWethBalance - 1)
|
getBalance(WETH).should('equal', initialWethBalance - 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,13 @@
|
|||||||
|
import { Currency } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
export const getTestSelector = (selectorId: string) => `[data-testid=${selectorId}]`
|
export const getTestSelector = (selectorId: string) => `[data-testid=${selectorId}]`
|
||||||
|
|
||||||
export const getTestSelectorStartsWith = (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)))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user