Skip to content

Commit

Permalink
test: add CCTP synpress config (#1861)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrstph-dvx authored Sep 2, 2024
1 parent 6c49689 commit 476230d
Show file tree
Hide file tree
Showing 12 changed files with 313 additions and 209 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"lint": "yarn workspace arb-token-bridge-ui lint",
"lint:fix": "yarn workspace arb-token-bridge-ui lint:fix",
"test:e2e": "yarn workspace arb-token-bridge-ui env-cmd --silent --file .e2e.env yarn synpress run --configFile synpress.config.ts",
"test:e2e:cctp": "E2E_CCTP=true yarn test:e2e",
"test:e2e:cctp": "yarn test:e2e --configFile synpress.cctp.config.ts",
"test:e2e:orbit": "E2E_ORBIT=true yarn test:e2e"
},
"resolutions": {
Expand Down
2 changes: 2 additions & 0 deletions packages/arb-token-bridge-ui/.e2e.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ CYPRESS_RECORD_VIDEO=false
# Below key is only used to fund the newly created wallet
PRIVATE_KEY_CUSTOM=b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659

PRIVATE_KEY_CCTP=

# We set up MetaMask ourselves
SKIP_METAMASK_SETUP=true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ export const AdvancedSettings = () => {
onChange={e =>
setDestinationAddress(e.target.value?.toLowerCase().trim())
}
aria-label="Custom Destination Address Input"
/>
{isEOA && (
<button
Expand Down
162 changes: 162 additions & 0 deletions packages/arb-token-bridge-ui/synpress.cctp.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { BigNumber, Wallet, utils } from 'ethers'
import { defineConfig } from 'cypress'
import { Provider, StaticJsonRpcProvider } from '@ethersproject/providers'
import synpressPlugins from '@synthetixio/synpress/plugins'
import logsPrinter from 'cypress-terminal-report/src/installLogsPrinter'
import { getCommonSynpressConfig } from './tests/e2e/getCommonSynpressConfig'
import {
setupCypressTasks,
fundEth,
getCustomDestinationAddress,
NetworkType
} from './tests/support/common'
import specFiles from './tests/e2e/cctp.json'
import { CommonAddress } from './src/util/CommonAddressUtils'
import { ERC20__factory } from '@arbitrum/sdk/dist/lib/abi/factories/ERC20__factory'

export async function fundUsdc({
address, // wallet address where funding is required
provider,
amount,
networkType,
sourceWallet
}: {
address: string
provider: Provider
amount: BigNumber
sourceWallet: Wallet
networkType: NetworkType
}) {
console.log(`Funding USDC ${address} on ${networkType}...`)
const usdcContractAddress =
networkType === 'parentChain'
? CommonAddress.Sepolia.USDC
: CommonAddress.ArbitrumSepolia.USDC

const contract = new ERC20__factory().connect(sourceWallet.connect(provider))
const token = contract.attach(usdcContractAddress)
await token.deployed()
const tx = await token.transfer(address, amount)
await tx.wait()
}

const shouldRecordVideo = process.env.CYPRESS_RECORD_VIDEO === 'true'

const tests = process.env.TEST_FILE
? [process.env.TEST_FILE]
: specFiles.map(file => file.file)

const INFURA_KEY = process.env.NEXT_PUBLIC_INFURA_KEY
if (typeof INFURA_KEY === 'undefined') {
throw new Error('Infura API key not provided')
}

const SEPOLIA_INFURA_RPC_URL = `https://sepolia.infura.io/v3/${INFURA_KEY}`
const sepoliaRpcUrl =
process.env.NEXT_PUBLIC_SEPOLIA_RPC_URL ?? SEPOLIA_INFURA_RPC_URL
const arbSepoliaRpcUrl = 'https://sepolia-rollup.arbitrum.io/rpc'

const sepoliaProvider = new StaticJsonRpcProvider(sepoliaRpcUrl)
const arbSepoliaProvider = new StaticJsonRpcProvider(arbSepoliaRpcUrl)

if (!process.env.PRIVATE_KEY_CCTP) {
throw new Error('PRIVATE_KEY_CCTP variable missing.')
}

if (!process.env.PRIVATE_KEY_USER) {
throw new Error('PRIVATE_KEY_USER variable missing.')
}

// Wallet funded on Sepolia and ArbSepolia with ETH and USDC
const localWallet = new Wallet(process.env.PRIVATE_KEY_CCTP)
// Generate a new wallet every time
const userWallet = Wallet.createRandom()

async function fundWallets() {
const userWalletAddress = userWallet.address
console.log(`Funding wallet ${userWalletAddress}`)

const fundEthHelper = (network: 'sepolia' | 'arbSepolia') => {
return () =>
fundEth({
address: userWalletAddress,
sourceWallet: localWallet,
...(network === 'sepolia'
? {
provider: sepoliaProvider,
amount: ethAmountSepolia,
networkType: 'parentChain'
}
: {
provider: arbSepoliaProvider,
amount: ethAmountArbSepolia,
networkType: 'childChain'
})
})
}
const fundUsdcHelper = (network: 'sepolia' | 'arbSepolia') => {
return () =>
fundUsdc({
address: userWalletAddress,
sourceWallet: localWallet,
amount: usdcAmount,
...(network === 'sepolia'
? {
provider: sepoliaProvider,
networkType: 'parentChain'
}
: {
provider: arbSepoliaProvider,
networkType: 'childChain'
})
})
}

/**
* We need 0.0002 USDC per test (0.0001 for same address and 0.0001 for custom address)
* And in the worst case, we run each tests 3 time
*/
const usdcAmount = utils.parseUnits('0.0006', 6)
const ethAmountSepolia = utils.parseEther('0.01')
const ethAmountArbSepolia = utils.parseEther('0.002')
const ethPromises: (() => Promise<void>)[] = []
const usdcPromises: (() => Promise<void>)[] = []

if (tests.some(testFile => testFile.includes('deposit'))) {
ethPromises.push(fundEthHelper('sepolia'))
usdcPromises.push(fundUsdcHelper('sepolia'))
}

if (tests.some(testFile => testFile.includes('withdraw'))) {
ethPromises.push(fundEthHelper('arbSepolia'))
usdcPromises.push(fundUsdcHelper('arbSepolia'))
}

await Promise.all(ethPromises.map(fn => fn()))
await Promise.all(usdcPromises.map(fn => fn()))
}

export default defineConfig({
...getCommonSynpressConfig(shouldRecordVideo),
e2e: {
async setupNodeEvents(on, config) {
logsPrinter(on)

await fundWallets()

config.env.PRIVATE_KEY = userWallet.privateKey
config.env.PRIVATE_KEY_CCTP = process.env.PRIVATE_KEY_CCTP
config.env.SEPOLIA_INFURA_RPC_URL = sepoliaRpcUrl
config.env.ARB_SEPOLIA_INFURA_RPC_URL = arbSepoliaRpcUrl
config.env.CUSTOM_DESTINATION_ADDRESS =
await getCustomDestinationAddress()

setupCypressTasks(on, { requiresNetworkSetup: false })
synpressPlugins(on, config)
return config
},
baseUrl: 'http://localhost:3000',
specPattern: tests,
supportFile: 'tests/support/index.ts'
}
})
91 changes: 18 additions & 73 deletions packages/arb-token-bridge-ui/synpress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ import { StaticJsonRpcProvider } from '@ethersproject/providers'
import synpressPlugins from '@synthetixio/synpress/plugins'
import { TestWETH9__factory } from '@arbitrum/sdk/dist/lib/abi/factories/TestWETH9__factory'
import { Erc20Bridger } from '@arbitrum/sdk'
import logsPrinter from 'cypress-terminal-report/src/installLogsPrinter'
import { getL2ERC20Address } from './src/util/TokenUtils'
import specFiles from './tests/e2e/specfiles.json'
import cctpFiles from './tests/e2e/cctp.json'
import { contractAbi, contractByteCode } from './testErc20Token'
import {
NetworkName,
checkForAssertions,
generateActivityOnChains,
NetworkType,
fundEth,
setupCypressTasks,
getCustomDestinationAddress,
ERC20TokenSymbol,
ERC20TokenDecimals,
ERC20TokenName
Expand All @@ -32,15 +33,11 @@ import {
defaultL3Network,
registerLocalNetwork
} from './src/util/networks'
import { getCommonSynpressConfig } from './tests/e2e/getCommonSynpressConfig'

let tests: string[]
if (process.env.TEST_FILE) {
tests = [process.env.TEST_FILE]
} else if (process.env.E2E_CCTP) {
tests = cctpFiles.map(file => file.file)
} else {
tests = specFiles.map(file => file.file)
}
const tests = process.env.TEST_FILE
? [process.env.TEST_FILE]
: specFiles.map(file => file.file)

const isOrbitTest = process.env.E2E_ORBIT == 'true'
const shouldRecordVideo = process.env.CYPRESS_RECORD_VIDEO === 'true'
Expand All @@ -58,27 +55,10 @@ const l2WethAddress = isOrbitTest
: defaultL2Network.tokenBridge!.childWeth

export default defineConfig({
userAgent: 'synpress',
retries: shouldRecordVideo ? 0 : 2,
screenshotsFolder: 'cypress/screenshots',
videosFolder: 'cypress/videos',
video: shouldRecordVideo,
screenshotOnRunFailure: true,
chromeWebSecurity: true,
modifyObstructiveCode: false,
scrollBehavior: false,
viewportWidth: 1366,
viewportHeight: 850,
env: {
coverage: false
},
defaultCommandTimeout: 30000,
pageLoadTimeout: 30000,
requestTimeout: 30000,
...getCommonSynpressConfig(shouldRecordVideo),
e2e: {
// @ts-ignore
async setupNodeEvents(on, config) {
require('cypress-terminal-report/src/installLogsPrinter')(on)
logsPrinter(on)
registerLocalNetwork()

if (!ethRpcUrl && !isOrbitTest) {
Expand All @@ -101,18 +81,18 @@ export default defineConfig({
// Fund the userWallet. We do this to run tests on a small amount of ETH.
await Promise.all([
fundEth({
networkType: 'parentChain',
address: userWalletAddress,
parentProvider,
childProvider,
sourceWallet: localWallet
provider: parentProvider,
sourceWallet: localWallet,
amount: utils.parseEther('2'),
networkType: 'parentChain'
}),
fundEth({
networkType: 'childChain',
address: userWalletAddress,
parentProvider,
childProvider,
sourceWallet: localWallet
provider: childProvider,
sourceWallet: localWallet,
amount: utils.parseEther('2'),
networkType: 'childChain'
})
])

Expand Down Expand Up @@ -163,7 +143,7 @@ export default defineConfig({
await generateTestTxForRedeemRetryable()

synpressPlugins(on, config)
setupCypressTasks(on)
setupCypressTasks(on, { requiresNetworkSetup: true })
return config
},
baseUrl: 'http://localhost:3000',
Expand Down Expand Up @@ -327,11 +307,6 @@ async function fundErc20ToChildChain(l1ERC20Token: Contract) {
await depositRec.waitForChildTransactionReceipt(childProvider)
}

async function getCustomDestinationAddress() {
console.log('Getting custom destination address...')
return (await Wallet.createRandom().getAddress()).toLowerCase()
}

async function generateTestTxForRedeemRetryable() {
console.log('Adding a test transaction for redeeming retryable...')

Expand Down Expand Up @@ -366,33 +341,3 @@ async function generateTestTxForRedeemRetryable() {
const receipt = await tx.wait()
return receipt.transactionHash
}

function setupCypressTasks(on: Cypress.PluginEvents) {
let currentNetworkName: NetworkName | null = null
let networkSetupComplete = false
let walletConnectedToDapp = false

on('task', {
setCurrentNetworkName: (networkName: NetworkName) => {
currentNetworkName = networkName
return null
},
getCurrentNetworkName: () => {
return currentNetworkName
},
setNetworkSetupComplete: () => {
networkSetupComplete = true
return null
},
getNetworkSetupComplete: () => {
return networkSetupComplete
},
setWalletConnectedToDapp: () => {
walletConnectedToDapp = true
return null
},
getWalletConnectedToDapp: () => {
return walletConnectedToDapp
}
})
}
10 changes: 3 additions & 7 deletions packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ import {
login,
logout,
openTransactionsPanel,
resetCctpAllowance,
fundUserUsdcTestnet,
fundUserWalletEth,
searchAndSelectToken,
fillCustomDestinationAddress,
typeAmount,
Expand All @@ -23,7 +20,8 @@ import {
findTransactionDetailsCustomDestinationAddress,
findTransactionInTransactionHistory,
findClaimButton,
selectTransactionsPanelTab
selectTransactionsPanelTab,
confirmSpending
} from '../support/commands'
import { NetworkType, NetworkName } from '../support/common'

Expand All @@ -45,9 +43,6 @@ declare global {
logout(): typeof logout
selectTransactionsPanelTab: typeof selectTransactionsPanelTab
openTransactionsPanel: typeof openTransactionsPanel
resetCctpAllowance: typeof resetCctpAllowance
fundUserUsdcTestnet: typeof fundUserUsdcTestnet
fundUserWalletEth: typeof fundUserWalletEth
searchAndSelectToken({
tokenName,
tokenAddress
Expand All @@ -69,6 +64,7 @@ declare global {
findTransactionDetailsCustomDestinationAddress: typeof findTransactionDetailsCustomDestinationAddress
findTransactionInTransactionHistory: typeof findTransactionInTransactionHistory
findClaimButton: typeof findClaimButton
confirmSpending: typeof confirmSpending
}
}
}
Loading

0 comments on commit 476230d

Please sign in to comment.