uniswap-interface-uncensored/cypress
Tina 4c58258f01
feat: additional routing option prototype (#6934)
* add npm secret and modify github actions

* inject npm secret for tests as well

* revert changes to staging and prod actions because we arent going to use themmm

* remove unused github actions

* minor copy change for convenience lol

* feat: add DutchOrderTrade type to Swap components (#8)

* feat: add flag for gouda (#5)

* feat: add new signature details type (#4)

* feat: local gouda activity (#9)

* feat: Unified Routing API classic and dutch limit quote requests (#10)

* chore: Rebase 5/26 (#13)

Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>

* feat: add UniswapX to Settings (#7)

* feat: merge upstream 5/31 (#16)

* feat: Upgrade unified-routing-api URL (#15)

* chore: merge upstream 6/2 (#19)

Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Tina <59578595+tinaszheng@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>

* feat: uniswapx gas tooltip (#12)

Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Tina <59578595+tinaszheng@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>

* feat: swap callback (#17)

* feat: gouda gating (#14)

Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Tina <59578595+tinaszheng@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>

* fix: settings e2e test (#22)

* feat: update swap callback to add orders to redux state (#18)

* chore: Fix types for useBestTrade return result (#21)

* feat: gql gouda orders (#20)

* feat: show $0 for gas fee for now (#25)

* chore: Rebase 06/08 (#26)

Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Tina <59578595+tinaszheng@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
Co-authored-by: Brendan Wong <35351983+LunrEclipse@users.noreply.github.com>
Co-authored-by: cartcrom <cartergcromer@gmail.com>
Co-authored-by: clrdo <129212060+clrdo@users.noreply.github.com>
Co-authored-by: clrdo <clrdo@github.com>
Co-authored-by: Eddie Dugan <eddie.dugan@uniswap.org>

* feat: poll on order submit (#23)

* feat: update gouda-sdk to 1.0.0-alpha.3 (#31)

* feat: rename gasUseEstimateUSD for dutch orders (#30)

Co-authored-by: Tina Zheng <tina.s.zheng+github@gmail.com>

* chore: Fix response types (#36)

* feat: Gouda ETH input flow (#29)

Co-authored-by: Eddie Dugan <eddie.dugan@uniswap.org>

* fix: use trade to determine what router label to show (#41)

* feat: open uniswapx modal on click (#32)

* feat: gouda logging new params in swap quote received (#33)

* fix: wrap step ui fixes (#40)

* feat: use BE deadline padding (#46)

* chore: merge 6/23 (#50)

Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
Co-authored-by: Brendan Wong <35351983+LunrEclipse@users.noreply.github.com>
Co-authored-by: cartcrom <cartergcromer@gmail.com>
Co-authored-by: clrdo <129212060+clrdo@users.noreply.github.com>
Co-authored-by: clrdo <clrdo@github.com>
Co-authored-by: Shubham Rasal <95695273+Shubham-Rasal@users.noreply.github.com>
Co-authored-by: Saro Vindigni <sarovindigni@bolket.com>
Co-authored-by: Jordan Frankfurt <<jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: John Short <john.short@CORN-Jack-899.local>

* feat: Gouda opt-in flow request logic (#37)

Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>

* feat: hide slippage and deadline settings when the current trade is gouda (#44)

* feat: use settled order amounts (#45)

* feat: fetch receipt before dispatch (#49)

* fix: updated order popups to launch modal (#48)

* feat: Use slippage value from URA response for UniswapX trades (#51)

* fix: Bump gouda-sdk to match backend response for quotes (#58)

* feat: Change gouda order status URL param from offerer -> swapper (#59)

* feat: disable opt in flow (#57)

* feat: Dont show USD value change for uniswapx trades (#55)

* fix: Don't use WETH as input currency for Classic ETH-in trades (#54)

* feat: Reset to WETH after wrap is complete (#52)

* fix: correct descriptor in UniswapX activity row items (#61)

* fix: align review modal and gouda activity modal (#60)

Co-authored-by: Charles Bachmeier <charles@bachmeier.io>

* feat: Get wrap and approve gas info (#53)

Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>

* fix: restore summary view when wrap is rejected (#66)

* fix: serialize tx receipts before storing (#64)

* fix: Insufficient balance check should read from the right currency (#65)

* feat: update designs for gas tooltips (#67)

* fix: UniswapX gas descriptor boolean (#69)

* chore: Bump conedison for better gas price formatting (#70)

* chore: Switch from gouda-sdk to uniswapx-sdk (#71)

* chore: Rename all variables `gouda` to UniswapX (#72)

* chore: Merge 7/8/23 (#73)

Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
Co-authored-by: Brendan Wong <35351983+LunrEclipse@users.noreply.github.com>
Co-authored-by: cartcrom <cartergcromer@gmail.com>
Co-authored-by: clrdo <129212060+clrdo@users.noreply.github.com>
Co-authored-by: clrdo <clrdo@github.com>
Co-authored-by: Shubham Rasal <95695273+Shubham-Rasal@users.noreply.github.com>
Co-authored-by: Saro Vindigni <sarovindigni@bolket.com>
Co-authored-by: Jordan Frankfurt <<jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: John Short <john.short@CORN-Jack-899.local>
Co-authored-by: Charlie Bachmeier <charlie.bachmeier@Charlies-MacBook-Pro.local>
Co-authored-by: UL Service Account <hello-happy-puppy@users.noreply.github.com>

* chore(conedison): update package (#77)

* feat: add opt-in UI (#68)

* chore: address some todos (#79)

* chore: Rename feature flag from gouda_enabled to uniswapx_enabled (#81)

* feat: Copy changes (#82)

* fix: improve timings on animations for gouda opt-in (#80)

* chore: Use updated URLs (#84)

* chore: Merge 7/14 (#85)

Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
Co-authored-by: Brendan Wong <35351983+LunrEclipse@users.noreply.github.com>
Co-authored-by: cartcrom <cartergcromer@gmail.com>
Co-authored-by: clrdo <129212060+clrdo@users.noreply.github.com>
Co-authored-by: clrdo <clrdo@github.com>
Co-authored-by: Shubham Rasal <95695273+Shubham-Rasal@users.noreply.github.com>
Co-authored-by: Saro Vindigni <sarovindigni@bolket.com>
Co-authored-by: Jordan Frankfurt <<jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: John Short <john.short@CORN-Jack-899.local>
Co-authored-by: Charlie Bachmeier <charlie.bachmeier@Charlies-MacBook-Pro.local>
Co-authored-by: UL Service Account <hello-happy-puppy@users.noreply.github.com>

* remove changes to github actions files

* fix import

* actually revert changes to yml

* remove method export

* feat: Add feature flag for synthetic quotes (#6938)

* fix: use Lingui Trans macro (#6943)

* fix: use trans macro

* add comments

* fix: update updater.tsx (#6942)

* fix: reformat variable to use ms

* move interval definition above getOrderStatus

* lint :)

* revert

* chore: bunch of nits (#6944)

bunch of nits

* fix: translations etc (#6945)

* chore: Remove placeholder signature types (#6937)

remove placeholder

* chore: merge main into branch (#6948)

* fix: Handle Scientific Notation for NFT Collection Activity Prices (#6936)

wrap nft activity price in

* fix: e2e tests (#6941)

* fix: e2e test

* fix: set flag for buy-crypto-modal test

* fix: fund DAI

---------

Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>

---------

Co-authored-by: Charles Bachmeier <charles@bachmeier.io>

* feat: make inputCurrency optional for swapheader (#6947)

* make inputCurrency optional for swapheader

* optional pass in

* fix: function defined twice (#6950)

fix lint

* test: add signatureToActivity undefined tests (#6949)

* fix: update token lists schema (#6951)

fix: update token list schema

* chore: some last nits (#6953)

* refactor: base type

* test: useUserDisabledUniswapX

* chore: simplify useAllSignatures usage

* chore: standard check order

* lint

---------

Co-authored-by: eddie <66155195+just-toby@users.noreply.github.com>
Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
Co-authored-by: Mike Grabowski <grabbou@gmail.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
Co-authored-by: Jack Short <john.short.tj@gmail.com>
Co-authored-by: Jordan Frankfurt <jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: Jordan Frankfurt <jordan@corn-jordan-949.lan>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Nate Wienert <natewienert@gmail.com>
Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
Co-authored-by: Brendan Wong <35351983+LunrEclipse@users.noreply.github.com>
Co-authored-by: cartcrom <cartergcromer@gmail.com>
Co-authored-by: clrdo <129212060+clrdo@users.noreply.github.com>
Co-authored-by: clrdo <clrdo@github.com>
Co-authored-by: Eddie Dugan <eddie.dugan@uniswap.org>
Co-authored-by: marktoda <toda.mark@gmail.com>
Co-authored-by: Shubham Rasal <95695273+Shubham-Rasal@users.noreply.github.com>
Co-authored-by: Saro Vindigni <sarovindigni@bolket.com>
Co-authored-by: Jordan Frankfurt <<jordan@CORN-Jordan-949.frankfurt>
Co-authored-by: John Short <john.short@CORN-Jack-899.local>
Co-authored-by: Charlie Bachmeier <charlie.bachmeier@Charlies-MacBook-Pro.local>
Co-authored-by: UL Service Account <hello-happy-puppy@users.noreply.github.com>
2023-07-14 14:46:59 -07:00
..
e2e feat: additional routing option prototype (#6934) 2023-07-14 14:46:59 -07:00
fixtures feat: additional routing option prototype (#6934) 2023-07-14 14:46:59 -07:00
staging test(staging): add staging-only t9n test (#6899) 2023-07-07 09:41:20 -07:00
support feat: upgrade sdk-core to 3.2.6 and add AVAX (#6757) 2023-07-06 21:44:06 -07:00
utils fix: combine userState with default injected wallet in cypress setup (#6849) 2023-07-06 14:01:13 -07:00
README.md docs(e2e): cypress README (#6523) 2023-06-05 19:38:25 -07:00
tsconfig.json fix: type error in cypress infra (#6700) 2023-06-07 18:16:57 -07:00

e2e testing with Cypress

End-to-end tests are run through Cypress, which runs tests in a real browser. Cypress is a little different than other testing frameworks, and e2e tests are a little different than unit tests, so this directory has its own set of patterns, idioms, and best practices. Not only that, but we're testing against a forked blockchain, not just against typical Web APIs, so we have unique flows that you may not have seen elsewhere.

Running your first e2e tests

Cypress tests run against a local server, so you'll need to run the application locally at the same time. The fastest way to run e2e tests is to use your dev server: yarn start.

Open cypress at the same time with yarn cypress:open. You should do this from another window or tab, so that you can continue to see any typechecking/linting warnings from yarn start.

Cypress opens its own instance of Chrome, with a list of "E2E specs" for you to select. When you're developing locally, you usually only want to run one spec file at a time. Select your spec by clicking on the filename and it will run.

Glossary

spec

Cypress considers each file a separate spec, or collection of tests. Specs are always run as a whole through yarn cypress:open or on the same machine through CI.

Thenable

Cypress queues commands to run in the browser using Thenables, not Promises. For this reason, you should not use async/await syntax in Cypress unless it is wholly-contained in a cy.then function argument.

Writing your first e2e test

For an excellent treatment on tests, check out the Cypress Fundamentals course. While some of that will be paraphrased here, this should be sufficient to get you started:

What is a test?

Cypress tests are just like any other test: you should set up an initial state, execute an action, and verify the action's consequence. This is codified in the AAA (Arrange-Act-Assert) pattern, and you'll see this in most of our tests. In our case, it plays out as:

  1. Arrange: Visit a page, eg cy.visit('/swap'), and set up the state, on the blockchain and the page.
  2. Act: Initiate your action under test, eg initiateSwap()
  3. Assert: Verify that the action has occured, eg // Verify swap has occured

You'll usually see the setup, followed by a newline, followed by assertions with comments stating what they are asserting. Because Cypress tests are translated into user actions, it may be hard to follow the action being described. You should use comments liberally to describe what you are doing and what you intend to test, to make tests easier to read and maintain in the future.

Thinking about tests: queuing up a sequence of commands

Cypress uses Thenables to achieve "command chaining". A test is described as a series of commands, which are only executed once the previous command in the chain has executed.

cy.visit('/swap')
cy.contains('Select token').click()
cy.contains('DAI').click()

In this example, cy.contains('Select token').click() is queued up right away (all the code is synchronous), but it will not execute until /swap has loaded (all the commands are chained); and click() will not execute until Select token has been found.

This becomes more relevant as you work with data on the blockchain, as you'll need to load it at the correct time, after it's been modified by the application:

cy.hardhat().then(async (hardhat) => {
  cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' })
  cy.get('#swap-currency-output .token-amount-input').type('1').should('have.value', '1')
  cy.get('#swap-button').click()
  cy.contains('Confirm swap').click()

  // wait for the transaction to be executed
  cy.get(getTestSelector('web3-status-connected')).should('contain', '1 Pending')
  cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')

  // BAD: This will get the balance _before_ the other queued actions have executed.
  const balance = await hardhat.getBalance(hardhat.wallet, USDC_MAINNET)
  cy.wrap(balance).should('deep.equal', expectedBalance)
})
  cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`, { ethereum: 'hardhat' })
  cy.get('#swap-currency-output .token-amount-input').type('1').should('have.value', '1')
  cy.get('#swap-button').click()
  cy.contains('Confirm swap').click()

  // wait for the transaction to be executed
  cy.get(getTestSelector('web3-status-connected')).should('contain', '1 Pending')
  cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')

  // GOOD: cy.then chains the command so that it runs _after_ executing the swap
  cy.hardhat()
    .then((hardhat) => hardhat.getBalance(hardhat.wallet, USDC_MAINNET))
    .should('deep.equal', expectedBalance)
})

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 }).

The hardhat integration has built-in utilities to let you modify and assert on balances, approvals, and permits, and should be fully typed. Check it out at Uniswap/cypress-hardhat.

Asserting on wallet methods

Wallet methods to hardhat are all aliased. If you'd like to assert that a method was sent to the wallet, you can do so using the method name, prefixed with @:

// Asserts that `eth_sendRawTransaction` was sent to the wallet.
cy.wait('@eth_sendRawTransaction')

Sometimes, you may want a method to fail. In this case, you can stub it, but you should disable logging to avoid spamming the test:

// Stub calls to eth_signTypedData_v4 and fail them
cy.hardhat().then((hardhat) => {
  // Note the closure to keep signTypedDataStub in scope. Using closures instead of variables (eg let) helps prevent misuse of chaining.
  const signTypedDataStub = cy.stub(hardhat.provider, 'send').log(false)
  signTypedDataStub.withArgs('eth_signTypedData_v4).rejects(USER_REJECTION)
  signTypedDataStub.callThrough() // allws other methods to call through to hardhat

  cy.contains('Confirm swap').click()

  // Verify the call occured
  // Note the call to cy.wrap to correctly queue the chained command. Without this, the test would occur before the stub is called.
  cy.wrap(permitApprovalStub).should('be.calledWith', 'eth_signTypedData_v4')

  // Restore the stub
  // note the call to cy.then to correctly queue the chained command. Without this, the stub would be restored immediately.
  cy.then(() => permitApprovalStub.restore())
})

Best practices

Spec / test grouping

Each spec should be specific to one route, not one functional behavior. For example, token-details.test.ts is separated from swap.test.ts.

If a route has different functional behaviors, that route should become a directory name, and its spec should be split. For example, swap.test.ts may be split into swap/swap.test.ts, swap/wrap.test.ts, swap/permit2.test.ts.

This prevents specs from growing too large, which is important because they are always run as a whole locally and on the same machine through CI. If a spec grows too large, it will have a longer local feedback loop, and it will become the bottleneck for CI test runtime.

Similarly, avoid actions outside the scope of your spec, as it will cause total testing time to increase.

Use closures instead of variables

Avoid usage of let, instead assigning a constant. In practice, this means using closures for your variables:

let badVariable

cy.hardhat({ automine: false })
  .then((hardhat) => cy.then(() => hardhat.provider.getBalance(hardhat.wallet.address)))
  .then((initialBalance) => {
    // Do not assign to a variable outside of your closure!
    badVariable = initialBalance // <-- bad!

    // Use initial balance here, within the closure.
  })

cy.get('.class-name').then((el) => {
  // Do not use badVariable here! It may have changed value due to the queued async nature of Cypress.
  expect(el).should('contain', badVariable) // <-- bad!
})

This prevents misuse of a not-yet-initialized variable, or a variable that has changed as the test progresses.

Prefer selecting elements using on-screen text over data-testid attributes

When selecting components (eg with cy.get), prefer defining your selector with visible UI. Sometimes this is not possible (eg if the text is duplicated on-screen), and you'll need to add a data-testid property.

Defining tests using visual fields helps ensure that we don't break them. data-testid may select an element that is only selectable programmatically, and should be used only when necessary, as its use may cover up UI breakages.

You'll still want to use data-testid in cases where the text is rendered in multiple containers and you need to select the correct one, or where the component doesn't render predictable text output.

Avoid branching logic

Do not write tests that rely on if-statements or conditionals. Do not create helper methods which do more than one thing, and rely on branching logic to apply to different but similar situations.

Tests should be readable and simple. Branching logic makes it harder to reason about tests, and may hide otherwise flaky or ill-defined behaviors.

Similarly, you should avoid complicated for-loops. Sometimes, for simple repetition, for-loops are ok.

Avoid spamming the console

It is ok to include logging while you are developing a test, but that logging should be removed if it is not needed to debug (potential) errors.

For example, stubbing a wallet method will result in dumping a hex string (the calldata) to the log. Instead, suppress logging from methods which you know will flood the log.

cy.stub(hardhat.wallet, 'sendTransaction')
  .log(false) // <-- suppresses logs from this stub
  .rejects(new Error('user cancelled'))

Unnecessary logs it makes it harder to reason about a test overall.

Name helper methods using transitive verbs

Name helper methods using "action verbs": expectsThisToHappen, not expectThisToHappen; selectsToken(token: string), not selectAToken(token: string).

This makes your tests read more naturally, and makes it easier to follow given existing should syntax.