diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 642839ec00..b848dd5668 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -100,6 +100,23 @@ jobs: path: build if-no-files-found: error + cypress-typecheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/setup + - uses: ./.github/actions/cache-on-main + with: + path: node_modules/.cache + key: ${{ runner.os }}-cypress-tsc-${{ github.run_id }} + restore-keys: ${{ runner.os }}-cypress-tsc- + - run: yarn typecheck:cypress + - if: failure() && github.ref_name == 'main' + uses: ./.github/actions/report + with: + name: Cypress typecheck + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }} + # Allows for parallel re-runs of cypress tests without re-building. cypress-rerun: runs-on: ubuntu-latest diff --git a/cypress.config.ts b/cypress.config.ts index 0bd5bbcf1e..60c757fc5a 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,7 +1,6 @@ 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', @@ -9,22 +8,11 @@ export default defineConfig({ chromeWebSecurity: false, experimentalMemoryManagement: true, // better memory management, see https://github.com/cypress-io/cypress/pull/25462 retries: { runMode: 2 }, - videoCompression: false, + video: false, // GH provides 2 CPUs, and cypress video eats one up, see https://github.com/cypress-io/cypress/issues/20468#issuecomment-1307608025 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 }, baseUrl: 'http://localhost:3000', diff --git a/cypress/README.md b/cypress/README.md index 3d33797bee..c1db9f2f1e 100644 --- a/cypress/README.md +++ b/cypress/README.md @@ -52,7 +52,7 @@ This becomes more relevant as you work with data on the blockchain, as you'll ne ``` cy.hardhat().then(async (hardhat) => { - cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`) cy.get('#swap-currency-output .token-amount-input').type('1').should('have.value', '1') cy.get('#swap-button').click() cy.contains('Confirm swap').click() @@ -68,7 +68,7 @@ cy.hardhat().then(async (hardhat) => { ``` ``` - cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`) cy.get('#swap-currency-output .token-amount-input').type('1').should('have.value', '1') cy.get('#swap-button').click() cy.contains('Confirm swap').click() @@ -87,7 +87,6 @@ cy.hardhat().then(async (hardhat) => { ### Working with the blockchain (ie hardhat) Our tests use a local hardhat node to simulate blockchain transactions. This can be accessed with `cy.hardhat().then((hardhat) => ...)`. -Currently, tests using hardhat must opt-in in when they load the page: `cy.visit('/swap', { ethereum: 'hardhat' })`. This will not be necessary once we've totally migrated to hardhat. By default, automining is turned on, so that any transaction that you send to the blockchain is mined immediately. If you want to assert on intermediate states (between sending a transaction and mining it), you can turn off automining: `cy.hardhat({ automine: false })`. diff --git a/cypress/e2e/add-liquidity.test.ts b/cypress/e2e/add-liquidity.test.ts index 37ae1499ff..6da0b076e6 100644 --- a/cypress/e2e/add-liquidity.test.ts +++ b/cypress/e2e/add-liquidity.test.ts @@ -9,36 +9,29 @@ describe('Add Liquidity', () => { }) }) - it('loads the two correct tokens', () => { - cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6/500') + it('loads the token pair', () => { + cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH/500') cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'UNI') cy.get('#add-liquidity-input-tokenb .token-symbol-container').should('contain.text', 'ETH') + cy.contains('0.05% fee tier') }) - it('does not crash if ETH is duplicated', () => { - cy.visit('/add/0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6/0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6') - cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'ETH') - cy.get('#add-liquidity-input-tokenb .token-symbol-container').should('not.contain.text', 'ETH') + it('does not crash if token is duplicated', () => { + cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984') + cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'UNI') + cy.get('#add-liquidity-input-tokenb .token-symbol-container').should('not.contain.text', 'UNI') }) - it.skip('token not in storage is loaded', () => { - cy.visit('/add/0x07865c6e87b9f70255377e024ace6630c1eaa37f/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984') - cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'USDC') - cy.get('#add-liquidity-input-tokenb .token-symbol-container').should('contain.text', 'UNI') - }) - - it.skip('single token can be selected', () => { - cy.visit('/add/0x07865c6e87b9f70255377e024ace6630c1eaa37f') - cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'USDC') + it('single token can be selected', () => { cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984') cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'UNI') }) - it.skip('loads fee tier distribution', () => { + it('loads fee tier distribution', () => { cy.fixture('feeTierDistribution.json').then((feeTierDistribution) => { cy.intercept('POST', '/subgraphs/name/uniswap/uniswap-v3', (req: CyHttpMessages.IncomingHttpRequest) => { - if (hasQuery(req, 'FeeTierDistributionQuery')) { - req.alias = 'FeeTierDistributionQuery' + if (hasQuery(req, 'FeeTierDistribution')) { + req.alias = 'FeeTierDistribution' req.reply({ body: { @@ -53,12 +46,10 @@ describe('Add Liquidity', () => { } }) - cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6') - - cy.wait('@FeeTierDistributionQuery') - + cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH') + cy.wait('@FeeTierDistribution') cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier') - cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40%') + cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40% select') }) }) }) diff --git a/cypress/e2e/mini-portfolio/accounts.test.ts b/cypress/e2e/mini-portfolio/accounts.test.ts index 59e180faf9..911ac0d1d5 100644 --- a/cypress/e2e/mini-portfolio/accounts.test.ts +++ b/cypress/e2e/mini-portfolio/accounts.test.ts @@ -3,7 +3,7 @@ import { getTestSelector } from '../../utils' describe('Mini Portfolio account drawer', () => { beforeEach(() => { cy.intercept(/api.uniswap.org\/v1\/graphql/, cy.spy().as('gqlSpy')) - cy.visit('/swap', { ethereum: 'hardhat' }) + cy.visit('/swap') }) it('fetches balances when account button is first hovered', () => { diff --git a/cypress/e2e/mini-portfolio/activity-history.test.ts b/cypress/e2e/mini-portfolio/activity-history.test.ts index 4d5978e54d..7c141185e6 100644 --- a/cypress/e2e/mini-portfolio/activity-history.test.ts +++ b/cypress/e2e/mini-portfolio/activity-history.test.ts @@ -94,9 +94,7 @@ describe('mini-portfolio activity history', () => { }) it('should deduplicate activity history by nonce', () => { - cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }).hardhat({ - automine: false, - }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`).hardhat({ automine: false }) // Input swap info. cy.get('#swap-currency-input .token-amount-input').clear().type('1').should('have.value', '1') diff --git a/cypress/e2e/nfts.test.ts b/cypress/e2e/nfts.test.ts index bd4562ed1c..22b08a8b61 100644 --- a/cypress/e2e/nfts.test.ts +++ b/cypress/e2e/nfts.test.ts @@ -52,7 +52,7 @@ describe('Testing nfts', () => { cy.visit('/') cy.get(getTestSelector('web3-status-connected')).click() cy.get(getTestSelector('mini-portfolio-navbar')).contains('NFTs').click() - cy.get(getTestSelector('mini-portfolio-nft')).click() + cy.get(getTestSelector('mini-portfolio-nft')).first().click() cy.get(getTestSelector('mini-portfolio-navbar')).should('not.be.visible') }) }) diff --git a/cypress/e2e/permit2.test.ts b/cypress/e2e/permit2.test.ts index 325f8945ae..e3fa74af7e 100644 --- a/cypress/e2e/permit2.test.ts +++ b/cypress/e2e/permit2.test.ts @@ -17,9 +17,7 @@ function initiateSwap() { describe('Permit2', () => { function setupInputs(inputToken: Token, outputToken: Token) { // Sets up a swap between inputToken and outputToken. - cy.visit(`/swap/?inputCurrency=${inputToken.address}&outputCurrency=${outputToken.address}`, { - ethereum: 'hardhat', - }) + cy.visit(`/swap/?inputCurrency=${inputToken.address}&outputCurrency=${outputToken.address}`) cy.get('#swap-currency-input .token-amount-input').type('0.01') } diff --git a/cypress/e2e/remove-liquidity.test.ts b/cypress/e2e/remove-liquidity.test.ts index 464b913402..dc448bdb17 100644 --- a/cypress/e2e/remove-liquidity.test.ts +++ b/cypress/e2e/remove-liquidity.test.ts @@ -1,25 +1,7 @@ describe('Remove Liquidity', () => { - it('eth remove', () => { + it('loads the token pair', () => { cy.visit('/remove/v2/ETH/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984') cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'ETH') cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'UNI') }) - - it('eth remove swap order', () => { - cy.visit('/remove/v2/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH') - cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'UNI') - cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'ETH') - }) - - it('loads the two correct tokens', () => { - cy.visit('/remove/v2/0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984') - cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'WETH') - cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'UNI') - }) - - it('does not crash if ETH is duplicated', () => { - cy.visit('/remove/v2/0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6/0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6') - cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'WETH') - cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'WETH') - }) }) diff --git a/cypress/e2e/swap/errors.test.ts b/cypress/e2e/swap/errors.test.ts index 13d8dfc7a0..cdb6f04cd5 100644 --- a/cypress/e2e/swap/errors.test.ts +++ b/cypress/e2e/swap/errors.test.ts @@ -7,7 +7,7 @@ import { getBalance, getTestSelector } from '../../utils' describe('Swap errors', () => { it('wallet rejection', () => { - cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`) cy.hardhat().then((hardhat) => { // Stub the wallet to reject any transaction. cy.stub(hardhat.wallet, 'sendTransaction').log(false).rejects(new Error('user cancelled')) @@ -28,7 +28,7 @@ describe('Swap errors', () => { }) it('transaction past deadline', () => { - cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`) cy.hardhat({ automine: false }) getBalance(USDC_MAINNET).then((initialBalance) => { // Enter amount to swap @@ -63,7 +63,7 @@ describe('Swap errors', () => { }) it('slippage failure', () => { - cy.visit(`/swap?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`, { ethereum: 'hardhat' }) + cy.visit(`/swap?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`) cy.hardhat({ automine: false }).then(async (hardhat) => { await hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDC_MAINNET, 500e6)) await hardhat.mine() @@ -113,9 +113,7 @@ describe('Swap errors', () => { cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending') cy.get(getTestSelector('popups')).contains('Swapped') cy.get(getTestSelector('popups')).contains('Swap failed') - getBalance(DAI).then((currentDaiBalance) => { - expect(currentDaiBalance).to.be.closeTo(initialBalance + 200, 1) - }) + getBalance(DAI).should('be.closeTo', initialBalance + 200, 1) }) }) }) diff --git a/cypress/e2e/swap/settings.test.ts b/cypress/e2e/swap/settings.test.ts index 6fdc98f1bc..253386ae7b 100644 --- a/cypress/e2e/swap/settings.test.ts +++ b/cypress/e2e/swap/settings.test.ts @@ -3,7 +3,7 @@ import { getTestSelector } from '../../utils' describe('Swap settings', () => { it('Opens and closes the settings menu', () => { - cy.visit('/swap', { featureFlags: [FeatureFlag.uniswapXEnabled], ethereum: 'hardhat' }) + cy.visit('/swap', { featureFlags: [FeatureFlag.uniswapXEnabled] }) cy.contains('Settings').should('not.exist') cy.get(getTestSelector('open-settings-dialog-button')).click() cy.contains('Max slippage').should('exist') diff --git a/cypress/e2e/swap/swap.test.ts b/cypress/e2e/swap/swap.test.ts index e1dc7e3a4a..27a6ee80c5 100644 --- a/cypress/e2e/swap/swap.test.ts +++ b/cypress/e2e/swap/swap.test.ts @@ -52,7 +52,7 @@ describe('Swap', () => { }) it('swaps ETH for USDC', () => { - cy.visit('/swap', { ethereum: 'hardhat' }) + cy.visit('/swap') cy.hardhat({ automine: false }) getBalance(USDC_MAINNET).then((initialBalance) => { // Select USDC diff --git a/cypress/e2e/swap/wrap.test.ts b/cypress/e2e/swap/wrap.test.ts index b41e296345..d4a5f422d4 100644 --- a/cypress/e2e/swap/wrap.test.ts +++ b/cypress/e2e/swap/wrap.test.ts @@ -6,9 +6,7 @@ const WETH = WETH9[ChainId.MAINNET] describe('Swap wrap', () => { beforeEach(() => { - cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${WETH.address}`, { ethereum: 'hardhat' }).hardhat({ - automine: false, - }) + cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${WETH.address}`).hardhat({ automine: false }) }) it('ETH to wETH is same value (wrapped swaps have no price impact)', () => { diff --git a/cypress/e2e/token-details.test.ts b/cypress/e2e/token-details.test.ts index 5b2221b687..382a35623d 100644 --- a/cypress/e2e/token-details.test.ts +++ b/cypress/e2e/token-details.test.ts @@ -93,9 +93,7 @@ describe('Token details', () => { beforeEach(() => { // On mobile widths, we just link back to /swap instead of rendering the swap component. cy.viewport(1200, 800) - cy.visit(`/tokens/ethereum/${UNI_MAINNET.address}`, { - ethereum: 'hardhat', - }).then(() => { + cy.visit(`/tokens/ethereum/${UNI_MAINNET.address}`).then(() => { cy.wait('@eth_blockNumber') cy.scrollTo('top') }) @@ -145,7 +143,7 @@ describe('Token details', () => { }) it('should show a L2 token even if the user is connected to a different network', () => { - cy.visit('/tokens', { ethereum: 'hardhat' }) + cy.visit('/tokens') cy.get(getTestSelector('tokens-network-filter-selected')).click() cy.get(getTestSelector('tokens-network-filter-option-arbitrum')).click() cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Arbitrum') diff --git a/cypress/e2e/token-explore.test.ts b/cypress/e2e/token-explore.test.ts index 35a8c9fff2..a418ac6b23 100644 --- a/cypress/e2e/token-explore.test.ts +++ b/cypress/e2e/token-explore.test.ts @@ -36,7 +36,7 @@ describe('Token explore', () => { .then(function ($elem) { cy.wrap($elem.text()).as('yearlyEthVol') }) - expect(cy.get('@dailyEthVol')).to.not.equal(cy.get('@yearlyEthVol')) + cy.get('@dailyEthVol').should('not.equal', cy.get('@yearlyEthVol')) }) it('should navigate to token detail page when row clicked', () => { diff --git a/cypress/e2e/wallet-connection/connect.test.ts b/cypress/e2e/wallet-connection/connect.test.ts index 3d7dc6b7b3..d26477a7dc 100644 --- a/cypress/e2e/wallet-connection/connect.test.ts +++ b/cypress/e2e/wallet-connection/connect.test.ts @@ -2,8 +2,8 @@ import { getTestSelector } from '../../utils' import { DISCONNECTED_WALLET_USER_STATE } from '../../utils/user-state' describe('disconnect wallet', () => { - it('should not clear state', () => { - cy.visit('/swap', { ethereum: 'hardhat' }) + it('should clear state', () => { + cy.visit('/swap') cy.get('#swap-currency-input .token-amount-input').clear().type('1') // Verify wallet is connected @@ -28,7 +28,7 @@ describe('disconnect wallet', () => { describe('connect wallet', () => { it('should load state', () => { - cy.visit('/swap', { ethereum: 'hardhat', userState: DISCONNECTED_WALLET_USER_STATE }) + cy.visit('/swap', { userState: DISCONNECTED_WALLET_USER_STATE }) // Connect the wallet cy.get(getTestSelector('navbar-connect-wallet')).contains('Connect').click() diff --git a/cypress/e2e/wallet-connection/switch-network.test.ts b/cypress/e2e/wallet-connection/switch-network.test.ts index a761f255e9..f75fcf0dfe 100644 --- a/cypress/e2e/wallet-connection/switch-network.test.ts +++ b/cypress/e2e/wallet-connection/switch-network.test.ts @@ -12,7 +12,7 @@ function switchChain(chain: string) { describe('network switching', () => { beforeEach(() => { - cy.visit('/swap', { ethereum: 'hardhat' }) + cy.visit('/swap') cy.get(getTestSelector('web3-status-connected')) }) @@ -123,14 +123,14 @@ describe('network switching', () => { describe('network switching from URL param', () => { it('should switch network from URL param', () => { - cy.visit('/swap?chain=polygon', { ethereum: 'hardhat' }) + cy.visit('/swap?chain=polygon') cy.get(getTestSelector('web3-status-connected')) cy.wait('@wallet_switchEthereumChain') waitsForActiveChain('Polygon') }) it('should be able to switch network after loading from URL param', () => { - cy.visit('/swap?chain=polygon', { ethereum: 'hardhat' }) + cy.visit('/swap?chain=polygon') cy.get(getTestSelector('web3-status-connected')) cy.wait('@wallet_switchEthereumChain') waitsForActiveChain('Polygon') diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 99c75f5403..fcbf3540ed 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -5,7 +5,6 @@ import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge' import { FeatureFlag } from '../../src/featureFlags' import { UserState } from '../../src/state/user/reducer' import { CONNECTED_WALLET_USER_STATE } from '../utils/user-state' -import { injected } from './ethereum' declare global { // eslint-disable-next-line @typescript-eslint/no-namespace @@ -16,12 +15,6 @@ declare global { interface VisitOptions { serviceWorker?: true featureFlags?: Array - /** - * The mock ethereum provider to inject into the page. - * @default 'goerli' - */ - // TODO(INFRA-175): Migrate all usage of 'goerli' to 'hardhat'. - ethereum?: 'goerli' | 'hardhat' /** * Initial user state. * @default {@type import('../utils/user-state').CONNECTED_WALLET_USER_STATE} @@ -39,8 +32,7 @@ Cypress.Commands.overwrite( if (typeof url !== 'string') throw new Error('Invalid arguments. The first argument to cy.visit must be the path.') // Add a hash in the URL if it is not present (to use hash-based routing correctly with queryParams). - let hashUrl = url.startsWith('/') && url.length > 2 && !url.startsWith('/#') ? `/#${url}` : url - if (options?.ethereum === 'goerli') hashUrl += `${url.includes('?') ? '&' : '?'}chain=goerli` + const hashUrl = url.startsWith('/') && url.length > 2 && !url.startsWith('/#') ? `/#${url}` : url return cy .intercept('/service-worker.js', options?.serviceWorker ? undefined : { statusCode: 404 }) @@ -68,11 +60,7 @@ Cypress.Commands.overwrite( } // Inject the mock ethereum provider. - if (options?.ethereum === 'hardhat') { - win.ethereum = provider - } else { - win.ethereum = injected - } + win.ethereum = provider }, }) ) diff --git a/cypress/support/ethereum.ts b/cypress/support/ethereum.ts deleted file mode 100644 index a7dc4fc207..0000000000 --- a/cypress/support/ethereum.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Updates cy.visit() to include an injected window.ethereum provider. - */ - -import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge' -import { JsonRpcProvider } from '@ethersproject/providers' -import { Wallet } from '@ethersproject/wallet' -import { ChainId } from '@uniswap/sdk-core' - -// todo: figure out how env vars actually work in CI -// const TEST_PRIVATE_KEY = Cypress.env('INTEGRATION_TEST_PRIVATE_KEY') -const TEST_PRIVATE_KEY = '0xe580410d7c37d26c6ad1a837bbae46bc27f9066a466fb3a66e770523b4666d19' - -// address of the above key -const TEST_ADDRESS_NEVER_USE = new Wallet(TEST_PRIVATE_KEY).address -const CHAIN_ID = ChainId.GOERLI -const HEXLIFIED_CHAIN_ID = `0x${CHAIN_ID.toString(16)}` - -const provider = new JsonRpcProvider('https://goerli.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847', 5) -const signer = new Wallet(TEST_PRIVATE_KEY, provider) -export const injected = new (class extends Eip1193Bridge { - chainId = CHAIN_ID - - async sendAsync(...args: any[]) { - console.debug('sendAsync called', ...args) - return this.send(...args) - } - async send(...args: any[]) { - console.debug('send called', ...args) - const isCallbackForm = typeof args[0] === 'object' && typeof args[1] === 'function' - let callback - let method - let params - if (isCallbackForm) { - callback = args[1] - method = args[0].method - params = args[0].params - } else { - method = args[0] - params = args[1] - } - if (method === 'eth_requestAccounts' || method === 'eth_accounts') { - if (isCallbackForm) { - callback({ result: [TEST_ADDRESS_NEVER_USE] }) - } else { - return Promise.resolve([TEST_ADDRESS_NEVER_USE]) - } - } - if (method === 'eth_chainId') { - if (isCallbackForm) { - callback(null, { result: HEXLIFIED_CHAIN_ID }) - } else { - return Promise.resolve(HEXLIFIED_CHAIN_ID) - } - } - try { - const result = await super.send(method, params) - console.debug('result received', method, params, result) - if (isCallbackForm) { - callback(null, { result }) - } else { - return result - } - } catch (error) { - if (isCallbackForm) { - callback(error, null) - } else { - throw error - } - } - } -})(signer, provider) diff --git a/cypress/support/setupTests.ts b/cypress/support/setupTests.ts index 5af540baa2..81a47e8c3c 100644 --- a/cypress/support/setupTests.ts +++ b/cypress/support/setupTests.ts @@ -9,13 +9,8 @@ beforeEach(() => { req.headers['origin'] = 'https://app.uniswap.org' }) - // Infura uses a test endpoint, which allow-lists http://localhost:3000 instead. - cy.intercept(/infura.io/, (req) => { - req.headers['referer'] = 'http://localhost:3000' - req.headers['origin'] = 'http://localhost:3000' - req.alias = req.body.method - req.continue() - }) + // Infura is disabled for cypress tests - calls should be routed through the connected wallet instead. + cy.intercept(/infura.io/, { statusCode: 404 }) // Log requests to hardhat. cy.intercept(/:8545/, logJsonRpc) @@ -49,7 +44,7 @@ function logJsonRpc(req: CyHttpMessages.IncomingHttpRequest) { const log = Cypress.log({ autoEnd: false, name: req.body.method, - message: req.body.params?.map((param: unknown) => + message: req.body.params?.map((param: any) => typeof param === 'object' ? '{...}' : param?.toString().substring(0, 10) ), }) diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json index e5823ce6bd..acbdcfdc1d 100644 --- a/cypress/tsconfig.json +++ b/cypress/tsconfig.json @@ -1,18 +1,13 @@ { + "extends": "../tsconfig.json", "compilerOptions": { - "esModuleInterop": true, + "composite": false, "incremental": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "noEmit": true, - "strict": true, + "isolatedModules": false, + "noImplicitAny": false, "target": "ES5", "tsBuildInfoFile": "../node_modules/.cache/tsbuildinfo/cypress", // avoid clobbering the build tsbuildinfo "types": ["cypress", "node"], - "jsx": "react" }, - "exclude": ["node_modules"], "include": ["**/*.ts"], - "watchOptions": { - "excludeDirectories": ["node_modules"] - } } diff --git a/cypress/utils/user-state.ts b/cypress/utils/user-state.ts index 0b4b54c1d6..8c6440a6d7 100644 --- a/cypress/utils/user-state.ts +++ b/cypress/utils/user-state.ts @@ -1,5 +1,6 @@ +import { ConnectionType } from '../../src/connection/types' import { UserState } from '../../src/state/user/reducer' -export const CONNECTED_WALLET_USER_STATE: Partial = { selectedWallet: 'INJECTED' } +export const CONNECTED_WALLET_USER_STATE: Partial = { selectedWallet: ConnectionType.INJECTED } export const DISCONNECTED_WALLET_USER_STATE: Partial = { selectedWallet: undefined } diff --git a/package.json b/package.json index 7d2aa58009..852106a61b 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "lint": "yarn eslint --ignore-path .gitignore --cache --cache-location node_modules/.cache/eslint/ .", "typecheck": "tsc", "typecheck:cloud": "tsc -p functions/tsconfig.json", + "typecheck:cypress": "tsc -p cypress/tsconfig.json", "test": "craco test", "test:cloud": "NODE_OPTIONS=--experimental-vm-modules yarn jest functions --config=functions/jest.config.json", "cypress:open": "cypress open --browser chrome --e2e", diff --git a/src/components/Settings/RouterPreferenceSettings/index.test.tsx b/src/components/Settings/RouterPreferenceSettings/index.test.tsx index 4eee8b2fa9..b69e3bff75 100644 --- a/src/components/Settings/RouterPreferenceSettings/index.test.tsx +++ b/src/components/Settings/RouterPreferenceSettings/index.test.tsx @@ -1,5 +1,5 @@ import store from 'state' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { updateUserRouterPreference } from 'state/user/reducer' import { fireEvent, render, screen } from 'test-utils/render' diff --git a/src/components/Settings/RouterPreferenceSettings/index.tsx b/src/components/Settings/RouterPreferenceSettings/index.tsx index 7c2f7ea357..056c938416 100644 --- a/src/components/Settings/RouterPreferenceSettings/index.tsx +++ b/src/components/Settings/RouterPreferenceSettings/index.tsx @@ -7,7 +7,7 @@ import Toggle from 'components/Toggle' import { isUniswapXSupportedChain } from 'constants/chains' import { useUniswapXEnabled } from 'featureFlags/flags/uniswapx' import { useAppDispatch } from 'state/hooks' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { useRouterPreference } from 'state/user/hooks' import { updateDisabledUniswapX } from 'state/user/reducer' import styled from 'styled-components/macro' diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx index 3cabb4a45e..3036bea5a9 100644 --- a/src/components/swap/SwapModalFooter.tsx +++ b/src/components/swap/SwapModalFooter.tsx @@ -11,7 +11,7 @@ import useTransactionDeadline from 'hooks/useTransactionDeadline' import useNativeCurrency from 'lib/hooks/useNativeCurrency' import { ReactNode } from 'react' import { AlertTriangle } from 'react-feather' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { InterfaceTrade } from 'state/routing/types' import { getTransactionCount, isClassicTrade } from 'state/routing/utils' import { useRouterPreference, useUserSlippageTolerance } from 'state/user/hooks' diff --git a/src/hooks/useBestTrade.test.ts b/src/hooks/useBestTrade.test.ts index 96609a4dd2..58e697cd97 100644 --- a/src/hooks/useBestTrade.test.ts +++ b/src/hooks/useBestTrade.test.ts @@ -1,7 +1,7 @@ import { renderHook } from '@testing-library/react' import { CurrencyAmount, TradeType } from '@uniswap/sdk-core' import { DAI, USDC_MAINNET } from 'constants/tokens' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { TradeState } from 'state/routing/types' import { useRouterPreference } from 'state/user/hooks' import { mocked } from 'test-utils/mocked' diff --git a/src/hooks/useBestTrade.ts b/src/hooks/useBestTrade.ts index 27ca6484ad..2250337fff 100644 --- a/src/hooks/useBestTrade.ts +++ b/src/hooks/useBestTrade.ts @@ -3,7 +3,7 @@ import { useWeb3React } from '@web3-react/core' import { WRAPPED_NATIVE_CURRENCY } from 'constants/tokens' import { DebounceSwapQuoteVariant, useDebounceSwapQuoteFlag } from 'featureFlags/flags/debounceSwapQuote' import { useMemo } from 'react' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { ClassicTrade, InterfaceTrade, QuoteMethod, TradeState } from 'state/routing/types' import { useRoutingAPITrade } from 'state/routing/useRoutingAPITrade' import { useRouterPreference } from 'state/user/hooks' diff --git a/src/lib/hooks/routing/useRoutingAPIArguments.ts b/src/lib/hooks/routing/useRoutingAPIArguments.ts index 049ddbc719..c51fb7c48e 100644 --- a/src/lib/hooks/routing/useRoutingAPIArguments.ts +++ b/src/lib/hooks/routing/useRoutingAPIArguments.ts @@ -4,7 +4,8 @@ import { useRoutingAPIForPrice } from 'featureFlags/flags/priceRoutingApi' import { useUniswapXEnabled } from 'featureFlags/flags/uniswapx' import { useUniswapXSyntheticQuoteEnabled } from 'featureFlags/flags/uniswapXUseSyntheticQuote' import { useMemo } from 'react' -import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from 'state/routing/slice' +import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { currencyAddressForSwapQuote } from 'state/routing/utils' import { useUserDisabledUniswapX } from 'state/user/hooks' diff --git a/src/nft/hooks/useDerivedPayWithAnyTokenSwapInfo.ts b/src/nft/hooks/useDerivedPayWithAnyTokenSwapInfo.ts index 59fc4b4d06..fb629006f9 100644 --- a/src/nft/hooks/useDerivedPayWithAnyTokenSwapInfo.ts +++ b/src/nft/hooks/useDerivedPayWithAnyTokenSwapInfo.ts @@ -2,7 +2,7 @@ import { Currency, CurrencyAmount, NativeCurrency, Percent, Token, TradeType } f import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance' import { useBestTrade } from 'hooks/useBestTrade' import { useMemo } from 'react' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { ClassicTrade, TradeState } from 'state/routing/types' import { isClassicTrade } from 'state/routing/utils' diff --git a/src/pages/Swap/UniswapXOptIn.tsx b/src/pages/Swap/UniswapXOptIn.tsx index f977649027..497781852b 100644 --- a/src/pages/Swap/UniswapXOptIn.tsx +++ b/src/pages/Swap/UniswapXOptIn.tsx @@ -19,7 +19,7 @@ import { PropsWithChildren, useEffect, useRef, useState } from 'react' import { X } from 'react-feather' import { Text } from 'rebass' import { useAppDispatch } from 'state/hooks' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { isClassicTrade } from 'state/routing/utils' import { SwapInfo } from 'state/swap/hooks' import { useRouterPreference, useUserDisabledUniswapX } from 'state/user/hooks' diff --git a/src/state/routing/slice.ts b/src/state/routing/slice.ts index 43eb6087fd..f36e4995c8 100644 --- a/src/state/routing/slice.ts +++ b/src/state/routing/slice.ts @@ -9,6 +9,7 @@ import { trace } from 'tracing/trace' import { QuoteMethod, QuoteState, + RouterPreference, RoutingConfig, SwapRouterNativeAssets, TradeResult, @@ -22,12 +23,6 @@ if (UNISWAP_API_URL === undefined) { throw new Error(`UNISWAP_API_URL must be a defined environment variable`) } -export enum RouterPreference { - X = 'uniswapx', - API = 'api', - CLIENT = 'client', -} - // This is excluded from `RouterPreference` enum because it's only used // internally for token -> USDC trades to get a USD value. export const INTERNAL_ROUTER_PREFERENCE_PRICE = 'price' as const diff --git a/src/state/routing/types.ts b/src/state/routing/types.ts index aba81fe2ba..fd86b8889c 100644 --- a/src/state/routing/types.ts +++ b/src/state/routing/types.ts @@ -18,6 +18,12 @@ export enum QuoteMethod { CLIENT_SIDE_FALLBACK = 'CLIENT_SIDE_FALLBACK', // If client-side was used after the routing-api call failed. } +export enum RouterPreference { + X = 'uniswapx', + API = 'api', + CLIENT = 'client', +} + // from https://github.com/Uniswap/routing-api/blob/main/lib/handlers/schema.ts type TokenInRoute = Pick diff --git a/src/state/routing/useRoutingAPITrade.ts b/src/state/routing/useRoutingAPITrade.ts index f847ecdc37..34ab580942 100644 --- a/src/state/routing/useRoutingAPITrade.ts +++ b/src/state/routing/useRoutingAPITrade.ts @@ -6,10 +6,10 @@ import { AVERAGE_L1_BLOCK_TIME } from 'constants/chainInfo' import { useRoutingAPIArguments } from 'lib/hooks/routing/useRoutingAPIArguments' import ms from 'ms.macro' import { useMemo } from 'react' -import { INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from 'state/routing/slice' +import { INTERNAL_ROUTER_PREFERENCE_PRICE } from 'state/routing/slice' import { useGetQuoteQuery } from 'state/routing/slice' -import { ClassicTrade, InterfaceTrade, QuoteMethod, QuoteState, TradeState } from './types' +import { ClassicTrade, InterfaceTrade, QuoteMethod, QuoteState, RouterPreference, TradeState } from './types' const TRADE_NOT_FOUND = { state: TradeState.NO_ROUTE_FOUND, trade: undefined } as const const TRADE_LOADING = { state: TradeState.LOADING, trade: undefined } as const diff --git a/src/state/routing/utils.ts b/src/state/routing/utils.ts index 82eb5b8b50..2f2664d59c 100644 --- a/src/state/routing/utils.ts +++ b/src/state/routing/utils.ts @@ -11,7 +11,7 @@ import { isAvalanche, isBsc, isMatic, nativeOnChain } from 'constants/tokens' import { toSlippagePercent } from 'utils/slippage' import { getApproveInfo, getWrapInfo } from './gas' -import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from './slice' +import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE } from './slice' import { ClassicQuoteData, ClassicTrade, @@ -21,6 +21,7 @@ import { PoolType, QuoteMethod, QuoteState, + RouterPreference, SwapRouterNativeAssets, TradeFillType, TradeResult, diff --git a/src/state/user/hooks.test.tsx b/src/state/user/hooks.test.tsx index e592f45ce9..964465aa76 100644 --- a/src/state/user/hooks.test.tsx +++ b/src/state/user/hooks.test.tsx @@ -2,7 +2,7 @@ import { act } from '@testing-library/react' import { Percent } from '@uniswap/sdk-core' import { USDC_MAINNET } from 'constants/tokens' import store from 'state' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { renderHook } from 'test-utils/render' import { diff --git a/src/state/user/hooks.tsx b/src/state/user/hooks.tsx index 755a09b624..90c656af01 100644 --- a/src/state/user/hooks.tsx +++ b/src/state/user/hooks.tsx @@ -7,7 +7,7 @@ import { L2_DEADLINE_FROM_NOW } from 'constants/misc' import JSBI from 'jsbi' import { useCallback, useMemo } from 'react' import { useAppDispatch, useAppSelector } from 'state/hooks' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { UserAddedToken } from 'types/tokens' import { BASES_TO_TRACK_LIQUIDITY_FOR, PINNED_PAIRS } from '../../constants/routing' diff --git a/src/state/user/reducer.test.ts b/src/state/user/reducer.test.ts index 6a5c29b42a..4146c49550 100644 --- a/src/state/user/reducer.test.ts +++ b/src/state/user/reducer.test.ts @@ -1,5 +1,5 @@ import { createStore, Store } from 'redux' -import { RouterPreference } from 'state/routing/slice' +import { RouterPreference } from 'state/routing/types' import { DEFAULT_DEADLINE_FROM_NOW } from '../../constants/misc' import { updateVersion } from '../global/actions' diff --git a/src/state/user/reducer.ts b/src/state/user/reducer.ts index 8918edff63..e44f13437c 100644 --- a/src/state/user/reducer.ts +++ b/src/state/user/reducer.ts @@ -1,9 +1,9 @@ import { createSlice } from '@reduxjs/toolkit' -import { ConnectionType } from 'connection/types' -import { SupportedLocale } from 'constants/locales' -import { RouterPreference } from 'state/routing/slice' +import { ConnectionType } from '../../connection/types' +import { SupportedLocale } from '../../constants/locales' import { DEFAULT_DEADLINE_FROM_NOW } from '../../constants/misc' +import { RouterPreference } from '../../state/routing/types' import { updateVersion } from '../global/actions' import { SerializedPair, SerializedToken, SlippageTolerance } from './types' diff --git a/tsconfig.json b/tsconfig.json index 19684f0a0a..28ffbced66 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,9 +30,5 @@ "types": ["jest"], "useUnknownInCatchVariables": false }, - "exclude": ["node_modules"], "include": ["src/**/*", "src/**/*.json"], - "watchOptions": { - "excludeDirectories": ["node_modules"] - } }