Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Add CCTP synpress config #1861

Merged
merged 19 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
135 changes: 135 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,135 @@
import { Wallet, utils } from 'ethers'
import { defineConfig } from 'cypress'
import { 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,
fundUsdc,
getCustomDestinationAddress
} from './tests/support/common'
import specFiles from './tests/e2e/cctp.json'
import { sepolia } from 'wagmi'
fionnachan marked this conversation as resolved.
Show resolved Hide resolved

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 ARB_SEPOLIA_INFURA_RPC_URL = `https://arbitrum-sepolia.infura.io/v3/${INFURA_KEY}`
fionnachan marked this conversation as resolved.
Show resolved Hide resolved

const sepoliaProvider = new StaticJsonRpcProvider(SEPOLIA_INFURA_RPC_URL)
const arbSepoliaProvider = new StaticJsonRpcProvider(ARB_SEPOLIA_INFURA_RPC_URL)

if (!process.env.PRIVATE_KEY_CCTP) {
throw new Error('PRIVATE_KEY_CCTP variable missing.')
}
Comment on lines +62 to +64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is checked twice, see L42-44

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are different keys, but the checks should be grouped together.


// 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()

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

async function fundWallets() {
const userWalletAddress = await userWallet.getAddress()
fionnachan marked this conversation as resolved.
Show resolved Hide resolved
console.log(`Funding wallet ${userWalletAddress}`)

const fundEthHelper = (network: 'sepolia' | 'arbSepolia') => {
return () =>
fundEth({
address: userWalletAddress,
sourceWallet: localWallet,
...(network === 'sepolia'
? {
provider: sepoliaProvider,
amount: ethAmountSepolia
}
: {
provider: arbSepoliaProvider,
amount: ethAmountArbSepolia
})
})
}
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 = SEPOLIA_INFURA_RPC_URL
config.env.ARB_SEPOLIA_INFURA_RPC_URL = ARB_SEPOLIA_INFURA_RPC_URL
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'
}
})
89 changes: 16 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,16 @@ 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')
}),
fundEth({
networkType: 'childChain',
address: userWalletAddress,
parentProvider,
childProvider,
sourceWallet: localWallet
provider: childProvider,
sourceWallet: localWallet,
amount: utils.parseEther('2')
})
])

Expand Down Expand Up @@ -163,7 +141,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 +305,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 +339,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 @@ -22,7 +19,8 @@ import {
findTransactionDetailsCustomDestinationAddress,
findTransactionInTransactionHistory,
findClaimButton,
selectTransactionsPanelTab
selectTransactionsPanelTab,
confirmSpending
} from '../support/commands'
import { NetworkType, NetworkName } from '../support/common'

Expand All @@ -44,9 +42,6 @@ declare global {
logout(): typeof logout
selectTransactionsPanelTab: typeof selectTransactionsPanelTab
openTransactionsPanel: typeof openTransactionsPanel
resetCctpAllowance: typeof resetCctpAllowance
fundUserUsdcTestnet: typeof fundUserUsdcTestnet
fundUserWalletEth: typeof fundUserWalletEth
typeRecursively(text: string): Chainable<JQuery<HTMLElement>>
searchAndSelectToken({
tokenName,
Expand All @@ -68,6 +63,7 @@ declare global {
findTransactionDetailsCustomDestinationAddress: typeof findTransactionDetailsCustomDestinationAddress
findTransactionInTransactionHistory: typeof findTransactionInTransactionHistory
findClaimButton: typeof findClaimButton
confirmSpending: typeof confirmSpending
}
}
}
21 changes: 21 additions & 0 deletions packages/arb-token-bridge-ui/tests/e2e/getCommonSynpressConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export function getCommonSynpressConfig(shouldRecordVideo: boolean) {
return {
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
} as const satisfies Cypress.ConfigOptions
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('Approve token for deposit', () => {
cy.findByRole('button', {
name: /Pay approval fee of/
}).click()
cy.confirmMetamaskPermissionToSpend('1')
cy.confirmSpending({ spendLimit: '1' })
})
})
})
Loading
Loading